From 2c3df98c784bd825b6c2faab508e20fe4f2c3966 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 16 十月 2026 19:32:34 +0800
Subject: [PATCH] feat(mes): 添加追溯定位页面URL配置功能

---
 yudao-server/src/main/resources/static/trace.html |  132 +++++++++++++++++++++++++++++--------------
 1 files changed, 88 insertions(+), 44 deletions(-)

diff --git a/yudao-server/src/main/resources/static/trace.html b/yudao-server/src/main/resources/static/trace.html
index 7579fb3..d89fb73 100644
--- a/yudao-server/src/main/resources/static/trace.html
+++ b/yudao-server/src/main/resources/static/trace.html
@@ -352,6 +352,7 @@
   // 鍥犳缁熶竴鐢卞悗绔笅鍙戯紙/public/mes/trace/config锛夛紝绂佹鍦ㄦ纭紪鐮併��
   var COMPANY_NAME = '';
   var TRACE_URL = '';
+  var TRACE_LOCATION_URL = '';
   var IS_IMPORTED = false;
 
   // 鎷夊彇婧簮椤甸厤缃紱澶辫触鏃朵笉闃绘柇鏌ヨ锛堟煡璇㈢粨鏋滄湰韬篃甯︾敓浜х粡钀ヨ�呬笌杩芥函缃戝潃锛�
@@ -362,6 +363,7 @@
         if (res && res.code === 0 && res.data) {
           COMPANY_NAME = res.data.operatorName || '';
           TRACE_URL = res.data.traceUrl || '';
+          TRACE_LOCATION_URL = res.data.traceLocationUrl || '';
           IS_IMPORTED = !!res.data.imported;
         }
       })
@@ -372,14 +374,6 @@
   var CODE_INPUT = document.getElementById('codeInput');
   var SEARCH_BTN = document.getElementById('searchBtn');
 
-  var FLOW_DIRECTION = { 1: ['鍏ュ簱', 'green'], 2: ['鍑哄簱', 'blue'] };
-  var FLOW_BIZ_TYPE = {
-    110: '閲囪喘鍏ュ簱', 111: '閲囪喘鍏ュ簱鍙栨秷', 112: '璋冩嫧鍑哄簱', 113: '璋冩嫧鍏ュ簱',
-    114: '鍏朵粬鍑哄簱', 115: '鍏朵粬鍏ュ簱', 116: '鐢熶骇棰嗘枡', 117: '鐢熶骇閫�鏂�',
-    118: '鐢熶骇鍏ュ簱', 119: '閿�鍞嚭搴�', 120: '閿�鍞��璐у叆搴�', 121: '澶栧崗鍙戞枡',
-    122: '澶栧崗鍏ュ簱', 123: '鐢熶骇娑堣��', 124: '浜у搧浜у嚭', 125: '渚涘簲鍟嗛��璐у嚭搴�',
-    126: '搴撳瓨璋冩暣鍏ュ簱', 127: '搴撳瓨璋冩暣鍑哄簱'
-  };
   var SOURCE_TYPE = { BAG: '琚嬬爜', PALLET: '鎵樼洏鐮�', BATCH: '鎵规鐮�' };
 
   // ========== 宸ュ叿鍑芥暟 ==========
@@ -411,12 +405,6 @@
   // 琛ㄦ牸绐勫垪锛堟暟閲� / 鏃ユ湡锛変笉鎹㈣锛岄伩鍏嶆暟瀛楄鎷嗚
   function nw(html) {
     return '<span style="white-space:nowrap">' + html + '</span>';
-  }
-
-  function statusBadge(map, key) {
-    var item = map[key];
-    if (!item) return '<span class="badge gray">' + (key === null || key === undefined ? '' : esc(key)) + '</span>';
-    return '<span class="badge ' + item[1] + '">' + esc(item[0]) + '</span>';
   }
 
   function kv(k, v, dim) {
@@ -499,14 +487,89 @@
       return;
     }
     var html = '';
+    if (new URLSearchParams(location.search).get('view') === 'location') {
+      html += locationSections(d);
+      html += sec('浜у搧杩芥函鏍囪瘑', null, tracePanel(d), null);
+      STATE.innerHTML = html;
+      window.scrollTo({ top: 0, behavior: 'smooth' });
+      return;
+    }
     html += sec('闃蹭吉鏌ヨ', null, fakePanel(d), null);
     html += sec('杩芥函鏌ヨ', null, tracePanel(d), null);
-    // 鐢熶骇鏄庣粏鎶樺彔鍖猴細瀵瑰灞曠ず绉嶅瓙娴佸悜銆佸姞宸ユ祦杞紝鐢熶骇鎵规淇℃伅涓嶅睍绀恒��
+    // 鐢熶骇鏄庣粏鎶樺彔鍖猴細瀵瑰灞曠ず鍔犲伐娴佽浆锛岀敓浜ф壒娆′俊鎭笉灞曠ず銆�
     // 璐ㄦ/浜哄憳/鎵樼洏/琚嬬爜/閲囪喘鏉ユ簮绛夊唴閮ㄦ槑缁嗕笉瀵瑰灞曠ず锛�
     // 濡傞渶涓�骞跺睍绀猴紝鏀逛负 detailSections(d, true) 鍗冲彲銆�
     html += detailSections(d, false);
     STATE.innerHTML = html || '<div class="empty-tip">鏆傛棤杩芥函鏁版嵁</div>';
     window.scrollTo({ top: 0, behavior: 'smooth' });
+  }
+
+  // 瀹氫綅鎺堟潈鍏ュ彛娌跨敤鏈〉鐨勫搧鐗岃儗鏅笌鍖哄潡鏍峰紡锛屾寜鐢熶骇銆佷粨鍌ㄣ�佺墿娴佺粍缁囧凡鏈夌湡瀹炴暟鎹��
+  function groupOutboundOrders(rows, codeOf, dateField) {
+    var grouped = [];
+    var byCode = new Map();
+    rows.forEach(function (item) {
+      var code = String(codeOf(item) || '').trim();
+      var quantity = Number(item.quantity);
+      var validQuantity = item.quantity !== null && item.quantity !== undefined && Number.isFinite(quantity);
+      var existing = code ? byCode.get(code) : null;
+      if (!existing) {
+        var order = Object.assign({}, item, { quantity: validQuantity ? Math.abs(quantity) : null });
+        grouped.push(order);
+        if (code) byCode.set(code, order);
+      } else {
+        if (validQuantity) existing.quantity = (existing.quantity || 0) + Math.abs(quantity);
+        if (!existing.contactName && item.contactName) existing.contactName = item.contactName;
+        if (item[dateField] && (!existing[dateField] || item[dateField] > existing[dateField])) {
+          existing[dateField] = item[dateField];
+        }
+      }
+    });
+    return grouped;
+  }
+
+  function locationSections(d) {
+    var production = kv('浜у搧鍚嶇О', text(d.itemName)) +
+      kv('瑙勬牸', text(d.itemSpecification || d.itemUnitMeasureName)) +
+      kv('鍔犲伐鎵规', text(d.batchCode || d.tempCode));
+    if (d.produceDate) production = kv('鐢熶骇鏃ユ湡', fmtDay(d.produceDate)) + production;
+    var html = sec('鐢熶骇淇℃伅', null, production, null);
+
+    var salesFlows = groupOutboundOrders((d.seedFlows || []).filter(function (item) { return item.bizType === 119; }),
+      function (item) { return item.bizCode; }, 'transactionTime');
+    var salesTargets = groupOutboundOrders(d.salesTargets || [],
+      function (item) { return item.salesCode || item.salesOrderCode; }, 'salesDate');
+    var flow = (d.seedFlows || []).find(function (item) { return item.warehouseName; });
+    var storage = '';
+    if (d.inboundTime) storage += kv('鍏ュ簱鏃ユ湡', fmtDay(d.inboundTime));
+    var outboundDates = salesFlows.map(function (item) { return item.transactionTime; })
+      .concat(salesTargets.map(function (item) { return item.salesDate; })).filter(Boolean).sort();
+    if (outboundDates.length) storage += kv('鏈�杩戝嚭搴撴棩鏈�', fmtDay(outboundDates[outboundDates.length - 1]));
+    if (flow) storage += kv('浠撳簱', text(flow.warehouseName));
+    html += sec('浠撳偍淇℃伅', null, storage || '<div class="empty-tip">鏆傛棤浠撳偍淇℃伅</div>', null);
+
+    var logistics = salesFlows.map(function (item) {
+      var route = [item.warehouseName, item.clientName].filter(Boolean).join(' 鈫� ');
+      var description = '璇ユ壒娆�' + (item.transactionTime ? '浜� ' + String(item.transactionTime).slice(0, 10) + ' ' : '') +
+        (item.warehouseName ? '浠�' + item.warehouseName + '鍑哄簱' : '瀹屾垚閿�鍞嚭搴�') +
+        (item.clientName ? '锛屽彂寰�' + item.clientName : '') + '銆�';
+      return li('<span class="li-ttl">' + text(route || '閿�鍞嚭搴�') + '</span>', fmtDay(item.transactionTime),
+        kv('鍑哄簱鍗曞彿', text(item.bizCode)) + kv('鏁伴噺', fmtNum(item.quantity)) +
+        kv('娴佽浆璇存槑', text(description)) +
+        (item.contactName ? kv('鑱旂郴浜�', text(item.contactName)) : ''));
+    }).join('');
+    if (!logistics && !isEmptyList(salesTargets)) {
+      logistics = salesTargets.map(function (item) {
+        var description = '璇ユ壒娆�' + (item.salesDate ? '浜� ' + String(item.salesDate).slice(0, 10) + ' ' : '') +
+          '瀹屾垚閿�鍞嚭搴�' + (item.clientName ? '锛屽幓鍚�' + item.clientName : '') + '銆�';
+        return li('<span class="li-ttl">' + text(item.clientName || '閿�鍞幓鍚�') + '</span>', fmtDay(item.salesDate),
+          kv('鍑哄簱鍗曞彿', text(item.salesCode || item.salesOrderCode)) + kv('鏁伴噺', fmtNum(item.quantity)) +
+          kv('娴佽浆璇存槑', text(description)) +
+          (item.contactName ? kv('鑱旂郴浜�', text(item.contactName)) : ''));
+      }).join('');
+    }
+    html += sec('鐗╂祦淇℃伅', null, logistics || '<div class="empty-tip">鏆傛棤鐗╂祦淇℃伅</div>', null);
+    return html;
   }
 
   function stripUrl(v) {
@@ -567,6 +630,8 @@
     // 鐢熶骇缁忚惀鑰呬笌杩芥函缃戝潃浼樺厛鍙栨煡璇㈢粨鏋滐紙涓庢爣绛惧嵃鍒峰唴瀹瑰悓婧愶級锛岄��鍥為〉闈㈤厤缃�
     var operatorName = d.operatorName || COMPANY_NAME;
     var traceUrl = d.traceUrl || TRACE_URL;
+    var locationUrl = new URL(TRACE_LOCATION_URL || location.pathname.replace(/trace\.html$/, 'trace-location.html'), location.href);
+    locationUrl.searchParams.set('code', code || '');
     var operatorLabel = IS_IMPORTED ? '杩涘彛鍟嗗悕绉�' : '鐢熶骇缁忚惀鑰�';
     // 鍙湁琚嬬爜鎵嶆槸銆屾渶灏忛攢鍞崟鍏冦�嶏紝鍏剁爜鍊兼墠绉般�屽崟鍏冭瘑鍒唬鐮併�嶏紱
     // 鎵樼洏鐮�/鎵规鐮佷笉灞炰簬鏈�灏忛攢鍞崟鍏冩爣璇嗭紝鎸夊疄闄呯被鍨嬪睍绀猴紝閬垮厤璇娑堣垂鑰�
@@ -583,7 +648,7 @@
       kv(operatorLabel, text(operatorName)) +
       kv(codeLabel, text(code || '-')) +
       kv('杩芥函缃戝潃', traceUrl
-        ? '<a class="link" href="' + esc(traceUrl) + '">' + esc(traceUrl) + '</a>'
+        ? '<a class="link" target="_top" href="' + esc(locationUrl.href) + '">' + esc(traceUrl) + '</a>'
         : '-') +
       kv('璁¢噺鍗曚綅', text(d.itemUnitMeasureName)) +
       kv('杩芥函绫诲瀷', esc(SOURCE_TYPE[d.sourceType] || '杩芥函鐮�')) +
@@ -664,27 +729,6 @@
       html += sec('閲囪喘鏉ユ簮', null, table(['閲囪喘鍏ュ簱鍗�', '渚涘簲鍟�', '鏁伴噺', '鏃ユ湡'], psRows), { collapsible: true, open: false });
     }
 
-    // 绉嶅瓙娴佸悜淇℃伅锛堜粎閿�鍞嚭搴� bizType=119锛�
-    var salesFlows = (d.seedFlows || []).filter(function (f) { return f.bizType === 119; });
-    if (!isEmptyList(salesFlows)) {
-      var sfBody = salesFlows.map(function (f) {
-        var qty = (f.quantity === null || f.quantity === undefined) ? '-' : fmtNum(Math.abs(Number(f.quantity)));
-        var wh = [f.warehouseName, f.locationName].filter(Boolean).join(' / ') || '-';
-        return li(statusBadge(FLOW_DIRECTION, f.type) + '<span class="li-ttl">' + esc(FLOW_BIZ_TYPE[f.bizType] || '') + '</span>',
-          fmtDate(f.transactionTime),
-          kv('鏉ユ簮鍗曞彿', text(f.bizCode)) +
-          kv('瀹㈡埛', text(f.clientName)) +
-          kv('鏁伴噺', qty) +
-          kv('浠撳簱/搴撳尯', text(wh)));
-      }).join('');
-      html += sec('绉嶅瓙娴佸悜淇℃伅', null, '<div class="scroll-list">' + sfBody + '</div>', { collapsible: true, open: false });
-    } else if (!isEmptyList(d.salesTargets)) {
-      var stRows = d.salesTargets.map(function (s) {
-        return [text(s.salesCode || s.salesOrderCode || ''), text(s.clientName), nw(fmtNum(s.quantity)), nw(fmtDay(s.salesDate))];
-      });
-      html += sec('绉嶅瓙娴佸悜淇℃伅', null, table(['閿�鍞嚭搴撳崟', '瀹㈡埛', '鏁伴噺', '鏃ユ湡'], stRows), { collapsible: true, open: false });
-    }
-
     // 鍔犲伐娴佽浆
     if (!isEmptyList(d.processTraces)) {
       var ptBody = d.processTraces.map(function (t) {
@@ -724,15 +768,15 @@
   })();
 
   // 鍏堟媺鍙栭〉闈㈤厤缃紙鐢熶骇缁忚惀鑰呭悕绉般�佽拷婧綉鍧�锛夛紝鍐嶆墽琛屾煡璇紱鏌ヨ缁撴灉涓悓鏍峰甫鏈夎繖涓ら」锛屼簰涓哄厹搴�
-  loadTraceConfig();
-
   var initialCode = new URLSearchParams(location.search).get('code') || '';
   CODE_INPUT.value = initialCode;
-  if (initialCode) {
-    query(initialCode);
-  } else {
-    renderState('<div class="empty-tip">鎵爜鎴栬緭鍏ヨ拷婧爜锛屽嵆鍙煡璇骇鍝佸叏绋嬫函婧愪俊鎭�</div>');
-  }
+  loadTraceConfig().then(function () {
+    if (initialCode) {
+      query(initialCode);
+    } else {
+      renderState('<div class="empty-tip">鎵爜鎴栬緭鍏ヨ拷婧爜锛屽嵆鍙煡璇骇鍝佸叏绋嬫函婧愪俊鎭�</div>');
+    }
+  });
 })();
 </script>
 </body>

--
Gitblit v1.9.3