From 7e3160579cb83558c87ce44df0b74784f0c9f916 Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期五, 20 三月 2026 13:50:28 +0800
Subject: [PATCH] fix: 修复离职日期编辑和删除按钮状态逻辑,优化表格操作样式

---
 src/views/personnelManagement/dimission/components/formDia.vue |    1 
 src/components/PIMTable/PIMTable.vue                           |   79 ++++++++++++++-
 src/views/salesManagement/returnOrder/index.vue                |    2 
 src/views/personnelManagement/analytics/index.vue              |  167 ++-------------------------------
 4 files changed, 84 insertions(+), 165 deletions(-)

diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index a418280..1a2ef5d 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -135,14 +135,12 @@
             <el-button
               v-show="o.type != 'upload'"
               v-if="o.showHide ? o.showHide(scope.row) : true"
-              :disabled="o.disabled ? o.disabled(scope.row) : false"
+              :disabled="isOperationDisabled(o, scope.row)"
               :plain="o.plain"
               type="primary"
               :style="{
-                color:
-                  o.name === '鍒犻櫎' || o.name === 'delete'
-                    ? '#f56c6c'
-                    : o.color,
+                color: getOperationColor(o, scope.row),
+                fontWeight: 'bold',
               }"
               link
               @click.stop="o.clickFun(scope.row)"
@@ -160,7 +158,7 @@
               ref="uploadRef"
               :multiple="o.multiple ? o.multiple : false"
               :limit="1"
-              :disabled="o.disabled ? o.disabled(scope.row) : false"
+              :disabled="isOperationDisabled(o, scope.row)"
               :accept="
                 o.accept
                   ? o.accept
@@ -188,7 +186,11 @@
               <el-button
                 link
                 type="primary"
-                :disabled="o.disabled ? o.disabled(scope.row) : false"
+                :disabled="isOperationDisabled(o, scope.row)"
+                :style="{
+                  color: getOperationColor(o, scope.row),
+                  fontWeight: 'bold',
+                }"
                 >{{ o.name }}</el-button
               >
             </el-upload>
@@ -373,6 +375,69 @@
   } else return "";
 };
 
+const isOperationDisabled = (operation, row) => {
+  if (!operation?.disabled) return false;
+  return typeof operation.disabled === "function"
+    ? !!operation.disabled(row)
+    : !!operation.disabled;
+};
+
+const parseHexToRgb = (hex) => {
+  const normalized = String(hex || "").trim().replace("#", "");
+  if (normalized.length === 3) {
+    const r = parseInt(normalized[0] + normalized[0], 16);
+    const g = parseInt(normalized[1] + normalized[1], 16);
+    const b = parseInt(normalized[2] + normalized[2], 16);
+    if ([r, g, b].some((n) => Number.isNaN(n))) return null;
+    return { r, g, b };
+  }
+  if (normalized.length === 6 || normalized.length === 8) {
+    const r = parseInt(normalized.slice(0, 2), 16);
+    const g = parseInt(normalized.slice(2, 4), 16);
+    const b = parseInt(normalized.slice(4, 6), 16);
+    if ([r, g, b].some((n) => Number.isNaN(n))) return null;
+    return { r, g, b };
+  }
+  return null;
+};
+
+const fadeColor = (color, alpha = 0.35) => {
+  const c = String(color || "").trim();
+  if (!c) return undefined;
+  if (c.startsWith("#")) {
+    const rgb = parseHexToRgb(c);
+    if (!rgb) return c;
+    return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
+  }
+  const rgbMatch = c.match(/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*[\d.]+\s*)?\)$/i);
+  if (rgbMatch) {
+    const r = Number(rgbMatch[1]);
+    const g = Number(rgbMatch[2]);
+    const b = Number(rgbMatch[3]);
+    if ([r, g, b].some((n) => Number.isNaN(n))) return c;
+    return `rgba(${r}, ${g}, ${b}, ${alpha})`;
+  }
+  if (c.includes("--el-color-primary")) {
+    return "var(--el-color-primary-light-5)";
+  }
+  if (c.includes("--el-color-danger")) {
+    return "var(--el-color-danger-light-5)";
+  }
+  return "var(--el-text-color-disabled)";
+};
+
+const getOperationColor = (operation, row) => {
+  const baseColor =
+    operation?.name === "鍒犻櫎" || operation?.name === "delete"
+      ? "#D93025"
+      : operation?.color || "var(--el-color-primary)";
+
+  if (isOperationDisabled(operation, row)) {
+    return fadeColor(baseColor, 0.35);
+  }
+  return baseColor;
+};
+
 // 鏂囦欢鍙樺寲澶勭悊
 const handleChange = (file, fileList, index) => {
   if (fileList.length > 1) {
diff --git a/src/views/personnelManagement/analytics/index.vue b/src/views/personnelManagement/analytics/index.vue
index db97619..9e6e449 100644
--- a/src/views/personnelManagement/analytics/index.vue
+++ b/src/views/personnelManagement/analytics/index.vue
@@ -86,15 +86,12 @@
 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)
@@ -151,43 +148,6 @@
 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 () => {
@@ -217,7 +177,7 @@
   try {
     const res = await findStaffAnalysisMonthlyTurnoverRateFor12Months()
     if (res && res.data) {
-      turnoverRateStatisticsRaw.value = res.data || []
+      turnoverRateStatistics.value = res.data || []
     }
   } catch (error) {
     console.error('鑾峰彇12涓湀鍛樺伐娴佸姩娴佸け鐜囧垎鏋愭暟鎹け璐�:', error)
@@ -226,112 +186,14 @@
 
 const getStaffAnalysisTotalStatistic = async () => {
   try {
-    const ranges = getLast12MonthRanges()
-    const leave12Range = {
-      leaveDateStart: ranges[0].start,
-      leaveDateEnd: ranges[ranges.length - 1].end
+    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 [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
   }
 }
 
@@ -376,8 +238,6 @@
       getMonthlyTurnoverRateFor12Months(),
       getStaffAnalysisTotalStatistic()
     ])
-
-    await applyNormalizedTurnoverStatistics()
 
     await nextTick()
     renderAllCharts()
@@ -457,17 +317,10 @@
       data: months,
       boundaryGap: false
     },
-    yAxis: turnoverSeriesNormalized.value
-      ? {
-          type: 'value',
-          axisLabel: { formatter: '{value}%' },
-          min: 0,
-          max: 100
-        }
-      : {
-          type: 'value',
-          axisLabel: { formatter: '{value}%' }
-        },
+    yAxis: {
+      type: 'value',
+      axisLabel: { formatter: '{value}%' }
+    },
     series: [
       {
         name: '娴佸姩鐜�',
diff --git a/src/views/personnelManagement/dimission/components/formDia.vue b/src/views/personnelManagement/dimission/components/formDia.vue
index 6d3cb46..84922ec 100644
--- a/src/views/personnelManagement/dimission/components/formDia.vue
+++ b/src/views/personnelManagement/dimission/components/formDia.vue
@@ -101,6 +101,7 @@
                 <el-date-picker
                     v-model="form.leaveDate"
                     type="date"
+                    :disabled="operationType === 'edit'"
                     placeholder="璇烽�夋嫨绂昏亴鏃ユ湡"
                     value-format="YYYY-MM-DD"
                     format="YYYY-MM-DD"
diff --git a/src/views/salesManagement/returnOrder/index.vue b/src/views/salesManagement/returnOrder/index.vue
index 5a5aa05..47866a4 100644
--- a/src/views/salesManagement/returnOrder/index.vue
+++ b/src/views/salesManagement/returnOrder/index.vue
@@ -35,7 +35,7 @@
     <div class="table_list">
       <div class="table_header" style="display: flex;justify-content: flex-end;margin-bottom: 10px;">
         <el-button type="primary" @click="openForm('add')">鏂板缓閿�鍞��璐�</el-button>
-        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+        <el-button type="danger" :disabled="selectedRows.length === 0 || selectedRows.some(row => row.status !== 0)" @click="handleDelete">鍒犻櫎</el-button>
       </div>
       <PIMTable
         rowKey="id"

--
Gitblit v1.9.3