From eb956d7f1a0d174c0d55fccebfa4872d2abfbe94 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 06 三月 2026 18:02:18 +0800
Subject: [PATCH] 增加采购退货单列表和新增页面
---
src/views/personnelManagement/attendanceCheckin/index.vue | 822 ++++++++++++++++++++++++++++++---------------------------
1 files changed, 431 insertions(+), 391 deletions(-)
diff --git a/src/views/personnelManagement/attendanceCheckin/index.vue b/src/views/personnelManagement/attendanceCheckin/index.vue
index bcfdb00..b7b0f92 100644
--- a/src/views/personnelManagement/attendanceCheckin/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/index.vue
@@ -1,10 +1,12 @@
<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>
+ <div class="title">鎵撳崱绛惧埌
+ </div>
<div class="sub-title">鏀寔涓�閿墦鍗★紝鑷姩璁板綍涓婁笅鐝椂闂�</div>
</div>
<div class="attendance-actions">
@@ -12,458 +14,496 @@
<div class="label">褰撳墠鏃堕棿</div>
<div class="value">{{ nowTime }}</div>
</div>
- <el-button type="primary" size="large" @click="handleCheckInOut">
+ <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="鍛樺伐濮撳悕">
- {{ currentUser.name }}
+ {{ todayRecord.staffName }}
</el-descriptions-item>
<el-descriptions-item label="宸ュ彿">
- {{ currentUser.no }}
+ {{ todayRecord.staffNo }}
</el-descriptions-item>
<el-descriptions-item label="鎵�灞為儴闂�">
- {{ currentUser.dept }}
+ {{ 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>
<el-descriptions-item label="涓婄彮鏃堕棿">
- {{ todayRecord?.checkInTime || '-' }}
+ {{ todayRecord?.workStartAt || '-' }}
</el-descriptions-item>
<el-descriptions-item label="涓嬬彮鏃堕棿">
- {{ todayRecord?.checkOutTime || '-' }}
+ {{ todayRecord?.workEndAt || '-' }}
</el-descriptions-item>
<el-descriptions-item label="宸ユ椂(灏忔椂)">
{{ todayRecord?.workHours ?? '-' }}
</el-descriptions-item>
<el-descriptions-item label="寮傚父鏍囪">
- <span v-if="todayRecord?.status === 'normal'">-</span>
- <el-tag v-else type="danger" size="small">
- {{ todayRecord?.statusText }}
+ <span v-if="!todayRecord.id || todayRecord?.status === 0">-</span>
+ <el-tag v-else
+ type="danger"
+ size="small">
+ {{ todayRecord?.status ? getStatusText(todayRecord.status) : '-' }}
</el-tag>
</el-descriptions-item>
</el-descriptions>
- </el-card>
-
- <!-- 鏌ヨ鏉′欢锛堢鐞嗗憳鑰冨嫟鏃ユ姤锛� -->
- <div class="search_form">
- <div>
- <span class="search_title">閮ㄩ棬锛�</span>
- <el-select
- v-model="searchForm.dept"
- placeholder="璇烽�夋嫨閮ㄩ棬"
- style="width: 180px"
- clearable
- >
- <el-option
- v-for="item in deptOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
-
- <span class="search_title ml10">鏃ユ湡锛�</span>
- <el-date-picker
- v-model="searchForm.date"
- type="date"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
- placeholder="璇烽�夋嫨鏃ユ湡"
- clearable
- />
-
- <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
- 鎼滅储
- </el-button>
- <el-button @click="resetSearch">閲嶇疆</el-button>
- </div>
- <div>
- <el-button icon="Download" @click="handleExport">
- 瀵煎嚭鑰冨嫟鏃ユ姤
- </el-button>
- </div>
+ </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-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>
+ <el-form-item>
+ <el-button type="primary"
+ @click="fetchData">
+ <el-icon>
+ <Search />
+ </el-icon>
+ 鎼滅储
+ </el-button>
+ <el-button @click="resetSearch">
+ <el-icon>
+ <Refresh />
+ </el-icon>
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ </el-form>
+ <el-button icon="Download"
+ @click="handleExport">
+ 瀵煎嚭鑰冨嫟鏃ユ姤
+ </el-button>
</div>
-
<!-- 鑰冨嫟鏃ユ姤琛ㄦ牸 -->
<div class="table_list">
- <el-table
- :data="tableData"
- border
- 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="dept"
- label="閮ㄩ棬"
- width="140"
- />
- <el-table-column
- prop="name"
- label="濮撳悕"
- width="120"
- />
- <el-table-column
- prop="no"
- label="宸ュ彿"
- width="120"
- />
- <el-table-column
- prop="checkInTime"
- label="涓婄彮鏃堕棿"
- width="140"
- />
- <el-table-column
- prop="checkOutTime"
- label="涓嬬彮鏃堕棿"
- width="140"
- />
- <el-table-column
- prop="workHours"
- label="宸ユ椂(灏忔椂)"
- width="110"
- align="center"
- />
- <el-table-column
- prop="statusText"
- label="鑰冨嫟鐘舵��"
- width="120"
- 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 === 'normal'"
- 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.statusText }}
+ <el-tag v-else
+ type="danger"
+ size="small">
+ <!-- {{ scope.row.status === 1 ? '杩熷埌' : scope.row.status === 2 ? '鏃╅��' : '杩熷埌銆佹棭閫�' }} -->
+ {{ getStatusText(scope.row.status) }}
</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="page.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 } from "element-plus";
+ import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
+ import { useRouter } from "vue-router";
+ 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, ArrowLeft } from "@element-plus/icons-vue";
-// 妯℃嫙褰撳墠鐧诲綍鍛樺伐
-const currentUser = reactive({
- id: 1,
- name: "寮犱笁",
- no: "E10001",
- dept: "鐢熶骇涓�閮�",
-});
-
-// 閮ㄩ棬閫夐」
-const deptOptions = [
- { label: "鐢熶骇涓�閮�", value: "鐢熶骇涓�閮�" },
- { label: "鐢熶骇浜岄儴", value: "鐢熶骇浜岄儴" },
- { label: "璁惧缁存姢閮�", value: "璁惧缁存姢閮�" },
- { label: "璐ㄦ閮�", value: "璐ㄦ閮�" },
-];
-
-// 妯℃嫙鑰冨嫟鍘熷鏁版嵁
-const rawAttendance = ref([
- {
- id: 1,
- date: "2024-12-01",
- userId: 1,
- name: "寮犱笁",
- no: "E10001",
- dept: "鐢熶骇涓�閮�",
- checkInTime: "08:58",
- checkOutTime: "18:10",
- workHours: 9.2,
- status: "normal",
- statusText: "姝e父",
- remark: "",
- },
- {
- id: 2,
- date: "2024-12-01",
- userId: 2,
- name: "鏉庡洓",
- no: "E10002",
- dept: "鐢熶骇涓�閮�",
- checkInTime: "09:15",
- checkOutTime: "18:05",
- workHours: 8.8,
- status: "late",
- statusText: "杩熷埌",
- remark: "鍥犱氦閫氭嫢鍫佃繜鍒�",
- },
- {
- id: 3,
- date: "2024-12-01",
- userId: 3,
- name: "鐜嬩簲",
- no: "E20001",
- dept: "璁惧缁存姢閮�",
- checkInTime: "08:50",
- checkOutTime: "17:20",
- workHours: 8.5,
- status: "early",
- statusText: "鏃╅��",
- remark: "澶栧嚭澶勭悊绱ф�ユ晠闅�",
- },
- {
- id: 4,
- date: "2024-12-02",
- userId: 1,
- name: "寮犱笁",
- no: "E10001",
- dept: "鐢熶骇涓�閮�",
- checkInTime: "08:45",
- checkOutTime: "18:30",
- workHours: 9.7,
- status: "normal",
- statusText: "姝e父",
- remark: "鍔犵彮0.5灏忔椂",
- },
-]);
-
-// 鏌ヨ琛ㄥ崟
-const searchForm = reactive({
- dept: "",
- 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 todayStr = computed(() => nowTime.value.slice(0, 10));
-
-// 褰撴棩褰撳墠鍛樺伐鑰冨嫟璁板綍
-const todayRecord = computed(() =>
- rawAttendance.value.find(
- (item) =>
- item.userId === currentUser.id && item.date === todayStr.value
- )
-);
-
-// 鎵撳崱鎸夐挳鏂囨湰
-const checkInOutText = computed(() => {
- if (!todayRecord.value || !todayRecord.value.checkInTime) {
- return "涓婄彮鎵撳崱";
- }
- if (!todayRecord.value.checkOutTime) {
- return "涓嬬彮鎵撳崱";
- }
- return "浠婃棩宸叉墦鍗″畬鎴�";
-});
-
-// 浠婃棩鐘舵�佸睍绀�
-const todayStatusTag = computed(() => {
- if (!todayRecord.value) return "info";
- if (todayRecord.value.status === "normal") return "success";
- return "danger";
-});
-
-const todayStatusText = computed(() => {
- if (!todayRecord.value) return "鏈墦鍗�";
- return todayRecord.value.statusText || "姝e父";
-});
-
-// 琛屾牱寮忥細寮傚父楂樹寒
-const rowClassName = ({ row }) => {
- if (row.status === "late" || row.status === "early") {
- return "row-abnormal";
- }
- return "";
-};
-
-// 鏌ヨ
-const recomputeTable = () => {
- const list = rawAttendance.value.filter((item) => {
- if (searchForm.dept && item.dept !== searchForm.dept) {
- return false;
- }
- if (searchForm.date && item.date !== searchForm.date) {
- return false;
- }
- return true;
+ const { proxy } = getCurrentInstance();
+ const router = useRouter();
+ const tableLoading = ref(false);
+ // 鍒嗛〉鍙傛暟
+ const page = reactive({
+ current: 1,
+ size: 10,
+ total: 0,
});
- tableData.value = list;
-};
+ // 浠婃棩鏁版嵁
+ const todayRecord = ref({});
-const handleQuery = () => {
- recomputeTable();
-};
+ // 閮ㄩ棬閫夐」
+ const deptOptions = ref([]);
-const resetSearch = () => {
- searchForm.dept = "";
- searchForm.date = "";
- recomputeTable();
-};
+ // 鏌ヨ琛ㄥ崟
+ const searchForm = reactive({
+ deptId: "",
+ date: "",
+ });
-// 瀵煎嚭锛堟紨绀猴級
-const handleExport = () => {
- ElMessage.success("褰撳墠涓烘紨绀洪〉闈紝瀵煎嚭鍔熻兘鏈鎺ュ疄闄呮帴鍙�");
-};
+ // 琛ㄦ牸鏁版嵁
+ const tableData = ref([]);
-// 鎵撳崱閫昏緫锛堜粎鍓嶇妯℃嫙锛�
-const handleCheckInOut = () => {
- const [dateStr, timeStr] = nowTime.value.split(" ");
- if (!dateStr || !timeStr) return;
+ // 褰撳墠鏃堕棿灞曠ず
+ const nowTime = ref("");
+ let timer = null;
- // 涓婄彮鎵撳崱
- if (!todayRecord.value) {
- const newId = rawAttendance.value.length
- ? Math.max(...rawAttendance.value.map((i) => i.id)) + 1
- : 1;
- const status =
- timeStr > "09:00:00" ? "late" : "normal";
- const statusText = status === "late" ? "杩熷埌" : "姝e父";
- rawAttendance.value.push({
- id: newId,
- date: dateStr,
- userId: currentUser.id,
- name: currentUser.name,
- no: currentUser.no,
- dept: currentUser.dept,
- checkInTime: timeStr.slice(0, 5),
- checkOutTime: "",
- workHours: null,
- status,
- statusText,
- remark: "",
- });
- ElMessage.success("涓婄彮鎵撳崱鎴愬姛");
- } else if (!todayRecord.value.checkOutTime) {
- // 涓嬬彮鎵撳崱
- todayRecord.value.checkOutTime = timeStr.slice(0, 5);
- // 绠�鍗曟寜 9:00-18:00 璁$畻宸ユ椂
- const start = todayRecord.value.checkInTime || "09:00";
- const [sh, sm] = start.split(":").map((v) => parseInt(v, 10));
- const [eh, em] = todayRecord.value.checkOutTime
- .split(":")
- .map((v) => parseInt(v, 10));
- const diff = (eh * 60 + em - (sh * 60 + sm)) / 60;
- todayRecord.value.workHours = Number(Math.max(diff, 0).toFixed(1));
+ 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}`;
+ };
- // 鏃╅��鍒ゆ柇锛�18:00 鍓嶇寮�瑙嗕负鏃╅��锛堝彧绀烘剰锛�
- if (timeStr < "18:00:00") {
- todayRecord.value.status = "early";
- todayRecord.value.statusText = "鏃╅��";
- } else if (todayRecord.value.status === "normal") {
- todayRecord.value.statusText = "姝e父";
+ // 鎵撳崱鎸夐挳鏂囨湰
+ const checkInOutText = computed(() => {
+ if (!todayRecord.value || !todayRecord.value.workStartAt) {
+ return "涓婄彮鎵撳崱";
}
- ElMessage.success("涓嬬彮鎵撳崱鎴愬姛");
- } else {
- ElMessage.info("浠婃棩宸插畬鎴愪笂涓嬬彮鎵撳崱");
+ 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;
+ });
}
- recomputeTable();
-};
+ // 鏌ヨ
+ const fetchData = () => {
+ tableLoading.value = true;
+ findPersonalAttendanceRecords({ ...page, ...searchForm })
+ .then(res => {
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ };
-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}`;
- recomputeTable();
-});
+ // 鏌ヨ浠婃棩鎵撳崱淇℃伅
+ const fetchTodayData = () => {
+ // findTodayPersonalAttendanceRecord({}).then(res => {
+ // todayRecord.value = res.data;
+ // });
+ };
-onBeforeUnmount(() => {
- if (timer) {
- clearInterval(timer);
- }
-});
+ 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 getCurrentLocation = () => {
+ return new Promise((resolve, reject) => {
+ if (!navigator.geolocation) {
+ reject(new Error("娴忚鍣ㄤ笉鏀寔鍦扮悊瀹氫綅"));
+ return;
+ }
+
+ // 妫�鏌ユ槸鍚︿娇鐢℉TTPS
+ const isSecureContext =
+ window.isSecureContext || window.location.protocol === "https:";
+ console.log(
+ "褰撳墠鍗忚:",
+ window.location.protocol,
+ "鏄惁瀹夊叏涓婁笅鏂�:",
+ isSecureContext
+ );
+
+ if (!isSecureContext) {
+ console.warn("褰撳墠涓嶆槸HTTPS鍗忚锛屽湴鐞嗕綅缃瓵PI鍙兘鍙楅檺");
+ }
+
+ navigator.geolocation.getCurrentPosition(
+ position => {
+ const { longitude, latitude } = position.coords;
+ console.log("鑾峰彇浣嶇疆鎴愬姛:", longitude, latitude);
+ resolve({ longitude, latitude });
+ },
+ error => {
+ console.log("鑾峰彇浣嶇疆澶辫触:", error);
+ let errorMessage = "鑾峰彇浣嶇疆澶辫触";
+
+ // 鏍规嵁閿欒绫诲瀷鎻愪緵鏇村叿浣撶殑鎻愮ず
+ switch (error.code) {
+ case error.PERMISSION_DENIED:
+ errorMessage =
+ "鐢ㄦ埛鎷掔粷浜嗕綅缃潈闄愯姹傦紝璇峰湪娴忚鍣ㄨ缃腑鍏佽浣嶇疆璁块棶";
+ break;
+ case error.POSITION_UNAVAILABLE:
+ errorMessage = "浣嶇疆淇℃伅涓嶅彲鐢紝璇锋鏌ヨ澶囧畾浣嶅姛鑳�";
+ break;
+ case error.TIMEOUT:
+ errorMessage = "鑾峰彇浣嶇疆瓒呮椂锛岃閲嶈瘯";
+ break;
+ case error.UNKNOWN_ERROR:
+ errorMessage = "鑾峰彇浣嶇疆鏃跺彂鐢熸湭鐭ラ敊璇�";
+ break;
+ default:
+ errorMessage = `鑾峰彇浣嶇疆澶辫触: ${error.message}`;
+ }
+
+ // 妫�鏌ユ槸鍚︽槸HTTPS闂
+ if (error.code === error.PERMISSION_DENIED && !isSecureContext) {
+ errorMessage += "锛堟敞鎰忥細鐢熶骇鐜闇�瑕佷娇鐢℉TTPS鍗忚鎵嶈兘鑾峰彇浣嶇疆锛�";
+ }
+
+ reject(new Error(errorMessage));
+ },
+ {
+ enableHighAccuracy: true,
+ timeout: 10000,
+ maximumAge: 0,
+ }
+ );
+ });
+ };
+
+ // 鎵撳崱
+ const handleCheckInOut = () => {
+ getCurrentLocation()
+ .then(location => {
+ console.log("浣嶇疆鎴愬姛");
+ createPersonalAttendanceRecord(location).then(res => {
+ fetchData();
+ fetchTodayData();
+ ElMessage.success("鎵撳崱鎴愬姛锛�");
+ });
+ })
+ .catch(error => {
+ // 鑾峰彇浣嶇疆澶辫触鏃讹紝浠嶅厑璁告墦鍗�
+ ElMessage.warning("鑾峰彇浣嶇疆澶辫触锛屽皢浣跨敤榛樿浣嶇疆鎵撳崱");
+ 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();
+ });
+
+ 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;
+ }
</style>
--
Gitblit v1.9.3