From 1ed366885433dfdec1241312356535b868c39eee Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 26 二月 2026 16:21:04 +0800
Subject: [PATCH] 合同管理模块开发

---
 src/pages/humanResources/attendance/checkin.vue |  351 +++++++++++++++++++++++++++++++++------------------------
 1 files changed, 202 insertions(+), 149 deletions(-)

diff --git a/src/pages/humanResources/attendance/checkin.vue b/src/pages/humanResources/attendance/checkin.vue
index 970d35a..483b264 100644
--- a/src/pages/humanResources/attendance/checkin.vue
+++ b/src/pages/humanResources/attendance/checkin.vue
@@ -14,14 +14,14 @@
           <u-icon name="calendar"
                   color="#348fe2"
                   size="16"></u-icon>
-          <text class="shift-text">鐧界彮: 09:00-18:00</text>
+          <text class="shift-text">鐧界彮: {{ todayRecord.startAt }}-{{ todayRecord.endAt }}</text>
         </view>
       </view>
       <!-- 鎵撳崱鎸夐挳 -->
       <view class="checkin-button-container">
         <view class="checkin-button-wrapper">
           <view class="checkin-button"
-                :class="{ 'disabled': checkInOutText === '宸叉墦鍗�' }"
+                :class="{ 'disabled': todayRecord.workEndAt || noNeedCheckIn }"
                 @click="handleCheckInOut">
             <text class="checkin-button-text">{{ checkInOutText }}</text>
             <text class="checkin-time">{{ nowTime.split(' ')[1] }}</text>
@@ -41,53 +41,53 @@
       <view class="employee-info">
         <view class="info-item">
           <text class="info-label">閮ㄩ棬</text>
-          <text class="info-value">{{ currentUser.dept }}</text>
+          <text class="info-value">{{ todayRecord.deptName || '-' }}</text>
         </view>
         <view class="info-item">
           <text class="info-label">濮撳悕</text>
-          <text class="info-value">{{ currentUser.name }}</text>
+          <text class="info-value">{{ todayRecord.staffName || '-' }}</text>
         </view>
         <view class="info-item">
           <text class="info-label">宸ュ彿</text>
-          <text class="info-value">{{ currentUser.no }}</text>
+          <text class="info-value">{{ todayRecord.staffNo || '-' }}</text>
         </view>
       </view>
       <!-- 浠婃棩鑰冨嫟鐘舵�� -->
       <view class="today-status">
-        <u-icon :name="todayRecord ? 'checkmark-circle' : 'close-circle'"
-                :color="todayRecord ? '#4cd964' : '#ff3b30'"
+        <u-icon :name="todayRecord.id ? 'checkmark-circle' : 'close-circle'"
+                :color="todayRecord.id ? '#4cd964' : '#ff3b30'"
                 size="16"></u-icon>
         <text class="status-text">
-          {{ todayRecord ? `浠婃棩鑰冨嫟: 涓婄彮 ${todayRecord.checkInTime}` : '浠婃棩鏈墦鍗�' }}
+          {{ todayRecord.id ? `浠婃棩鑰冨嫟: 涓婄彮 ${todayRecord.workStartAt || '-'}` : '浠婃棩鏈墦鍗�' }}
         </text>
       </view>
       <!-- 涓嬬彮鑰冨嫟鐘舵�� -->
-      <view v-if="todayRecord && todayRecord.checkOutTime"
+      <view v-if="todayRecord.id && todayRecord.workEndAt"
             class="today-status">
-        <u-icon :name="todayRecord ? 'checkmark-circle' : 'close-circle'"
-                :color="todayRecord ? '#4cd964' : '#ff3b30'"
+        <u-icon name="checkmark-circle"
+                color="#4cd964"
                 size="16"></u-icon>
         <text class="status-text">
-          {{ `浠婃棩鑰冨嫟: 涓嬬彮 ${todayRecord.checkOutTime}` }}
+          {{ `浠婃棩鑰冨嫟: 涓嬬彮 ${todayRecord.workEndAt}` }}
         </text>
       </view>
       <!-- 鎵撳崱鐘舵�� -->
-      <view v-if="todayRecord"
-            class="today-status">
-        <u-icon :name="todayRecord.status === 'normal' ? 'checkmark-circle' : 'clock'"
-                :color="todayRecord.status === 'normal' ? '#4cd964' : '#ff3b30'"
+      <view class="today-status">
+        <u-icon :name="todayRecord.id ? (todayRecord.status === 0 ? 'checkmark-circle' : 'clock') : 'clock'"
+                :color="todayRecord.id ? (todayRecord.status === 0 ? '#4cd964' : '#ff3b30') : '#ff3b30'"
                 size="16"></u-icon>
         <text class="status-text">
-          {{ `鎵撳崱鐘舵��: ${todayRecord.statusText}` }}
+          {{ `鎵撳崱鐘舵��: ${todayStatusText}` }}
         </text>
       </view>
-      <view v-else
+      <!-- 宸ユ椂淇℃伅 -->
+      <view v-if="todayRecord.id && todayRecord.workHours"
             class="today-status">
         <u-icon name="clock"
-                color="#ff3b30"
+                color="#348fe2"
                 size="16"></u-icon>
         <text class="status-text">
-          鎵撳崱鐘舵��: 缂哄崱
+          {{ `宸ユ椂(灏忔椂): ${todayRecord.workHours}` }}
         </text>
       </view>
     </view>
@@ -97,56 +97,57 @@
 <script setup>
   import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue";
   import PageHeader from "@/components/PageHeader.vue";
-  // 妯℃嫙褰撳墠鐧诲綍鍛樺伐
-  const currentUser = reactive({
-    id: 1,
-    name: "寮犱笁",
-    no: "E10001",
-    dept: "鐢熶骇涓�閮�",
-  });
+  import { getDicts } from "@/api/system/dict/data";
+  import {
+    createPersonalAttendanceRecord,
+    findTodayPersonalAttendanceRecord,
+  } from "@/api/personnelManagement/attendance.js";
+  // 浠婃棩鎵撳崱璁板綍
+  const todayRecord = ref({});
 
-  // 妯℃嫙鑰冨嫟鍘熷鏁版嵁
-  const rawAttendance = ref([
-    {
-      id: 2,
-      date: "2026-02-08",
-      userId: 1,
-      name: "寮犱笁",
-      no: "E10001",
-      dept: "鐢熶骇涓�閮�",
-      checkInTime: "09:15",
-      checkOutTime: "18:05",
-      workHours: 8.8,
-      status: "late",
-      statusText: "杩熷埌",
-      remark: "鍥犱氦閫氭嫢鍫佃繜鍒�",
-    },
-    {
-      id: 3,
-      date: "2026-02-07",
-      userId: 1,
-      name: "寮犱笁",
-      no: "E10001",
-      dept: "鐢熶骇涓�閮�",
-      checkInTime: "08:45",
-      checkOutTime: "18:30",
-      workHours: 9.7,
-      status: "normal",
-      statusText: "姝e父",
-      remark: "鍔犵彮0.5灏忔椂",
-    },
-  ]);
+  // 鐝淇℃伅
+  const workTimeDict = ref({
+    startAt: "09:00",
+    endAt: "18:00",
+  });
 
   // 褰撳墠鏃堕棿灞曠ず
   const nowTime = ref("");
   let timer = null;
+
+  // 涓婃鎵撳崱鏃堕棿
+  const lastCheckInTime = ref(null);
+
+  // 鎵撳崱鍐峰嵈鏃堕棿锛堟绉掞級
+  const CHECKIN_COOLDOWN = 5000;
   // 杩斿洖涓婁竴椤�
   const goBack = () => {
     uni.navigateBack();
   };
+  // 鏌ヨ浠婃棩鎵撳崱淇℃伅
+  const fetchTodayData = () => {
+    findTodayPersonalAttendanceRecord({}).then(res => {
+      if (res.data) {
+        todayRecord.value = res.data;
+        // 妫�鏌tartAt鍜宔ndAt鏄惁涓虹┖锛屼负绌哄垯鏃犻渶鎵撳崱
+        if (!todayRecord.value.startAt || !todayRecord.value.endAt) {
+          noNeedCheckIn.value = true;
+        } else {
+          noNeedCheckIn.value = false;
+        }
+      } else {
+        // 椤甸潰鏄剧ず鈥滄棤闇�鎵撳崱鈥�
+        todayRecord.value = {};
+        noNeedCheckIn.value = true;
+      }
+    });
+  };
 
   // 鎵撳崱鑼冨洿鐘舵��
   const inCheckRange = ref(true);
+
+  // 鏄惁鏃犻渶鎵撳崱
+  const noNeedCheckIn = ref(false);
 
   // 褰撳墠浣嶇疆
   const currentLocation = ref(null);
@@ -165,22 +166,42 @@
   // 浠婃棩鏃ユ湡
   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) {
+    if (noNeedCheckIn.value) {
+      return "鏃犻渶鎵撳崱";
+    }
+    if (!todayRecord.value || !todayRecord.value.workStartAt) {
       return "涓婄彮鎵撳崱";
     }
-    if (!todayRecord.value.checkOutTime) {
+    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 "鏃╅��";
+      case 3:
+        return "杩熷埌銆佹棭閫�";
+      case 4:
+        return "缂哄嫟";
+    }
   });
 
   // 瀵艰埅鍒拌缁嗘姤鍛婇〉闈�
@@ -220,31 +241,104 @@
       // #endif
     });
   };
+  const form = ref({
+    longitude: "",
+    latitude: "",
+  });
 
-  // 鑾峰彇褰撳墠浣嶇疆
   const getCurrentLocation = () => {
-    return new Promise((resolve, reject) => {
-      uni.getLocation({
-        type: "wgs84",
-        success: res => {
-          currentLocation.value = res;
-          // 妯℃嫙妫�鏌ユ槸鍚﹀湪鎵撳崱鑼冨洿鍐咃紙瀹為檯椤圭洰涓簲鏍规嵁鍏徃浣嶇疆鍜屽厑璁哥殑鍗婂緞杩涜璁$畻锛�
-          // 杩欓噷绠�鍗曟ā鎷熶负濮嬬粓鍦ㄨ寖鍥村唴
-          inCheckRange.value = true;
-          resolve(res);
-        },
-        fail: err => {
-          console.error("鑾峰彇浣嶇疆澶辫触:", err);
-          // 澶辫触鏃堕粯璁ゅ厑璁告墦鍗★紙瀹為檯椤圭洰涓簲鏍规嵁涓氬姟闇�姹傚鐞嗭級
-          inCheckRange.value = true;
-          reject(err);
-        },
-      });
+    uni.showLoading({ title: "鑾峰彇浣嶇疆涓�..." });
+
+    uni.getLocation({
+      type: "gcj02",
+      success: res => {
+        uni.hideLoading();
+        form.value.latitude = res.latitude;
+        form.value.longitude = res.longitude;
+      },
+      fail: err => {
+        uni.hideLoading();
+        console.error("鑾峰彇浣嶇疆澶辫触:", err);
+
+        // 鏄剧ず閿欒鎻愮ず骞跺紩瀵肩敤鎴锋鏌ユ潈闄�
+        showToast("鑾峰彇浣嶇疆澶辫触锛岃妫�鏌ュ畾浣嶆潈闄�");
+
+        // 寮曞鐢ㄦ埛妫�鏌ユ潈闄愯缃�
+        uni.showModal({
+          title: "浣嶇疆鏉冮檺鎻愮ず",
+          content:
+            "鑾峰彇浣嶇疆澶辫触锛屽彲鑳芥槸鍥犱负浣嶇疆鏉冮檺鏈紑鍚紝璇峰湪璁惧璁剧疆涓鏌ュ苟寮�鍚綅缃潈闄愩��",
+          confirmText: "鐭ラ亾浜�",
+          cancelText: "鍙栨秷",
+          success: res => {
+            if (res.confirm) {
+              // 鍙互灏濊瘯鎵撳紑璁剧疆椤甸潰锛堝鏋滄敮鎸侊級
+              if (uni.openSetting) {
+                uni.openSetting({
+                  success: settingRes => {
+                    console.log("璁剧疆缁撴灉:", settingRes);
+                  },
+                });
+              }
+            }
+          },
+        });
+
+        // 澶辫触鏃舵樉绀洪敊璇俊鎭�
+        form.value.visitAddress = "浣嶇疆鑾峰彇澶辫触";
+      },
     });
   };
 
-  // 鎵撳崱閫昏緫锛堜粎鍓嶇妯℃嫙锛�
+  // 鑾峰彇鐝瀛楀吀鏁版嵁
+  const getWorkTimeDict = () => {
+    getDicts("sys_work_time")
+      .then(res => {
+        if (res.data && res.data.length > 0) {
+          const dictData = res.data;
+          workTimeDict.value = {
+            startAt: dictData[0].dictValue || "-",
+            endAt: dictData[1].dictValue || "-",
+          };
+        }
+      })
+      .catch(error => {
+        console.error("鑾峰彇鐝瀛楀吀澶辫触:", error);
+      });
+  };
+
+  // 鎵撳崱閫昏緫
   const handleCheckInOut = async () => {
+    if (noNeedCheckIn.value) {
+      uni.showToast({
+        title: "浠婃棩鏃犻渶鎵撳崱",
+        icon: "none",
+      });
+      return;
+    }
+
+    if (todayRecord.value.workEndAt) {
+      uni.showToast({
+        title: "鎮ㄥ凡缁忔墦杩囧崱浜�,鏃犻渶閲嶅鎵撳崱!!!",
+        icon: "none",
+      });
+      return;
+    }
+
+    // 妫�鏌ユ槸鍚﹀湪鎵撳崱鍐峰嵈鏃堕棿鍐�
+    if (lastCheckInTime.value) {
+      const currentTime = Date.now();
+      const timeDiff = currentTime - lastCheckInTime.value;
+      if (timeDiff < CHECKIN_COOLDOWN) {
+        const remainingTime = Math.ceil((CHECKIN_COOLDOWN - timeDiff) / 1000);
+        uni.showToast({
+          title: `璇�${remainingTime}绉掑悗鍐嶈瘯`,
+          icon: "none",
+        });
+        return;
+      }
+    }
+
     // 妫�鏌ユ槸鍚﹀湪鎵撳崱鑼冨洿鍐�
     if (!inCheckRange.value) {
       uni.showToast({
@@ -254,79 +348,38 @@
       return;
     }
 
-    const [dateStr, timeStr] = nowTime.value.split(" ");
-    if (!dateStr || !timeStr) return;
+    // 璋冪敤鎵撳崱API
+    createPersonalAttendanceRecord({
+      ...form.value,
+    })
+      .then(res => {
+        // 璁板綍鎵撳崱鏃堕棿
+        lastCheckInTime.value = Date.now();
 
-    // 涓婄彮鎵撳崱
-    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: "",
+        uni.showToast({
+          title: "鎵撳崱鎴愬姛锛�",
+          icon: "success",
+        });
+        // 閲嶆柊鑾峰彇浠婃棩鎵撳崱淇℃伅
+        fetchTodayData();
+      })
+      .catch(error => {
+        uni.showToast({
+          title: error.msg || "鎵撳崱澶辫触锛岃閲嶈瘯",
+          icon: "none",
+        });
       });
-      uni.showToast({
-        title: "涓婄彮鎵撳崱鎴愬姛",
-        icon: "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));
-
-      // 鏃╅��鍒ゆ柇锛�18:00 鍓嶇寮�瑙嗕负鏃╅��锛堝彧绀烘剰锛�
-      if (timeStr < "18:00:00") {
-        if (todayRecord.value.status === "late") {
-          // 鏃㈣繜鍒板張鏃╅��
-          todayRecord.value.status = "late-early";
-          todayRecord.value.statusText = "杩熷埌 + 鏃╅��";
-        } else {
-          // 浠呮棭閫�
-          todayRecord.value.status = "early";
-          todayRecord.value.statusText = "鏃╅��";
-        }
-      } else if (todayRecord.value.status === "normal") {
-        todayRecord.value.statusText = "姝e父";
-      }
-      uni.showToast({
-        title: "涓嬬彮鎵撳崱鎴愬姛",
-        icon: "success",
-      });
-    } else {
-      uni.showToast({
-        title: "浠婃棩宸插畬鎴愪笂涓嬬彮鎵撳崱",
-        icon: "none",
-      });
-    }
   };
 
   onMounted(async () => {
+    fetchTodayData();
     updateNowTime();
     timer = setInterval(updateNowTime, 1000);
+    getWorkTimeDict();
 
     // 鑾峰彇浣嶇疆鏉冮檺骞舵鏌ヤ綅缃�
     try {
-      await getLocationPermission();
+      // await getLocationPermission();
       await getCurrentLocation();
     } catch (error) {
       console.error("浣嶇疆鏉冮檺鑾峰彇澶辫触:", error);

--
Gitblit v1.9.3