From 2656f822915dcf4314a54622bf2dba9b1a2cb9b5 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 10 二月 2026 14:17:04 +0800
Subject: [PATCH] 打卡签到状态修改

---
 src/views/personnelManagement/attendanceCheckin/index.vue |  631 +++++++++++++++++++++++++++++----------------------------
 1 files changed, 322 insertions(+), 309 deletions(-)

diff --git a/src/views/personnelManagement/attendanceCheckin/index.vue b/src/views/personnelManagement/attendanceCheckin/index.vue
index 98a94b8..6fd1357 100644
--- a/src/views/personnelManagement/attendanceCheckin/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/index.vue
@@ -1,7 +1,8 @@
 <template>
   <div class="app-container">
     <!-- 鍛樺伐鎵撳崱鍖� -->
-    <el-card shadow="never" class="mb16">
+    <el-card shadow="never"
+             class="mb16">
       <div class="attendance-header">
         <div>
           <div class="title">鎵撳崱绛惧埌</div>
@@ -12,12 +13,17 @@
             <div class="label">褰撳墠鏃堕棿</div>
             <div class="value">{{ nowTime }}</div>
           </div>
-          <el-button type="primary" size="large" @click="handleCheckInOut" :disabled="todayRecord.workEndAt">
+          <el-button type="primary"
+                     size="large"
+                     @click="handleCheckInOut"
+                     :disabled="todayRecord.workEndAt">
             {{ checkInOutText }}
           </el-button>
         </div>
       </div>
-      <el-descriptions border :column="4" class="mt10">
+      <el-descriptions border
+                       :column="4"
+                       class="mt10">
         <el-descriptions-item label="鍛樺伐濮撳悕">
           {{ todayRecord.staffName }}
         </el-descriptions-item>
@@ -28,7 +34,8 @@
           {{ todayRecord.deptName }}
         </el-descriptions-item>
         <el-descriptions-item label="浠婃棩鐘舵��">
-          <el-tag :type="todayStatusTag" size="small">
+          <el-tag :type="todayStatusTag"
+                  size="small">
             {{ todayStatusText }}
           </el-tag>
         </el-descriptions-item>
@@ -43,370 +50,376 @@
         </el-descriptions-item>
         <el-descriptions-item label="寮傚父鏍囪">
           <span v-if="!todayRecord.id || todayRecord?.status === 0">-</span>
-          <el-tag v-else type="danger" size="small">
-            {{ todayRecord?.status === 1 ? '杩熷埌' : '鏃╅��' }}
+          <el-tag v-else
+                  type="danger"
+                  size="small">
+            {{ todayRecord?.status ? getStatusText(todayRecord.status) : '-' }}
           </el-tag>
         </el-descriptions-item>
       </el-descriptions>
     </el-card>
-
     <div class="attendance-operation">
       <!-- 鏌ヨ鏉′欢锛堢鐞嗗憳鑰冨嫟鏃ユ姤锛� -->
-      <el-form :model="searchForm" :inline="true" class="search-form">
-        <el-form-item label="閮ㄩ棬锛�" prop="deptId">
-          <el-tree-select
-              v-model="searchForm.deptId"
-              :data="deptOptions"
-              :props="{ value: 'id', label: 'label', children: 'children' }"
-              value-key="id"
-              placeholder="璇烽�夋嫨閮ㄩ棬"
-              check-strictly
-              style="width: 200px"
-          />
+      <el-form :model="searchForm"
+               :inline="true"
+               class="search-form">
+        <el-form-item label="閮ㄩ棬锛�"
+                      prop="deptId">
+          <el-tree-select v-model="searchForm.deptId"
+                          :data="deptOptions"
+                          :props="{ value: 'id', label: 'label', children: 'children' }"
+                          value-key="id"
+                          placeholder="璇烽�夋嫨閮ㄩ棬"
+                          check-strictly
+                          style="width: 200px" />
         </el-form-item>
-
-        <el-form-item label="鏃ユ湡锛�" prop="date">
-          <el-date-picker
-              v-model="searchForm.date"
-              type="date"
-              value-format="YYYY-MM-DD"
-              format="YYYY-MM-DD"
-              placeholder="璇烽�夋嫨鏃ユ湡"
-              clearable
-          />
+        <el-form-item label="鏃ユ湡锛�"
+                      prop="date">
+          <el-date-picker v-model="searchForm.date"
+                          type="date"
+                          value-format="YYYY-MM-DD"
+                          format="YYYY-MM-DD"
+                          placeholder="璇烽�夋嫨鏃ユ湡"
+                          clearable />
         </el-form-item>
-
         <el-form-item>
-          <el-button type="primary" @click="fetchData">
-            <el-icon><Search /></el-icon>
+          <el-button type="primary"
+                     @click="fetchData">
+            <el-icon>
+              <Search />
+            </el-icon>
             鎼滅储
           </el-button>
           <el-button @click="resetSearch">
-            <el-icon><Refresh /></el-icon>
+            <el-icon>
+              <Refresh />
+            </el-icon>
             閲嶇疆
           </el-button>
         </el-form-item>
       </el-form>
-
-      <el-button icon="Download" @click="handleExport">
+      <el-button icon="Download"
+                 @click="handleExport">
         瀵煎嚭鑰冨嫟鏃ユ姤
       </el-button>
     </div>
-
     <!-- 鑰冨嫟鏃ユ姤琛ㄦ牸 -->
     <div class="table_list">
-      <el-table
-        :data="tableData"
-        border
-        v-loading="tableLoading"
-        style="width: 100%"
-        height="calc(100vh - 24em)"
-        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-        :row-class-name="rowClassName"
-      >
-        <el-table-column type="index" label="搴忓彿" width="60" align="center" />
-        <el-table-column
-          prop="date"
-          label="鏃ユ湡"
-          width="120"
-        />
-        <el-table-column
-          prop="deptName"
-          label="閮ㄩ棬"
-          width="140"
-        />
-        <el-table-column
-          prop="staffName"
-          label="濮撳悕"
-          width="120"
-        />
-        <el-table-column
-          prop="staffNo"
-          label="宸ュ彿"
-          width="120"
-        />
-        <el-table-column
-          prop="workStartAt"
-          label="涓婄彮鏃堕棿"
-          width="140"
-        />
-        <el-table-column
-          prop="workEndAt"
-          label="涓嬬彮鏃堕棿"
-          width="140"
-        />
-        <el-table-column
-          prop="workHours"
-          label="宸ユ椂(灏忔椂)"
-          align="center"
-        />
-        <el-table-column
-          prop="status"
-          label="鑰冨嫟鐘舵��"
-          align="center"
-        >
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                style="width: 100%"
+                height="calc(100vh - 24em)"
+                :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+                :row-class-name="rowClassName">
+        <el-table-column type="index"
+                         label="搴忓彿"
+                         width="60"
+                         align="center" />
+        <el-table-column prop="date"
+                         label="鏃ユ湡"
+                         width="120" />
+        <el-table-column prop="deptName"
+                         label="閮ㄩ棬"
+                         width="140" />
+        <el-table-column prop="staffName"
+                         label="濮撳悕"
+                         width="120" />
+        <el-table-column prop="staffNo"
+                         label="宸ュ彿"
+                         width="120" />
+        <el-table-column prop="workStartAt"
+                         label="涓婄彮鏃堕棿"
+                         width="140" />
+        <el-table-column prop="workEndAt"
+                         label="涓嬬彮鏃堕棿"
+                         width="140" />
+        <el-table-column prop="workHours"
+                         label="宸ユ椂(灏忔椂)"
+                         align="center" />
+        <el-table-column prop="status"
+                         label="鑰冨嫟鐘舵��"
+                         align="center">
           <template #default="scope">
-            <el-tag
-              v-if="scope.row.status === 0"
-              type="success"
-              size="small"
-            >
+            <el-tag v-if="scope.row.status === 0"
+                    type="success"
+                    size="small">
               姝e父
             </el-tag>
-            <el-tag
-              v-else
-              type="danger"
-              size="small"
-            >
-              {{ scope.row.status === 1 ? '杩熷埌' : '鏃╅��' }}
+            <el-tag v-else
+                    type="danger"
+                    size="small">
+              {{ scope.row.status === 1 ? '杩熷埌' : scope.row.status === 2 ? '鏃╅��' : '杩熷埌銆佹棭閫�' }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column
-          prop="remark"
-          label="澶囨敞"
-          show-overflow-tooltip
-        />
+        <el-table-column prop="remark"
+                         label="澶囨敞"
+                         show-overflow-tooltip />
       </el-table>
-
-      <pagination :total="total" layout="total, sizes, prev, pager, next, jumper"
-                  :page="page.current" :limit="page.size" @pagination="paginationChange" />
+      <pagination :total="total"
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :page="page.current"
+                  :limit="page.size"
+                  @pagination="paginationChange" />
     </div>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
-import {ElMessage, ElMessageBox} from "element-plus";
-import {
-  createPersonalAttendanceRecord,
-  findPersonalAttendanceRecords, findTodayPersonalAttendanceRecord
-} 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 { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import {
+    createPersonalAttendanceRecord,
+    findPersonalAttendanceRecords,
+    findTodayPersonalAttendanceRecord,
+  } 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";
 
-const { proxy } = getCurrentInstance()
-const tableLoading = ref(false)
-// 鍒嗛〉鍙傛暟
-const page = reactive({
-  current: 1,
-  size: 10,
-  total: 0
-})
-// 浠婃棩鏁版嵁
-const todayRecord = ref({})
-
-// 閮ㄩ棬閫夐」
-const deptOptions = ref([])
-
-// 鏌ヨ琛ㄥ崟
-const searchForm = reactive({
-  deptId: "",
-  date: "",
-});
-
-// 琛ㄦ牸鏁版嵁
-const tableData = ref([]);
-
-// 褰撳墠鏃堕棿灞曠ず
-const nowTime = ref("");
-let timer = null;
-
-const updateNowTime = () => {
-  const now = new Date();
-  const Y = now.getFullYear();
-  const M = String(now.getMonth() + 1).padStart(2, "0");
-  const D = String(now.getDate()).padStart(2, "0");
-  const h = String(now.getHours()).padStart(2, "0");
-  const m = String(now.getMinutes()).padStart(2, "0");
-  const s = String(now.getSeconds()).padStart(2, "0");
-  nowTime.value = `${Y}-${M}-${D} ${h}:${m}:${s}`;
-};
-
-// 鎵撳崱鎸夐挳鏂囨湰
-const checkInOutText = computed(() => {
-  if (!todayRecord.value || !todayRecord.value.workStartAt) {
-    return "涓婄彮鎵撳崱";
-  }
-  if (!todayRecord.value.workEndAt) {
-    return "涓嬬彮鎵撳崱";
-  }
-  return "浠婃棩宸叉墦鍗″畬鎴�";
-});
-
-// 浠婃棩鐘舵�佸睍绀�
-const todayStatusTag = computed(() => {
-  if (!todayRecord.value.id) return "info";
-  if (todayRecord.value.status === 0) return "success";
-  return "danger";
-});
-
-const todayStatusText = computed(() => {
-  if (!todayRecord.value.id) return "鏈墦鍗�";
-  switch (todayRecord.value.status) {
-    case 0:
-      return "姝e父"
-    case 1:
-      return "杩熷埌"
-    case 2:
-      return "鏃╅��"
-  }
-});
-
-// 琛屾牱寮忥細寮傚父楂樹寒
-const rowClassName = ({ row }) => {
-  if (row.status === 1 || row.status === 2) {
-    return "row-abnormal";
-  }
-  return "";
-};
-
-// 鏌ヨ閮ㄩ棬鍒楄〃
-const fetchDeptOptions = () => {
-  deptTreeSelect().then(response => {
-    deptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
-  })
-}
-
-/** 杩囨护绂佺敤鐨勯儴闂� */
-function 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 fetchData = () => {
-  tableLoading.value = true
-  findPersonalAttendanceRecords({...page, ...searchForm}).then((res) => {
-    tableData.value = res.data.records;
-    page.value.total = res.data.total;
-  }).finally(() => {
-    tableLoading.value = false;
+  const { proxy } = getCurrentInstance();
+  const tableLoading = ref(false);
+  // 鍒嗛〉鍙傛暟
+  const page = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
   });
-};
+  // 浠婃棩鏁版嵁
+  const todayRecord = ref({});
 
-// 鏌ヨ浠婃棩鎵撳崱淇℃伅
-const fetchTodayData = () => {
-  findTodayPersonalAttendanceRecord({}).then((res) => {
-    todayRecord.value = res.data;
-  })
-};
+  // 閮ㄩ棬閫夐」
+  const deptOptions = ref([]);
 
-const paginationChange = (pagination) => {
-  page.current = pagination.page;
-  page.size = pagination.limit;
-  fetchData();
-}
+  // 鏌ヨ琛ㄥ崟
+  const searchForm = reactive({
+    deptId: "",
+    date: "",
+  });
 
-const resetSearch = () => {
-  searchForm.deptId = "";
-  searchForm.date = "";
-  fetchData();
-};
+  // 琛ㄦ牸鏁版嵁
+  const tableData = ref([]);
 
-const handleExport = () => {
-  ElMessageBox.confirm("鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
-    confirmButtonText: "纭",
-    cancelButtonText: "鍙栨秷",
-    type: "warning",
-  })
+  // 褰撳墠鏃堕棿灞曠ず
+  const nowTime = ref("");
+  let timer = null;
+
+  const updateNowTime = () => {
+    const now = new Date();
+    const Y = now.getFullYear();
+    const M = String(now.getMonth() + 1).padStart(2, "0");
+    const D = String(now.getDate()).padStart(2, "0");
+    const h = String(now.getHours()).padStart(2, "0");
+    const m = String(now.getMinutes()).padStart(2, "0");
+    const s = String(now.getSeconds()).padStart(2, "0");
+    nowTime.value = `${Y}-${M}-${D} ${h}:${m}:${s}`;
+  };
+
+  // 鎵撳崱鎸夐挳鏂囨湰
+  const checkInOutText = computed(() => {
+    if (!todayRecord.value || !todayRecord.value.workStartAt) {
+      return "涓婄彮鎵撳崱";
+    }
+    if (!todayRecord.value.workEndAt) {
+      return "涓嬬彮鎵撳崱";
+    }
+    return "浠婃棩宸叉墦鍗″畬鎴�";
+  });
+
+  // 浠婃棩鐘舵�佸睍绀�
+  const todayStatusTag = computed(() => {
+    if (!todayRecord.value.id) return "info";
+    if (todayRecord.value.status === 0) return "success";
+    return "danger";
+  });
+  const getStatusText = status => {
+    switch (status) {
+      case 0:
+        return "姝e父";
+      case 1:
+        return "杩熷埌";
+      case 2:
+        return "鏃╅��";
+      case 3:
+        return "杩熷埌銆佹棭閫�";
+      case 4:
+        return "缂哄嫟";
+    }
+  };
+
+  const todayStatusText = computed(() => {
+    if (!todayRecord.value.id) return "鏈墦鍗�";
+    switch (todayRecord.value.status) {
+      case 0:
+        return "姝e父";
+      case 1:
+        return "杩熷埌";
+      case 2:
+        return "鏃╅��";
+      case 3:
+        return "杩熷埌銆佹棭閫�";
+      case 4:
+        return "缂哄嫟";
+    }
+  });
+
+  // 琛屾牱寮忥細寮傚父楂樹寒
+  const rowClassName = ({ row }) => {
+    if (row.status === 1 || row.status === 2) {
+      return "row-abnormal";
+    }
+    return "";
+  };
+
+  // 鏌ヨ閮ㄩ棬鍒楄〃
+  const fetchDeptOptions = () => {
+    deptTreeSelect().then(response => {
+      deptOptions.value = filterDisabledDept(
+        JSON.parse(JSON.stringify(response.data))
+      );
+    });
+  };
+
+  /** 杩囨护绂佺敤鐨勯儴闂� */
+  function 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 fetchData = () => {
+    tableLoading.value = true;
+    findPersonalAttendanceRecords({ ...page, ...searchForm })
+      .then(res => {
+        tableData.value = res.data.records;
+        page.value.total = res.data.total;
+      })
+      .finally(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  // 鏌ヨ浠婃棩鎵撳崱淇℃伅
+  const fetchTodayData = () => {
+    findTodayPersonalAttendanceRecord({}).then(res => {
+      todayRecord.value = res.data;
+    });
+  };
+
+  const paginationChange = pagination => {
+    page.current = pagination.page;
+    page.size = pagination.limit;
+    fetchData();
+  };
+
+  const resetSearch = () => {
+    searchForm.deptId = "";
+    searchForm.date = "";
+    fetchData();
+  };
+
+  const handleExport = () => {
+    ElMessageBox.confirm("鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
       .then(() => {
         proxy.download("/personalAttendanceRecords/export", {}, "鑰冨嫟璁板綍.xlsx");
       })
       .catch(() => {
         proxy.$modal.msg("宸插彇娑�");
       });
-};
+  };
 
-// 鎵撳崱
-const handleCheckInOut = () => {
-  createPersonalAttendanceRecord({}).then((res) => {
-    fetchData()
-    fetchTodayData()
-    ElMessage.success("鎵撳崱鎴愬姛锛�");
-  })
-};
+  // 鎵撳崱
+  const handleCheckInOut = () => {
+    createPersonalAttendanceRecord({}).then(res => {
+      fetchData();
+      fetchTodayData();
+      ElMessage.success("鎵撳崱鎴愬姛锛�");
+    });
+  };
 
-onMounted(() => {
-  updateNowTime();
-  timer = setInterval(updateNowTime, 1000);
-  // 榛樿灞曠ず褰撳ぉ鏁版嵁
-  const today = new Date();
-  const Y = today.getFullYear();
-  const M = String(today.getMonth() + 1).padStart(2, "0");
-  const D = String(today.getDate()).padStart(2, "0");
-  searchForm.date = `${Y}-${M}-${D}`;
-  fetchData();
-  fetchTodayData()
-  fetchDeptOptions();
-});
+  onMounted(() => {
+    updateNowTime();
+    timer = setInterval(updateNowTime, 1000);
+    // 榛樿灞曠ず褰撳ぉ鏁版嵁
+    const today = new Date();
+    const Y = today.getFullYear();
+    const M = String(today.getMonth() + 1).padStart(2, "0");
+    const D = String(today.getDate()).padStart(2, "0");
+    searchForm.date = `${Y}-${M}-${D}`;
+    fetchData();
+    fetchTodayData();
+    fetchDeptOptions();
+  });
 
-onBeforeUnmount(() => {
-  if (timer) {
-    clearInterval(timer);
-  }
-});
+  onBeforeUnmount(() => {
+    if (timer) {
+      clearInterval(timer);
+    }
+  });
 </script>
 
 <style scoped lang="scss">
-.mb16 {
-  margin-bottom: 16px;
-}
+  .mb16 {
+    margin-bottom: 16px;
+  }
 
-.attendance-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
+  .attendance-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
 
-.attendance-header .title {
-  font-size: 18px;
-  font-weight: 600;
-  margin-bottom: 4px;
-}
+  .attendance-header .title {
+    font-size: 18px;
+    font-weight: 600;
+    margin-bottom: 4px;
+  }
 
-.attendance-header .sub-title {
-  font-size: 13px;
-  color: #909399;
-}
+  .attendance-header .sub-title {
+    font-size: 13px;
+    color: #909399;
+  }
 
-.attendance-actions {
-  display: flex;
-  align-items: center;
-  gap: 16px;
-}
+  .attendance-actions {
+    display: flex;
+    align-items: center;
+    gap: 16px;
+  }
 
-.time-block {
-  text-align: right;
-}
+  .time-block {
+    text-align: right;
+  }
 
-.time-block .label {
-  font-size: 12px;
-  color: #909399;
-}
+  .time-block .label {
+    font-size: 12px;
+    color: #909399;
+  }
 
-.time-block .value {
-  font-size: 18px;
-  font-weight: 600;
-  color: #333;
-}
+  .time-block .value {
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+  }
 
-::v-deep(.row-abnormal) {
-  background-color: #fff5f5;
-}
+  ::v-deep(.row-abnormal) {
+    background-color: #fff5f5;
+  }
 
-.attendance-operation {
-  display: flex;
-  justify-content: space-between;
-}
+  .attendance-operation {
+    display: flex;
+    justify-content: space-between;
+  }
 </style>
 

--
Gitblit v1.9.3