docs/trace-location-gate.md
@@ -1,6 +1,6 @@ # 追溯网址定位授权入口 旧追溯页的“追溯网址”文字仍显示标签印刷所用的 `mes.trace-base-url`,点击后进入同目录的 `trace-location.html?code=...`。授权页以原追溯页的品牌页面为背景。用户主动点击“开启定位并继续”,只有浏览器返回当前位置、且服务端成功保存记录后才在新网址中显示产品追溯内容。定位视图沿用原有背景和版式,把已有真实数据按“生产信息、仓储信息、物流信息”组织;没有来源数据的字段不臆造。直接打开不带追溯码的新网址也可以授权后进入手动查询。拒绝授权、定位失败或保存失败会停留在授权页并给出重试提示。刷新新网址需重新获取位置。 旧追溯页的“追溯网址”文字仍显示标签印刷所用的 `mes.trace-base-url`,点击后进入 `mes.trace-location-url` 配置的完整公网地址,并附带 `code` 参数;未配置时从当前页生成同目录的绝对网址。授权页以原追溯页的品牌页面为背景。用户主动点击“开启定位并继续”,只有浏览器返回当前位置、且服务端成功保存记录后才在新网址中显示产品追溯内容。定位视图沿用原有背景和版式,把已有真实数据按“生产信息、仓储信息、物流信息”组织;没有来源数据的字段不臆造。直接打开不带追溯码的新网址也可以授权后进入手动查询。拒绝授权、定位失败或保存失败会停留在授权页并给出重试提示。刷新新网址需重新获取位置。 后台“消费者扫码统计”新增“定位授权访问”区块,沿用 `mes:trace-consumer-scan:query` 权限,可按时间和追溯码查询,显示访问次数、坐标、精度、时间,并可打开地图;热门位置将经纬度分别保留两位小数后聚合(最多 20 处)。记录与原有按 IP 推断省市的扫码事件分开存储,避免影响原统计口径。 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicConfigRespVO.java
@@ -21,6 +21,10 @@ example = "http://1.95.78.124:9008/prod/trace.html") private String traceUrl; @Schema(description = "定位追溯页完整网址(不含 code 参数)", example = "http://1.95.78.124:9008/prod/trace-location.html") private String traceLocationUrl; @Schema(description = "是否进口种子场景:为 true 时页面标签应展示「进口商名称」") private Boolean imported; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/config/MesProperties.java
@@ -24,6 +24,9 @@ */ private String traceBaseUrl = ""; /** 定位追溯页的完整公网 URL(不含 code 参数),供 H5 页面链接跳转使用。 */ private String traceLocationUrl = ""; /** 定位版追溯页是否必须先取得用户定位;仅本地调试配置为 false。 */ private boolean traceLocationRequired = true; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -135,6 +135,7 @@ MesProTracePublicConfigRespVO respVO = new MesProTracePublicConfigRespVO(); respVO.setOperatorName(MesProQrLabelBuilder.resolveOperatorName()); respVO.setTraceUrl(MesProQrLabelBuilder.resolveTraceUrl()); respVO.setTraceLocationUrl(mesProperties.getTraceLocationUrl()); respVO.setImported(MesProQrLabelBuilder.isImported()); respVO.setTraceLocationRequired(mesProperties.isTraceLocationRequired()); return respVO; yudao-server/src/main/resources/application-local.yaml
@@ -5,6 +5,8 @@ mes: # 追溯网址(二维码内容前缀),需为公众扫码可访问的地址 trace-base-url: http://192.168.0.10:48080/trace.html # 点击追溯网址后进入的定位追溯页(完整本地地址,不含 code 参数) trace-location-url: http://192.168.0.10:48080/trace-location.html # 本地 HTTP 调试时跳过浏览器定位授权;生产环境使用默认值 true trace-location-required: false # 生产经营者名称(种子标签四要素之一,标签与溯源页统一取此值;未配置则无法导出标签) yudao-server/src/main/resources/application-thzy.yaml
@@ -5,6 +5,8 @@ mes: # 追溯网址(二维码内容前缀),需为公众扫码可访问的地址 trace-base-url: http://1.95.78.124:9008/prod/trace.html # 点击追溯网址后进入的定位追溯页(完整公网地址,不含 code 参数) trace-location-url: http://1.95.78.124:9008/prod/trace-location.html # 生产经营者名称(种子标签四要素之一,标签与溯源页统一取此值) operator-name: 新疆塔里木河种业股份有限公司 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; } }) @@ -628,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 ? '进口商名称' : '生产经营者'; // 只有袋码才是「最小销售单元」,其码值才称「单元识别代码」; // 托盘码/批次码不属于最小销售单元标识,按实际类型展示,避免误导消费者 @@ -644,7 +648,7 @@ kv(operatorLabel, text(operatorName)) + kv(codeLabel, text(code || '-')) + kv('追溯网址', traceUrl ? '<a class="link" target="_top" href="' + esc(location.pathname.replace(/trace\.html$/, 'trace-location.html') + '?code=' + encodeURIComponent(code || '')) + '">' + 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] || '追溯码')) + @@ -764,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>