From cc2f6601aa3fef21173c40534687f6fd50c520de Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期四, 23 七月 2026 18:25:23 +0800
Subject: [PATCH] feat: 优化扫码逻辑,重构弹窗与员工验证缓存

---
 api/employee.js |  165 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 151 insertions(+), 14 deletions(-)

diff --git a/api/employee.js b/api/employee.js
index 2259f57..88160a6 100644
--- a/api/employee.js
+++ b/api/employee.js
@@ -3,10 +3,57 @@
 
 const EMPLOYEE_VERIFY_LIST_KEY = 'employee_verify_list';
 const EMPLOYEE_FACE_IMAGE_DIR = 'employee-face-images';
+let employeeVerifyListSyncPromise = null;
 
 const yieldMainThread = (delay = 0) => {
   return new Promise((resolve) => {
     setTimeout(resolve, delay);
+  });
+};
+
+const saveEmployeeVerifyListCache = async (employeeList = []) => {
+  await saveOfflineConfig(EMPLOYEE_VERIFY_LIST_KEY, employeeList);
+  uni.setStorageSync(EMPLOYEE_VERIFY_LIST_KEY, employeeList);
+};
+
+const getCurrentNetworkType = async () => {
+  return new Promise((resolve) => {
+    uni.getNetworkType({
+      success: (res) => resolve(res.networkType),
+      fail: () => resolve('unknown'),
+    });
+  });
+};
+
+const isLocalEmployeeFacePath = (value = '') => {
+  const normalizedValue = String(value || '').trim();
+  return /^(file:\/\/|_doc\/|\/storage\/)/.test(normalizedValue);
+};
+
+const isLocalFileExists = (filePath = '') => {
+  return new Promise((resolve) => {
+    const normalizedFilePath = String(filePath || '').trim();
+    if (!normalizedFilePath) {
+      resolve(false);
+      return;
+    }
+
+    // #ifdef APP-PLUS
+    if (typeof plus === 'undefined' || !plus.io || !plus.io.resolveLocalFileSystemURL) {
+      resolve(false);
+      return;
+    }
+
+    plus.io.resolveLocalFileSystemURL(normalizedFilePath, () => {
+      resolve(true);
+    }, () => {
+      resolve(false);
+    });
+    // #endif
+
+    // #ifndef APP-PLUS
+    resolve(true);
+    // #endif
   });
 };
 
@@ -156,6 +203,80 @@
   return [];
 };
 
+const sanitizeEmployeeFaceImageCache = async (employee = {}) => {
+  if (!employee || typeof employee !== 'object') {
+    return {
+      employee,
+      invalidLocalFaceImage: false,
+    };
+  }
+
+  const normalizedEmployee = { ...employee };
+  const normalizedFaceImage = String(employee.faceImage || '').trim();
+  if (!isLocalEmployeeFacePath(normalizedFaceImage)) {
+    return {
+      employee: normalizedEmployee,
+      invalidLocalFaceImage: false,
+    };
+  }
+
+  const isFaceImageFileExists = await isLocalFileExists(normalizedFaceImage);
+  if (isFaceImageFileExists) {
+    return {
+      employee: normalizedEmployee,
+      invalidLocalFaceImage: false,
+    };
+  }
+
+  // 本地图片文件被系统清理后,必须立刻清空失效路径,避免离线状态继续拿脏地址做人脸比对。
+  normalizedEmployee.faceImage = '';
+  return {
+    employee: normalizedEmployee,
+    invalidLocalFaceImage: true,
+  };
+};
+
+const sanitizeEmployeeVerifyListCache = async (employeeList = []) => {
+  const sanitizedEmployeeList = [];
+  let hasInvalidLocalFaceImage = false;
+
+  for (let index = 0; index < employeeList.length; index += 1) {
+    const sanitizeResult = await sanitizeEmployeeFaceImageCache(employeeList[index]);
+    sanitizedEmployeeList.push(sanitizeResult.employee);
+    hasInvalidLocalFaceImage = hasInvalidLocalFaceImage || sanitizeResult.invalidLocalFaceImage;
+  }
+
+  return {
+    employeeList: sanitizedEmployeeList,
+    hasInvalidLocalFaceImage,
+  };
+};
+
+const performSyncEmployeeVerifyList = async () => {
+  const res = await getAllEmployeeVerifyAPI();
+  if (res && res.code === 200) {
+    const employeeList = normalizeEmployeeListResponse(res.data);
+    const normalizedEmployeeList = await normalizeEmployeeListFaceImages(employeeList);
+    await saveEmployeeVerifyListCache(normalizedEmployeeList);
+    return normalizedEmployeeList;
+  }
+
+  throw new Error(res?.msg || '同步员工验证列表失败');
+};
+
+const runEmployeeVerifyListSync = async () => {
+  if (employeeVerifyListSyncPromise) {
+    return employeeVerifyListSyncPromise;
+  }
+
+  employeeVerifyListSyncPromise = performSyncEmployeeVerifyList();
+  try {
+    return await employeeVerifyListSyncPromise;
+  } finally {
+    employeeVerifyListSyncPromise = null;
+  }
+};
+
 export const getAllEmployeeVerifyAPI = (data = {}) => {
   return request({
     url: '/api/employee/verify/allEmployee',
@@ -166,27 +287,43 @@
 
 export const syncEmployeeVerifyList = async () => {
   try {
-    const res = await getAllEmployeeVerifyAPI();
-    if (res && res.code === 200) {
-      const employeeList = normalizeEmployeeListResponse(res.data);
-      const normalizedEmployeeList = await normalizeEmployeeListFaceImages(employeeList);
-      await saveOfflineConfig(EMPLOYEE_VERIFY_LIST_KEY, normalizedEmployeeList);
-      uni.setStorageSync(EMPLOYEE_VERIFY_LIST_KEY, normalizedEmployeeList);
-      return normalizedEmployeeList;
-    }
+    return await runEmployeeVerifyListSync();
   } catch (error) {
     console.error('同步员工验证列表失败:', error);
+    return [];
   }
-
-  return [];
 };
 
 export const getLocalEmployeeVerifyList = async () => {
   const offlineEmployeeList = await getOfflineConfig(EMPLOYEE_VERIFY_LIST_KEY);
-  if (Array.isArray(offlineEmployeeList)) {
-    return offlineEmployeeList;
+  const storageEmployeeList = uni.getStorageSync(EMPLOYEE_VERIFY_LIST_KEY);
+  const localEmployeeList = Array.isArray(offlineEmployeeList)
+    ? offlineEmployeeList
+    : (Array.isArray(storageEmployeeList) ? storageEmployeeList : []);
+
+  if (!Array.isArray(localEmployeeList) || localEmployeeList.length === 0) {
+    return [];
   }
 
-  const storageEmployeeList = uni.getStorageSync(EMPLOYEE_VERIFY_LIST_KEY);
-  return Array.isArray(storageEmployeeList) ? storageEmployeeList : [];
+  const {
+    employeeList: sanitizedEmployeeList,
+    hasInvalidLocalFaceImage,
+  } = await sanitizeEmployeeVerifyListCache(localEmployeeList);
+
+  if (!hasInvalidLocalFaceImage) {
+    return sanitizedEmployeeList;
+  }
+
+  await saveEmployeeVerifyListCache(sanitizedEmployeeList);
+
+  const networkType = await getCurrentNetworkType();
+  if (networkType !== 'none') {
+    try {
+      return await runEmployeeVerifyListSync();
+    } catch (error) {
+      console.error('员工人脸缓存失效后自动重同步失败:', error);
+    }
+  }
+
+  return sanitizedEmployeeList;
 };

--
Gitblit v1.7.1