spring
昨天 6e763136fdf4469143ebbae0b717eb8e9b0ca954
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
import { ref, computed, onUnmounted } from "vue";
import { onShow, onHide } from "@dcloudio/uni-app";
import RoutingInspectionApi from "@/api/routingInspection/routingInspection";
 
/**
 * 扫码数据接口
 */
interface ScanCodeData {
  uid?: string;
  deviceModel?: string;
  [key: string]: any;
}
 
// 全局监听器状态映射(确保每个事件名只有一个监听器)
const globalListeners = new Map<string, boolean>();
 
// 添加一个全局的捕获所有扫码事件的监听器(用于调试)
let debugListenerInitialized = false;
 
const initDebugListener = () => {
  if (debugListenerInitialized) return;
  
  // 监听所有可能的扫码事件
  const eventNames = ["scan", "scanIndex", "scanJX", "scanLS"];
  eventNames.forEach((eventName) => {
    uni.$on(eventName, (data: any) => {
      console.log(`🔍 [全局调试] 捕获到 ${eventName} 事件:`, data);
    });
  });
  
  debugListenerInitialized = true;
  console.log("🔍 [全局调试] 调试监听器已初始化");
};
 
/**
 * 扫码管理 Composable
 * 统一管理扫码事件监听、缓存存储和数据读取
 * 全局监听器,不随页面切换而关闭
 * @param eventName 监听的事件名称,默认为 "scan"
 */
export function useScanCode(eventName: string = "scan") {
  // 当前扫码的设备 UID
  const deviceUid = ref<string>("");
  // 当前扫码的机台型号
  const deviceModel = ref<string>("");
  // 完整的扫码数据
  const scanData = ref<ScanCodeData>({});
  // 保存事件名称
  const currentEventName = eventName;
 
  /**
   * 从本地缓存加载扫码数据
   */
  const loadFromCache = () => {
    try {
      const cachedData = uni.getStorageSync("scanCodeData");
      if (cachedData) {
        scanData.value = cachedData;
        deviceUid.value = cachedData.uid || "";
        deviceModel.value = cachedData.deviceModel || "";
        console.log("[useScanCode] 从缓存加载扫码数据:", cachedData);
        return cachedData;
      }
    } catch (error) {
      console.error("[useScanCode] 读取缓存失败:", error);
    }
    return null;
  };
 
  /**
   * 保存扫码数据到缓存
   */
  const saveToCache = (data: ScanCodeData) => {
    try {
      uni.setStorageSync("scanCodeData", data);
      console.log("[useScanCode] 已保存到缓存:", data);
      return true;
    } catch (error) {
      console.error("[useScanCode] 保存缓存失败:", error);
      return false;
    }
  };
 
  /**
   * 清空扫码数据和缓存
   */
  const clearScanData = () => {
    try {
      uni.removeStorageSync("scanCodeData");
      deviceUid.value = "";
      deviceModel.value = "";
      scanData.value = {};
      console.log("[useScanCode] 已清空扫码数据");
    } catch (error) {
      console.error("[useScanCode] 清空缓存失败:", error);
    }
  };
 
  /**
   * 验证二维码(仅调用接口,不处理返回结果)
   */
  const validateQRCode = async (uid: string): Promise<void> => {
    try {
      console.log("[useScanCode] 调用验证二维码接口, deviceUid:", uid);
      await RoutingInspectionApi.assertScanQR({ deviceUid: uid });
      console.log("[useScanCode] 验证接口调用完成");
    } catch (error: any) {
      console.error("[useScanCode] 验证接口调用异常:", error);
      // 即使异常也不影响后续流程
    }
  };
 
  /**
   * 处理扫码事件
   */
  const handleScanEvent = async (params: any) => {
    console.log(`========== [useScanCode][${currentEventName}] 收到扫码事件 ==========`);
    console.log(`[useScanCode][${currentEventName}] 接收参数:`, params);
    console.log(`[useScanCode][${currentEventName}] 触发时间:`, new Date().toLocaleTimeString());
 
    try {
      if (!params?.code) {
        console.warn("[useScanCode] 扫码内容为空");
        return;
      }
 
      let codeObj: ScanCodeData = {};
      try {
        codeObj = JSON.parse(params.code);
        console.log("[useScanCode] 解析后的对象:", codeObj);
      } catch (err) {
        console.error("[useScanCode] JSON 解析失败:", err);
        console.log("[useScanCode] 原始字符串:", params.code);
        // 如果不是 JSON,尝试作为普通字符串处理
        codeObj = { code: params.code };
      }
 
      // 检查是否有必要的字段(uid 或 deviceModel)
      if (!codeObj.uid && !codeObj.deviceModel) {
        console.warn("[useScanCode] 扫码数据缺少 uid 和 deviceModel,不保存缓存");
        uni.showToast({
          title: "扫码数据无效",
          icon: "none",
        });
        return;
      }
 
      // 更新本地状态
      scanData.value = codeObj;
      deviceUid.value = codeObj.uid || "";
      deviceModel.value = codeObj.deviceModel || "";
 
      // 保存到缓存
      saveToCache(codeObj);
 
      // 如果有 uid,调用验证接口(不等待结果)
      if (codeObj.uid) {
        validateQRCode(codeObj.uid);
      }
 
      // 显示成功提示
      uni.showToast({
        title: "扫码成功",
        icon: "success",
      });
 
      console.log("[useScanCode] 扫码数据已更新:", {
        uid: deviceUid.value,
        deviceModel: deviceModel.value,
      });
    } catch (error) {
      console.error("[useScanCode] 处理扫码数据异常:", error);
    }
  };
 
  /**
   * 启用扫码监听(全局,每次都重新注册以确保有效)
   */
  const enableListener = () => {
    // 先移除可能存在的旧监听器
    uni.$off(currentEventName, handleScanEvent);
    // 添加新的监听器
    uni.$on(currentEventName, handleScanEvent);
    // 标记为全局已启用
    globalListeners.set(currentEventName, true);
    console.log(
      `[useScanCode][${currentEventName}] ✅ 全局监听器已启用/刷新(不会随页面切换关闭)`
    );
  };
 
  /**
   * 禁用扫码监听(仅用于应用退出时清理,正常页面切换不调用)
   */
  const disableListener = () => {
    if (!globalListeners.get(currentEventName)) {
      console.log(`[useScanCode][${currentEventName}] 监听器未启用,跳过`);
      return;
    }
 
    uni.$off(currentEventName, handleScanEvent);
    globalListeners.delete(currentEventName);
    console.log(`[useScanCode][${currentEventName}] ❌ 全局监听器已禁用`);
  };
 
  /**
   * 设置页面生命周期钩子(全局监听器模式)
   * 监听器全局启用一次,不随页面切换关闭
   * @param options 配置选项
   */
  const setupLifecycle = (
    options: {
      loadCacheOnShow?: boolean; // 是否在 onShow 时加载缓存
    } = {}
  ) => {
    const { loadCacheOnShow = true } = options;
 
    // 只在 onShow 时加载缓存,不禁用监听器
    if (loadCacheOnShow) {
      onShow(() => {
        console.log(`[useScanCode][${currentEventName}] onShow 触发`);
        loadFromCache();
      });
    }
 
    // 注意:不再在 onHide 和 onUnmounted 中禁用监听器
    // 监听器保持全局激活状态
  };
 
  // 页面加载时自动从缓存读取
  loadFromCache();
 
  return {
    // 状态
    deviceUid,
    deviceModel,
    scanData,
    // 计算属性
    hasScanned: computed(() => !!deviceUid.value),
    displayText: computed(() => deviceModel.value || "未扫码"),
    // 方法
    loadFromCache,
    saveToCache,
    clearScanData,
    validateQRCode,
    enableListener,
    disableListener,
    setupLifecycle,
  };
}