要实现我的日程,首先需要做一个日历页面,可以进行日、天、周、月的切换,其次在日历上展示各种日程,也可以直接在日历上边进行日程的添加操作等处理,本次直接借助第三方日程组件进行处理。以下是我的日程的前端代码
<template>
<el-card class="aui-card--fill" shadow="never">
<div>
<el-row :gutter="10">
<el-col :span="0">
<ul id="list-group-item">
</ul>
</el-col>
<el-col :span="24">
<FullCalendar ref="fullCalendar" :options="calendarOptions"/>
</el-col>
</el-row>
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getEventList"></add-or-update>
<view-info v-if="viewInfoVisible" ref="viewInfo" @refreshDataList="getEventList"></view-info>
</div>
</el-card></template><script>import FullCalendar from '@fullcalendar/vue'import dayGridPlugin from '@fullcalendar/daygrid'import timeGridPlugin from '@fullcalendar/timegrid'import interactionPlugin, { Draggable } from '@fullcalendar/interaction'import listPlugin from '@fullcalendar/list'import AddOrUpdate from './schedule-add-or-update'import ViewInfo from './schedule-view-info'import * as moment from 'moment'export default {
data () {
return {
addOrUpdateVisible: false, // 新增/更新,弹窗visible状态
viewInfoVisible: false,
calendarOptions: {
plugins: [
dayGridPlugin,
timeGridPlugin,
listPlugin,
interactionPlugin // needed for dateClick
],
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,list'
},
// 设置按钮中文
buttonText: {
today: '今天',
dayGridMonth: '月',
timeGridWeek: '周',
timeGridDay: '日',
list: '列表'
},
customButtons: {
prev: {
// this overrides the prev button
text: 'PREV',
click: () => {
this.prevMethod()
},
},
next: {
// this overrides the next button
text: 'PREV',
click: () => {
this.nextMethod()
},
},
today: {
text: '今天',
click: () => {
this.todayMethod()
},
},
},
eventTextColor: '#000000',
firstDay: '1', // 设置一周开始的第一天
locale: 'zh', // 设置语言
initialView: 'dayGridMonth', // 初始视图
editable: false, // 确定是否可以修改日历上的事件。
selectable: true, // 允许用户通过单击和拖动来突出显示多天或多个时间段。
selectMirror: false, // 是否在用户拖动时绘制“占位符”事件。
dayMaxEvents: true,
weekends: true, // 是否在任何日历视图中包括周六/周日列。
dropAccept: '.list-group-item',
drop: this.drop,
select: this.openAddView,
eventClick: this.openUpdateView,
eventAdd: this.eventAdd,
events: []
}
}
},
components: {
AddOrUpdate, ViewInfo, FullCalendar },
mounted () {
var containerEl = document.getElementById('list-group-item')
// 初始化外部事件
// eslint-disable-next-line no-new
new Draggable(containerEl, {
itemSelector: '.list-group-item'
})
// 获取历史数据
this.getEventList()
},
methods: {
/* 打开添加页面 */
openAddView (selectInfo) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init()
})
},
/* 打开更新页面 */
openUpdateView (selectInfo) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.dataForm.id = selectInfo.event.id this.$refs.addOrUpdate.init()
})
},
/** 获日程 */
getEventList () {
// 获取当前视图日历的范围
const time = this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange this.$http.get(`/oaschedule/schedule/list`, {
params: {
startDate: moment(time.start).format('YYYY-MM-DD HH:mm:ss'), // 视图开始时间
endDate: moment(time.end).format('YYYY-MM-DD HH:mm:ss')// 视图结束时间
}
}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
const data = res.data const arr = []
data.forEach(item => {
const obj = {
id: item.id,
title: item.title,
start: item.start,
end: item.end,
allDay: true,
backgroundColor: item.backgroundColor }
arr.push(obj)
})
this.calendarOptions.events = arr }).catch(() => {
})
},
/** 上个月 */
prevMethod () {
this.$refs.fullCalendar.getApi().prev() // 更新上个月视图
this.getEventList() // 调用获取视图活动数据方法
},
/** 下个月 */
nextMethod () {
this.$refs.fullCalendar.getApi().next() // 更新下个月视图
this.getEventList() // 调用获取视图活动数据方法
},
/** 今天 */
todayMethod () {
this.$refs.fullCalendar.getApi().today() // 更新今天视图
this.getEventList() // 调用获取视图活动数据方法
},
}}</script><style lang="scss" scoped>.fc {
max-width: 1200px;
margin: 0 auto;}/*周六周日背景颜色*/.fc-day-sat{
background: darkred;
color:#0000FF;}.fc-day-sun{
background: darkred;
color:#FF0000 ;}.el-flex-row {
flex-wrap: wrap}.demo-app-main {
flex-grow: 1;
padding: 3em;}</style>页面效果如下:
从以上代码可以看出,使用了Element UI库的常用组件,包括el-card、el-row、el-col等。其中,el-card是一个卡片组件,el-form是一个表单组件,el-input是一个输入框组件,el-row和el-col是用来布局的组件。 还使用了FullCalendar第三方日历组件,使用FullCalendar来创建日历、事件、视图等内容。同时,你也可以了解有关日历、事件和视图的所有属性和方法的详细信息。 methods定义了openAddView、openUpdateView、getEventList、prevMethod、nextMethod、todayMethod等方法。openAddView方法用于打开添加日程页面,openUpdateView方法用于打开修改页面,getEventList方法用于获取日程数据,prevMethod、nextMethod、todayMethod这三个方法用于日期切换时更新数据的操作。以上方法皆通过发送HTTP请求并根据返回结果进行相应的提示和操作。 点击日历框时,弹出新增文件的dialog,代码如下:
<template>
<el-dialog :visible.sync="visible" :title="!dataForm.id ? $t('add') : $t('update')" :close-on-click-modal="false" :close-on-press-escape="false">
<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmitHandle()" :label-width="$i18n.locale === 'en-US' ? '120px' : '120px'">
<el-form-item label="名称" prop="scheduleTitle">
<el-input v-model="dataForm.scheduleTitle" placeholder="名称" maxlength="32"></el-input>
</el-form-item>
<el-form-item label="内容" prop="scheduleContent">
<el-input v-model="dataForm.scheduleContent" placeholder="内容" maxlength="100"></el-input>
</el-form-item>
<el-form-item label="重要程度" prop="scheduleLevel">
<my-select v-model="dataForm.scheduleLevel" dict-type="ScheduleLevelEnum" placeholder="重要程度"></my-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<my-select v-model="dataForm.status" dict-type="status" placeholder="状态" clearable></my-select>
</el-form-item>
<el-form-item label="开始时间" prop="startDate">
<el-date-picker v-model="dataForm.startDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="开始时间"></el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="endDate">
<el-date-picker v-model="dataForm.endDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="结束时间"></el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input type="textarea" v-model="dataForm.remarks" placeholder="备注" maxlength="200"></el-input>
</el-form-item>
</el-form>
<template slot="footer">
<el-button v-if="dataForm.id" icon="el-icon-delete" @click="delSchedule">删除</el-button>
<el-button @click="visible = false" icon="el-icon-close">{{ $t('cancel') }}</el-button>
<el-button type="primary" @click="dataFormSubmitHandle()" icon="el-icon-check">{{ $t('confirm') }}</el-button>
</template>
</el-dialog></template><script>import debounce from 'lodash/debounce'export default {
data () {
return {
visible: false,
dataForm: {
id: '',
scheduleTitle: '',
scheduleContent: '',
scheduleLevel: '',
status: '',
userId: '',
startDate: '',
endDate: '',
remarks: '',
creator: '',
createDate: '',
updater: '',
updateDate: ''
}
}
},
computed: {
dataRule () {
return {
scheduleTitle: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
scheduleContent: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
scheduleLevel: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
status: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
startDate: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
endDate: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
]
}
}
},
methods: {
init () {
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
if (this.dataForm.id) {
this.getInfo()
}
})
},
// 获取信息
getInfo () {
this.$http.get(`/oaschedule/schedule/${this.dataForm.id}`).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.dataForm = {
...this.dataForm,
...res.data }
}).catch(() => {})
},
// 表单提交
dataFormSubmitHandle: debounce(function () {
this.$refs['dataForm'].validate((valid) => {
if (!valid) {
return false
}
this.$http[!this.dataForm.id ? 'post' : 'put']('/oaschedule/schedule/', this.dataForm).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
}).catch(() => {})
})
}, 1000, { 'leading': true, 'trailing': false }),
delSchedule () {
this.$http.delete('/oaschedule/schedule/' + this.dataForm.id).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
}).catch(() => {
})
}
}}</script><style lang="scss" scoped></style>页面效果如下:
以上代码的主要逻辑是为了实现form表单的添加校验功能。以下是部分代码解释: 是一个对话框组件,用于展示文件上传的弹窗。:visible.sync="visible"表示通过visible属性控制对话框的显示和隐藏,:title属性根据dataForm.id的值来确定对话框的标题是"添加"还是"更新",:close-on-click-modal="false"和:close-on-press-escape="false"表示点击对话框外部和按下ESC键时不关闭对话框。
methods中的方法解释: init方法用于初始化对话框,设置对话框的显示状态,并重置表单的字段。 getInfo方法用于获取文件的相关信息(在修改时),发送HTTP请求并根据返回结果进行相应的操作。 delSchedule方法在用户日程的删除功能,发送HTTP请求并根据返回结果进行相应的提示。 dataFormSubmitHandle方法用于表单的提交,先进行表单的校验,然后发送HTTP请求进行数据的添加或更新。
要实现资产入库,首先需要做一个资产入库的列表记录,之后还需要新增、详情等页面的支持。以下是资产入库的前端代码
<template>
<el-card shadow="never" class="aui-card--fill">
<div class="mod-oaassets__assetswarehousing}">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
<el-form-item>
<my-select v-model="dataForm.receiveStatus" dict-type="status" placeholder="验收状态" clearable></my-select>
</el-form-item>
<el-form-item>
<my-select-user ref="mySelectUser" v-model="dataForm.receiveUserId" placeholder="验收人"></my-select-user>
</el-form-item>
<el-form-item>
<el-date-picker v-model="createDateRange" type="datetimerange" clearable :change="changeCreateDateRange()"
range-separator="至" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="getDataList()" icon="el-icon-search">{{ $t('query') }}</el-button>
</el-form-item>
<el-form-item>
<el-button type="info" @click="exportHandle()" icon="el-icon-download">{{ $t('export') }}</el-button>
</el-form-item>
<el-form-item>
<el-button v-if="$hasPermission('oaassets:assetswarehousing:save')" type="primary"
@click="addOrUpdateHandle()" icon="el-icon-plus">{{ $t('add') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button v-if="$hasPermission('oaassets:assetswarehousing:delete')" type="danger" @click="deleteHandle()"
icon="el-icon-delete">{{ $t('deleteBatch') }}
</el-button>
</el-form-item>
</el-form>
<el-table stripe @sort-change="dataListSortChangeHandle" v-loading="dataListLoading" :data="dataList" border
@selection-change="dataListSelectionChangeHandle" style="width: 100%;">
<el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
<el-table-column prop="buyDocNumber" label="申购单号" header-align="center" align="center" min-width="160"
show-overflow-tooltip></el-table-column>
<el-table-column prop="receiveStatus" label="验收状态" header-align="center" align="center" min-width="160"
show-overflow-tooltip>
<template slot-scope="scope">
<el-tag effect="dark" type="info">
{{ $getDictLabel('AssetsWarehousingEnums', scope.row.receiveStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="receiveDate" label="验收日期" header-align="center" align="center" min-width="160"
show-overflow-tooltip></el-table-column>
<el-table-column prop="receiveUserId" label="验收人" header-align="center" align="center" min-width="160"
show-overflow-tooltip></el-table-column>
<el-table-column prop="remarks" label="备注" header-align="center" align="center" min-width="160"
show-overflow-tooltip></el-table-column>
<el-table-column align="createDate" header-align="center" label="申请时间" min-width="160" prop="createDate"
show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('handle')" fixed="right" header-align="center" align="center" width="180">
<template slot-scope="scope">
<el-button v-if="$hasPermission('oaassets:assetswarehousing:info')" type="text" size="small"
@click="viewInfoHandle(scope.row.id)" icon="el-icon-view">{{ $t('info') }}
</el-button>
<el-button v-if="$hasPermission('oaassets:assetswarehousing:update') && scope.row.receiveStatus ===0"
type="text" size="small" @click="addOrUpdateHandle(scope.row.id)" icon="el-icon-edit">
{{ $t('update') }}
</el-button>
<el-button v-if="$hasPermission('oaassets:assetswarehousing:delete') && scope.row.receiveStatus ===0"
type="text" size="small" @click="deleteHandle(scope.row.id)" icon="el-icon-delete">
{{ $t('delete') }}
</el-button>
<el-button v-if="scope.row.receiveStatus ===0" icon="el-icon-delete" size="small"
type="text" @click="submitApprovalHandle(scope.row.id)">提交 </el-button>
<el-button v-if="scope.row.receiveStatus ===1" icon="el-icon-delete" size="small"
type="text" @click="approvalHandle(scope.row.id)">审批 </el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="page"
:page-sizes="[10, 20, 50, 100]"
:page-size="limit"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="pageSizeChangeHandle"
@current-change="pageCurrentChangeHandle">
</el-pagination>
<!-- 弹窗, 新增 / 修改 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
<view-info v-if="viewInfoVisible" ref="viewInfo" @refreshDataList="getDataList"></view-info>
</div>
</el-card></template><script>import mixinViewModule from '@/mixins/view-module'import AddOrUpdate from './assetswarehousing-add-or-update'import ViewInfo from './assetswarehousing-view-info'import dateUtil from '@/utils/dateUtil'export default {
mixins: [mixinViewModule],
data () {
return {
mixinViewModuleOptions: {
getDataListURL: '/oaassets/assetswarehousing/page',
getDataListIsPage: true,
createdIsNeed: false,
exportURL: '/oaassets/assetswarehousing/export',
deleteURL: '/oaassets/assetswarehousing',
deleteIsBatch: true
},
dataForm: {
receiveStatus: '',
receiveUserId: '',
createDateBegin: '',
createDateEnd: ''
},
createDateRange: dateUtil.getDefaultDateRangeStringArray('nearlyMonth', 'YYYY-MM-DD 00:00:00')
}
},
components: {
AddOrUpdate, ViewInfo },
mounted () {
this.createDateRange = dateUtil.getDefaultDateRangeStringArray('nearlyMonth', 'YYYY-MM-DD 00:00:00')
this.changeCreateDateRange()
this.getDataList()
},
methods: {
changeCreateDateRange () {
if (this.createDateRange && this.createDateRange.length !== 0) {
this.dataForm.createDateBegin = this.createDateRange[0]
this.dataForm.createDateEnd = this.createDateRange[1]
} else {
this.dataForm.createDateBegin = null
this.dataForm.createDateEnd = null
}
},
submitApprovalHandle (id) {
this.$http.get(`/oaassets/assetswarehousing/submitApprovalHandle/` + id).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.getDataList()
}).catch(() => {
})
},
approvalHandle (id) {
this.$http.get(`/oaassets/assetswarehousing/approvalHandle/` + id).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.getDataList()
}).catch(() => {
})
}
}}</script><style lang="scss" scoped></style>页面效果如下:
从以上代码可以看出,使用了Element UI库的常用组件,包括el-card、el-form、el-input、el-row、el-col、el-button、el-table、el-table-column和el-pagination等。其中,el-card是一个卡片组件,el-form是一个表单组件,el-input是一个输入框组件,el-row和el-col是用来布局的组件,el-button是一个按钮组件,el-table是一个表格组件,el-table-column是表格的列组件,el-pagination是一个分页组件。 是一个表单组件,用于展示文件搜索的表单。@keyup.enter.native="getDataList()"表示在按下回车键时触发相关搜索的方法。 和是用于布局的组件,:span属性表示占据的列数,:gutter属性表示列之间的间隔。 用于展示文件列表。:data属性绑定了dataList属性,表示表格的数据来源。 中,使用了组件定义了表格的列。prop属性表示列对应的数据字段,label属性表示列的标题。 methods定义了两个方法submitApprovalHandle和approvalHandle。submitApprovalHandle方法用于触发表单的提交启动流程操作,发送HTTP请求并根据返回结果进行相应的提示和操作。approvalHandle方法用于流程的审批操作。 点击新增按钮时,弹出新增文件的dialog,代码如下:
<template>
<el-dialog :close-on-click-modal="false" :close-on-press-escape="false"
:title="!dataForm.id ? $t('add') : $t('update')"
:visible.sync="visible">
<el-form ref="dataForm" :label-width="$i18n.locale === 'en-US' ? '120px' : '120px'" :model="dataForm"
:rules="dataRule"
@keyup.enter.native="dataFormSubmitHandle()">
<el-form-item label="申购单号" prop="buyDocNumber">
<el-input v-model="dataForm.buyDocNumber" placeholder="申购单号"
@blur="getAssetsListInfo(dataForm.buyDocNumber)"></el-input>
</el-form-item>
<el-form-item label="资产" prop="assetsList">
<template>
<el-table :data="dataForm.assetsList" border style="width: 98%">
<el-table-column label="资产名称" prop="assetsName">
</el-table-column>
<el-table-column label="编号" prop="assetsCode">
</el-table-column>
<el-table-column label="规格" prop="assetsNorm">
</el-table-column>
<el-table-column label="入库数量" prop="num">
<template slot-scope="scope">
<el-input-number v-model="scope.row.num" min="1" placeholder="入库数量" size="small"></el-input-number>
</template>
</el-table-column>
</el-table>
</template>
</el-form-item>
<el-form-item label="验收日期" prop="receiveDate">
<el-date-picker v-model="dataForm.receiveDate" placeholder="验收日期" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input type="textarea" v-model="dataForm.remarks" maxlength="200" placeholder="备注"></el-input>
</el-form-item>
</el-form>
<template slot="footer">
<el-button icon="el-icon-close" @click="visible = false">{{ $t('cancel') }}</el-button>
<el-button icon="el-icon-check" type="primary" @click="dataFormSubmitHandle()">{{ $t('confirm') }}</el-button>
<el-button icon="el-icon-check" type="primary" @click="submitHandle()">提交</el-button>
</template>
</el-dialog></template><script>import debounce from 'lodash/debounce'export default {
data () {
return {
visible: false,
dataForm: {
id: '',
buyDocNumber: '',
receiveStatus: '',
receiveDate: '',
receiveUserId: '',
remarks: '',
creator: '',
createDate: '',
updater: '',
updateDate: '',
assetsList: []
}
}
},
computed: {
dataRule () {
return {
receiveStatus: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
receiveDate: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
assetsList: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
receiveUserId: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
buyDocNumber: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
],
}
}
},
methods: {
init () {
this.visible = true
this.$nextTick(() => {
this.$refs['dataForm'].resetFields()
if (this.dataForm.id) {
this.getInfo()
}
})
},
getAssetsListInfo (buyDocNumber) {
if (buyDocNumber === null || buyDocNumber === undefined || buyDocNumber === ''){
return
}
this.$http.get(`/oaassets/assetsbuy/getByDocNumber/` + buyDocNumber).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data === null || res.data.assetsList === null
|| res.data.assetsList === undefined || res.data.assetsList.length === 0) {
return this.$message.error('未查询到采购数据,请检查采购单号是否正确!')
}
this.dataForm.assetsList = res.data.assetsList }).catch(() => {
})
},
// 获取信息
getInfo () {
this.$http.get(`/oaassets/assetswarehousing/${this.dataForm.id}`).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.dataForm = {
...this.dataForm,
...res.data }
}).catch(() => {
})
},
// 表单提交
dataFormSubmitHandle: debounce(function () {
this.$refs['dataForm'].validate((valid) => {
if (!valid) {
return false
}
this.$http[!this.dataForm.id ? 'post' : 'put']('/oaassets/assetswarehousing/', this.dataForm).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message({
message: this.$t('prompt.success'),
type: 'success',
duration: 500,
onClose: () => {
this.visible = false
this.$emit('refreshDataList')
}
})
}).catch(() => {
})
})
}, 1000, { 'leading': true, 'trailing': false }),
submitHandle(){
this.dataForm.receiveStatus = 1;
this.dataFormSubmitHandle();
}
}}</script><style lang="scss" scoped></style>页面效果如下:
是一个对话框组件,用于展示文件上传的弹窗。:visible.sync="visible"表示通过visible属性控制对话框的显示和隐藏,:title属性根据dataForm.id的值来确定对话框的标题是"添加"还是"更新",:close-on-click-modal="false"和:close-on-press-escape="false"表示点击对话框外部和按下ESC键时不关闭对话框。 是一个表单组件,用于表单输入。 methods定义了init、getAssetsListInfo、getInfo、dataFormSubmitHandle等放。 init方法用于初始化对话框,设置对话框的显示状态。 getAssetsListInfo用于获取关联的资产申购单,发送HTTP请求并根据返回结果进行相应的操作。 getInfo方法用于编辑是获取当前表单的信息,发送HTTP请求并根据返回结果进行相应的操作。 dataFormSubmitHandle方法是表单提交的处理函数,使用了debounce函数来防止抖动。this.http.post方法向服务器发送登录请求,根据服务器返回的结果进行处理,如果登录成功则将token保存到Cookies中,并跳转到首页,否则重新获取验证码并显示错误信息。
要实现报销统计,首先需要考虑统计的方式,可以按时间、部门、类型来进行统计,本次直接借助第三方图表组件echars进行处理。以下是报销统计的前端代码
<template>
<div class="mod-oareimburse__reimbursestatistics}">
<el-card class="box-card" shadow="hover">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="searchData()">
<el-form-item>
<el-date-picker v-model="defDate" type="datetimerange" @change="changeDate"
range-separator="至" value-format="yyyy-MM-dd" format="yyyy-MM-dd" start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button @click="searchData()" icon="el-icon-search">{{ $t('query') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<el-row :gutter="24" type="flex" class="el-flex-row">
<el-col :span="24">
<el-card class="box-card" shadow="hover">
<div class="custHead">
<span>按时间</span>
</div>
<div id="chart1" style="height: 240px;"></div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="24" type="flex" class="el-flex-row">
<el-col :span="12">
<el-card class="box-card" shadow="hover">
<div class="custHead">
<span>按部门</span>
</div>
<div id="chart2" style="height: 240px;"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="box-card" shadow="hover">
<div class="custHead">
<span>按类型</span>
</div>
<div id="chart3" style="height: 240px;"></div>
</el-card>
</el-col>
</el-row>
</div></template><script>
import mixinViewModule from '@/mixins/view-module'
import dateUtil from '@/utils/dateUtil'
export default {
mixins: [mixinViewModule],
created() {
const start =dateUtil.getNowDate(1,"YYYY-MM-DD")//获取当前的日期
this.defDate[0] = start;
const end =dateUtil.getNowDate(0,"YYYY-MM-DD")//获取当前的日期
this.defDate[1] = end;
this.dataForm.startDate = start this.dataForm.endDate = end //将转换完的正确格式的结束时间赋值到timeCycle数组的第二项
Promise.all([]).then(() => {
this.searchData()
})
},
data() {
return {
mixinViewModuleOptions: {
createdIsNeed: false
},
defDate:['2022-06-02', '2022-07-02'],
dataForm: {
startDate: '',
endDate: ''
}
}
},
methods: {
changeDate:function (){
this.dataForm.startDate = this.defDate[0]
this.dataForm.endDate = this.defDate[1]
},
searchData: function () {
this.getChart1List()
this.getChart2List()
this.getChart3List()
},
getChart1List: function () {
let myChart = this.$echarts.init(document.getElementById('chart1'))
myChart.clear()
let option = [{
color: this.baseColor,
title: {
text: ''
},
toolbox: {
show: true,
right: 7,
iconStyle: {
normal: {
borderColor: this.darkSetting ? '#ccc' : '#333'
}
},
feature: {
restore: {
show: true,
title: ' '
},
saveAsImage: {
show: true,
title: ' '
}
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '30',
right: '30',
top: '70',
bottom: '10',
containLabel: true
},
legend: {
data: []
},
xAxis: {
type: 'category',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: this.darkSetting ? '#6499fb' : '#333'
}
},
data: []
},
yAxis: [
{
type: 'value',
position: 'left',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: this.darkSetting ? '#6499fb' : '#333'
}
},
minInterval: 1,
name: '金额'
}
],
series: [
{
type: 'line',
name: '金额',
// areaStyle: {},
data: []
}]
}]
this.$http.get('/oareimburse/reimbursestatistics/chart1/list', {
params: {
...this.dataForm }
}).then(({data: res}) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
let xData = []
let v_totalAmount = []
res.data.forEach(item => {
xData.push(item.date)
v_totalAmount.push(item.totalAmount)
})
option[0].xAxis.data = xData
option[0].series[0].data = v_totalAmount
myChart.setOption(option[0])
}
}).catch(() => {
})
},
getChart2List: function () {
let that = this
let myChart = this.$echarts.init(document.getElementById('chart2'))
let option = [{
color: this.baseColor,
tooltip: {
trigger: 'item',
position: 'inside',
formatter: function (params) {
let res = ''
res += params.data.name
res += '<br/>' + params.data.value return res }
},
grid: {
left: '5',
right: '5',
top: '5',
bottom: '5',
containLabel: true
},
legend: {
type: 'scroll',
height: 220,
orient: 'vertical',
left: 10,
data: []
},
toolbox: {
show: true,
right: 7,
iconStyle: {
normal: {
borderColor: this.darkSetting ? '#ccc' : '#333'
}
},
feature: {
restore: {
show: true,
color: this.darkSetting ? '#ccc' : '#333',
title: ' '
},
saveAsImage: {
show: true,
title: ' '
}
}
},
series: [{
name: '',
type: 'pie',
breadcrumb: {show: false},
visibleMin: 1,
roam: false,
nodeClick: false,
data: []
}]
}]
this.$http.get('/oareimburse/reimbursestatistics/chart2/list', {
params: {
...this.dataForm }
}).then(({data: res}) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
let legendData = []
let itemData = []
res.data.forEach(item => {
let chartData = {}
legendData.push({name: item.deptName})
chartData.name = item.deptName
chartData.value = item.totalAmount
itemData.push(chartData)
})
option[0].legend.data = legendData
option[0].series[0].data = itemData
myChart.setOption(option[0])
}
}).catch(() => {
})
},
getChart3List: function () {
let that = this
let myChart = this.$echarts.init(document.getElementById('chart3'))
let option = [{
color: this.baseColor,
tooltip: {
trigger: 'item',
position: 'inside',
formatter: function (params) {
let res = ''
res += params.data.name
res += '<br/>' + params.data.value return res }
},
grid: {
left: '5',
right: '5',
top: '5',
bottom: '5',
containLabel: true
},
legend: {
type: 'scroll',
height: 220,
orient: 'vertical',
left: 10,
data: []
},
toolbox: {
show: true,
right: 7,
iconStyle: {
normal: {
borderColor: this.darkSetting ? '#ccc' : '#333'
}
},
feature: {
restore: {
show: true,
color: this.darkSetting ? '#ccc' : '#333',
title: ' '
},
saveAsImage: {
show: true,
title: ' '
}
}
},
series: [{
name: '',
type: 'pie',
breadcrumb: {show: false},
visibleMin: 1,
roam: false,
nodeClick: false,
data: []
}]
}]
this.$http.get('/oareimburse/reimbursestatistics/chart3/list', {
params: {
...this.dataForm }
}).then(({data: res}) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
if (res.data) {
let legendData = []
let itemData = []
res.data.forEach(item => {
let chartData = {}
legendData.push({name: item.typeName})
chartData.name = item.typeName
chartData.value = item.reimburseAmount
itemData.push(chartData)
})
option[0].legend.data = legendData
option[0].series[0].data = itemData
myChart.setOption(option[0])
}
}).catch(() => {
})
},
}
}
</script>
<style lang="scss" scoped>
.el-flex-row {
flex-wrap: wrap }
</style>页面效果如下:
从以上代码可以看出,使用了Element UI库的常用组件,包括el-card、el-form、el-row、el-col、el-date-picker等。其中,el-card是一个卡片组件,el-form是一个表单组件,el-date-picker是一个日期输入框组件,el-row和el-col是用来布局的组件。 还使用了echars第三方t图表组件,使用echars来创建曲线图、饼状图等图表内容。同时,你也可以了解其他图表的用法和详细信息。 methods定义了changeDate、searchData、getChart1List、getChart2List、getChart3List等方法。changeDate方法用改变查询时间,searchData用于刷新图表,getChart1List方法用于图表1的创建和数据组装,getChart2List方法用于图表2的创建和数据组装,getChart3List方法用于图表3的创建和数据组装。以上方法皆通过发送HTTP请求并根据返回结果进行相应的提示和操作。
要实现文档管理,首先要考虑以一个什么样的效果呈现,可以复杂,也可以简单的用树形+列表实现,在项目当中为了更美观好用,我们选择借助第三方组件进行处理。以下是文档管理的前端代码
<template>
<div id="app">
<wlExplorer
ref="wl-explorer-cpt"
:header-dropdown="headerHandle"
:upload-options="uploadOptions"
:columns="file_table_columns"
:all-path="all_folder_list"
:is-folder-fn="isFolderFn"
:folderType="rource_type"
:data="file_table_data"
:props="explorer_prop"
:uploadUrl="uploadUrl"
size="small"
@handleFolder="handleFolder"
@upload="fileUpload"
@uploadSuccess="uploadSuccess"
@download="download"
@search="fileSearch"
@del="fileDel"
@move="moveUpdate"
>
<fadeIn v-show="fade.folder">
<h3 class="edit-header">
<p>{{folder_form.Id?'编辑':'新增'}}文件夹</p>
</h3>
<el-scrollbar class="scroll">
<el-form
size="medium"
ref="folder_form"
label-position="top"
:model="folder_form"
:rules="folder_rules"
class="folder_form rule-form"
@keyup.enter.native="submitFolderFrom('folder_form')"
>
<el-form-item label="文件路径" prop="ParentId">
<WlTreeSelect class="u-full"
nodeKey="Id"
placeholder="请选择文件路径"
:props="tree_select_prop"
:data="tree_folder_list"
v-model="folder_form.ParentId"
></WlTreeSelect>
</el-form-item>
<el-form-item label="文件夹名称" prop="Name">
<el-input v-model="folder_form.Name" placeholder="请输入文件夹名称"></el-input>
</el-form-item>
<el-form-item label="备注说明" prop="Describe">
<el-input :rows="3"
type="textarea"
v-model="folder_form.Describe"
placeholder="请输入备注说明"
></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
<div class="submit-btn-box">
<submit-btn @btn="submitFolderFrom('folder_form')" :status="load.folder"></submit-btn>
<el-button size="medium" @click="fade.folder = false">取消</el-button>
</div>
</fadeIn>
</wlExplorer>
</div></template><script>import Cookies from 'js-cookie'import fadeIn from "@/components/document/fade-in"; // 导入文件管理器import submitBtn from "@/components/document/submit-btn"; // 导入防抖提交组件import { closeOtherLayout, arrayToTree } from "@/utils";export default {
inject: ['refresh'],
name: "app",
components: {
fadeIn,
submitBtn },
data() {
const _GB = 1024 * 1024;
// const vm = this;
return {
uploadUrl:"",
load: {
folder: false,
}, // loading管理
fade: {
folder: false,
}, // 弹出类视图管理
headerHandle: [], // 头部按钮更多操作-自定义权限
file_table_columns: [
{
label: "名称",
prop: "name",
minWidth: 120,
},
{
label: "修改日期",
align: "center",
width: 120,
formatter(row) {
return row.createDate;
},
},
{
label: "创建日期",
align: "center",
width: 120,
formatter(row) {
return row.createDate;
},
},
{
label: "描述",
minWidth: 100,
formatter(row) {
return row.remarks || "-";
},
},
], // 自定义表格列
file_table_data: [], // 表格数据
all_folder_list: [], // 所有文件夹列表
tree_folder_list: [], // 树形文件夹列表
type: {
folder: 1,
img: 2,
video: 3,
other: 4,
}, // 文件类型
rource_type: {
self: 1, // 自建
}, // 数据来源类型
explorer_prop: {
name: "name",
match: "name",
splic: true,
suffix: "suffix",
pathId: "id",
pathPid: "pid",
pathName: "name",
pathChildren: "children", // String 路径数据 children字段
pathConnector: "\\", // String 路径父子数据拼接连接符,默认为'\'
pathParents: "parentIds", // String 路径数据所有直系祖先节点自增长identityId逗号拼接
pathIdentityId: "id", // String 路径数据自增长id
}, // 文件管理器配置项
path: {}, // 路径数据
folder_form: {
ParentId: "",
Name: "",
preview: [],
handle: [],
Describe: "",
}, // 文件夹表单
folder_rules: {
ParentId: [
{ required: true, message: "请选择文件路径", trigger: "blur" },
],
Name: [
{ required: true, message: "请填写文件夹名称", trigger: "blur" },
],
}, // 文件夹表单验证
child_act_saved: {}, // 存储子组件数据,用于编辑更新
tree_select_prop: {
label: "name",
children: "children",
}, // 树形下拉框配置项
uploadOptions: {
aa: 1212,
}, // 上传文件附加参数
};
},
methods: {
/**
* @name 上传文件提交操作
*/
fileUpload(file, cb) {
this.uploadOptions.pid = 0
if (file.pathId != '' && file.pathId != undefined){
this.uploadOptions.pid = file.pathId;
}
cb();
},
/**
* @name 上传文件回调
*/
uploadSuccess(res){
res.data.pid = this.uploadOptions.pid this.saveDoc(res.data)
},
saveDoc(fileData){
this.$http.post(`/oadocument/document/saveDoc`, fileData).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.refresh()
}).catch(() => {})
},
download(data, func) {
if (Number(data[0].type) === this.type.folder){
this.$message.error("暂不支持文件夹下载")
return
}
window.open(data[0].ossList[0].url)
},
/**
* 根据关键词搜索文件
* file: Object 文件属性
* update: Boolean 数据是否需要更新(不需要表示已存在)
*/
fileSearch(file, update) {
if (update) {
this.path = file;
this.getFileList();
}
},
// 获取文件列表
getFileList() {
this.$http.get(`/oadocument/document/list`,{
params: this.path }).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.file_table_data = res.data || [];
}).catch(() => {})
},
/**
* 编辑文件夹
* act:Object 当前选中文件夹
* type:String 操作类型 add添加edit编辑
* file:Object 当前路径信息
*/
handleFolder(act, type, file) {
this.path = file;
this.fade.folder = true;
if (type === "add") {
this.$refs["folder_form"].resetFields();
this.folder_form.Id = "";
this.folder_form.ParentId = file.id;
return;
}
this.child_act_saved = act;
this.folder_form = { ...act };
},
// 提交文件夹表单
submitFolderFrom(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.load.folder = true;
this.$http.post(`/oadocument/document/saveOrUpdateFolder`,this.folder_form).then(({ data: res }) => {
this.load.folder = false;
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message.success(this.$t('prompt.success'))
this.fade.folder = false;
this.refresh()
}).catch(() => {})
} else {
return false;
}
});
},
// 删除文件
fileDel(data) {
let cannot_del_data = []; // 收集不可删除数据
let normal_data_file = []; // 收集可删除文件
let normal_data_folder = []; // 收集可删除文件夹
data.forEach((i) => {
i.RourceType !== this.rource_type.self ? cannot_del_data.push(i) // 不可删除数据
: i.Type === this.type.folder ? normal_data_folder.push(i.Id) // 可删除文件夹
: normal_data_file.push(i.Id); // 可删除文件
});
// 不可删除数据进行提示
if (cannot_del_data.length > 0) {
let _msg = '<p class="title">以下文件或文件夹不可删除,已自动过滤</p>';
cannot_del_data.forEach((i) => {
_msg += `<p class="msg">${i.Name}</p>`;
});
this.$message({
dangerouslyUseHTMLString: true,
showClose: true,
message: _msg,
type: "warning",
customClass: "mulit-msg",
});
}
if (normal_data_folder.length === 0 && normal_data_file.length === 0)
return;
// 可删除数据正常删除
let _data = {
FolderIds: normal_data_folder,
FolderFileIds: normal_data_file,
};
},
// 获取所有文件夹
getAllFolders() {
this.$http.get(`/oadocument/document/getFolderList`).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.all_folder_list = res.data || [];
let _list = [...this.all_folder_list];
let options = {
id: this.explorer_prop.pathId,
pid: this.explorer_prop.pathPid,
children: "children",
};
let root_node = {
children: [],
id: '0',
name: '根目录',
pid: '-1',
remarks:'测试',
type: 1
};
_list.push(root_node)
this.tree_folder_list = arrayToTree(_list,options)
console.log(this.tree_folder_list)
}).catch(() => {})
},
// 判断是否文件夹函数
isFolderFn(row) {
return Number(row.type) === this.type.folder;
},
moveUpdate(to, data, load){
data[0].pid=to.id this.$http.post(`/oadocument/document/moveUpdate`,data[0]).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.$message.success(this.$t('prompt.success'))
this.refresh()
}).catch(() => {})
}
},
created() {
this.closeOtherLayout = closeOtherLayout;
this.getAllFolders();
this.getFileList();
this.uploadUrl = `${window.SITE_CONFIG['apiURL']}/sys/oss/upload?token=${Cookies.get('token')}`
},};</script><style>#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
position: absolute;
top: 0;
left: 0;
padding: 25px;
width: 100%;
height: 100%;
background: #f7f7f7;
box-sizing: border-box;}</style>页面效果如下:
从以上代码可以看出,除了使用了Element UI库的常用组件外,还是用了一个第三方的组件wlExplorer,该组件是一个基于Vue和ElementUi的文件管理器插件,提供类似某云盘操作台的功能。 methods定义了fileUpload、uploadSuccess、download、fileSearch、getFileList、handleFolder、submitFolderFrom、fileDel、getAllFolders、isFolderFn等方法。fileUpload方法用于上传文件提交操作,uploadSuccess方法用于上传文件回调,download方法用于文件额下载,fileSearch方法用于根据关键词搜索文件的操作,getFileList方法用于初始化页面获取文件列表的操作,handleFolder方法用于编辑文件夹的操作,submitFolderFrom方法用于提交文件夹表单的操作,fileDel方法用于删除文件的操作,getAllFolders方法用于获取所有文件夹的操作,fileUpload方法用于上传文件提交操作,isFolderFn方法用于判断是否文件夹函数,fileUpload方法用于上传文件提交操作。以上方法皆通过发送HTTP请求并根据返回结果进行相应的提示和操作。
扫码关注不迷路!!!
郑州升龙商业广场B座25层
service@iqiqiqi.cn
联系电话:187-0363-0315
联系电话:199-3777-5101