Explorar o código

花名册-人员选择组件封装

lizhenhao %!s(int64=2) %!d(string=hai) anos
pai
achega
258b1a7a46

+ 407 - 0
src/views/common/RosterSelectDialog.vue

@@ -0,0 +1,407 @@
+<!--花名册-人员选择  dialog 组件-->
+<template>
+  <div>
+    <el-dialog
+    title="花名册-人员选择"
+    width="1000px"
+    :close-on-click-modal="false"
+    :append-to-body="true"
+     v-dialogDrag
+     class="rosterDialog"
+    :visible.sync="visible">
+    <el-container style="height: 500px">
+      <el-aside width="200px">
+
+        <el-card class="org">
+          <div slot="header" class="clearfix">
+            <el-input
+              placeholder="请输入组织机构过滤"
+              size="small"
+              v-model="filterText">
+            </el-input>
+          </div>
+           <el-tree
+            :data="officeTreeData"
+            :props="{
+                  value: 'id',             // ID字段名
+                  label: 'name',         // 显示名称
+                  children: 'children'    // 子级字段名
+                }"
+            default-expand-all
+            highlight-current
+            node-key="id"
+            :render-content="renderContent"
+            :filter-node-method="filterNode"
+            :expand-on-click-node="false"
+            @node-click="handleNodeClick"
+            ref="officeTree">
+          </el-tree>
+        </el-card>
+      </el-aside>
+
+    <el-container>
+      <el-header style="text-align: left; font-size: 12px;height:30px">
+        <el-form size="small" :inline="true" ref="searchForm" :model="searchForm" @keyup.enter.native="refreshList()" @submit.native.prevent>
+            <el-form-item prop="name">
+              <el-input size="small" v-model="searchForm.name" placeholder="姓名" clearable></el-input>
+            </el-form-item>
+
+            <el-form-item>
+              <el-button  type="primary" @click="refreshList()" size="small" icon="el-icon-search">查询</el-button>
+              <el-button @click="resetSearch()" size="small" icon="el-icon-refresh-right">重置</el-button>
+            </el-form-item>
+          </el-form>
+      </el-header>
+
+      <el-main>
+        <el-table
+          :data="dataList"
+          v-loading="loading"
+          size="small"
+          border
+          ref="rosterTable"
+          @selection-change="selectionChangeHandle"
+          @sort-change="sortChangeHandle"
+          height="calc(100% - 40px)"
+          style="width: 100%;">
+          <el-table-column
+            header-align="center"
+            align="center"
+            v-if="limit <= 1"
+            width="50">
+              <template slot-scope="scope">
+                  <el-radio :label="scope.row.id" :value="dataListAllSelections[0]&&dataListAllSelections[0].id" @change.native="getTemplateRow(scope.$index,scope.row)"><span></span></el-radio>
+              </template>
+          </el-table-column>
+          <el-table-column
+            type="selection"
+            header-align="center"
+            v-if="limit > 1"
+            align="center"
+            width="50">
+          </el-table-column>
+          <el-table-column
+            prop="headshotLsUrl"
+            header-align="center"
+            align="center"
+            label="头像">
+            <template slot-scope="scope">
+              <img :src="scope.row.headshotLsUrl === ''?'/static/img/avatar.png':scope.row.headshotLsUrl" style="height:35px"/>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="name"
+            header-align="center"
+            align="center"
+            sortable="custom"
+            min-width="90"
+            label="姓名">
+          </el-table-column>
+          <el-table-column
+            prop="officeName"
+            header-align="center"
+            align="center"
+            sortable="custom"
+            min-width="110"
+            label="所属部门">
+          </el-table-column>
+        </el-table>
+        <el-pagination
+          @size-change="sizeChangeHandle"
+          @current-change="currentChangeHandle"
+          :current-page="pageNo"
+          :page-sizes="[5, 10, 50, 100]"
+          :page-size="pageSize"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper">
+        </el-pagination>
+      </el-main>
+    </el-container>
+
+    <el-aside width="200px">
+      <el-tag
+        :key="tag.id"
+        v-for="tag in dataListAllSelections"
+        closable
+        :disable-transitions="false"
+        @close="del(tag)">
+        {{tag.name}}
+      </el-tag>
+  </el-aside>
+</el-container>
+     <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="visible = false" icon="el-icon-circle-close">关闭</el-button>
+      <el-button size="small" type="primary" icon="el-icon-circle-check" @click="doSubmit()">确定</el-button>
+    </span>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+  export default {
+    data () {
+      return {
+        searchForm: {
+          name: '',
+          companyId: '',
+          officeId: ''
+        },
+        filterText: '',
+        dataListAllSelections: [],   // 所有选中的数据包含跨页数据
+        dataListSelections: [],
+        idKey: 'id', // 标识列表数据中每一行的唯一键的名称(需要按自己的数据改一下)
+        dataList: [],
+        dynamicTags: [],
+        officeTreeData: [],
+        pageNo: 1,
+        pageSize: 10,
+        total: 0,
+        orders: [],
+        loading: false,
+        visible: false
+      }
+    },
+    props: {
+      selectData: {
+        type: Array,
+        default: () => { return [] }
+      },
+      limit: {
+        type: Number,
+        default: 999999
+      }
+    },
+    watch: {
+      filterText (val) {
+        this.$refs.officeTree.filter(val)
+      }
+    },
+    methods: {
+      init () {
+        this.visible = true
+        this.$nextTick(() => {
+          this.dataListAllSelections = JSON.parse(JSON.stringify(this.selectData))
+          this.refreshTree()
+          this.resetSearch()
+        })
+      },
+      renderContent (h, { node, data, store }) {
+        return (
+              <span class="custom-tree-node">
+                {
+                  data.type === '1' ? <i class="fa fa-sitemap"></i> : <i class="fa fa-users"></i>
+                }
+                <span class="text">{node.label}</span>
+              </span>
+        )
+      },
+      getTemplateRow (index, row) {                                 // 获取选中数据
+        this.dataListSelections = [row]
+        this.$nextTick(() => {
+          this.changePageCoreRecordData()
+        })
+      },
+           // 设置选中的方法
+      setSelectRow () {
+        if (!this.dataListAllSelections || this.dataListAllSelections.length <= 0) {
+          this.$refs.rosterTable.clearSelection()
+          return
+        }
+                // 标识当前行的唯一键的名称
+        let idKey = this.idKey
+        let selectAllIds = []
+        this.dataListAllSelections.forEach(row => {
+          selectAllIds.push(row[idKey])
+        })
+        this.$refs.rosterTable.clearSelection()
+        for (var i = 0; i < this.dataList.length; i++) {
+          if (selectAllIds.indexOf(this.dataList[i][idKey]) >= 0) {
+                        // 设置选中,记住table组件需要使用ref="table"
+            this.$refs.rosterTable.toggleRowSelection(this.dataList[i], true)
+          }
+        }
+      },
+            // 记忆选择核心方法
+      changePageCoreRecordData () {
+                // 标识当前行的唯一键的名称
+        let idKey = this.idKey
+        let that = this
+              // 如果总记忆中还没有选择的数据,那么就直接取当前页选中的数据,不需要后面一系列计算
+        if (this.dataListAllSelections.length <= 0) {
+          this.dataListSelections.forEach(row => {
+            that.dataListAllSelections.push(row)
+          })
+          return
+        }
+                // 总选择里面的key集合
+        let selectAllIds = []
+        this.dataListAllSelections.forEach(row => {
+          selectAllIds.push(row[idKey])
+        })
+        let selectIds = []
+                // 获取当前页选中的id
+        this.dataListSelections.forEach(row => {
+          selectIds.push(row[idKey])
+                  // 如果总选择里面不包含当前页选中的数据,那么就加入到总选择集合里
+          if (selectAllIds.indexOf(row[idKey]) < 0) {
+            that.dataListAllSelections.push(row)
+          }
+        })
+        let noSelectIds = []
+              // 得到当前页没有选中的id
+        this.dataList.forEach(row => {
+          if (selectIds.indexOf(row[idKey]) < 0) {
+            noSelectIds.push(row[idKey])
+          }
+        })
+        noSelectIds.forEach(id => {
+          if (selectAllIds.indexOf(id) >= 0) {
+            for (let i = 0; i < that.dataListAllSelections.length; i++) {
+              if (that.dataListAllSelections[i][idKey] === id) {
+                                // 如果总选择中有未被选中的,那么就删除这条
+                that.dataListAllSelections.splice(i, 1)
+                break
+              }
+            }
+          }
+        })
+      },
+     // 得到选中的所有数据
+      getAllSelectionData () {
+         // 再执行一次记忆勾选数据匹配,目的是为了在当前页操作勾选后直接获取选中数据
+        this.changePageCoreRecordData()
+      },
+      filterNode (value, data) {
+        if (!value) return true
+        return data.name.indexOf(value) !== -1
+      },
+      del (tag) {
+        this.dataListAllSelections.splice(this.dataListAllSelections.indexOf(tag), 1)
+        this.$nextTick(() => {
+          this.setSelectRow()
+        })
+      },
+      // 获取数据列表
+      refreshList () {
+        this.loading = true
+        this.$http({
+          url: '/roster/base/list',
+          method: 'get',
+          params: {
+            'current': this.pageNo,
+            'size': this.pageSize,
+            'orders': this.orders,
+            ...this.searchForm
+          }
+        }).then(({data}) => {
+          this.dataList = data.records
+          this.total = data.total
+          this.pageNo = data.current
+          this.loading = false
+          this.$nextTick(() => {
+            this.setSelectRow()
+          })
+        })
+      },
+      refreshTree () {
+        this.$http({
+          url: `/sys/office/treeData`,
+          method: 'get'
+        }).then(({data}) => {
+          this.officeTreeData = data
+        })
+      },
+      // 每页数
+      sizeChangeHandle (val) {
+        this.pageSize = val
+        this.pageNo = 1
+        this.refreshList()
+        this.$nextTick(() => {
+          this.changePageCoreRecordData()
+        })
+      },
+      // 当前页
+      currentChangeHandle (val) {
+        this.pageNo = val
+        this.refreshList()
+        this.$nextTick(() => {
+          this.changePageCoreRecordData()
+        })
+      },
+      // 多选
+      selectionChangeHandle (val) {
+        this.dataListSelections = val
+        this.$nextTick(() => {
+          this.changePageCoreRecordData()
+        })
+      },
+       // 排序
+      sortChangeHandle (column) {
+        if (column.prop === 'officeDTO.name') {
+          column.prop = 'o.name'
+        }
+        if (column.prop === 'companyDTO.name') {
+          column.prop = 'c.name'
+        }
+        this.orders = []
+        if (column.order != null) {
+          this.orders.push({column: this.$utils.toLine(column.prop), asc: column.order === 'ascending'})
+        }
+        this.refreshList()
+      },
+      handleNodeClick (data) {
+        if (data.type === '1') {
+          this.searchForm.companyId = data.id
+          this.searchForm.officeId = ''
+        } else {
+          this.searchForm.companyId = ''
+          this.searchForm.officeId = data.id
+        }
+        this.refreshList()
+      },
+      resetSearch () {
+        this.searchForm.companyId = ''
+        this.searchForm.officeId = ''
+        this.$refs.officeTree.setCurrentKey(null)
+        this.$refs.searchForm.resetFields()
+        this.refreshList()
+      },
+      doSubmit () {
+        if (this.limit < this.dataListAllSelections.length) {
+          this.$message.error(`你最多只能选择${this.limit}个人员`)
+          return
+        }
+        this.visible = false
+        this.$emit('doSubmit', this.dataListAllSelections)
+      }
+    }
+  }
+</script>
+<style lang="scss">
+.org {
+  height: 100%;
+  .el-card__header {
+    padding: 10px;
+  }
+  .el-card__body {
+    padding: 10px;
+    max-height: 520px;
+    overflow: auto;
+  }
+}
+.rosterDialog{
+  .el-dialog__body {
+    padding: 10px 0px 0px 10px;
+    color: #606266;
+    font-size: 14px;
+    word-break: break-all;
+  }
+  .el-main {
+    padding: 20px 20px 5px 20px;
+    .el-pagination{
+      margin-top: 5px;
+    }
+  }
+}
+</style>

+ 143 - 0
src/views/common/RosterSelectForm.vue

@@ -0,0 +1,143 @@
+<template>
+  <div>
+    <el-autocomplete
+      style="width: 100%"
+      popper-class="my-autocomplete"
+      :disabled="disabled"  :readonly="readonly"
+      v-model="name"
+      :fetch-suggestions="querySearchAsync"
+      placeholder="请输入内容"
+      @select="handleSelect">
+      <el-button slot="append" :disabled="disabled"  :readonly="readonly" @click="openRoster" icon="el-icon-search"></el-button>
+      <template slot-scope="{ item }">
+        <div class="name">{{ item.name }}</div>
+        <span class="office-name">{{ commonJS.isEmpty(item.officeName) ? '部门:- - -' : '部门:' + item.officeName}}</span>
+      </template>
+    </el-autocomplete>
+    <RosterSelectDialog ref="rosterSelect" @doSubmit="selectRosterToInput" :limit="limit" :selectData="selectData"></RosterSelectDialog>
+  </div>
+</template>
+<script>
+  import RosterSelectDialog from './RosterSelectDialog'
+  import RosterService from '@/api/roster/RosterService'
+  export default {
+    data () {
+      return {
+        name: '',
+        labelValue: this.value,
+        selectData: [],
+        rosterData: []
+      }
+    },
+    props: {
+      limit: Number,
+      value: String,
+      size: {
+        type: String,
+        default: () => { return 'small' }
+      },
+      readonly: {
+        type: Boolean,
+        default: () => { return false }
+      },
+      disabled: {
+        type: Boolean,
+        default: () => { return false }
+      }
+    },
+    components: {
+      RosterSelectDialog
+    },
+    rosterService: null,
+    beforeCreate () {
+      this.rosterService = new RosterService()
+    },
+    watch: {
+      value: {
+        handler (newVal) {
+          this.selectData = []
+          if (newVal) {
+            newVal.split(',').forEach((id) => {
+              this.rosterService.queryById(id).then(({data}) => {
+                if (data && data.id !== '') {
+                  this.selectData.push(data)
+                }
+              })
+            })
+          }
+        },
+        immediate: true,
+        deep: false
+      },
+      selectData: {
+        handler (newVal) {
+          this.name = newVal.map(roster => { return roster.name }).join(',')
+        },
+        immediate: false,
+        deep: false
+      }
+    },
+    mounted () {
+      this.getRosterData()
+    },
+    methods: {
+      selectRosterToInput (rosterList) {
+        this.selectData = rosterList
+        this.labelValue = rosterList.map(roster => { return roster.id }).join(',')
+        this.name = rosterList.map(roster => { return roster.name }).join(',')
+        this.$emit('getValue', this.labelValue)
+      },
+      openRoster () {
+        this.$refs.rosterSelect.init()
+      },
+      handleSelect (item) {
+        this.$emit('getValue', item.id)
+        this.name = item.name
+      },
+      getRosterData () {
+        this.rosterService.list({
+          'current': '1',
+          'size': '-1'
+        }).then(({data}) => {
+          this.rosterData = JSON.parse(JSON.stringify(data.records))
+        })
+      },
+      querySearchAsync (queryString, cb) {
+        let rosterDataList = this.rosterData
+        let results = queryString ? rosterDataList.filter(this.createFilter(queryString)) : rosterDataList
+        cb(results)
+      },
+      createFilter (queryString) {
+        return (item) => {
+          return (item.name.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+        }
+      }
+    }
+  }
+</script>
+<style>
+  .el-form-item__content .el-input-group {
+    vertical-align: middle;
+  }
+  .el-tag + .el-tag {
+    margin-left: 5px;
+    margin-bottom: 5px;
+  }
+  .my-autocomplete li {
+    line-height: normal;
+    padding: 7px;
+  }
+  .my-autocomplete li .name {
+    text-overflow: ellipsis;
+    overflow: hidden;
+  }
+  .my-autocomplete li .office-name {
+    font-size: 12px;
+    color: #b4b4b4;
+  }
+  .my-autocomplete li .highlighted .office-name {
+    color: #ddd;
+  }
+</style>
+
+

+ 65 - 12
src/views/modules/changes/dimission/DimissionForm.vue

@@ -12,16 +12,20 @@
         <el-row  :gutter="15">
           <el-col :span="12">
             <el-form-item label="姓名" prop="rosterId"
-                          :rules="[{required: true, message: '姓名不能为空', trigger: 'blur'}]"
+                          :rules="[{required: true, message: '姓名不能为空', trigger: 'blur'},{required: true, message: '姓名不能为空', trigger: 'change'}]"
             >
-              <el-select :disabled="method === 'sure'" v-model="inputForm.rosterId" style="width:100%" placeholder="请选择姓名">
-                <el-option
-                  v-for="item in supervisorList"
-                  :key="item.id"
-                  :label="item.name"
-                  :value="item.id">
-                </el-option>
-              </el-select>
+<!--              <el-select :disabled="method === 'sure'" v-model="inputForm.rosterId" style="width:100%" placeholder="请选择姓名">-->
+<!--                <el-option-->
+<!--                  v-for="item in supervisorList"-->
+<!--                  :key="item.id"-->
+<!--                  :label="item.name"-->
+<!--                  :value="item.id">-->
+<!--                </el-option>-->
+<!--              </el-select>-->
+<!--              <el-input style="width:100%" v-model="inputForm.rosterId" placeholder="请填写姓名"  disabled  >-->
+<!--                <el-button slot="append" @click="openRoster" icon="el-icon-search"></el-button>-->
+<!--              </el-input>-->
+              <RosterSelectForm :limit='1' :disabled="method==='view'||method==='sure'" :readonly="method==='view'||method==='sure'" :value="inputForm.rosterId" @getValue='(value) => {inputForm.rosterId=value}'></RosterSelectForm>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -115,6 +119,45 @@
             </el-form-item>
           </el-col>
         </el-row>
+        <el-row v-if="method === 'sure'">
+          <el-divider content-position="left"><i class="el-icon-document"></i> 福利缴纳</el-divider>
+          <el-col :span="12">
+            <el-form-item label="社保最后缴纳月:" prop="socialSecurityLast"
+                          :rules="[]"
+            >
+              <el-date-picker
+                v-model="inputForm.socialSecurityLast"
+                type="month"
+                value-format="yyyy-MM"
+                placement="bottom-start"
+                placeholder="选择月">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="公积金后缴纳月:" prop="providentFundLast"
+                          :rules="[]"
+            >
+              <el-date-picker
+                v-model="inputForm.providentFundLast"
+                type="month"
+                value-format="yyyy-MM"
+                placement="bottom-start"
+                placeholder="选择月">
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row v-if="method === 'sure'">
+          <el-divider content-position="left"><i class="el-icon-document"></i> 系统调整</el-divider>
+          <el-col :span="24">
+            <el-form-item label="审批交接给:" prop="handoverId"
+                          :rules="[]"
+            >
+              <RosterSelectForm :limit='1'  :value="inputForm.handoverId" @getValue='(value) => {inputForm.handoverId=value}'></RosterSelectForm>
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <!--        附件-->
       <UpLoadComponent v-if="method === 'sure'" ref="uploadComponent"></UpLoadComponent>
@@ -131,6 +174,7 @@
   import DimissionService from '@/api/changes/dimission/DimissionService'
   import RosterService from '@/api/roster/RosterService'
   import UpLoadComponent from '@/views/common/UpLoadComponent'
+  import RosterSelectForm from '@/views/common/RosterSelectForm'
   export default {
     data () {
       return {
@@ -152,7 +196,10 @@
           payrollSettlementDate: '',
           requestDate: '',
           reaTypeList: [],
-          changesDimissionFilesDTOList: []
+          changesDimissionFilesDTOList: [],
+          handoverId: '',
+          socialSecurityLast: [],
+          providentFundLast: []
         },
         supervisorList: []
       }
@@ -164,7 +211,8 @@
       this.rosterService = new RosterService()
     },
     components: {
-      UpLoadComponent
+      UpLoadComponent,
+      RosterSelectForm
     },
     methods: {
       init (method, id) {
@@ -172,6 +220,7 @@
         this.queryAllSupervisor()
         this.inputForm = {
           id: '',
+          createBy: '',
           remarks: '',
           rosterId: '',
           lastWorkDate: '',
@@ -184,7 +233,10 @@
           payrollSettlementDate: '',
           requestDate: '',
           reaTypeList: [],
-          changesDimissionFilesDTOList: []
+          changesDimissionFilesDTOList: [],
+          handoverId: '',
+          socialSecurityLast: [],
+          providentFundLast: []
         }
         this.inputForm.id = id
         if (method === 'add') {
@@ -246,6 +298,7 @@
         })
       },
       close () {
+        this.selectData = []
         if (this.method === 'sure') {
           this.$refs.uploadComponent.clearUpload()
         }

+ 18 - 3
src/views/modules/changes/dimission/DimissionList.vue

@@ -41,8 +41,8 @@
           <vxe-column type="checkbox"  width="40px"></vxe-column>
           <vxe-column width="200" title="姓名" field="rosterBaseDTO.name">
             <template slot-scope="scope">
-              <el-link  type="primary" :underline="false" v-if="hasPermission('changes:dimission:view')"  @click="view(scope.row.id)">{{scope.row.rosterBaseDTO.name !== undefined?scope.row.rosterBaseDTO.name:'--'}}</el-link>
-              <span v-else>{{scope.row.rosterBaseDTO.name !== undefined?scope.row.rosterBaseDTO.name:'--'}}</span>
+              <el-link  type="primary" :underline="false" v-if="hasPermission('changes:dimission:view')"  @click="view(scope.row.id)">{{!commonJS.isEmpty(scope.row.rosterBaseDTO.name)?scope.row.rosterBaseDTO.name:'--'}}</el-link>
+              <span v-else>{{!commonJS.isEmpty(scope.row.rosterBaseDTO.name)?scope.row.rosterBaseDTO.name:'--'}}</span>
             </template>
           </vxe-column>
 
@@ -65,12 +65,27 @@
             </template>
           </vxe-column>
           <vxe-column width="200" title="备注" field="remarks"></vxe-column>
+          <vxe-column width="200" title="离职审批" field="vettingStatus">
+            <template slot-scope="scope">
+              {{$dictUtils.getDictLabel('vetting_status', scope.row.vettingStatus, '-')}}
+            </template>
+          </vxe-column>
+          <vxe-column width="200" title="离职交接" field="handoverStatus">
+            <template slot-scope="scope">
+              {{$dictUtils.getDictLabel('handover_status', scope.row.handoverStatus, '-')}}
+            </template>
+          </vxe-column>
+          <vxe-column width="200" title="离职状态" field="status">
+            <template slot-scope="scope">
+              {{$dictUtils.getDictLabel('dimission_status', scope.row.status, '-')}}
+            </template>
+          </vxe-column>
 
           <vxe-column title="操作" width="50px" fixed="right" align="center">
             <template  slot-scope="scope">
               <el-dropdown size="small"  @command="handleCommand">
                     <span class="el-dropdown-link">
-                      ...
+                      . . .
                     </span>
                 <el-dropdown-menu slot="dropdown">
                   <el-dropdown-item  v-if="hasPermission('changes:dimission:view')" :command="{method:'view', id:scope.row.id}">