OA系统代码讲解(前端-业务)
作者:企起期小编 阅读次数:

业务代码讲解

我的日程

要实现我的日程,首先需要做一个日历页面,可以进行日、天、周、月的切换,其次在日历上展示各种日程,也可以直接在日历上边进行日程的添加操作等处理,本次直接借助第三方日程组件进行处理。以下是我的日程的前端代码

<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>

页面效果如下: image.png image.png image.png image.png 从以上代码可以看出,使用了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>
页面效果如下:

image.png 以上代码的主要逻辑是为了实现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>

页面效果如下: image.png 从以上代码可以看出,使用了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>

页面效果如下:image.png 是一个对话框组件,用于展示文件上传的弹窗。: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>

页面效果如下: image.png 从以上代码可以看出,使用了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>

页面效果如下: image.png 从以上代码可以看出,除了使用了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

企起期科技 qiqiqi

联系电话:400-8049-474

联系电话:187-0363-0315

联系电话:199-3777-5101