From a5f5e2c3fa5953a5474e4ad5d504c23acab94900 Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期五, 20 三月 2026 10:25:27 +0800
Subject: [PATCH] fix(analytics): 修正员工分析页面数据计算和样式问题

---
 src/views/customerService/feedbackRegistration/components/formDia.vue |    6 +
 src/views/personnelManagement/employeeRecord/index.vue                |   26 +++++-
 src/views/personnelManagement/analytics/index.vue                     |  167 +++++++++++++++++++++++++++++++++++++++--
 3 files changed, 183 insertions(+), 16 deletions(-)

diff --git a/src/views/customerService/feedbackRegistration/components/formDia.vue b/src/views/customerService/feedbackRegistration/components/formDia.vue
index 71cd167..8f9bb91 100644
--- a/src/views/customerService/feedbackRegistration/components/formDia.vue
+++ b/src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -365,7 +365,11 @@
 // 鎵撳紑寮规
 const openDialog =async (type, row) => {
   // 璇锋眰澶氫釜鎺ュ彛锛岃幏鍙栨暟鎹�
-  let res = await getAllCustomerList();
+  let res = await getAllCustomerList({
+    current: 1,
+  size: 1000,
+  total: 0,
+  });
   if(res.records){
     customerNameOptions.value = res.records.map(item => ({
       label: item.customerName,
diff --git a/src/views/personnelManagement/analytics/index.vue b/src/views/personnelManagement/analytics/index.vue
index 9e6e449..db97619 100644
--- a/src/views/personnelManagement/analytics/index.vue
+++ b/src/views/personnelManagement/analytics/index.vue
@@ -86,12 +86,15 @@
 import { ref, onMounted, onUnmounted, nextTick } from 'vue'
 import { ElMessage } from 'element-plus'
 import * as echarts from 'echarts'
+import dayjs from 'dayjs'
 import {listDept} from "@/api/system/dept.js";
 import {
   findStaffAnalysisMonthlyTurnoverRateFor12Months,
   findStaffLeaveReasonAnalysis,
   findStaffAnalysisTotalStatistic
 } from "@/api/personnelManagement/staffAnalytics.js";
+import { staffOnJobListPage } from "@/api/personnelManagement/staffOnJob.js";
+import { findStaffLeaveListPage } from "@/api/personnelManagement/staffLeave.js";
 
 // 鍝嶅簲寮忔暟鎹�
 const loading = ref(false)
@@ -148,6 +151,43 @@
 const staffLeaveReasons = ref([])
 // 12涓湀鍛樺伐娴佸姩娴佸け鐜囧垎鏋愭暟鎹�
 const turnoverRateStatistics = ref([])
+const turnoverRateStatisticsRaw = ref([])
+const turnoverSeriesNormalized = ref(false)
+
+const staffCounts = ref({
+  onJobTotal: 0,
+  leaveTotal: 0,
+  totalStaff: 0,
+  leaveLast12Months: 0,
+  joinLeaveRatio: 1
+})
+
+const safeNum = (val) => {
+  const num = Number(val)
+  return Number.isFinite(num) ? num : 0
+}
+
+const round2 = (val) => {
+  const num = safeNum(val)
+  return Number(num.toFixed(2))
+}
+
+const getListTotal = (res) => safeNum(res?.data?.total ?? res?.data?.count ?? 0)
+
+const getLast12MonthRanges = () => {
+  const end = dayjs()
+  const start = end.subtract(11, 'month').startOf('month')
+  const ranges = []
+  for (let i = 0; i < 12; i++) {
+    const cur = start.add(i, 'month')
+    ranges.push({
+      month: cur.format('YYYY-MM'),
+      start: cur.startOf('month').format('YYYY-MM-DD'),
+      end: cur.endOf('month').format('YYYY-MM-DD')
+    })
+  }
+  return ranges
+}
 
 // 鑾峰彇閮ㄩ棬鏁版嵁
 const getDepartmentData = async () => {
@@ -177,7 +217,7 @@
   try {
     const res = await findStaffAnalysisMonthlyTurnoverRateFor12Months()
     if (res && res.data) {
-      turnoverRateStatistics.value = res.data || []
+      turnoverRateStatisticsRaw.value = res.data || []
     }
   } catch (error) {
     console.error('鑾峰彇12涓湀鍛樺伐娴佸姩娴佸け鐜囧垎鏋愭暟鎹け璐�:', error)
@@ -186,14 +226,112 @@
 
 const getStaffAnalysisTotalStatistic = async () => {
   try {
-    const res = await findStaffAnalysisTotalStatistic()
-    if (res && res.data) {
-      keyMetrics.value[0].value = res.data.totalFlowRate || 0
-      keyMetrics.value[1].value = res.data.totalTurnoverRate || 0
-      keyMetrics.value[2].value = res.data.currentOnJobCount || 0
+    const ranges = getLast12MonthRanges()
+    const leave12Range = {
+      leaveDateStart: ranges[0].start,
+      leaveDateEnd: ranges[ranges.length - 1].end
     }
+
+    const [totalRes, onJobRes, leaveRes, leave12Res] = await Promise.all([
+      findStaffAnalysisTotalStatistic(),
+      staffOnJobListPage({ current: 1, size: 1, staffState: 1 }),
+      findStaffLeaveListPage({ current: 1, size: 1 }),
+      findStaffLeaveListPage({ current: 1, size: 1, ...leave12Range })
+    ])
+
+    const totalFlowRate = safeNum(totalRes?.data?.totalFlowRate)
+    const totalTurnoverRate = safeNum(totalRes?.data?.totalTurnoverRate)
+    const joinLeaveRatio =
+      totalTurnoverRate > 0 && totalFlowRate > 0 ? totalFlowRate / totalTurnoverRate : 1
+
+    const onJobTotal = getListTotal(onJobRes)
+    const leaveTotal = getListTotal(leaveRes)
+    const totalStaff = onJobTotal + leaveTotal
+    const leaveLast12Months = getListTotal(leave12Res)
+
+    staffCounts.value = {
+      onJobTotal,
+      leaveTotal,
+      totalStaff,
+      leaveLast12Months,
+      joinLeaveRatio: safeNum(joinLeaveRatio)
+    }
+
+    const turnoverRateNew =
+      totalStaff > 0 ? (leaveLast12Months / totalStaff) * 100 : 0
+    const flowRateNew =
+      totalStaff > 0 ? (leaveLast12Months * staffCounts.value.joinLeaveRatio / totalStaff) * 100 : 0
+
+    keyMetrics.value[0].value = round2(flowRateNew)
+    keyMetrics.value[1].value = round2(turnoverRateNew)
+    keyMetrics.value[2].value = onJobTotal || safeNum(totalRes?.data?.currentOnJobCount)
   } catch (error) {
     console.error('鑾峰彇鍛樺伐鍒嗘瀽鎬荤粺璁℃暟鎹け璐�:', error)
+  }
+}
+
+const getLeaveCountsByMonthForLast12Months = async () => {
+  const ranges = getLast12MonthRanges()
+  const tasks = ranges.map((r) =>
+    findStaffLeaveListPage({
+      current: 1,
+      size: 1,
+      leaveDateStart: r.start,
+      leaveDateEnd: r.end
+    })
+  )
+
+  const results = await Promise.allSettled(tasks)
+  const counts = {}
+  results.forEach((res, idx) => {
+    const month = ranges[idx].month
+    counts[month] = res.status === 'fulfilled' ? getListTotal(res.value) : 0
+  })
+  const sum = Object.values(counts).reduce((acc, cur) => acc + safeNum(cur), 0)
+  return { counts, sum }
+}
+
+const applyNormalizedTurnoverStatistics = async () => {
+  const raw = Array.isArray(turnoverRateStatisticsRaw.value) ? turnoverRateStatisticsRaw.value : []
+  if (raw.length === 0) {
+    turnoverRateStatistics.value = []
+    turnoverSeriesNormalized.value = false
+    return
+  }
+
+  const totalStaff = safeNum(staffCounts.value.totalStaff)
+  const leaveLast12Months = safeNum(staffCounts.value.leaveLast12Months)
+  const ratio = safeNum(staffCounts.value.joinLeaveRatio) || 1
+
+  if (totalStaff <= 0 || leaveLast12Months < 0) {
+    turnoverRateStatistics.value = raw
+    turnoverSeriesNormalized.value = false
+    return
+  }
+
+  try {
+    const { counts, sum } = await getLeaveCountsByMonthForLast12Months()
+    if (sum > leaveLast12Months) {
+      turnoverRateStatistics.value = raw
+      turnoverSeriesNormalized.value = false
+      return
+    }
+
+    turnoverRateStatistics.value = raw.map((item) => {
+      const monthKey = String(item?.month ?? '')
+      const leaveCount = safeNum(counts[monthKey])
+      const turnoverRate = totalStaff > 0 ? (leaveCount / totalStaff) * 100 : 0
+      const flowRate = totalStaff > 0 ? (leaveCount * ratio / totalStaff) * 100 : 0
+      return {
+        ...item,
+        flowRate: round2(flowRate),
+        turnoverRate: round2(turnoverRate)
+      }
+    })
+    turnoverSeriesNormalized.value = true
+  } catch (e) {
+    turnoverRateStatistics.value = raw
+    turnoverSeriesNormalized.value = false
   }
 }
 
@@ -238,6 +376,8 @@
       getMonthlyTurnoverRateFor12Months(),
       getStaffAnalysisTotalStatistic()
     ])
+
+    await applyNormalizedTurnoverStatistics()
 
     await nextTick()
     renderAllCharts()
@@ -317,10 +457,17 @@
       data: months,
       boundaryGap: false
     },
-    yAxis: {
-      type: 'value',
-      axisLabel: { formatter: '{value}%' }
-    },
+    yAxis: turnoverSeriesNormalized.value
+      ? {
+          type: 'value',
+          axisLabel: { formatter: '{value}%' },
+          min: 0,
+          max: 100
+        }
+      : {
+          type: 'value',
+          axisLabel: { formatter: '{value}%' }
+        },
     series: [
       {
         name: '娴佸姩鐜�',
diff --git a/src/views/personnelManagement/employeeRecord/index.vue b/src/views/personnelManagement/employeeRecord/index.vue
index db0d4d6..7c269bb 100644
--- a/src/views/personnelManagement/employeeRecord/index.vue
+++ b/src/views/personnelManagement/employeeRecord/index.vue
@@ -11,7 +11,7 @@
             clearable
             :prefix-icon="Search"
         />
-        <span class="search_title">閮ㄩ棬锛�</span>
+        <span class="search_title search_title2">閮ㄩ棬锛�</span>
           <el-tree-select
             v-model="searchForm.sysDeptId"
             :data="deptOptions"
@@ -20,9 +20,16 @@
             style="width: 240px"
             placeholder="璇烽�夋嫨"
           />
-        <span  style="margin-left: 10px" class="search_title">鍚堝悓缁撴潫鏃ユ湡锛�</span>
-        <el-date-picker  v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
-                         placeholder="璇烽�夋嫨" clearable @change="changeDaterange" />
+          <span class="search_title search_title2">鍏ヨ亴鏃ユ湡锛�</span>
+          <el-date-picker
+            v-model="searchForm.entryDateStart"
+            value-format="YYYY-MM-DD"
+            format="YYYY-MM-DD"
+            placeholder="璇烽�夋嫨"
+          />
+        <!-- <span  style="margin-left: 10px" class="search_title">鍚堝悓缁撴潫鏃ユ湡锛�</span> -->
+        <!-- <el-date-picker  v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
+                         placeholder="璇烽�夋嫨" clearable @change="changeDaterange" /> -->
         <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
         >鎼滅储</el-button
         >
@@ -129,6 +136,11 @@
   {
     label: "鍑虹敓鏃ユ湡",
     prop: "birthDate",
+    width: 120,
+  },
+  {
+    label: "鍏ヨ亴鏃ユ湡",
+    prop: "entryDate",
     width: 120,
   },
   {
@@ -307,4 +319,8 @@
 });
 </script>
 
-<style scoped></style>
+<style scoped>
+.search_title2 {
+  margin-left: 10px;
+}
+</style>

--
Gitblit v1.9.3