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