云
4 小时以前 2c3df98c784bd825b6c2faab508e20fe4f2c3966
feat(mes): 添加追溯定位页面URL配置功能

- 在MesProperties中增加traceLocationUrl属性用于配置定位追溯页完整公网URL
- 在应用配置文件application-local.yaml和application-thzy.yaml中添加trace-location-url配置项
- 在MesProTracePublicConfigRespVO响应对象中增加traceLocationUrl字段
- 修改MesProTracePublicServiceImpl实现类将traceLocationUrl传递给前端
- 更新trace.html页面实现动态加载配置并在追溯链接中使用定位URL
- 调整页面初始化逻辑确保配置加载完成后再执行查询操作
- 更新文档说明追溯网址定位授权入口的URL配置方式
已修改7个文件
34 ■■■■■ 文件已修改
docs/trace-location-gate.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/pub/trace/vo/MesProTracePublicConfigRespVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/config/MesProperties.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/application-local.yaml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/application-thzy.yaml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/static/trace.html 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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>