From a4d0446d7c1c1e56641fd4e887ad4d0ecd0534ca Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 05 三月 2026 17:43:55 +0800
Subject: [PATCH] 排班管理页面完成70%

---
 src/api/personnelManagement/attendanceRules.js                                   |   10 
 src/api/personnelManagement/class.js                                             |  108 ++
 src/views/personnelManagement/classsSheduling/index.vue                          | 2209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue           |   14 
 src/views/personnelManagement/attendanceCheckin/index.vue                        |   20 
 src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue |    6 
 6 files changed, 2,351 insertions(+), 16 deletions(-)

diff --git a/src/api/personnelManagement/attendanceRules.js b/src/api/personnelManagement/attendanceRules.js
index 021442e..5b07b8b 100644
--- a/src/api/personnelManagement/attendanceRules.js
+++ b/src/api/personnelManagement/attendanceRules.js
@@ -1,6 +1,6 @@
 import request from "@/utils/request";
 
-// 鑾峰彇鎵撳崱瑙勫垯鍒楄〃
+// 鑾峰彇鐝鍒楄〃
 export function getAttendanceRules(query) {
   return request({
     url: "/personalAttendanceLocationConfig/listPage",
@@ -9,7 +9,7 @@
   });
 }
 
-// 鏂板鎵撳崱瑙勫垯
+// 鏂板鐝
 export function addAttendanceRule(data) {
   return request({
     url: "/personalAttendanceLocationConfig/add",
@@ -18,7 +18,7 @@
   });
 }
 
-// 鏇存柊鎵撳崱瑙勫垯
+// 鏇存柊鐝
 export function updateAttendanceRule(data) {
   return request({
     url: "/attendanceRules/update",
@@ -27,7 +27,7 @@
   });
 }
 
-// 鍒犻櫎鎵撳崱瑙勫垯
+// 鍒犻櫎鐝
 export function deleteAttendanceRule(ids) {
   return request({
     url: `/personalAttendanceLocationConfig/del`,
@@ -36,7 +36,7 @@
   });
 }
 
-// 鑾峰彇鍗曚釜鎵撳崱瑙勫垯璇︽儏
+// 鑾峰彇鍗曚釜鐝璇︽儏
 export function getAttendanceRuleDetail(id) {
   return request({
     url: `/attendanceRules/detail/${id}`,
diff --git a/src/api/personnelManagement/class.js b/src/api/personnelManagement/class.js
new file mode 100644
index 0000000..cdba456
--- /dev/null
+++ b/src/api/personnelManagement/class.js
@@ -0,0 +1,108 @@
+// 鐝鐩稿叧鎺ュ彛
+
+import request from "@/utils/request";
+
+// 缁╂晥绠$悊-鐝-鍒嗛〉鏌ヨ
+export function page(query) {
+  return request({
+    url: "/performanceShift/page",
+    method: "get",
+    params: query,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-骞翠唤鍒嗛〉鏌ヨ
+export function pageYear(query) {
+  return request({
+    url: "/performanceShift/pageYear",
+    method: "get",
+    params: query,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-鎺掔彮
+export function add(data) {
+  return request({
+    url: "/performanceShift/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-鏃堕棿閰嶇疆-鏌ヨ鏃堕棿閰嶇疆淇℃伅
+export function list(query) {
+  return request({
+    url: "/shiftTime/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-鏃堕棿閰嶇疆-鏂板
+export function shiftAdd(data) {
+  return request({
+    url: "/shiftTime/add",
+    method: "post",
+    data: data,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-鏃堕棿閰嶇疆-淇敼
+export function shiftUpdate(data) {
+  return request({
+    url: "/shiftTime/update",
+    method: "post",
+    data: data,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-鏃堕棿閰嶇疆-鍒犻櫎
+export function shiftRemove(query) {
+  return request({
+    url: "/shiftTime/remove",
+    method: "delete",
+    params: query,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-瀵煎嚭
+export function exportFile(query) {
+  return request({
+    url: "/performanceShift/export",
+    method: "get",
+    params: query,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-瀵煎嚭
+export function obtainItemParameterList(query) {
+  return request({
+    url: "/laboratoryScope/obtainItemParameterList",
+    method: "get",
+    params: query,
+  });
+}
+
+// 缁╂晥绠$悊-鐝-鐝鐘舵�佷慨鏀�
+export function update(data) {
+  return request({
+    url: "/performanceShift/update",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鑾峰彇鐢ㄦ埛鍒楄〃
+// export function selectUserCondition(query) {
+//   return request({
+//     url: "/system/newUser/selectUserCondition",
+//     method: "get",
+//     params: query,
+//   });
+// }
+export function selectUserCondition() {
+  return request({
+    url: '/system/user/userListNoPage',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
index 11e21bc..49eafa9 100644
--- a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
@@ -140,9 +140,9 @@
   });
 
   const dialogTitle = computed(() => {
-    if (props.operationType === "add") return "鏂板鎵撳崱瑙勫垯";
-    if (props.operationType === "edit") return "缂栬緫鎵撳崱瑙勫垯";
-    return "鏌ョ湅鎵撳崱瑙勫垯";
+    if (props.operationType === "add") return "鏂板鐝";
+    if (props.operationType === "edit") return "缂栬緫鐝";
+    return "鏌ョ湅鐝";
   });
 
   // 琛ㄥ崟鏁版嵁
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
index 1fd19f3..9064274 100644
--- a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
@@ -2,14 +2,14 @@
   <div class="app-container">
     <!-- 椤甸潰鏍囬鍜屾搷浣滄寜閽� -->
     <div class="page-header">
-      <div class="title">鎵撳崱瑙勫垯閰嶇疆</div>
+      <div class="title">鐝閰嶇疆</div>
       <div class="actions">
         <el-button type="primary"
                    @click="openForm('add')">
           <el-icon>
             <Plus />
           </el-icon>
-          鏂板瑙勫垯
+          鏂板鐝
         </el-button>
       </div>
     </div>
@@ -50,7 +50,7 @@
         </el-button>
       </el-form-item>
     </el-form> -->
-    <!-- 瑙勫垯鍒楄〃 -->
+    <!-- 鐝鍒楄〃 -->
     <el-card shadow="never"
              class="mb16">
       <el-table :data="tableData"
@@ -110,7 +110,7 @@
                   @pagination="paginationChange"
                   class="mt10" />
     </el-card>
-    <!-- 鏂板/缂栬緫瑙勫垯寮圭獥 -->
+    <!-- 鏂板/缂栬緫鐝寮圭獥 -->
     <rule-form ref="ruleFormRef"
                v-model="dialogVisible"
                :operation-type="operationType"
@@ -206,7 +206,7 @@
     return "";
   };
 
-  // 鏌ヨ瑙勫垯鍒楄〃
+  // 鏌ヨ鐝鍒楄〃
   const fetchData = () => {
     tableLoading.value = true;
     getAttendanceRules({ ...page, ...searchForm })
@@ -240,9 +240,9 @@
     dialogVisible.value = true;
   };
 
-  // 鍒犻櫎瑙勫垯
+  // 鍒犻櫎鐝
   const handleDelete = id => {
-    ElMessageBox.confirm("纭畾瑕佸垹闄よ繖鏉¤鍒欏悧锛�", "鍒犻櫎纭", {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ繖鏉$彮娆″悧锛�", "鍒犻櫎纭", {
       confirmButtonText: "纭畾",
       cancelButtonText: "鍙栨秷",
       type: "warning",
diff --git a/src/views/personnelManagement/attendanceCheckin/index.vue b/src/views/personnelManagement/attendanceCheckin/index.vue
index f2d8776..9a3acfa 100644
--- a/src/views/personnelManagement/attendanceCheckin/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/index.vue
@@ -60,6 +60,15 @@
       </el-descriptions>
     </el-card> -->
     <div class="attendance-operation">
+      <el-button @click="handleBack"
+                 type="default"
+                 size="small"
+                 style="margin-right: 16px">
+        <el-icon>
+          <ArrowLeft />
+        </el-icon>
+        杩斿洖鎺掔彮绠$悊
+      </el-button>
       <!-- 鏌ヨ鏉′欢锛堢鐞嗗憳鑰冨嫟鏃ユ姤锛� -->
       <el-form :model="searchForm"
                :inline="true"
@@ -170,6 +179,7 @@
 
 <script setup>
   import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
+  import { useRouter } from "vue-router";
   import { ElMessage, ElMessageBox } from "element-plus";
   import {
     createPersonalAttendanceRecord,
@@ -178,9 +188,10 @@
   } from "@/api/personnelManagement/personalAttendanceRecords.js";
   import Pagination from "@/components/Pagination/index.vue";
   import { deptTreeSelect } from "@/api/system/user.js";
-  import { Refresh, Search } from "@element-plus/icons-vue";
+  import { Refresh, Search, ArrowLeft } from "@element-plus/icons-vue";
 
   const { proxy } = getCurrentInstance();
+  const router = useRouter();
   const tableLoading = ref(false);
   // 鍒嗛〉鍙傛暟
   const page = reactive({
@@ -445,6 +456,13 @@
     fetchDeptOptions();
   });
 
+  // 杩斿洖鎺掔彮绠$悊椤甸潰
+  const handleBack = () => {
+    router.push({
+      path: "/personnelManagement/classsSheduling/index",
+    });
+  };
+
   onBeforeUnmount(() => {
     if (timer) {
       clearInterval(timer);
diff --git a/src/views/personnelManagement/classsSheduling/index.vue b/src/views/personnelManagement/classsSheduling/index.vue
new file mode 100644
index 0000000..bc5ed7f
--- /dev/null
+++ b/src/views/personnelManagement/classsSheduling/index.vue
@@ -0,0 +1,2209 @@
+<template>
+  <div class="class-page">
+    <div class="search-container">
+      <div class="search-form">
+        <div class="search-row">
+          <div class="search-item">
+            <label class="search-label">閫夋嫨鏃堕棿锛�</label>
+            <div class="search-input-group">
+              <el-date-picker v-model="query.year"
+                              type="year"
+                              size="small"
+                              format="YYYY"
+                              placeholder="閫夋嫨骞�"
+                              @change="refreshTable()"
+                              style="width: 90px"
+                              :clearable="false" />
+              <el-select v-model="query.month"
+                         clearable
+                         placeholder="閫夋嫨鏈�"
+                         style="width: 70px; margin-left: 8px"
+                         size="small"
+                         @change="refreshTable()">
+                <el-option v-for="item in monthOptions"
+                           :key="item.value"
+                           :label="item.label"
+                           :value="item.value" />
+              </el-select>
+            </div>
+          </div>
+          <div class="search-item">
+            <el-input v-model="query.userName"
+                      placeholder="璇疯緭鍏ヤ汉鍛樺悕绉�"
+                      size="small"
+                      style="width: 120px"
+                      clearable
+                      @keyup.enter="refreshTable()" />
+          </div>
+          <div class="search-item">
+            <el-tree-select v-model="query.deptId"
+                            :data="deptOptions"
+                            :props="{ value: 'id', label: 'label', children: 'children' }"
+                            value-key="id"
+                            placeholder="璇烽�夋嫨閮ㄩ棬"
+                            size="small"
+                            clearable
+                            @change="refreshTable()"
+                            style="width: 140px" />
+          </div>
+          <div class="search-actions">
+            <el-button size="small"
+                       type="primary"
+                       @click="refreshTable()"
+                       :icon="Search">
+              鏌ヨ
+            </el-button>
+            <el-button size="small"
+                       @click="refresh()"
+                       :icon="Refresh"
+                       style="margin-left: 8px">
+              閲嶇疆
+            </el-button>
+          </div>
+          <div class="search-buttons">
+            <el-button size="small"
+                       type="primary"
+                       @click="configTime"
+                       :icon="Setting">
+              鐝閰嶇疆
+            </el-button>
+            <el-button size="small"
+                       type="success"
+                       @click="handleDown"
+                       :loading="downLoading"
+                       :icon="Download"
+                       style="margin-left: 8px">
+              瀵煎嚭
+            </el-button>
+            <el-button size="small"
+                       type="warning"
+                       @click="schedulingVisible = true"
+                       :icon="Calendar"
+                       style="margin-left: 8px">
+              鎺掔彮
+            </el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="scheduling-container"
+         v-loading="pageLoading">
+      <!-- 鏈堝害鎺掔彮 -->
+      <div class="scheduling-table"
+           v-show="query.month">
+        <div class="scheduling-left">
+          <div class="scheduling-header">
+            浜哄憳鍚嶇О
+          </div>
+          <div class="scheduling-user"
+               :class="{ 'scheduling-user-hover': currentUserIndex == index }"
+               v-for="(item, index) in listForm"
+               :key="'e' + index"
+               @mouseenter="onMouseEnter(index)"
+               @mouseleave="currentUserIndex = null">
+            <div class="user-avatar">
+              {{ item.name ? item.name.charAt(0) : "" }}
+            </div>
+            <div class="user-details">
+              <h4 class="user-name">{{ item.name }}</h4>
+              <!-- <div class="user-stats">
+                <span class="stat-item">鏃�:{{ item.day0 }}</span>
+                <span class="stat-item">涓�:{{ item.day1 }}</span>
+                <span class="stat-item">澶�:{{ item.day2 }}</span>
+                <span class="stat-item">浼�:{{ item.day3 }}</span>
+                <span class="stat-item">鍋�:{{ item.day4 }}</span>
+                <span class="stat-item">宸�:{{ item.day6 }}</span>
+              </div> -->
+              <div class="user-total">
+                <span class="total-label">鍚堣鍑哄嫟:</span>
+                <span class="total-value">{{ item.monthlyAttendance.totalAttendance }}澶�</span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="scheduling-right">
+          <div class="scheduling-calendar">
+            <div class="calendar-header">
+              <div class="calendar-header-item"
+                   v-for="(item, index) in weeks"
+                   :key="'b' + index">
+                <span class="week-number"
+                      v-if="item.week == '鍛ㄦ棩'">{{ item.weekNum }}鍛�</span>
+                <div class="day-info">
+                  <span class="day-number">{{ item.day }}</span>
+                  <span class="day-week">{{ item.week.charAt(1) }}</span>
+                </div>
+              </div>
+            </div>
+            <div class="calendar-body">
+              <div class="calendar-row"
+                   v-for="(item, index) in listForm"
+                   :key="'c' + index"
+                   :class="{ 'calendar-row-hover': currentUserIndex == index }"
+                   @mouseenter="onMouseEnter(index)"
+                   @mouseleave="currentUserIndex = null">
+                <div class="calendar-cell"
+                     v-for="(m, i) in item.list"
+                     :key="'d' + i">
+                  <el-dropdown trigger="click"
+                               placement="bottom"
+                               @command="(e) => handleCommand(e, m)"
+                               class="shift-dropdown">
+                    <div class="shift-box"
+                         :class="{
+                      'shift-box-early': m.shift === '0',
+                      'shift-box-mid': m.shift === '1',
+                      'shift-box-night': m.shift === '2',
+                      'shift-box-rest': m.shift === '3',
+                      'shift-box-leave': m.shift === '4',
+                      'shift-box-other': m.shift === '5',
+                      'shift-box-business': m.shift === '6',
+                    }">
+                      <span class="shift-text">{{ getShiftByDic(m.shift) || '鈥�' }}</span>
+                    </div>
+                    <template #dropdown>
+                      <el-dropdown-menu>
+                        <el-dropdown-item v-for="(n, j) in classType"
+                                          :key="'h' + j"
+                                          :command="n.id">{{ n.locationName
+                          }}</el-dropdown-item>
+                      </el-dropdown-menu>
+                    </template>
+                  </el-dropdown>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 骞村害鎺掔彮 -->
+      <div class="yearly-table"
+           v-show="!query.month">
+        <div class="scheduling-left">
+          <div class="scheduling-header">
+            浜哄憳鍚嶇О
+          </div>
+          <div class="scheduling-user"
+               :class="{ 'scheduling-user-hover': currentUserIndex == index }"
+               v-for="(item, index) in yearList"
+               :key="'e' + index"
+               @mouseenter="onMouseEnter(index)"
+               @mouseleave="currentUserIndex = null">
+            <div class="user-avatar">
+              {{ item.name ? item.name.charAt(0) : "" }}
+            </div>
+            <div class="user-details">
+              <h4 class="user-name">{{ item.name }}</h4>
+              <!-- <div class="user-stats">
+                <span class="stat-item">鏃�:{{ item.day0 }}</span>
+                <span class="stat-item">涓�:{{ item.day1 }}</span>
+                <span class="stat-item">澶�:{{ item.day2 }}</span>
+                <span class="stat-item">浼�:{{ item.day3 }}</span>
+                <span class="stat-item">鍋�:{{ item.day4 }}</span>
+                <span class="stat-item">宸�:{{ item.day6 }}</span>
+              </div> -->
+              <div class="user-total">
+                <span class="total-label">鍚堣鍑哄嫟:</span>
+                <span class="total-value">{{ item.work_time }}澶�</span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="scheduling-right">
+          <div class="yearly-calendar">
+            <div class="yearly-header">
+              <div class="yearly-header-item"
+                   v-for="(item, index) in monthList"
+                   :key="'b' + index">
+                <span class="month-name">{{ item }}鏈�</span>
+              </div>
+            </div>
+            <div class="yearly-body">
+              <div class="yearly-row"
+                   v-for="(item, index) in yearList"
+                   :key="'c' + index"
+                   :class="{ 'calendar-row-hover': currentUserIndex == index }"
+                   @mouseenter="onMouseEnter(index)"
+                   @mouseleave="currentUserIndex = null">
+                <div class="yearly-cell"
+                     v-for="(m, i) in item.monthList"
+                     :key="'d' + i">
+                  <div class="monthly-attendance">
+                    <span class="attendance-label">鍚堣鍑哄嫟锛�</span>
+                    <span class="attendance-value">{{ m.totalMonthAttendance }}</span>
+                  </div>
+                  <!-- <div class="monthly-stats">
+                    <span class="stat-item">鏃�:{{ m.day0 }}</span>
+                    <span class="stat-item">涓�:{{ m.day1 }}</span>
+                    <span class="stat-item">澶�:{{ m.day2 }}</span>
+                    <span class="stat-item">浼�:{{ m.day3 }}</span>
+                    <span class="stat-item">鍋�:{{ m.day4 }}</span>
+                    <span class="stat-item">宸�:{{ m.day6 }}</span>
+                  </div> -->
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div style="display: flex; justify-content: flex-end; margin-top: 10px; margin-right: 30px">
+      <el-pagination background
+                     @current-change="currentChange"
+                     :page-size="pageSize"
+                     :current-page="currentPage"
+                     layout="total, prev, pager, next, jumper"
+                     :total="total">
+      </el-pagination>
+    </div>
+    <el-dialog title="鎺掔彮"
+               v-model="schedulingVisible"
+               width="400px">
+      <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-date-picker v-model="schedulingQuery.week"
+                          type="week"
+                          format="YYYY 绗� ww 鍛�"
+                          placeholder="閫夋嫨鍛ㄦ"
+                          style="width: 100%">
+          </el-date-picker>
+        </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">
+          <el-select v-model="schedulingQuery.userId"
+                     placeholder="璇烽�夋嫨"
+                     style="width: 100%"
+                     multiple
+                     clearable
+                     collapse-tags>
+            <el-option v-for="item in personList"
+                       :key="item.userId"
+                       :label="item.nickName"
+                       :value="item.userId">
+            </el-option>
+          </el-select>
+        </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">
+          <el-select v-model="schedulingQuery.shift"
+                     placeholder="璇烽�夋嫨"
+                     style="width: 100%">
+            <el-option v-for="item in classType"
+                       :key="item.id"
+                       :label="item.locationName"
+                       :value="item.id">
+            </el-option>
+          </el-select>
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="schedulingVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary"
+                     @click="confirmScheduling"
+                     :loading="loading">纭� 瀹�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+  import { useRouter } from "vue-router";
+  import {
+    page,
+    pageYear,
+    add,
+    exportFile,
+    update,
+    selectUserCondition,
+  } from "@/api/personnelManagement/class";
+  import { deptTreeSelect } from "@/api/system/user.js";
+  import { getAttendanceRules } from "@/api/personnelManagement/attendanceRules.js";
+  const { proxy } = getCurrentInstance();
+  const router = useRouter();
+
+  // 鏌ヨ鏉′欢
+  const query = reactive({
+    userName: "",
+    deptId: "",
+    year: new Date(),
+    month: new Date().getMonth() + 1,
+  });
+
+  // 鏈堜唤閫夐」
+  const monthOptions = [
+    { value: 1, label: "1鏈�" },
+    { value: 2, label: "2鏈�" },
+    { value: 3, label: "3鏈�" },
+    { value: 4, label: "4鏈�" },
+    { value: 5, label: "5鏈�" },
+    { value: 6, label: "6鏈�" },
+    { value: 7, label: "7鏈�" },
+    { value: 8, label: "8鏈�" },
+    { value: 9, label: "9鏈�" },
+    { value: 10, label: "10鏈�" },
+    { value: 11, label: "11鏈�" },
+    { value: 12, label: "12鏈�" },
+  ];
+
+  // 閮ㄩ棬鍒楄〃
+  const deptOptions = ref([]);
+
+  // 鍛ㄥ垪琛�
+  const weeks = ref([
+    { weekNum: 1, week: "鍛ㄤ竴", day: "01" },
+    { weekNum: 1, week: "鍛ㄤ簩", day: "02" },
+    { weekNum: 1, week: "鍛ㄤ笁", day: "03" },
+    { weekNum: 1, week: "鍛ㄥ洓", day: "04" },
+    { weekNum: 1, week: "鍛ㄤ簲", day: "05" },
+    { weekNum: 1, week: "鍛ㄥ叚", day: "06" },
+    { weekNum: 2, week: "鍛ㄦ棩", day: "07" },
+    { weekNum: 2, week: "鍛ㄤ竴", day: "08" },
+    { weekNum: 2, week: "鍛ㄤ簩", day: "09" },
+    { weekNum: 2, week: "鍛ㄤ笁", day: "10" },
+    { weekNum: 2, week: "鍛ㄥ洓", day: "11" },
+    { weekNum: 2, week: "鍛ㄤ簲", day: "12" },
+    { weekNum: 2, week: "鍛ㄥ叚", day: "13" },
+    { weekNum: 3, week: "鍛ㄦ棩", day: "14" },
+    { weekNum: 3, week: "鍛ㄤ竴", day: "15" },
+    { weekNum: 3, week: "鍛ㄤ簩", day: "16" },
+    { weekNum: 3, week: "鍛ㄤ笁", day: "17" },
+    { weekNum: 3, week: "鍛ㄥ洓", day: "18" },
+    { weekNum: 3, week: "鍛ㄤ簲", day: "19" },
+    { weekNum: 3, week: "鍛ㄥ叚", day: "20" },
+    { weekNum: 4, week: "鍛ㄦ棩", day: "21" },
+    { weekNum: 4, week: "鍛ㄤ竴", day: "22" },
+    { weekNum: 4, week: "鍛ㄤ簩", day: "23" },
+    { weekNum: 4, week: "鍛ㄤ笁", day: "24" },
+    { weekNum: 4, week: "鍛ㄥ洓", day: "25" },
+    { weekNum: 4, week: "鍛ㄤ簲", day: "26" },
+    { weekNum: 4, week: "鍛ㄥ叚", day: "27" },
+    { weekNum: 5, week: "鍛ㄦ棩", day: "28" },
+    { weekNum: 5, week: "鍛ㄤ竴", day: "29" },
+    { weekNum: 5, week: "鍛ㄤ簩", day: "30" },
+  ]);
+
+  // 鐝绫诲瀷
+  const classType = ref([]);
+
+  // 褰撳墠鐢ㄦ埛绱㈠紩
+  const currentUserIndex = ref(null);
+
+  // 鎺掔彮寮圭獥鏄剧ず鐘舵��
+  const schedulingVisible = ref(false);
+
+  // 浜哄憳鍒楄〃
+  const personList = ref([]);
+
+  // 鍔犺浇鐘舵��
+  const loading = ref(false);
+
+  // 鎺掔彮鏌ヨ鏉′欢
+  const schedulingQuery = reactive({
+    week: "",
+    userId: null,
+    shift: "",
+  });
+
+  // 鍒楄〃鏁版嵁
+  const listForm = ref([
+    {
+      id: 1,
+      name: "寮犱笁",
+      monthlyAttendance: {
+        totalAttendance: 22,
+        鏃╃彮: 10,
+        涓彮: 8,
+        澶滅彮: 4,
+        浼戞伅: 6,
+        璇峰亣: 0,
+        鍑哄樊: 0,
+      },
+      day0: 10,
+      day1: 8,
+      day2: 4,
+      day3: 6,
+      day4: 0,
+      day6: 0,
+      list: [
+        { id: 1, shift: "0" },
+        { id: 2, shift: "0" },
+        { id: 3, shift: "1" },
+        { id: 4, shift: "1" },
+        { id: 5, shift: "2" },
+        { id: 6, shift: "2" },
+        { id: 7, shift: "3" },
+        { id: 8, shift: "0" },
+        { id: 9, shift: "0" },
+        { id: 10, shift: "1" },
+        { id: 11, shift: "1" },
+        { id: 12, shift: "2" },
+        { id: 13, shift: "2" },
+        { id: 14, shift: "3" },
+        { id: 15, shift: "0" },
+        { id: 16, shift: "0" },
+        { id: 17, shift: "1" },
+        { id: 18, shift: "1" },
+        { id: 19, shift: "2" },
+        { id: 20, shift: "2" },
+        { id: 21, shift: "3" },
+        { id: 22, shift: "0" },
+        { id: 23, shift: "0" },
+        { id: 24, shift: "1" },
+        { id: 25, shift: "1" },
+        { id: 26, shift: "2" },
+        { id: 27, shift: "2" },
+        { id: 28, shift: "3" },
+        { id: 29, shift: "0" },
+        { id: 30, shift: "0" },
+      ],
+    },
+    {
+      id: 2,
+      name: "鏉庡洓",
+      monthlyAttendance: {
+        totalAttendance: 20,
+        鏃╃彮: 8,
+        涓彮: 6,
+        澶滅彮: 6,
+        浼戞伅: 8,
+        璇峰亣: 2,
+        鍑哄樊: 0,
+      },
+      day0: 8,
+      day1: 6,
+      day2: 6,
+      day3: 8,
+      day4: 2,
+      day6: 0,
+      list: [
+        { id: 31, shift: "1" },
+        { id: 32, shift: "1" },
+        { id: 33, shift: "2" },
+        { id: 34, shift: "2" },
+        { id: 35, shift: "3" },
+        { id: 36, shift: "0" },
+        { id: 37, shift: "0" },
+        { id: 38, shift: "1" },
+        { id: 39, shift: "1" },
+        { id: 40, shift: "2" },
+        { id: 41, shift: "2" },
+        { id: 42, shift: "3" },
+        { id: 43, shift: "0" },
+        { id: 44, shift: "0" },
+        { id: 45, shift: "1" },
+        { id: 46, shift: "1" },
+        { id: 47, shift: "2" },
+        { id: 48, shift: "2" },
+        { id: 49, shift: "3" },
+        { id: 50, shift: "0" },
+        { id: 51, shift: "0" },
+        { id: 52, shift: "4" },
+        { id: 53, shift: "4" },
+        { id: 54, shift: "1" },
+        { id: 55, shift: "1" },
+        { id: 56, shift: "2" },
+        { id: 57, shift: "2" },
+        { id: 58, shift: "3" },
+        { id: 59, shift: "0" },
+        { id: 60, shift: "0" },
+      ],
+    },
+    {
+      id: 3,
+      name: "鐜嬩簲",
+      monthlyAttendance: {
+        totalAttendance: 23,
+        鏃╃彮: 9,
+        涓彮: 9,
+        澶滅彮: 5,
+        浼戞伅: 5,
+        璇峰亣: 0,
+        鍑哄樊: 2,
+      },
+      day0: 9,
+      day1: 9,
+      day2: 5,
+      day3: 5,
+      day4: 0,
+      day6: 2,
+      list: [
+        { id: 61, shift: "2" },
+        { id: 62, shift: "2" },
+        { id: 63, shift: "3" },
+        { id: 64, shift: "0" },
+        { id: 65, shift: "0" },
+        { id: 66, shift: "1" },
+        { id: 67, shift: "1" },
+        { id: 68, shift: "2" },
+        { id: 69, shift: "2" },
+        { id: 70, shift: "3" },
+        { id: 71, shift: "0" },
+        { id: 72, shift: "0" },
+        { id: 73, shift: "1" },
+        { id: 74, shift: "1" },
+        { id: 75, shift: "2" },
+        { id: 76, shift: "2" },
+        { id: 77, shift: "3" },
+        { id: 78, shift: "0" },
+        { id: 79, shift: "0" },
+        { id: 80, shift: "1" },
+        { id: 81, shift: "1" },
+        { id: 82, shift: "6" },
+        { id: 83, shift: "6" },
+        { id: 84, shift: "2" },
+        { id: 85, shift: "2" },
+        { id: 86, shift: "3" },
+        { id: 87, shift: "0" },
+        { id: 88, shift: "0" },
+        { id: 89, shift: "1" },
+        { id: 90, shift: "1" },
+      ],
+    },
+    {
+      id: 4,
+      name: "寮犱笁",
+      monthlyAttendance: {
+        totalAttendance: 22,
+        鏃╃彮: 10,
+        涓彮: 8,
+        澶滅彮: 4,
+        浼戞伅: 6,
+        璇峰亣: 0,
+        鍑哄樊: 0,
+      },
+      day0: 10,
+      day1: 8,
+      day2: 4,
+      day3: 6,
+      day4: 0,
+      day6: 0,
+      list: [
+        { id: 1, shift: "0" },
+        { id: 2, shift: "0" },
+        { id: 3, shift: "1" },
+        { id: 4, shift: "1" },
+        { id: 5, shift: "2" },
+        { id: 6, shift: "2" },
+        { id: 7, shift: "3" },
+        { id: 8, shift: "0" },
+        { id: 9, shift: "0" },
+        { id: 10, shift: "1" },
+        { id: 11, shift: "1" },
+        { id: 12, shift: "2" },
+        { id: 13, shift: "2" },
+        { id: 14, shift: "3" },
+        { id: 15, shift: "0" },
+        { id: 16, shift: "0" },
+        { id: 17, shift: "1" },
+        { id: 18, shift: "1" },
+        { id: 19, shift: "2" },
+        { id: 20, shift: "2" },
+        { id: 21, shift: "3" },
+        { id: 22, shift: "0" },
+        { id: 23, shift: "0" },
+        { id: 24, shift: "1" },
+        { id: 25, shift: "1" },
+        { id: 26, shift: "2" },
+        { id: 27, shift: "2" },
+        { id: 28, shift: "3" },
+        { id: 29, shift: "0" },
+        { id: 30, shift: "0" },
+      ],
+    },
+    {
+      id: 5,
+      name: "寮犱笁",
+      monthlyAttendance: {
+        totalAttendance: 22,
+        鏃╃彮: 10,
+        涓彮: 8,
+        澶滅彮: 4,
+        浼戞伅: 6,
+        璇峰亣: 0,
+        鍑哄樊: 0,
+      },
+      day0: 10,
+      day1: 8,
+      day2: 4,
+      day3: 6,
+      day4: 0,
+      day6: 0,
+      list: [
+        { id: 1, shift: "0" },
+        { id: 2, shift: "0" },
+        { id: 3, shift: "1" },
+        { id: 4, shift: "1" },
+        { id: 5, shift: "2" },
+        { id: 6, shift: "2" },
+        { id: 7, shift: "3" },
+        { id: 8, shift: "0" },
+        { id: 9, shift: "0" },
+        { id: 10, shift: "1" },
+        { id: 11, shift: "1" },
+        { id: 12, shift: "2" },
+        { id: 13, shift: "2" },
+        { id: 14, shift: "3" },
+        { id: 15, shift: "0" },
+        { id: 16, shift: "0" },
+        { id: 17, shift: "1" },
+        { id: 18, shift: "1" },
+        { id: 19, shift: "2" },
+        { id: 20, shift: "2" },
+        { id: 21, shift: "3" },
+        { id: 22, shift: "0" },
+        { id: 23, shift: "0" },
+        { id: 24, shift: "1" },
+        { id: 25, shift: "1" },
+        { id: 26, shift: "2" },
+        { id: 27, shift: "2" },
+        { id: 28, shift: "3" },
+        { id: 29, shift: "0" },
+        { id: 30, shift: "0" },
+      ],
+    },
+    {
+      id: 6,
+      name: "寮犱笁",
+      monthlyAttendance: {
+        totalAttendance: 22,
+        鏃╃彮: 10,
+        涓彮: 8,
+        澶滅彮: 4,
+        浼戞伅: 6,
+        璇峰亣: 0,
+        鍑哄樊: 0,
+      },
+      day0: 10,
+      day1: 8,
+      day2: 4,
+      day3: 6,
+      day4: 0,
+      day6: 0,
+      list: [
+        { id: 1, shift: "0" },
+        { id: 2, shift: "0" },
+        { id: 3, shift: "1" },
+        { id: 4, shift: "1" },
+        { id: 5, shift: "2" },
+        { id: 6, shift: "2" },
+        { id: 7, shift: "3" },
+        { id: 8, shift: "0" },
+        { id: 9, shift: "0" },
+        { id: 10, shift: "1" },
+        { id: 11, shift: "1" },
+        { id: 12, shift: "2" },
+        { id: 13, shift: "2" },
+        { id: 14, shift: "3" },
+        { id: 15, shift: "0" },
+        { id: 16, shift: "0" },
+        { id: 17, shift: "1" },
+        { id: 18, shift: "1" },
+        { id: 19, shift: "2" },
+        { id: 20, shift: "2" },
+        { id: 21, shift: "3" },
+        { id: 22, shift: "0" },
+        { id: 23, shift: "0" },
+        { id: 24, shift: "1" },
+        { id: 25, shift: "1" },
+        { id: 26, shift: "2" },
+        { id: 27, shift: "2" },
+        { id: 28, shift: "3" },
+        { id: 29, shift: "0" },
+        { id: 30, shift: "0" },
+      ],
+    },
+  ]);
+
+  // 褰撳墠椤�
+  const currentPage = ref(1);
+
+  // 姣忛〉鏉℃暟
+  const pageSize = ref(6);
+
+  // 鎬绘潯鏁�
+  const total = ref(3);
+
+  // 椤甸潰鍔犺浇鐘舵��
+  const pageLoading = ref(false);
+
+  // 鏈堜唤鍒楄〃
+  const monthList = ref([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
+
+  // 骞村害鍒楄〃
+  const yearList = ref([
+    {
+      id: 1,
+      name: "寮犱笁",
+      work_time: 260,
+      day0: 98,
+      day1: 78,
+      day2: 46,
+      day3: 74,
+      day4: 14,
+      day6: 10,
+      monthList: [
+        {
+          totalMonthAttendance: 22,
+          day0: 10,
+          day1: 8,
+          day2: 4,
+          day3: 6,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 19,
+          day0: 7,
+          day1: 6,
+          day2: 6,
+          day3: 9,
+          day4: 3,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 9,
+          day1: 9,
+          day2: 5,
+          day3: 5,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 0,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 18,
+          day0: 6,
+          day1: 6,
+          day2: 6,
+          day3: 8,
+          day4: 4,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 0,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 19,
+          day0: 7,
+          day1: 7,
+          day2: 5,
+          day3: 8,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+      ],
+    },
+    {
+      id: 2,
+      name: "鏉庡洓",
+      work_time: 252,
+      day0: 90,
+      day1: 72,
+      day2: 50,
+      day3: 76,
+      day4: 18,
+      day6: 8,
+      monthList: [
+        {
+          totalMonthAttendance: 21,
+          day0: 9,
+          day1: 7,
+          day2: 5,
+          day3: 7,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 18,
+          day0: 6,
+          day1: 6,
+          day2: 6,
+          day3: 10,
+          day4: 4,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 8,
+          day1: 8,
+          day2: 6,
+          day3: 6,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 6,
+          day2: 7,
+          day3: 8,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 17,
+          day0: 5,
+          day1: 5,
+          day2: 7,
+          day3: 9,
+          day4: 5,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 1,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 6,
+          day2: 7,
+          day3: 8,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 18,
+          day0: 6,
+          day1: 6,
+          day2: 6,
+          day3: 9,
+          day4: 3,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 0,
+        },
+      ],
+    },
+    {
+      id: 3,
+      name: "鐜嬩簲",
+      work_time: 268,
+      day0: 102,
+      day1: 82,
+      day2: 48,
+      day3: 70,
+      day4: 10,
+      day6: 14,
+      monthList: [
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 24,
+          day0: 10,
+          day1: 9,
+          day2: 5,
+          day3: 4,
+          day4: 0,
+          day6: 3,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 8,
+          day2: 5,
+          day3: 5,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 24,
+          day0: 10,
+          day1: 9,
+          day2: 5,
+          day3: 4,
+          day4: 0,
+          day6: 3,
+        },
+      ],
+    },
+    {
+      id: 4,
+      name: "璧靛叚",
+      work_time: 248,
+      day0: 88,
+      day1: 70,
+      day2: 50,
+      day3: 78,
+      day4: 20,
+      day6: 6,
+      monthList: [
+        {
+          totalMonthAttendance: 20,
+          day0: 8,
+          day1: 6,
+          day2: 6,
+          day3: 8,
+          day4: 3,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 17,
+          day0: 5,
+          day1: 5,
+          day2: 7,
+          day3: 10,
+          day4: 5,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 7,
+          day1: 7,
+          day2: 7,
+          day3: 7,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 19,
+          day0: 6,
+          day1: 6,
+          day2: 7,
+          day3: 9,
+          day4: 2,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 7,
+          day2: 6,
+          day3: 8,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 16,
+          day0: 4,
+          day1: 4,
+          day2: 8,
+          day3: 10,
+          day4: 6,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 7,
+          day2: 6,
+          day3: 8,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 19,
+          day0: 6,
+          day1: 6,
+          day2: 7,
+          day3: 9,
+          day4: 2,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 7,
+          day2: 6,
+          day3: 8,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 18,
+          day0: 6,
+          day1: 6,
+          day2: 6,
+          day3: 9,
+          day4: 4,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 7,
+          day2: 6,
+          day3: 7,
+          day4: 1,
+          day6: 1,
+        },
+      ],
+    },
+    {
+      id: 5,
+      name: "閽变竷",
+      work_time: 266,
+      day0: 100,
+      day1: 84,
+      day2: 46,
+      day3: 72,
+      day4: 12,
+      day6: 12,
+      monthList: [
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 21,
+          day0: 8,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 9,
+          day1: 9,
+          day2: 5,
+          day3: 5,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 7,
+          day2: 6,
+          day3: 8,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 0,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 9,
+          day1: 9,
+          day2: 5,
+          day3: 5,
+          day4: 0,
+          day6: 2,
+        },
+        {
+          totalMonthAttendance: 22,
+          day0: 9,
+          day1: 8,
+          day2: 5,
+          day3: 6,
+          day4: 1,
+          day6: 1,
+        },
+        {
+          totalMonthAttendance: 20,
+          day0: 7,
+          day1: 7,
+          day2: 6,
+          day3: 8,
+          day4: 2,
+          day6: 0,
+        },
+        {
+          totalMonthAttendance: 23,
+          day0: 10,
+          day1: 9,
+          day2: 4,
+          day3: 5,
+          day4: 0,
+          day6: 0,
+        },
+      ],
+    },
+  ]);
+
+  // 瀵煎嚭鍔犺浇鐘舵��
+  const downLoading = ref(false);
+
+  // 鑾峰彇閮ㄩ棬鍒楄〃
+  const fetchDeptOptions = () => {
+    deptTreeSelect().then(response => {
+      deptOptions.value = filterDisabledDept(
+        JSON.parse(JSON.stringify(response.data))
+      );
+    });
+  };
+
+  // 杩囨护绂佺敤鐨勯儴闂�
+  const filterDisabledDept = deptList => {
+    return deptList.filter(dept => {
+      if (dept.disabled) {
+        return false;
+      }
+      if (dept.children && dept.children.length) {
+        dept.children = filterDisabledDept(dept.children);
+      }
+      return true;
+    });
+  };
+
+  // 鍒锋柊
+  const refresh = () => {
+    listForm.value = [];
+    yearList.value = [];
+    currentPage.value = 1;
+    query.userName = "";
+    query.deptId = "";
+    query.year = new Date();
+    query.month = new Date().getMonth() + 1;
+    if (query.month) {
+      init();
+    } else {
+      initYear();
+    }
+  };
+
+  // 鍒锋柊琛ㄦ牸
+  const refreshTable = () => {
+    currentPage.value = 1;
+    if (query.month) {
+      listForm.value = [];
+      init();
+    } else {
+      yearList.value = [];
+      initYear();
+    }
+  };
+
+  // 椤电爜鏀瑰彉
+  const currentChange = num => {
+    currentPage.value = num;
+    if (query.month) {
+      init();
+    } else {
+      initYear();
+    }
+  };
+
+  // 鏁板瓧杞腑鏂�
+  const transFromNumber = num => {
+    let changeNum = ["闆�", "涓�", "浜�", "涓�", "鍥�", "浜�", "鍏�", "涓�", "鍏�", "涔�"];
+    let unit = ["", "鍗�", "鐧�", "鍗�", "涓�"];
+    num = parseInt(num);
+    let getWan = temp => {
+      let strArr = temp.toString().split("").reverse();
+      let newNum = "";
+      for (var i = 0; i < strArr.length; i++) {
+        newNum =
+          (i == 0 && strArr[i] == 0
+            ? ""
+            : i > 0 && strArr[i] == 0 && strArr[i - 1] == 0
+            ? ""
+            : changeNum[strArr[i]] + (strArr[i] == 0 ? unit[0] : unit[i])) +
+          newNum;
+      }
+      return newNum;
+    };
+    let overWan = Math.floor(num / 10000);
+    let noWan = num % 10000;
+    if (noWan.toString().length < 4) noWan = "0" + noWan;
+    return overWan ? getWan(overWan) + "涓�" + getWan(noWan) : getWan(num);
+  };
+
+  // 鍒濆鍖栨湀搴︽暟鎹�
+  const init = () => {
+    pageLoading.value = true;
+    console.log(query.year, "query.year");
+    let year = query.year.getFullYear();
+    let month0 = query.month ? query.month : new Date().getMonth() + 1;
+    let month = month0 > 9 ? month0 : "0" + month0;
+    page({
+      size: pageSize.value,
+      current: currentPage.value,
+      time: year + "-" + month + "-01 00:00:00",
+      userName: query.userName,
+      deptId: query.deptId,
+    })
+      .then(res => {
+        pageLoading.value = false;
+        total.value = res.data.page.total;
+        listForm.value = res.data.page.records.map(item => {
+          for (let key in item.monthlyAttendance) {
+            let type = getDayByDic(key);
+            if (type != undefined || type != null) {
+              item[`day${type}`] = item.monthlyAttendance[key];
+            }
+          }
+          return item;
+        });
+        let headerList = res.data.headerList;
+        weeks.value = [];
+        headerList.forEach(item => {
+          let obj = {
+            weekNum: item.weekly,
+            week: item.headerTime.split(" ")[1],
+            day: item.headerTime.split(" ")[0],
+          };
+          weeks.value.push(obj);
+        });
+      })
+      .catch(() => {
+        pageLoading.value = false;
+      });
+  };
+
+  // 鍒濆鍖栧勾搴︽暟鎹�
+  const initYear = () => {
+    pageLoading.value = true;
+    let year = query.year.getFullYear();
+    pageYear({
+      size: pageSize.value,
+      current: currentPage.value,
+      time: year + "-01-01 00:00:00",
+      userName: query.userName,
+      deptId: query.deptId,
+    }).then(res => {
+      pageLoading.value = false;
+      total.value = res.data.total;
+      yearList.value = res.data.records.map(item => {
+        for (let key in item.year) {
+          let type = getDayByDic(key);
+          if (type != undefined || type != null) {
+            item[`day${type}`] = item.year[key];
+          }
+        }
+        item.monthList = [];
+        for (let m in item.month) {
+          let obj = {};
+          for (let key in item.month[m]) {
+            let type = getDayByDic(key);
+            if (type != undefined || type != null) {
+              obj[`day${type}`] = item.month[m][key];
+            }
+          }
+          obj.totalMonthAttendance = item.month[m].totalMonthAttendance;
+          item.monthList.push(obj);
+        }
+        return item;
+      });
+    });
+  };
+
+  // 榧犳爣杩涘叆
+  const onMouseEnter = index => {
+    currentUserIndex.value = index;
+  };
+
+  // 纭鎺掔彮
+  const confirmScheduling = () => {
+    if (!schedulingQuery.week) {
+      proxy.$modal.msgError("璇烽�夋嫨鍛ㄦ");
+      return;
+    }
+    let time = schedulingQuery.week.getTime();
+
+    // 鏍煎紡鍖栨棩鏈熶负 YYYY-MM-DD 鏍煎紡
+    const formatDate = date => {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, "0");
+      const day = String(date.getDate()).padStart(2, "0");
+      return `${year}-${month}-${day}`;
+    };
+
+    let startWeek =
+      formatDate(new Date(time - 24 * 60 * 60 * 1000)) + " 00:00:00";
+    let endWeek =
+      formatDate(new Date(time + 24 * 60 * 60 * 1000 * 5)) + " 00:00:00";
+
+    if (!schedulingQuery.userId || schedulingQuery.userId.length == 0) {
+      proxy.$modal.msgError("璇烽�夋嫨浜哄憳");
+      return;
+    }
+    if (!schedulingQuery.shift) {
+      proxy.$modal.msgError("璇烽�夋嫨鐝");
+      return;
+    }
+    loading.value = true;
+    add({
+      startWeek,
+      endWeek,
+      userId: schedulingQuery.userId.join(","),
+      shift: schedulingQuery.shift,
+    })
+      .then(res => {
+        loading.value = false;
+        proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
+        schedulingVisible.value = false;
+        schedulingQuery.week = "";
+        schedulingQuery.userId = null;
+        schedulingQuery.shift = "";
+        refresh();
+      })
+      .catch(err => {
+        loading.value = false;
+      });
+  };
+
+  // 鏃堕棿閰嶇疆
+  const configTime = () => {
+    // 璺宠浆鍒拌�冨嫟鎵撳崱椤甸潰
+    router.push({
+      path: "/personnelManagement/checkinRules",
+    });
+  };
+
+  // 鍒ゆ柇鏄惁涓虹┖瀵硅薄
+  const isObjectEmpty = obj => {
+    return Object.keys(obj).some(key => !obj[key]);
+  };
+
+  // 瀵煎嚭
+  const handleDown = () => {
+    let year = query.year.getFullYear();
+    let time = "";
+    if (query.month) {
+      let month = query.month > 9 ? query.month : "0" + query.month;
+      time = year + "-" + month + "-01 00:00:00";
+    } else {
+      time = year + "-01-01 00:00:00";
+    }
+    downLoading.value = true;
+    exportFile({
+      time,
+      userName: query.userName,
+      deptId: query.deptId,
+      isMonth: query.month ? true : false,
+    })
+      .then(res => {
+        proxy.$modal.msgSuccess("涓嬭浇鎴愬姛");
+        downLoading.value = false;
+        const blob = new Blob([res], {
+          type: "application/force-download",
+        });
+        let fileName = "";
+        if (query.month) {
+          fileName = year + "-" + query.month + " 鐝淇℃伅";
+        } else {
+          fileName = year + " 鐝姹囨��";
+        }
+        proxy.$download.saveAs(blob, fileName + ".xlsx");
+      })
+      .catch(err => {
+        downLoading.value = false;
+      });
+  };
+  // 澶勭悊鍛戒护
+  const handleCommand = (e, m) => {
+    if (e != m.shift) {
+      update({
+        id: m.id,
+        shift: e,
+      }).then(res => {
+        proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
+        m.shift = e;
+      });
+    }
+  };
+  // 鏌ヨ瑙勫垯鍒楄〃
+  const fetchData = () => {
+    getAttendanceRules({ current: -1, size: -1 }).then(res => {
+      classType.value = res.data.records;
+    });
+  };
+  // 鑾峰彇鐢ㄦ埛
+  const getUsers = () => {
+    // selectUserCondition({ type: 1 }).then(res => {
+    //   let arr = res.data;
+    //   personList.value = arr;
+    // });
+    selectUserCondition().then(res => {
+      let arr = res.data;
+      personList.value = arr;
+    });
+  };
+
+  // 鏍规嵁瀛楀吀鑾峰彇鏃ユ湡
+  const getDayByDic = e => {
+    let obj = classType.value.find(m => m.locationName == e);
+    if (obj) {
+      return obj.id;
+    }
+  };
+
+  // 鏍规嵁瀛楀吀鑾峰彇鐝
+  const getShiftByDic = e => {
+    let obj = classType.value.find(m => m.id == e);
+    if (obj) {
+      return obj.locationName;
+    }
+    return "鏃�";
+  };
+
+  // 鍒濆鍖�
+  onMounted(() => {
+    fetchData();
+    getUsers();
+    fetchDeptOptions();
+    if (query.month) {
+      init();
+    } else {
+      initYear();
+    }
+    monthList.value = [];
+    for (let i = 12; i > 0; i--) {
+      monthList.value.push(i);
+    }
+    monthList.value.reverse();
+  });
+</script>
+
+<style scoped>
+  .class-page {
+    padding: 16px;
+  }
+
+  .form_title {
+    height: 36px;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    font-weight: 800;
+  }
+
+  /* 鎼滅储鍖哄煙鏍峰紡 */
+  .search-container {
+    background: #f9fafb;
+    border-radius: 8px;
+    padding: 20px;
+    margin-bottom: 20px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  }
+
+  .search-form {
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+  }
+
+  .search-row {
+    display: flex;
+    align-items: center;
+    gap: 16px;
+    flex-wrap: nowrap;
+    overflow-x: auto;
+  }
+
+  .search-item {
+    display: flex;
+    align-items: center;
+    gap: 6px;
+  }
+
+  .search-label {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333;
+    min-width: 65px;
+    text-align: right;
+  }
+
+  .search-input-group {
+    display: flex;
+    align-items: center;
+  }
+
+  .search-actions {
+    display: flex;
+    align-items: center;
+    margin-left: 8px;
+  }
+
+  .search-buttons {
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    flex: 1;
+  }
+
+  /* 鍝嶅簲寮忚皟鏁� */
+  @media (max-width: 1200px) {
+    .search-row {
+      gap: 12px;
+    }
+
+    .search-item {
+      gap: 4px;
+    }
+
+    .search-label {
+      min-width: 60px;
+      font-size: 13px;
+    }
+
+    .search-actions {
+      margin-left: 4px;
+    }
+
+    .search-buttons {
+      margin-left: 12px;
+    }
+  }
+
+  @media (max-width: 992px) {
+    .search-row {
+      flex-wrap: wrap;
+      justify-content: flex-start;
+    }
+
+    .search-buttons {
+      margin-left: 0;
+      margin-top: 12px;
+      width: 100%;
+      justify-content: flex-start;
+    }
+  }
+
+  /* 鎺掔彮瀹瑰櫒 */
+  .scheduling-container {
+    width: 100%;
+    min-height: calc(100vh - 280px);
+    background-color: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    overflow: hidden;
+    margin-bottom: 20px;
+  }
+
+  /* 鎺掔彮琛ㄦ牸 */
+  .scheduling-table {
+    display: flex;
+    width: 100%;
+    height: calc(100vh - 280px);
+  }
+
+  /* 宸︿晶浜哄憳淇℃伅 */
+  .scheduling-left {
+    width: 240px;
+    min-width: 240px;
+    background-color: #f9fafb;
+    border-right: 1px solid #e5e7eb;
+  }
+
+  /* 鍙充晶鎺掔彮鍐呭 */
+  .scheduling-right {
+    flex: 1;
+    overflow-x: auto;
+  }
+
+  /* 琛ㄥご */
+  .scheduling-header {
+    height: 48px;
+    line-height: 48px;
+    padding: 0 20px;
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+    background-color: #f3f4f6;
+    border-bottom: 1px solid #e5e7eb;
+  }
+
+  /* 浜哄憳淇℃伅琛� */
+  .scheduling-user {
+    display: flex;
+    align-items: center;
+    padding: 10px 10px;
+    border-bottom: 1px solid #e5e7eb;
+    transition: all 0.3s ease;
+    height: 65px;
+    box-sizing: border-box;
+  }
+
+  .scheduling-user:hover,
+  .scheduling-user-hover {
+    background-color: rgba(59, 130, 246, 0.05);
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  }
+
+  /* 鐢ㄦ埛澶村儚 */
+  .user-avatar {
+    width: 42px;
+    height: 42px;
+    border-radius: 50%;
+    background: linear-gradient(135deg, #3b82f6, #60a5fa);
+    color: #fff;
+    font-size: 18px;
+    font-weight: 600;
+    text-align: center;
+    line-height: 42px;
+    margin-right: 16px;
+    box-shadow: 0 2px 4px rgba(59, 130, 246, 0.2);
+    transition: all 0.3s ease;
+  }
+
+  .scheduling-user:hover .user-avatar {
+    transform: scale(1.05);
+    box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
+  }
+
+  /* 鐢ㄦ埛璇︽儏 */
+  .user-details {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    height: 100%;
+  }
+
+  /* 鐢ㄦ埛鍚� */
+  .user-name {
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+    margin: 0 0 6px 0;
+    line-height: 1.2;
+  }
+
+  /* 鐢ㄦ埛缁熻 */
+  .user-stats {
+    /* display: flex; */
+    /* flex-wrap: wrap;
+                                                                                                                                                                        gap: 10px; */
+    margin-bottom: 4px;
+  }
+
+  .stat-item {
+    font-size: 12px;
+    color: #666;
+    /* background-color: #f9fafb; */
+    /* padding: 2px 8px; */
+    padding-right: 4px;
+    /* border-radius: 10px; */
+    /* border: 1px solid #e5e7eb; */
+    /* transition: all 0.3s ease; */
+  }
+
+  .scheduling-user:hover .stat-item {
+    background-color: rgba(59, 130, 246, 0.1);
+    border-color: rgba(59, 130, 246, 0.3);
+  }
+
+  /* 鍚堣鍑哄嫟 */
+  .user-total {
+    display: flex;
+    align-items: center;
+  }
+
+  .total-label {
+    font-size: 12px;
+    color: #666;
+    margin-right: 6px;
+    font-weight: 500;
+  }
+
+  .total-value {
+    font-size: 14px;
+    font-weight: 600;
+    color: #3b82f6;
+    background-color: rgba(59, 130, 246, 0.1);
+    padding: 2px 10px;
+    border-radius: 10px;
+    border: 1px solid rgba(59, 130, 246, 0.2);
+  }
+
+  /* 鏃ュ巻澶撮儴 */
+  .calendar-header {
+    display: flex;
+
+    border-bottom: 1px solid #e5e7eb;
+  }
+
+  .calendar-header-item {
+    width: 50px;
+    min-width: 50px;
+    height: 48px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    border-right: 1px solid #e5e7eb;
+    background-color: #f3f4f6;
+    position: relative;
+  }
+
+  .week-number {
+    position: absolute;
+    top: 6px;
+    font-size: 10px;
+    font-weight: 600;
+    color: #3b82f6;
+    background-color: #dbeafe;
+    padding: 3px 6px;
+    border-radius: 12px;
+    box-shadow: 0 1px 3px rgba(59, 130, 246, 0.2);
+    transition: all 0.3s ease;
+  }
+
+  .week-number:hover {
+    background-color: #3b82f6;
+    color: #fff;
+    transform: translateY(-1px);
+  }
+
+  .day-info {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  .day-number {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333;
+  }
+
+  .day-week {
+    font-size: 12px;
+    color: #666;
+  }
+
+  /* 鏃ュ巻涓讳綋 */
+  .calendar-body {
+    display: flex;
+    flex-direction: column;
+  }
+
+  /* 鏃ュ巻琛� */
+  .calendar-row {
+    display: flex;
+    border-bottom: 1px solid #e5e7eb;
+    transition: all 0.3s ease;
+  }
+
+  .calendar-row:hover,
+  .calendar-row-hover {
+    background-color: rgba(59, 130, 246, 0.03);
+  }
+
+  /* 鏃ュ巻鍗曞厓鏍� */
+  .calendar-cell {
+    width: 50px;
+    min-width: 50px;
+    height: 65px;
+    border-right: 1px solid #e5e7eb;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  /* 鐝涓嬫媺妗� */
+  .shift-dropdown {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  /* 鐝妗� */
+  .shift-box {
+    width: 90%;
+    height: 80%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 6px;
+    font-size: 12px;
+    font-weight: 500;
+    transition: all 0.3s ease;
+  }
+
+  .shift-box:hover {
+    transform: scale(1.05);
+  }
+
+  /* 鐝绫诲瀷鏍峰紡 */
+  .shift-box-early {
+    background: rgba(59, 130, 246, 0.15);
+    color: #3b82f6;
+  }
+
+  .shift-box-mid {
+    background: rgba(139, 92, 246, 0.15);
+    color: #8b5cf6;
+  }
+
+  .shift-box-night {
+    background: rgba(245, 158, 11, 0.15);
+    color: #f59e0b;
+  }
+
+  .shift-box-rest {
+    background: rgba(16, 185, 129, 0.15);
+    color: #10b981;
+  }
+
+  .shift-box-leave {
+    background: rgba(239, 68, 68, 0.15);
+    color: #ef4444;
+  }
+
+  .shift-box-other {
+    background: rgba(236, 72, 153, 0.15);
+    color: #ec4899;
+  }
+
+  .shift-box-business {
+    background: rgba(17, 24, 39, 0.15);
+    color: #111827;
+  }
+
+  /* 鐝鏂囨湰 */
+  .shift-text {
+    text-align: center;
+  }
+
+  /* 骞村害琛ㄦ牸 */
+  .yearly-table {
+    display: flex;
+    width: 100%;
+    height: calc(100vh - 280px);
+  }
+
+  /* 骞村害鏃ュ巻 */
+  .yearly-calendar {
+    width: 100%;
+  }
+
+  /* 骞村害琛ㄥご */
+  .yearly-header {
+    display: grid;
+    grid-template-columns: repeat(12, 1fr);
+    background-color: #f3f4f6;
+    border-bottom: 1px solid #e5e7eb;
+  }
+
+  .yearly-header-item {
+    height: 48px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-right: 1px solid #e5e7eb;
+  }
+
+  .month-name {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333;
+  }
+
+  /* 骞村害涓讳綋 */
+  .yearly-body {
+    display: flex;
+    flex-direction: column;
+  }
+
+  /* 骞村害琛� */
+  .yearly-row {
+    display: grid;
+    grid-template-columns: repeat(12, 1fr);
+    border-bottom: 1px solid #e5e7eb;
+    transition: all 0.3s ease;
+  }
+
+  /* 骞村害鍗曞厓鏍� */
+  .yearly-cell {
+    padding: 12px;
+    border-right: 1px solid #e5e7eb;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  /* 鏈堝害鍑哄嫟 */
+  .monthly-attendance {
+    margin-bottom: 8px;
+  }
+
+  .attendance-label {
+    font-size: 12px;
+    color: #666;
+    margin-right: 4px;
+  }
+
+  .attendance-value {
+    font-size: 14px;
+    font-weight: 600;
+    color: #333;
+  }
+
+  /* 鏈堝害缁熻 */
+  .monthly-stats {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 4px;
+    justify-content: center;
+  }
+
+  .monthly-stats .stat-item {
+    font-size: 11px;
+  }
+
+  /* 婊氬姩鏉℃牱寮� */
+  .scheduling-right::-webkit-scrollbar {
+    height: 8px;
+  }
+
+  .scheduling-right::-webkit-scrollbar-track {
+    background: #f1f1f1;
+  }
+
+  .scheduling-right::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 4px;
+  }
+
+  .scheduling-right::-webkit-scrollbar-thumb:hover {
+    background: #a8a8a8;
+  }
+
+  .search_label {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333;
+    margin-bottom: 8px;
+    margin-top: 12px;
+  }
+</style>

--
Gitblit v1.9.3