Răsfoiți Sursa

fix: 新账号组织树读取失败可诊断——shopTree 带出服务端真实原因/登录态标记,诊断自动重试并抓原始返回与目标页 URL,报错给出重启指引

KenZ1117 2 săptămâni în urmă
părinte
comite
70e78d0a9a
3 a modificat fișierele cu 29 adăugiri și 4 ștergeri
  1. 26 4
      napos-service.js
  2. 2 0
      napos/kit.js
  3. 1 0
      public/reports.js

+ 26 - 4
napos-service.js

@@ -228,13 +228,32 @@ async function runNaposDiagnose({ date, shopId } = {}) {
   const report = { generatedAt: new Date().toISOString(), port: DEFAULT_CDP_PORT };
   try {
     const st = await kit.status(DEFAULT_CDP_PORT);
-    report.status = { portOk: !!st.portOk, browser: st.browser || null, targets: (st.targets || []).length };
+    report.status = { portOk: !!st.portOk, browser: st.browser || null, targets: (st.targets || []).length, targetUrls: (st.targets || []).slice(0, 6) };
     if (!st.portOk) {
       report.conclusion = '客户端不在线:请完全退出商家客户端,用「启动.bat」附带调试端口的方式重启并登录后再诊断。';
       return report;
     }
 
-    const tree = await kit.shopTree({ port: DEFAULT_CDP_PORT });
+    // 组织树:失败自动重试一次(热切换账号后内部页面常需几秒恢复),并把原始返回带回报告
+    let tree = await kit.shopTree({ port: DEFAULT_CDP_PORT });
+    if (!tree.ok || !tree.merchant) {
+      await new Promise((res) => setTimeout(res, 1500));
+      tree = await kit.shopTree({ port: DEFAULT_CDP_PORT });
+    }
+    report.treeDiag = {
+      ok: !!tree.ok && !!tree.merchant,
+      code: tree.code ?? null,
+      msg: tree.msg || null,
+      authFail: !!tree.authFail,
+      risk: !!tree.risk,
+      rawHead: (() => { try { return JSON.stringify(tree.raw).slice(0, 600); } catch { return null; } })(),
+    };
+    if (!tree.ok || !tree.merchant) {
+      report.conclusion = '客户端端口在线但读不到门店组织树:多半是刚切换/新登录账号后内部页面状态未刷新。'
+        + '请在客户端里打开一次「门店管理」页面,仍不行就完全退出客户端、以调试端口重启并重新登录,再重跑本诊断。'
+        + (report.treeDiag.code || report.treeDiag.msg ? `(服务端返回:${[report.treeDiag.code, report.treeDiag.msg].filter(Boolean).join(' ')})` : '');
+      return report;
+    }
     report.merchant = tree.merchant || null;
     report.chains = (tree.chains || []).map((c) => ({ chainId: String(c.chainId), chainName: c.chainName }));
     const shops = (tree.shops || []).map((s) => ({
@@ -357,8 +376,11 @@ async function fetchTree({ refresh = false } = {}) {
     return treeCache.tree;
   }
   const tree = await kit.shopTree({ port: DEFAULT_CDP_PORT });
-  if (!tree.ok) {
-    const err = new Error('读取门店组织树失败:' + (tree.code || tree.status || '未知错误'));
+  if (!tree.ok || !tree.merchant) {
+    // 新账号/热切换账号后内部页面登录态常失效:把服务端真实原因带出来,别只说「未知错误」
+    const reason = [tree.code, tree.msg, tree.authFail ? '登录态失效' : null]
+      .filter(Boolean).join(' ') || `HTTP ${tree.status || '?'}`;
+    const err = new Error(`读取门店组织树失败:${reason}。若刚切换过账号,请完全退出客户端后以调试端口重启并重新登录,再重试`);
     err.code = 'NAPOS_TREE_FAIL';
     throw err;
   }

+ 2 - 0
napos/kit.js

@@ -236,6 +236,8 @@ async function shopTree(o = {}) {
   walk(root, null);
   return {
     ok: r.ok, code: (r.data && r.data.code) || r.status,
+    msg: (r.data && (r.data.msg || r.data.message)) || undefined,
+    authFail: !!r.authFail, risk: !!r.risk,
     merchant: root ? { id: root.id, name: root.name, nodeType: root.nodeType } : null,
     chains, shops, raw: r.data,
   };

+ 1 - 0
public/reports.js

@@ -1605,6 +1605,7 @@
     $('diagnoseSummary').innerHTML = `
       <div class="diagnose-block">
         ${diagnoseRow('客户端', r.status && r.status.portOk ? `已连接(${esc(r.status.browser || '')})` : '不在线')}
+        ${r.treeDiag ? diagnoseRow('组织树', r.treeDiag.ok ? '读取正常' : `读取失败${r.treeDiag.code || r.treeDiag.msg ? `:${esc([r.treeDiag.code, r.treeDiag.msg].filter(Boolean).join(' '))}` : ''}`) : ''}
         ${diagnoseRow('主体', `${esc((r.merchant && r.merchant.name) || '?')}(${r.shopCount ?? 0} 家门店 · 测试日期 ${esc(r.testDate || '–')})`)}
         ${diagnoseRow('门店状态', esc(busyText))}
         ${diagnoseRow('暂停营业/下架', paused.length ? paused.map((s) => esc(s.shopName)).join('、') : '无')}