| | |
| | | (function () { |
| | | 'use strict'; |
| | | |
| | | // ========== 页面可配置项 ========== |
| | | // 生产经营者(追溯查询区块展示) |
| | | var COMPANY_NAME = '新疆塔里木河种业股份有限公司'; |
| | | // 追溯网址(外网访问地址,与包装/二维码上印制的一致) |
| | | var TRACE_URL = 'http://1.95.78.124:9008/'; |
| | | // ========== 页面配置 ========== |
| | | // 生产经营者名称与追溯网址是种子标签四要素的组成部分,必须与二维码/标签印刷内容一致, |
| | | // 因此统一由后端下发(/public/mes/trace/config),禁止在此硬编码。 |
| | | var COMPANY_NAME = ''; |
| | | var TRACE_URL = ''; |
| | | var IS_IMPORTED = false; |
| | | |
| | | // 拉取溯源页配置;失败时不阻断查询(查询结果本身也带生产经营者与追溯网址) |
| | | function loadTraceConfig() { |
| | | return fetch('/public/mes/trace/config') |
| | | .then(function (resp) { return resp.json(); }) |
| | | .then(function (res) { |
| | | if (res && res.code === 0 && res.data) { |
| | | COMPANY_NAME = res.data.operatorName || ''; |
| | | TRACE_URL = res.data.traceUrl || ''; |
| | | IS_IMPORTED = !!res.data.imported; |
| | | } |
| | | }) |
| | | .catch(function () { /* 配置拉取失败:退回使用查询结果中的同名字段 */ }); |
| | | } |
| | | |
| | | var STATE = document.getElementById('state'); |
| | | var CODE_INPUT = document.getElementById('codeInput'); |
| | |
| | | renderState('<div class="empty-tip error">未查询到该追溯码,请核对二维码或联系官方</div>'); |
| | | return; |
| | | } |
| | | // 已作废的追溯码(破损替换后作废)不得作为有效产品流通,直接给出警示并停止展示溯源详情 |
| | | if (d.codeStatus === 'CANCELED') { |
| | | renderState('<div class="empty-tip error">该追溯码已作废,非本公司有效产品,谨防假冒。<br>' |
| | | + '如有疑问请联系官方核实。</div>'); |
| | | return; |
| | | } |
| | | var html = ''; |
| | | html += sec('防伪查询', null, fakePanel(d), null); |
| | | html += sec('追溯查询', null, tracePanel(d), null); |
| | | // 生产明细折叠区(批次/质检/人员/托盘/袋码/采购来源/种子流向/加工流转)按需求不展示, |
| | | // detailSections 保留以便后续按需开启 |
| | | // 生产明细折叠区:国标要求追溯网址可查询「种子加工批次」及「物流销售信息」,故对外展示 |
| | | // (加工批次、种子流向、加工流转;折叠不展开)。质检/人员/托盘/袋码/采购来源等内部明细不对外展示, |
| | | // 如需一并展示,改为 detailSections(d, true) 即可。 |
| | | html += detailSections(d, false); |
| | | STATE.innerHTML = html || '<div class="empty-tip">暂无追溯数据</div>'; |
| | | window.scrollTo({ top: 0, behavior: 'smooth' }); |
| | | } |
| | |
| | | } |
| | | |
| | | // 区块2:追溯查询(未录入批次时只展示品种信息 + 提示) |
| | | // 四要素(品种名称 → 生产经营者 → 单元识别代码 → 追溯网址)按国标顺序排列,其余信息排在其后 |
| | | function tracePanel(d) { |
| | | var code = resolveCode(d); |
| | | var name = [d.itemName, d.itemSpecification].filter(Boolean).join(' '); |
| | | // 生产经营者与追溯网址优先取查询结果(与标签印刷内容同源),退回页面配置 |
| | | var operatorName = d.operatorName || COMPANY_NAME; |
| | | var traceUrl = d.traceUrl || TRACE_URL; |
| | | var operatorLabel = IS_IMPORTED ? '进口商名称' : '生产经营者'; |
| | | // 只有袋码才是「最小销售单元」,其码值才称「单元识别代码」; |
| | | // 托盘码/批次码不属于最小销售单元标识,按实际类型展示,避免误导消费者 |
| | | var codeLabel = d.sourceType === 'BAG' |
| | | ? '单元识别代码' |
| | | : (SOURCE_TYPE[d.sourceType] ? SOURCE_TYPE[d.sourceType] + '(非最小销售单元)' : '追溯码'); |
| | | var unbound = d.batchBound === false; |
| | | var batchRows = unbound |
| | | ? '<div class="notice">该追溯码尚未录入生产批次,批次号、生产日期、产线等信息待完善;当前展示该码对应的品种信息。</div>' |
| | |
| | | kv('生产日期', fmtDate(d.produceDate)) + |
| | | kv('产线', text(d.lineName || d.lineCode)); |
| | | return kv('品种名称', text(name)) + |
| | | kv(operatorLabel, text(operatorName)) + |
| | | kv(codeLabel, text(code || '-')) + |
| | | kv('追溯网址', traceUrl |
| | | ? '<a class="link" href="' + esc(traceUrl) + '">' + esc(traceUrl) + '</a>' |
| | | : '-') + |
| | | kv('计量单位', text(d.itemUnitMeasureName)) + |
| | | kv('生产经营者', esc(COMPANY_NAME)) + |
| | | kv('单元识别代码', text(code || '-')) + |
| | | kv('追溯网址', '<a class="link" href="' + esc(TRACE_URL) + '">' + esc(TRACE_URL) + '</a>') + |
| | | kv('追溯类型', esc(SOURCE_TYPE[d.sourceType] || '追溯码')) + |
| | | batchRows; |
| | | } |
| | | |
| | | // 区块3~:生产明细(折叠,有数据才展示) |
| | | function detailSections(d) { |
| | | // full=true 时展示全部明细(质检/人员/托盘/袋码/采购来源); |
| | | // 默认只展示国标要求的「加工批次」与「物流销售(种子流向)」信息,其余区块不对外展示。 |
| | | function detailSections(d, full) { |
| | | var html = ''; |
| | | |
| | | // 生产批次信息 |
| | | var batchBody = |
| | | kv('批次状态', d.batchStatusName ? statusBadge({ v: [d.batchStatusName, 'blue'] }, 'v') : text(d.batchStatus)) + |
| | | kv('计划数量', fmtNum(d.planQuantity)) + |
| | | kv('已生成袋码', fmtNum(d.bagQuantity)) + |
| | | kv('已生成托盘', fmtNum(d.palletQuantity)) + |
| | | kv('入库时间', fmtDate(d.inboundTime)) + |
| | | kv('临时批次码', text(d.tempCode)) + |
| | | kv('备注', text(d.remark)); |
| | | html += sec('生产批次信息', null, batchBody, { collapsible: true, open: false }); |
| | | // 生产批次信息(国标要求:追溯网址应可查询种子加工批次) |
| | | // 未录入批次时不展示空区块,避免给出"无加工批次信息"的错误暗示 |
| | | if (d.batchBound !== false) { |
| | | var batchBody = |
| | | kv('批次号', text(d.batchCode)) + |
| | | kv('批次状态', d.batchStatusName ? statusBadge({ v: [d.batchStatusName, 'blue'] }, 'v') : text(d.batchStatus)) + |
| | | kv('生产日期', fmtDate(d.produceDate)) + |
| | | kv('产线', text(d.lineName || d.lineCode)) + |
| | | kv('计划数量', fmtNum(d.planQuantity)) + |
| | | kv('已生成袋码', fmtNum(d.bagQuantity)) + |
| | | kv('已生成托盘', fmtNum(d.palletQuantity)) + |
| | | kv('入库时间', fmtDate(d.inboundTime)) + |
| | | kv('备注', text(d.remark)); |
| | | html += sec('生产批次信息', null, batchBody, { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // 质检信息 |
| | | if (d.quality) { |
| | | // 质检信息(仅完整模式展示) |
| | | if (full && d.quality) { |
| | | var q = d.quality; |
| | | var qBody = |
| | | kv('质检结论', q.resultName ? '<span class="badge ' + (q.result === 1 ? 'green' : 'red') + '">' + esc(q.resultName) + '</span>' : '-') + |
| | |
| | | html += sec('质检信息', null, qBody, { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // 生产人员 |
| | | if (!isEmptyList(d.workers)) { |
| | | // 生产人员(仅完整模式展示:涉及个人信息,不对外公开) |
| | | if (full && !isEmptyList(d.workers)) { |
| | | var wBody = d.workers.map(function (w) { |
| | | return li('<span class="li-ttl">' + text(w.userName) + '</span>' + |
| | | (w.workerTypeName ? '<span class="badge gray">' + esc(w.workerTypeName) + '</span>' : ''), |
| | |
| | | html += sec('生产人员', d.workers.length + ' 人', '<div class="scroll-list">' + wBody + '</div>', { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // 托盘信息 |
| | | if (!isEmptyList(d.pallets)) { |
| | | // 托盘信息(仅完整模式展示) |
| | | if (full && !isEmptyList(d.pallets)) { |
| | | var pRows = d.pallets.map(function (p) { |
| | | return [text(p.code), fmtNum(p.palletNo), fmtNum(p.bagCount), fmtNum(p.capacity)]; |
| | | }); |
| | |
| | | { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // 袋码列表 |
| | | if (!isEmptyList(d.bags)) { |
| | | // 袋码列表(仅完整模式展示) |
| | | if (full && !isEmptyList(d.bags)) { |
| | | var bBody = d.bags.map(function (b) { |
| | | return li('<span class="li-ttl">' + text(b.code) + '</span>' + |
| | | (b.statusName ? '<span class="badge gray">' + esc(b.statusName) + '</span>' : ''), |
| | |
| | | html += sec('袋码列表', bagCountText, '<div class="scroll-list">' + bBody + '</div>', { collapsible: true, open: false }); |
| | | } |
| | | |
| | | // 采购来源 |
| | | if (!isEmptyList(d.purchaseSources)) { |
| | | // 采购来源(仅完整模式展示) |
| | | if (full && !isEmptyList(d.purchaseSources)) { |
| | | var psRows = d.purchaseSources.map(function (s) { |
| | | return [text(s.receiptCode), text(s.vendorName), nw(fmtNum(s.receivedQuantity)), nw(fmtDay(s.receiptDate))]; |
| | | }); |
| | |
| | | }); |
| | | })(); |
| | | |
| | | // 先拉取页面配置(生产经营者名称、追溯网址),再执行查询;查询结果中同样带有这两项,互为兜底 |
| | | loadTraceConfig(); |
| | | |
| | | var initialCode = new URLSearchParams(location.search).get('code') || ''; |
| | | CODE_INPUT.value = initialCode; |
| | | if (initialCode) { |