From 59e4906ad374bb44b481012b4b2a7d3d077b8677 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 06 七月 2026 17:00:00 +0800
Subject: [PATCH] 排班模块逻辑修改

---
 src/views/personnelManagement/classsSheduling/index.vue                          |  151 +++++++++++++++++++++++--
 src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue           |   31 ++++-
 src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue |  151 +++++++++++++++++-------
 3 files changed, 269 insertions(+), 64 deletions(-)

diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
index cbbb8af..0ddea67 100644
--- a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
@@ -37,11 +37,17 @@
           <el-option v-for="item in shifts_list"
                      :key="item.value"
                      :label="item.label"
-                     :value="item.value" />
+                     :value="item.value"
+                     :disabled="
+              operationType === 'add' &&
+              (String(item.label || '').includes('鍋�') ||
+                String(item.label || '').includes('浼�'))
+            " />
         </el-select>
       </el-form-item>
       <el-form-item label="鎵撳崱鑼冨洿(m)"
-                    prop="radius">
+                    prop="radius"
+                    v-show="!hideClockFields">
         <el-input-number v-model="form.radius"
                          :min="10"
                          :max="1000"
@@ -51,7 +57,8 @@
       </el-form-item>
       <!-- 楂樺痉鍦板浘閫夋嫨 -->
       <el-form-item label="鎵撳崱浣嶇疆"
-                    prop="longitude">
+                    prop="longitude"
+                    v-show="!hideClockFields">
         <div class="map-container">
           <div class="map-header"
                style="margin-bottom: 10px">
@@ -82,14 +89,16 @@
         </div>
       </el-form-item>
       <el-form-item label="鍦扮偣鍚嶇О"
-                    prop="locationName">
+                    prop="locationName"
+                    v-show="!hideClockFields">
         <el-input v-model="form.locationName"
                   :disabled="operationType === 'view'"
                   placeholder="璇疯緭鍏ュ湴鐐瑰悕绉�" />
       </el-form-item>
       <!-- 涓婁笅鐝椂闂� -->
       <el-form-item label="涓婄彮鏃堕棿"
-                    prop="startAt">
+                    prop="startAt"
+                    v-show="!hideClockFields">
         <el-time-picker v-model="form.startAt"
                         format="HH:mm"
                         value-format="HH:mm"
@@ -97,7 +106,8 @@
                         :disabled="operationType === 'view'" />
       </el-form-item>
       <el-form-item label="涓嬬彮鏃堕棿"
-                    prop="endAt">
+                    prop="endAt"
+                    v-show="!hideClockFields">
         <el-time-picker v-model="form.endAt"
                         format="HH:mm"
                         value-format="HH:mm"
@@ -110,7 +120,9 @@
     </el-form>
     <template #footer>
       <span class="dialog-footer">
-        <el-button type="primary" @click="submitForm" v-if="operationType !== 'view'">纭畾</el-button>
+        <el-button type="primary"
+                   @click="submitForm"
+                   v-if="operationType !== 'view'">纭畾</el-button>
         <el-button @click="dialogVisible = false">鍙栨秷</el-button>
       </span>
     </template>
@@ -157,6 +169,21 @@
   // 鑾峰彇鐝瀛楀吀鍊�
   const { shifts_list } = useDict("shifts_list");
 
+  const selectedShiftLabel = computed(() => {
+    const item = shifts_list.value?.find(
+      s => String(s.value) === String(form.shift)
+    );
+    return item?.label || "";
+  });
+
+  const hideClockFields = computed(() => {
+    if (props.operationType === "view") return false;
+    return (
+      selectedShiftLabel.value.includes("鍋�") ||
+      selectedShiftLabel.value.includes("浼�")
+    );
+  });
+
   // 琛ㄥ崟鏁版嵁
   const formRef = ref();
   const form = reactive({
@@ -172,44 +199,53 @@
   });
 
   // 琛ㄥ崟楠岃瘉瑙勫垯
-  const rules = {
-    sysDeptId: [{ required: true, message: "璇烽�夋嫨閮ㄩ棬", trigger: "change" }],
-    locationName: [
-      { required: true, message: "璇疯緭鍏ュ湴鐐瑰悕绉�", trigger: "blur" },
-    ],
-    longitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
-    latitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
-    shift: [{ required: true, message: "璇烽�夋嫨鐝", trigger: "change" }],
-    radius: [{ required: true, message: "璇疯緭鍏ユ墦鍗¤寖鍥�", trigger: "blur" }],
-    startAt: [{ required: true, message: "璇烽�夋嫨涓婄彮鏃堕棿", trigger: "change" }],
-    endAt: [
-      { required: true, message: "璇烽�夋嫨涓嬬彮鏃堕棿", trigger: "change" },
-      {
-        validator: (rule, value, callback) => {
-          // 濡傛灉鏄鐝紝涓嶉檺鍒舵椂闂撮『搴�
-          if (form.shift && ['澶滅彮', '澶�'].includes(form.shift)) {
-            callback();
-            return;
-          }
-          if (form.startAt && value) {
-            const startParts = form.startAt.split(":");
-            const endParts = value.split(":");
-            const startTime =
-              parseInt(startParts[0]) * 60 + parseInt(startParts[1]);
-            const endTime = parseInt(endParts[0]) * 60 + parseInt(endParts[1]);
-            if (endTime <= startTime) {
-              callback(new Error("涓嬬彮鏃堕棿涓嶈兘鏃╀簬涓婄彮鏃堕棿"));
+  const rules = computed(() => {
+    const base = {
+      sysDeptId: [{ required: true, message: "璇烽�夋嫨閮ㄩ棬", trigger: "change" }],
+      shift: [{ required: true, message: "璇烽�夋嫨鐝", trigger: "change" }],
+    };
+
+    if (hideClockFields.value) {
+      return base;
+    }
+
+    return {
+      ...base,
+      locationName: [
+        { required: true, message: "璇疯緭鍏ュ湴鐐瑰悕绉�", trigger: "blur" },
+      ],
+      longitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
+      latitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
+      radius: [{ required: true, message: "璇疯緭鍏ユ墦鍗¤寖鍥�", trigger: "blur" }],
+      startAt: [{ required: true, message: "璇烽�夋嫨涓婄彮鏃堕棿", trigger: "change" }],
+      endAt: [
+        { required: true, message: "璇烽�夋嫨涓嬬彮鏃堕棿", trigger: "change" },
+        {
+          validator: (rule, value, callback) => {
+            if (form.shift && ["澶滅彮", "澶�"].includes(form.shift)) {
+              callback();
+              return;
+            }
+            if (form.startAt && value) {
+              const startParts = form.startAt.split(":");
+              const endParts = value.split(":");
+              const startTime =
+                parseInt(startParts[0]) * 60 + parseInt(startParts[1]);
+              const endTime = parseInt(endParts[0]) * 60 + parseInt(endParts[1]);
+              if (endTime <= startTime) {
+                callback(new Error("涓嬬彮鏃堕棿涓嶈兘鏃╀簬涓婄彮鏃堕棿"));
+              } else {
+                callback();
+              }
             } else {
               callback();
             }
-          } else {
-            callback();
-          }
+          },
+          trigger: "change",
         },
-        trigger: "change",
-      },
-    ],
-  };
+      ],
+    };
+  });
 
   // 閮ㄩ棬閫夐」
   const deptOptions = ref([]);
@@ -393,8 +429,8 @@
   watch(
     () => form.radius,
     newValue => {
-      if (circle) {
-        circle.setRadius(newValue);
+      if (circle && newValue != null && newValue !== "") {
+        circle.setRadius(Number(newValue));
       }
     }
   );
@@ -405,6 +441,29 @@
     () => {
       if (formRef.value && form.endAt) {
         formRef.value.validateField("endAt");
+      }
+    }
+  );
+
+  watch(
+    () => hideClockFields.value,
+    val => {
+      if (!val) return;
+      form.radius = null;
+      form.longitude = "";
+      form.latitude = "";
+      form.locationName = "";
+      form.startAt = "";
+      form.endAt = "";
+      if (formRef.value) {
+        formRef.value.clearValidate([
+          "radius",
+          "longitude",
+          "latitude",
+          "locationName",
+          "startAt",
+          "endAt",
+        ]);
       }
     }
   );
@@ -442,7 +501,9 @@
 
         // 鍒濆鍖栧湴鍥�
         setTimeout(() => {
-          initMap();
+          if (!hideClockFields.value) {
+            initMap();
+          }
         }, 100);
       }
     }
@@ -513,4 +574,4 @@
   .mt8 {
     margin-top: 8px;
   }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
index c47dd2e..d09329b 100644
--- a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
@@ -74,23 +74,39 @@
           </template>
         </el-table-column>
         <el-table-column prop="locationName"
-                         label="鍦扮偣鍚嶇О" />
+                         label="鍦扮偣鍚嶇О">
+          <template #default="scope">
+            {{ scope.row.locationName || "-" }}
+          </template>
+        </el-table-column>
         <el-table-column prop="longitude"
-                         label="缁忓害" />
+                         label="缁忓害">
+          <template #default="scope">
+            {{ scope.row.longitude ?? "-" }}
+          </template>
+        </el-table-column>
         <el-table-column prop="latitude"
-                         label="绾害" />
+                         label="绾害">
+          <template #default="scope">
+            {{ scope.row.latitude ?? "-" }}
+          </template>
+        </el-table-column>
         <el-table-column prop="radius"
-                         label="鎵撳崱鑼冨洿(m)" />
+                         label="鎵撳崱鑼冨洿(m)">
+          <template #default="scope">
+            {{ scope.row.radius ?? "-" }}
+          </template>
+        </el-table-column>
         <el-table-column prop="startAt"
                          label="涓婄彮鏃堕棿">
           <template #default="scope">
-            {{ scope.row.startAt }}
+            {{ scope.row.startAt || "-" }}
           </template>
         </el-table-column>
         <el-table-column prop="endAt"
                          label="涓嬬彮鏃堕棿">
           <template #default="scope">
-            {{ scope.row.endAt }}
+            {{ scope.row.endAt || "-" }}
           </template>
         </el-table-column>
         <el-table-column label="鎿嶄綔"
@@ -232,7 +248,8 @@
     tableLoading.value = true;
     getAttendanceRules({ ...page, ...searchForm })
       .then(res => {
-        tableData.value = res.data.records;
+        const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+        tableData.value = records.filter(r => String(r?.id) !== "999");
         page.total = res.data.total;
       })
       .finally(() => {
diff --git a/src/views/personnelManagement/classsSheduling/index.vue b/src/views/personnelManagement/classsSheduling/index.vue
index 140ffba..8228be9 100644
--- a/src/views/personnelManagement/classsSheduling/index.vue
+++ b/src/views/personnelManagement/classsSheduling/index.vue
@@ -149,12 +149,12 @@
                       'shift-box-early': m.shift === '鏃╃彮',
                       'shift-box-mid': m.shift === '涓彮',
                       'shift-box-night': m.shift === '澶滅彮',
-                      'shift-box-rest': m.shift === '浼戞伅',
+                      'shift-box-rest': !m.shift || m.shift === '浼戞伅',
                       'shift-box-leave': m.shift === '璇峰亣',
                       'shift-box-other': m.shift === '澶�11',
                       'shift-box-business': m.shift === '澶�12',
                     }">
-                      <span class="shift-text">{{ getShiftNameByValue(m.shift) || '鈥�' }}</span>
+                      <span class="shift-text">{{ getShiftNameByValue(m.shift) || '浼戞伅' }}</span>
                     </div>
                     <template #dropdown>
                       <el-dropdown-menu>
@@ -199,7 +199,7 @@
               </div> -->
               <div class="user-total">
                 <span class="total-label">鍚堣鍑哄嫟:</span>
-                <span class="total-value">{{ item.work_time }}澶�</span>
+                <span class="total-value">{{ item.year.totalYearAttendance }}澶�</span>
               </div>
             </div>
           </div>
@@ -271,6 +271,23 @@
       <div class="search_thing">
         <div class="search_label"
              style="width: 90px">
+          <span style="color: red; margin-right: 4px">*</span>閮ㄩ棬锛�
+        </div>
+        <div class="search_input">
+          <el-tree-select v-model="schedulingQuery.deptId"
+                          :data="deptOptions"
+                          :props="{ value: 'id', label: 'label', children: 'children' }"
+                          value-key="id"
+                          placeholder="璇烽�夋嫨閮ㄩ棬"
+                          check-strictly
+                          clearable
+                          @change="onSchedulingDeptChange"
+                          style="width: 100%" />
+        </div>
+      </div>
+      <div class="search_thing">
+        <div class="search_label"
+             style="width: 90px">
           <span style="color: red; margin-right: 4px">*</span>浜哄憳鍚嶇О锛�
         </div>
         <div class="search_input">
@@ -279,7 +296,8 @@
                      style="width: 100%"
                      multiple
                      clearable
-                     collapse-tags>
+                     collapse-tags
+                     :disabled="!schedulingQuery.deptId">
             <el-option v-for="item in personList"
                        :key="item.id"
                        :label="item.staffName"
@@ -296,8 +314,9 @@
         <div class="search_input">
           <el-select v-model="schedulingQuery.shift"
                      placeholder="璇烽�夋嫨"
-                     style="width: 100%">
-            <el-option v-for="item in classType"
+                     style="width: 100%"
+                     :disabled="!schedulingQuery.deptId">
+            <el-option v-for="item in schedulingClassType"
                        :key="item.id"
                        :label="getShiftNameByValue(item.shift)"
                        :value="item.id">
@@ -318,7 +337,14 @@
 </template>
 
 <script setup>
-  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+  import {
+    ref,
+    reactive,
+    computed,
+    watch,
+    onMounted,
+    getCurrentInstance,
+  } from "vue";
   import { useRouter } from "vue-router";
   import {
     page,
@@ -376,6 +402,7 @@
 
   // 浜哄憳鍒楄〃
   const personList = ref([]);
+  const personListAll = ref([]);
 
   // 鍔犺浇鐘舵��
   const loading = ref(false);
@@ -383,8 +410,18 @@
   // 鎺掔彮鏌ヨ鏉′欢
   const schedulingQuery = reactive({
     week: "",
+    deptId: "",
     userId: null,
     shift: "",
+  });
+
+  const schedulingClassType = computed(() => {
+    if (!schedulingQuery.deptId) return classType.value || [];
+    return (classType.value || []).filter(item => {
+      if (["998", "999"].includes(String(item?.id))) return true;
+      const itemDeptId = item.deptId ?? item.sysDeptId ?? item.dept_id;
+      return String(itemDeptId) === String(schedulingQuery.deptId);
+    });
   });
 
   // 鍒楄〃鏁版嵁
@@ -593,6 +630,10 @@
       proxy.$modal.msgError("璇烽�夋嫨鍛ㄦ");
       return;
     }
+    if (!schedulingQuery.deptId) {
+      proxy.$modal.msgError("璇烽�夋嫨閮ㄩ棬");
+      return;
+    }
     let time = schedulingQuery.week.getTime();
 
     // 鏍煎紡鍖栨棩鏈熶负 YYYY-MM-DD 鏍煎紡
@@ -628,8 +669,10 @@
         proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
         schedulingVisible.value = false;
         schedulingQuery.week = "";
+        schedulingQuery.deptId = "";
         schedulingQuery.userId = null;
         schedulingQuery.shift = "";
+        personList.value = [];
         refresh();
       })
       .catch(err => {
@@ -683,8 +726,7 @@
         }
         proxy.$download.saveAs(blob, fileName + ".xlsx");
       })
-      .catch(err => {
-      })
+      .catch(err => {})
       .finally(() => {
         downLoading.value = false;
       });
@@ -709,7 +751,18 @@
   // 鏌ヨ瑙勫垯鍒楄〃
   const fetchData = () => {
     getAttendanceRules({ current: -1, size: -1 }).then(res => {
-      classType.value = res.data.records;
+      const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+      const appendList = [
+        { id: 998, shift: "浼戞伅" },
+        { id: 999, shift: "璇峰亣" },
+      ];
+      const exists = new Set(records.map(r => String(r?.id)));
+      appendList.forEach(item => {
+        if (!exists.has(String(item.id))) {
+          records.push(item);
+        }
+      });
+      classType.value = records;
     });
   };
   // 鑾峰彇鐢ㄦ埛
@@ -724,8 +777,61 @@
       staffState: 1,
     }).then(res => {
       let arr = res.data.records;
-      personList.value = arr;
+      personListAll.value = arr;
+      updatePersonListByDept();
     });
+  };
+
+  const findDeptNodeById = (deptId, deptList = deptOptions.value) => {
+    const list = Array.isArray(deptList) ? deptList : [];
+    for (const node of list) {
+      if (String(node.id) === String(deptId)) return node;
+      if (node.children && node.children.length) {
+        const found = findDeptNodeById(deptId, node.children);
+        if (found) return found;
+      }
+    }
+    return null;
+  };
+
+  const collectDeptIds = node => {
+    const ids = [];
+    if (!node) return ids;
+    ids.push(String(node.id));
+    if (node.children && node.children.length) {
+      node.children.forEach(child => {
+        ids.push(...collectDeptIds(child));
+      });
+    }
+    return ids;
+  };
+
+  const updatePersonListByDept = () => {
+    if (!schedulingQuery.deptId) {
+      personList.value = [];
+      return;
+    }
+    const node = findDeptNodeById(schedulingQuery.deptId);
+    const deptIds = new Set(collectDeptIds(node));
+    personList.value = (personListAll.value || []).filter(item => {
+      const itemDeptId = item.deptId ?? item.sysDeptId ?? item.dept_id;
+      return deptIds.has(String(itemDeptId));
+    });
+  };
+
+  const setDefaultShiftByDept = () => {
+    if (!schedulingQuery.deptId) {
+      schedulingQuery.shift = "";
+      return;
+    }
+    const first = schedulingClassType.value?.[0];
+    schedulingQuery.shift = first ? first.id : "";
+  };
+
+  const onSchedulingDeptChange = () => {
+    schedulingQuery.userId = null;
+    updatePersonListByDept();
+    setDefaultShiftByDept();
   };
 
   // 鏍规嵁瀛楀吀鑾峰彇鏃ユ湡
@@ -761,6 +867,27 @@
     }
     monthList.value.reverse();
   });
+
+  watch(
+    () => classType.value,
+    () => {
+      if (schedulingVisible.value && schedulingQuery.deptId) {
+        setDefaultShiftByDept();
+      }
+    }
+  );
+
+  watch(
+    () => schedulingVisible.value,
+    val => {
+      if (!val) return;
+      schedulingQuery.week = "";
+      schedulingQuery.deptId = "";
+      schedulingQuery.userId = null;
+      schedulingQuery.shift = "";
+      personList.value = [];
+    }
+  );
 </script>
 
 <style scoped>
@@ -973,7 +1100,7 @@
   .user-stats {
     /* display: flex; */
     /* flex-wrap: wrap;
-                                                                                                                                                                                                                                                                                        gap: 10px; */
+                                                                                                                                                                                                                                                                                                      gap: 10px; */
     margin-bottom: 4px;
   }
 

--
Gitblit v1.9.3