zhengnaiwen_citu 6 달 전
부모
커밋
7dece8672e

+ 6 - 0
src/api/home.js

@@ -0,0 +1,6 @@
+import http from '@/utils/request'
+
+// 获取统计图
+export function getPerformanceBranchYearStatistics (data) {
+  return http.post('/employee/performance/branch/year/statistics', data)
+}

+ 2 - 1
src/components/AutoComponents/MDialog/index.vue

@@ -11,7 +11,7 @@
     v-on="$listeners"
   >
     <slot></slot>
-    <span slot="footer">
+    <span slot="footer" v-if="!hideFooter">
       <m-button @click="show = false">{{ option?.textCancel ?? '取 消'}}</m-button>
       <m-button type="primary" @click="sure">{{ option?.textSure ?? '确 定'}}</m-button>
     </span>
@@ -24,6 +24,7 @@ export default {
   props: {
     title: String,
     width: String,
+    hideFooter: Boolean,
     option: {
       type: Object,
       default: () => ({

+ 1 - 1
src/utils/request.js

@@ -84,7 +84,7 @@ service.interceptors.response.use(
       if (res.data && Object.keys(res.data).length) {
         return Promise.reject(res)
       }
-      return Promise.reject(res.msg.error || res.msg)
+      return Promise.reject(res.msg?.error || res.msg || `Error ${res.code}`)
     }
     return res
   },

+ 35 - 123
src/views/bonus/allocation/index.vue

@@ -1,70 +1,34 @@
 <template>
   <div class="white pa-3">
     <m-search :items="searchItems" v-model="searchValues" class="mb-3" @search="onSearch"></m-search>
-    <BonusTable ref="bonusTableRefs">
+    <BonusTable ref="bonusTableRefs" :filter-header="auditStatus !== 0 && auditStatus !== 1 ? [] : ['actions']">
       <template #header="{ items }">
-        <div class="content">
+        <div class="content mb-3">
           <div>
-            可发放绩效:<el-tag>{{ totalAllocationPerformanceSalary }}</el-tag>
-            总绩效: <el-tag>{{ totalGrantPerformanceSalary }}</el-tag>
             <template v-if="auditStatusList[auditStatus]">
-              审批状态:<el-tag :type="auditStatusList[auditStatus]?.type ?? 'info'">{{ auditStatusList[auditStatus]?.label ?? '未知状态' }}</el-tag>
+              审批状态:
+              <el-tag :type="auditStatusList[auditStatus]?.type ?? 'info'" class="mr-3">
+                {{ auditStatusList[auditStatus]?.label ?? '未知状态' }}
+              </el-tag>
             </template>
-            <el-button
-              class="ml-3"
-              type="primary"
-              size="small"
-              :loading="auditStatusLoading"
-              :disabled="auditStatus === 0 || auditStatus === 1 || !items.length"
-              @click="onSave">
-              确认分配
-            </el-button>
-          </div>
-        </div>
-      </template>
-      <template #actions="{ row }">
-        <el-input :disabled="auditStatusLoading" v-model="values[row.employeePerformanceId]" placeholder="请输入绩效" size="small"></el-input>
-      </template>
-    </BonusTable>
-    <!-- <m-table
-      :items="items"
-      :headers="headers"
-      v-loading="loading"
-      :total="total"
-      :page-size="pageInfo.size"
-      :page-current="pageInfo.current"
-      @page-change="onPageChange"
-    >
-      <template #header>
-        <div class="content">
-          <div>
             可发放绩效:<el-tag>{{ totalAllocationPerformanceSalary }}</el-tag>
             总绩效: <el-tag>{{ totalGrantPerformanceSalary }}</el-tag>
-            <template v-if="auditStatusList[auditStatus]">
-              审批状态:<el-tag :type="auditStatusList[auditStatus]?.type ?? 'info'">{{ auditStatusList[auditStatus]?.label ?? '未知状态' }}</el-tag>
-            </template>
             <el-button
               class="ml-3"
               type="primary"
               size="small"
               :loading="auditStatusLoading"
-              :disabled="auditStatus === 0 || auditStatus === 1 || !items.length"
+              v-show="auditStatus !== 0 && auditStatus !== 1 && items.length"
               @click="onSave">
               确认分配
             </el-button>
           </div>
         </div>
       </template>
-      <template #status="{ row }">
-        <el-tag :type="statusList[row.status].color">{{ statusList[row.status].text }}</el-tag>
-      </template>
-      <template #dataType="{row}">
-        {{ row.dataType === 1 ? '手工数据' : '系统数据' }}
+      <template #actions="{ row, items }">
+        <el-input v-show="auditStatus !== 0 && auditStatus !== 1 && items.length" v-model="values[row.employeePerformanceId]" placeholder="请输入绩效" size="small"></el-input>
       </template>
-      <template #actions="{ row }">
-        <el-input :disabled="auditStatusLoading" v-model="values[row.employeePerformanceId]" placeholder="请输入绩效" size="small"></el-input>
-      </template>
-    </m-table> -->
+    </BonusTable>
   </div>
 </template>
 
@@ -95,20 +59,6 @@ export default {
       auditStatus: null,
       auditStatusLoading: true,
       values: {},
-      statusList: {
-        0: {
-          text: '未分配',
-          color: 'warning'
-        },
-        1: {
-          text: '已分配',
-          color: 'success'
-        },
-        2: {
-          text: '已确认',
-          color: 'info'
-        }
-      },
       searchValues: {
         month: dateFormat('YYYY-mm', new Date()),
         organizationNo: null,
@@ -117,32 +67,10 @@ export default {
       query: {
         month: dateFormat('YYYY-mm', new Date())
       },
-      // headers: [
-      //   { label: '月份', prop: 'month' },
-      //   { label: '机构名称', prop: 'organizationName', width: 150 },
-      //   { label: '员工姓名', prop: 'employeeName' },
-      //   { label: '分配状态', prop: 'status', align: 'center' },
-      //   { label: '员工类型', prop: 'employeeCategory', align: 'center' },
-      //   { label: '可分配绩效薪资', prop: 'assignablePerformanceSalary', align: 'center', width: 150 },
-      //   { label: '领导分配绩效薪资', prop: 'allocationPerformanceSalary', align: 'center', width: 150 },
-      //   { label: '基础绩效薪资', prop: 'basicPerformanceSalary', align: 'center', width: 120 },
-      //   { label: '总绩效薪资', prop: 'performanceSalary', align: 'center', width: 120 },
-      //   { label: '数据来源', prop: 'dataType', align: 'center' },
-      //   { label: '数据版本', prop: 'version', width: 160 },
-      //   { label: '创建时间', prop: 'createDate', width: 160 },
-      //   { label: '操作', prop: 'actions', width: 160, fixed: 'right' }
-      // ],
-      // items: [],
-      // loading: false,
-      // total: 0,
-      // pageInfo: {
-      //   current: 1,
-      //   size: 50
-      // },
-      // orders: [],
       employeeCategoryItems: [],
       totalGrantPerformanceSalary: 0,
-      deptItems: []
+      deptItems: [],
+      loading: false
     }
   },
   computed: {
@@ -206,40 +134,27 @@ export default {
     this.loading = true
     this.onGetDept()
     await this.getEmployeeCategoryItems()
-    this.onInit()
+    this.$nextTick(() => {
+      this.onInit()
+    })
   },
   methods: {
-    // async onInit () {
-    //   this.loading = true
-    //   try {
-    //     const { data } = await getAllocationPage({
-    //       page: {
-    //         ...this.pageInfo,
-    //         orders: this.orders
-    //       },
-    //       entity: {
-    //         ...this.searchValues
-    //       }
-    //     })
-    //     await this.onCheckStatus()
-    //     await this.onStatistics()
-    //     data.records.forEach(e => {
-    //       if (Object.prototype.hasOwnProperty.call(this.values, e.employeePerformanceId)) {
-    //         return
-    //       }
-    //       this.$set(this.values, e.employeePerformanceId, e.allocationPerformanceSalary || null)
-    //     })
-    //     this.items = data.records.map(e => {
-    //       e.createDate = dateFormat('YYYY-mm-dd HH:MM:SS', new Date(e.createDate))
-    //       return e
-    //     })
-    //     this.total = data.total
-    //   } catch (error) {
-    //     this.$message.error(error)
-    //   } finally {
-    //     this.loading = false
-    //   }
-    // },
+    async onInit (pageInfo) {
+      this.loading = true
+      await this.onCheckStatus()
+      await this.onStatistics()
+      const data = await this.$refs.bonusTableRefs.onInit(this.query, pageInfo)
+      this.loading = false
+      if (!data) {
+        return
+      }
+      data.records.forEach(e => {
+        if (Object.prototype.hasOwnProperty.call(this.values, e.employeePerformanceId)) {
+          return
+        }
+        this.$set(this.values, e.employeePerformanceId, e.allocationPerformanceSalary || null)
+      })
+    },
     async onGetDept () {
       const data = await getOrganizationTree()
       if (!data) {
@@ -269,16 +184,15 @@ export default {
       }
     },
     onSearch () {
-      this.pageInfo.current = 1
       this.query = { ...this.searchValues }
-      this.onInit()
+      this.onInit({ current: 1 })
     },
     // 领导分配绩效薪资
     onSave () {
       const h = this.$createElement
       const _el = [
-        h('p', undefined, `更新月份:${this.query.month}`),
-        h('p', undefined, `更新物业线:${this.query.category ?? null}`)
+        h('p', undefined, `提交月份:${this.query.month}`),
+        h('p', undefined, `提交员工类型:${this.query.employeeCategory ?? null}`)
       ]
       try {
         if (this.totalGrantPerformanceSalary !== this.totalAllocationPerformanceSalary) {
@@ -292,9 +206,7 @@ export default {
             type: 'warning'
           }).then(() => {
             this.onSaveAll(true)
-          }).catch(_ => {
-            this.onSaveAll(false)
-          })
+          }).catch(_ => {})
           return
         }
         const el = h('div', [

+ 33 - 10
src/views/bonus/approve/approveDetails.vue

@@ -1,29 +1,52 @@
 <template>
-  <m-dialog ref="dialog" :title="title" v-bind="$attrs" v-on="$listeners"></m-dialog>
+  <m-dialog ref="dialog" title="审批详情" v-bind="$attrs" v-on="$listeners" hideFooter>
+    <div class="mb-3 content">
+      <div>
+        <el-tag v-if="item.month" class="mr-3">{{ item.month }}</el-tag>
+        <el-tag v-if="item.opOrganizationName" class="mr-3">{{ item.opOrganizationName }}</el-tag>
+        <el-tag v-if="item.employeeCategory" class="mr-3">{{ item.employeeCategory }}</el-tag>
+      </div>
+      <div>
+        <m-button type="success" size="small" icon="el-icon-check">通过</m-button>
+        <m-button type="danger" size="small" icon="el-icon-close">拒绝</m-button>
+      </div>
+    </div>
+    <BonusTable ref="bonusTableRefs" :filter-header="filterHeader" shadow="never"></BonusTable>
+  </m-dialog>
 </template>
 
 <script>
+import BonusTable from '../components/bonusTable.vue'
 export default {
   name: 'approveDetails',
-  components: {},
-  props: {},
+  components: {
+    BonusTable
+  },
   data () {
     return {
-      title: '审批详情'
+      item: {},
+      filterHeader: ['month', 'organizationName', 'employeeCategory', 'status', 'actions', 'assignablePerformanceSalary', 'version', 'dataType', 'createDate']
     }
   },
-  computed: {},
-  watch: {},
-  created () {},
-  mounted () {},
   methods: {
-    open () {
+    open (item) {
+      this.item = item
       this.$refs.dialog.open()
+      this.$nextTick(() => {
+        this.$refs.bonusTableRefs.onInit({
+          month: item.month,
+          organizationNo: item.opOrganizationNo,
+          employeeCategory: item.employeeCategory
+        })
+      })
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-
+.content {
+  display: flex;
+  justify-content: space-between;
+}
 </style>

+ 5 - 5
src/views/bonus/approve/index.vue

@@ -39,7 +39,7 @@ export default {
       items: [],
       headers: [
         { label: '月份', prop: 'month' },
-        { label: '分配机构', prop: 'opOrganizationName' },
+        { label: '发起机构', prop: 'opOrganizationName' },
         // { label: '分配员工', prop: 'opNickname', align: 'center' },
         { label: '员工类型', prop: 'employeeCategory', align: 'center' },
         { label: '状态', prop: 'status', align: 'center' },
@@ -71,11 +71,11 @@ export default {
           }
         },
         {
-          label: '机构',
+          label: '发起机构',
           prop: 'organizationName',
           type: 'input',
           options: {
-            placeholder: '请输入机构'
+            placeholder: '请输入发起机构'
           }
         },
         {
@@ -115,8 +115,8 @@ export default {
       this.pageInfo.current = 1
       this.onInit()
     },
-    onShowDetails () {
-      this.$refs.approveDetailsRefs.open()
+    onShowDetails (row) {
+      this.$refs.approveDetailsRefs.open(row)
     }
   }
 }

+ 45 - 33
src/views/bonus/components/bonusTable.vue

@@ -6,6 +6,8 @@
     :total="total"
     :page-size="pageInfo.size"
     :page-current="pageInfo.current"
+    max-height="600px"
+    v-bind="$attrs"
     @page-change="onPageChange"
   >
     <template #header>
@@ -18,7 +20,7 @@
       {{ row.dataType === 1 ? '手工数据' : '系统数据' }}
     </template>
     <template #actions="{ row }">
-      <slot name="actions" :row="row"></slot>
+      <slot name="actions" :row="row" :items="items"></slot>
     </template>
   </m-table>
 </template>
@@ -26,37 +28,32 @@
 <script>
 import {
   getAllocationPage
-  // saveAllocationGrant,
-  // getAllocationEmployeeCategory,
-  // checkAllocationSubmitStatus,
-  // getAllocationStatistics,
-  // saveAllocation
 } from '@/api/bonus'
 import { dateFormat } from '@/utils/date'
 export default {
   name: 'bonusTable',
   props: {
-    showActions: {
-      type: Boolean,
-      default: true
+    filterHeader: {
+      type: Array,
+      default: () => []
     }
   },
   data () {
     return {
-      headers: [
-        { label: '月份', prop: 'month' },
-        { label: '机构名称', prop: 'organizationName', width: 150 },
-        { label: '员工姓名', prop: 'employeeName' },
-        { label: '分配状态', prop: 'status', align: 'center' },
-        { label: '员工类型', prop: 'employeeCategory', align: 'center' },
-        { label: '可分配绩效薪资', prop: 'assignablePerformanceSalary', align: 'center', width: 150 },
-        { label: '领导分配绩效薪资', prop: 'allocationPerformanceSalary', align: 'center', width: 150 },
-        { label: '基础绩效薪资', prop: 'basicPerformanceSalary', align: 'center', width: 120 },
-        { label: '总绩效薪资', prop: 'performanceSalary', align: 'center', width: 120 },
-        { label: '数据来源', prop: 'dataType', align: 'center' },
-        { label: '数据版本', prop: 'version', width: 160 },
-        { label: '创建时间', prop: 'createDate', width: 160 }
-      ],
+      statusList: {
+        0: {
+          text: '未分配',
+          color: 'warning'
+        },
+        1: {
+          text: '已分配',
+          color: 'success'
+        },
+        2: {
+          text: '已确认',
+          color: 'info'
+        }
+      },
       items: [],
       loading: false,
       total: 0,
@@ -67,13 +64,33 @@ export default {
       orders: []
     }
   },
-  created () {
-    if (this.showActions) {
-      this.headers.push({ label: '操作', prop: 'actions', width: 160, fixed: 'right' })
+  computed: {
+    headers () {
+      const headers = [
+        { label: '月份', prop: 'month' },
+        { label: '机构名称', prop: 'organizationName', width: 150 },
+        { label: '员工姓名', prop: 'employeeName', width: 80, align: 'center' },
+        { label: '分配状态', prop: 'status', align: 'center', width: 100 },
+        { label: '员工类型', prop: 'employeeCategory', align: 'center' },
+        { label: '可分配绩效薪资', prop: 'assignablePerformanceSalary', align: 'center', width: 150 },
+        { label: '领导分配绩效薪资', prop: 'allocationPerformanceSalary', align: 'center', width: 150 },
+        { label: '基础绩效薪资', prop: 'basicPerformanceSalary', align: 'center', width: 120 },
+        { label: '总绩效薪资', prop: 'performanceSalary', align: 'center', minWidth: 120 },
+        { label: '数据来源', prop: 'dataType', align: 'center' },
+        { label: '数据版本', prop: 'version', width: 160 },
+        { label: '创建时间', prop: 'createDate', width: 160 }
+      ]
+      if (this.items.length) {
+        headers.push({ label: '操作', prop: 'actions', width: 160, fixed: 'right' })
+      }
+      return headers.filter(e => !this.filterHeader.includes(e.prop))
     }
   },
   methods: {
-    async onInit (searchValues) {
+    async onInit (searchValues, pageInfo) {
+      if (pageInfo) {
+        Object.assign(this.pageInfo, pageInfo)
+      }
       this.loading = true
       try {
         const { data } = await getAllocationPage({
@@ -85,17 +102,12 @@ export default {
             ...searchValues
           }
         })
-        data.records.forEach(e => {
-          if (Object.prototype.hasOwnProperty.call(this.values, e.employeePerformanceId)) {
-            return
-          }
-          this.$set(this.values, e.employeePerformanceId, e.allocationPerformanceSalary || null)
-        })
         this.items = data.records.map(e => {
           e.createDate = dateFormat('YYYY-mm-dd HH:MM:SS', new Date(e.createDate))
           return e
         })
         this.total = data.total
+        return data
       } catch (error) {
         this.$message.error(error)
       } finally {

+ 0 - 58
src/views/bonus/index.vue

@@ -1,58 +0,0 @@
-<template>
-  <div class="white pa-3">
-    <el-tabs v-model="activeName" @tab-click="handleClick">
-      <el-tab-pane
-        v-for="item in items"
-        :key="item.name"
-        :label="item.label"
-        :name="item.name"
-      >
-        <component :is="item.component" :ref="item.name" @hook:mounted="onComponentMounted"></component>
-      </el-tab-pane>
-    </el-tabs>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'salary-calculate',
-  data () {
-    return {
-      activeName: '',
-      items: [],
-      itemData: {}
-    }
-  },
-  created () {
-    this.items = this.$route.meta.roles.filter(e => e.hidden === 1).sort((a, b) => b - a).map(e => {
-      return {
-        name: e.name,
-        label: e.label,
-        component: () => import(`./${e.component}/index.vue`)
-      }
-    })
-    if (this.$route.query.name) {
-      this.activeName = this.$route.query.name
-    } else {
-      this.activeName = this.items[0].name
-    }
-  },
-  methods: {
-    handleClick () {
-      this.$router.push(`${this.$route.path}?name=${this.activeName}`)
-      this.$nextTick(() => {
-        this.$refs[this.activeName][0].onReady()
-      })
-    },
-    onComponentMounted () {
-      this.$refs[this.activeName] && this.$refs[this.activeName][0].onReady()
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-::v-deep .el-tabs__content  {
-  overflow: visible !important;
-}
-</style>

+ 19 - 37
src/views/home/components/performance.vue

@@ -1,49 +1,31 @@
 <template>
-  <m-card header="各支行绩效结果2024年度排行榜">
+  <m-card >
     <e-charts ref="eChart" class="box"></e-charts>
   </m-card>
 </template>
 
 <script>
+import { getPerformanceBranchYearStatistics } from '@/api/home'
 export default {
   name: 'performance-statistics',
+  data () {
+    return {
+      chart: null
+    }
+  },
   mounted () {
-    const chart = this.$refs.eChart.onInit()
-    chart.setOption({
-      tooltip: {
-        trigger: 'axis',
-        axisPointer: {
-          type: 'cross'
-        }
-      },
-      toolbox: {
-        feature: {
-          dataView: { show: true, readOnly: false },
-          restore: { show: true },
-          saveAsImage: { show: true }
-        }
-      },
-      legend: {
-        data: ['Evaporation', 'Precipitation', 'Temperature']
-      },
-      xAxis: {
-        name: '支行',
-        data: ['分行本部', '遂溪支行', '坡头支行', '霞山支行', '吴川支行', '赤坎支行', '分行营业部', '廉江支行', '徐闻支行', '雷州支行', '开发区支行', '第二支行']
-      },
-      yAxis: {
-        name: '万元'
-      },
-      series: [
-        {
-          label: {
-            show: true,
-            position: 'top'
-          },
-          type: 'bar',
-          data: [5400.00, 4832.55, 3200.00, 2842.52, 2500.00, 2400.00, 2522.56, 2422.56, 2422.56, 2422.56, 2422.56, 2422.56]
-        }
-      ]
-    })
+    this.chart = this.$refs.eChart.onInit()
+    this.onInit()
+  },
+  methods: {
+    async onInit () {
+      try {
+        const { data } = await getPerformanceBranchYearStatistics({})
+        this.chart.setOption(data)
+      } catch (error) {
+        this.$message.error(error)
+      }
+    }
   }
 }
 </script>

+ 10 - 6
src/views/humanResources/panorama/panoramaDetails.vue

@@ -18,7 +18,7 @@
       </el-breadcrumb>
     </div>
     <div class="content-body">
-      <component :is="componentsPath" :key="$route.fullPath"></component>
+      <component :is="componentsPath" :key="$route.fullPath" ref="panorama"></component>
     </div>
   </div>
 </template>
@@ -38,7 +38,8 @@ export default {
   data () {
     return {
       activeIndex: 'humanResources/payroll',
-      breadcrumbs: []
+      breadcrumbs: [],
+      componentsPath: null
     }
   },
   computed: {
@@ -61,6 +62,7 @@ export default {
   },
   created () {
     this.getDept()
+    this.componentsPath = () => import(`@/views/${this.activeIndex}`)
   },
   methods: {
     async getDept () {
@@ -73,9 +75,10 @@ export default {
         this.breadcrumbs.push({ value: this.$route.query.employeeNo, label: this.$route.query.employeeName })
       }
     },
-    componentsPath () {
-      return import(`./dynamic/${this.activeIndex}`)
-    },
+    // 使用原菜单页面,通过ref调用开启页面内部的onInitPanorama方法开启全景页面
+    // componentsPath () {
+    //   return import(`@/views/${this.activeIndex}`)
+    // },
     filterRoute (items) {
       return items.filter(item => {
         if (item.children && item.children.length) {
@@ -85,7 +88,8 @@ export default {
       })
     },
     onSelect (v) {
-      console.log(v)
+      this.activeIndex = v
+      this.componentsPath = () => import(`@/views/${this.activeIndex}`)
     },
     onRun (path) {
       window.open(this.$route.path + '?organizationNo=' + path)

+ 21 - 15
src/views/humanResources/payroll/index.vue

@@ -32,21 +32,6 @@ export default {
   data () {
     return {
       exportLoading: false,
-      searchItems: [
-        {
-          label: '月份',
-          prop: 'month',
-          type: 'datePicker',
-          options: {
-            placeholder: '请选择月份',
-            type: 'month',
-            valueFormat: 'yyyy-MM',
-            format: 'yyyy 年 MM 月'
-          }
-        },
-        { label: '部门', prop: 'organizationName', type: 'input', options: { placeholder: '请输入部门' } },
-        { label: '姓名', prop: 'employeeName', type: 'input', options: { placeholder: '请输入姓名' } }
-      ],
       searchValues: {
         month: null,
         organizationName: null,
@@ -62,10 +47,31 @@ export default {
       }
     }
   },
+  computed: {
+    searchItems () {
+      return [
+        {
+          label: '月份',
+          prop: 'month',
+          type: 'datePicker',
+          options: {
+            placeholder: '请选择月份',
+            type: 'month',
+            valueFormat: 'yyyy-MM',
+            format: 'yyyy 年 MM 月'
+          }
+        },
+        { label: '部门', prop: 'organizationName', type: 'input', options: { placeholder: '请输入部门' } },
+        { label: '姓名', prop: 'employeeName', type: 'input', options: { placeholder: '请输入姓名' } }
+      ]
+    }
+  },
   created () {
     this.init()
   },
   methods: {
+    // 执行全景初始化操作
+    onInitPanorama () {},
     async init () {
       try {
         const { data } = await getPayrollPage({

+ 1 - 1
src/views/humanResources/roster/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="white pa-3">
     <m-search :items="searchItems" v-model="searchValues" class="mb-3" @search="onSearch">
       <template #button>
         <m-button type="primary" icon="el-icon-plus" plain @click="onAdd">新增</m-button>