| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Fresh Mint · 购买证关联运输计划 · 校验与比对 Demo</title>
- <link rel="preconnect" href="https://fonts.googleapis.com" />
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
- <style>
- :root {
- --primary: #10b981;
- --primary-dark: #059669;
- --primary-bg: #ecfdf5;
- --text: #1e293b;
- --text-muted: #64748b;
- --border: #d9e8e2;
- --surface: #ffffff;
- --bg-page: #f1f5f9;
- --shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
- --shadow-lg: 0 12px 40px rgba(15, 23, 42, 0.14);
- --radius: 10px;
- --warn: #d97706;
- --warn-bg: #fffbeb;
- --warn-border: #fde68a;
- --danger: #dc2626;
- --danger-bg: #fef2f2;
- --danger-border: #fecaca;
- --ok: #059669;
- --ok-bg: #ecfdf5;
- --ok-border: #a7f3d0;
- }
- * { box-sizing: border-box; }
- body {
- margin: 0;
- min-height: 100vh;
- font-family: Inter, -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
- font-size: 14px;
- line-height: 1.5;
- color: var(--text);
- background: var(--bg-page);
- }
- .demo-page { max-width: 1100px; margin: 0 auto; padding: 28px 24px 80px; }
- .demo-head { margin-bottom: 18px; }
- .demo-head h1 { margin: 0 0 8px; font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
- .demo-head h1 span { color: var(--primary); }
- .demo-head p { margin: 0; color: var(--text-muted); max-width: 920px; }
- .meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
- .pill {
- display: inline-flex; align-items: center; gap: 6px;
- padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 500;
- background: var(--primary-bg); color: var(--primary-dark); border: 1px solid #a7f3d0;
- }
- .pill.muted { background: #f1f5f9; color: var(--text-muted); border-color: #e2e8f0; }
- .pill.warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-border); }
- .pill.danger { background: var(--danger-bg); color: var(--danger); border-color: var(--danger-border); }
- .brief {
- display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px;
- }
- @media (max-width: 900px) { .brief { grid-template-columns: 1fr; } }
- .card {
- background: var(--surface); border: 1px solid var(--border);
- border-radius: var(--radius); padding: 14px 16px; box-shadow: var(--shadow);
- }
- .card h2 {
- margin: 0 0 8px; font-size: 14px; font-weight: 600;
- padding-left: 10px; border-left: 3px solid var(--primary);
- color: var(--primary-dark);
- }
- .card.danger-card h2 { border-left-color: var(--danger); color: var(--danger); }
- .card.warn-card h2 { border-left-color: var(--warn); color: var(--warn); }
- .card ul { margin: 0; padding-left: 18px; color: var(--text-muted); font-size: 13px; }
- .card li { margin: 4px 0; }
- .card li strong { color: var(--text); }
- .formula {
- margin-top: 8px; padding: 8px 10px; border-radius: 8px;
- background: var(--primary-bg); color: var(--primary-dark);
- font-size: 12px; font-weight: 500;
- }
- .formula.warn { background: var(--warn-bg); color: #92400e; }
- .formula.danger { background: var(--danger-bg); color: #991b1b; }
- .scenario-tabs {
- display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap;
- }
- .scenario-tab {
- appearance: none; border: 1px solid var(--border); background: #fff;
- height: 36px; padding: 0 14px; border-radius: 8px; cursor: pointer;
- font-size: 13px; font-weight: 500; color: var(--text);
- }
- .scenario-tab:hover { border-color: #a7f3d0; color: var(--primary-dark); }
- .scenario-tab.active {
- background: var(--primary-bg); border-color: #a7f3d0; color: var(--primary-dark);
- }
- /* Dialog shell */
- .stage {
- background: rgba(15, 23, 42, 0.35);
- border-radius: 14px;
- padding: 28px 20px 36px;
- min-height: 640px;
- display: flex;
- align-items: flex-start;
- justify-content: center;
- }
- .dialog {
- width: min(920px, 100%);
- background: var(--surface);
- border-radius: 12px;
- box-shadow: var(--shadow-lg);
- overflow: hidden;
- display: flex;
- flex-direction: column;
- max-height: calc(100vh - 120px);
- }
- .dialog-hd {
- display: flex; align-items: center; justify-content: space-between;
- padding: 16px 20px; border-bottom: 1px solid var(--border);
- }
- .dialog-hd h3 { margin: 0; font-size: 16px; font-weight: 600; }
- .dialog-hd .x {
- width: 28px; height: 28px; border: none; background: transparent;
- color: var(--text-muted); font-size: 18px; cursor: pointer; border-radius: 6px;
- }
- .dialog-hd .x:hover { background: #f1f5f9; }
- .dialog-bd {
- padding: 16px 20px;
- overflow-y: auto;
- flex: 1;
- }
- .dialog-ft {
- display: flex; justify-content: flex-end; gap: 10px;
- padding: 12px 20px; border-top: 1px solid var(--border);
- background: #fafafa;
- }
- .btn {
- display: inline-flex; align-items: center; gap: 6px;
- height: 36px; padding: 0 14px; border-radius: 8px;
- font-size: 14px; font-weight: 500; cursor: pointer;
- border: 1px solid var(--border); background: #fff; color: var(--text);
- }
- .btn:hover { border-color: #a7f3d0; }
- .btn:disabled { opacity: 0.45; cursor: not-allowed; }
- .btn-primary {
- background: var(--primary); border-color: var(--primary); color: #fff;
- }
- .btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
- .btn-primary:disabled { background: #94a3b8; border-color: #94a3b8; }
- .field-label {
- display: block; font-size: 11px; color: var(--text-muted);
- margin-bottom: 6px; font-weight: 500;
- }
- .select-like {
- height: 36px; border: 1px solid var(--border); border-radius: 8px;
- padding: 0 12px; display: flex; align-items: center; justify-content: space-between;
- background: #fff; color: var(--text); font-size: 14px;
- }
- .select-like .chev { color: var(--text-muted); font-size: 12px; }
- .plan-meta {
- margin: 12px 0 14px; padding: 10px 12px; border-radius: 8px;
- background: #f8fafc; border: 1px solid #e2e8f0;
- font-size: 13px; color: var(--text-muted);
- }
- .plan-meta strong { color: var(--text); }
- .link-row {
- border: 1px solid var(--border);
- border-radius: 10px;
- padding: 12px 14px;
- margin-bottom: 12px;
- background: #fff;
- }
- .link-row-title {
- display: flex; align-items: center; justify-content: space-between;
- gap: 10px; margin-bottom: 10px; flex-wrap: wrap;
- }
- .link-row-title .name { font-weight: 600; }
- .tag {
- display: inline-flex; align-items: center;
- height: 22px; padding: 0 8px; border-radius: 4px;
- font-size: 12px; font-weight: 500;
- background: transparent; color: var(--text); border: 1px solid #e2e8f0;
- }
- .tag.ok { background: var(--ok); color: #fff; border-color: var(--ok); }
- .tag.warn { background: var(--warn); color: #fff; border-color: var(--warn); }
- .tag.danger { background: var(--danger); color: #fff; border-color: var(--danger); }
- .link-row-fields {
- display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
- }
- @media (max-width: 700px) { .link-row-fields { grid-template-columns: 1fr; } }
- /* Hard gate / soft compare panels */
- .gate-panel {
- margin-top: 12px;
- border-radius: 10px;
- border: 1px solid var(--border);
- overflow: hidden;
- }
- .gate-panel.ok { border-color: var(--ok-border); }
- .gate-panel.warn { border-color: var(--warn-border); }
- .gate-panel.danger { border-color: var(--danger-border); }
- .gate-hd {
- display: flex; align-items: center; justify-content: space-between;
- padding: 10px 12px; font-weight: 600; font-size: 13px;
- }
- .gate-panel.ok .gate-hd { background: var(--ok-bg); color: var(--ok); }
- .gate-panel.warn .gate-hd { background: var(--warn-bg); color: var(--warn); }
- .gate-panel.danger .gate-hd { background: var(--danger-bg); color: var(--danger); }
- .gate-bd { padding: 0; }
- .gate-row {
- display: grid;
- grid-template-columns: 110px 1fr 1fr 88px;
- gap: 8px;
- padding: 10px 12px;
- border-top: 1px solid #f1f5f9;
- font-size: 13px;
- align-items: start;
- }
- .gate-row.header {
- background: #f8fafc;
- color: var(--text-muted);
- font-size: 11px;
- font-weight: 600;
- text-transform: none;
- border-top: none;
- }
- @media (max-width: 700px) {
- .gate-row { grid-template-columns: 1fr; gap: 4px; }
- .gate-row.header { display: none; }
- }
- .gate-row .col-label { color: var(--text-muted); font-size: 12px; }
- .gate-row .col-plan, .gate-row .col-cert { word-break: break-all; }
- .gate-row.mismatch .col-plan,
- .gate-row.mismatch .col-cert { color: var(--warn); font-weight: 500; }
- .gate-row.block .col-plan,
- .gate-row.block .col-cert { color: var(--danger); font-weight: 500; }
- .gate-row.match .result { color: var(--ok); }
- .gate-row.mismatch .result { color: var(--warn); }
- .gate-row.block .result { color: var(--danger); }
- .qty-breakdown {
- margin: 10px 12px 12px;
- padding: 10px 12px;
- border-radius: 8px;
- background: #f8fafc;
- border: 1px solid #e2e8f0;
- font-size: 12px;
- color: var(--text-muted);
- }
- .qty-breakdown .line {
- display: flex; justify-content: space-between; gap: 12px; margin: 3px 0;
- }
- .qty-breakdown .line.total {
- margin-top: 8px; padding-top: 8px; border-top: 1px dashed #cbd5e1;
- font-weight: 600; color: var(--text); font-size: 13px;
- }
- .qty-breakdown .line.over { color: var(--danger); }
- .qty-breakdown .num { font-variant-numeric: tabular-nums; color: var(--text); font-weight: 500; }
- .toast {
- position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
- background: #1e293b; color: #fff; padding: 10px 16px; border-radius: 8px;
- font-size: 13px; box-shadow: var(--shadow-lg); opacity: 0; pointer-events: none;
- transition: opacity 0.2s;
- z-index: 50;
- }
- .toast.show { opacity: 1; }
- .note {
- margin-top: 16px; font-size: 12px; color: var(--text-muted);
- }
- </style>
- </head>
- <body>
- <div class="demo-page">
- <header class="demo-head">
- <h1>购买证关联运输计划 · <span>校验与比对</span> Demo</h1>
- <p>
- 关联「已安排待确认」计划时:有效期与数量为硬拦截;销售单位 / 购买单位 / 购买物品与计划字段比对后展示差异,
- 由用户确认或取消。切换下方场景查看不同结果态。
- </p>
- <div class="meta">
- <span class="pill">Fresh Mint</span>
- <span class="pill muted">关联弹窗</span>
- <span class="pill warn">软比对 · 可确认</span>
- <span class="pill danger">硬门禁 · 不可确认</span>
- </div>
- </header>
- <div class="brief">
- <div class="card danger-card">
- <h2>硬门禁(不通过则禁用「确定」)</h2>
- <ul>
- <li><strong>有效期</strong>:本次计划送货/装货日期须落在购买证有效期内</li>
- <li><strong>数量</strong>:已归档实际量 + 已确认未归档计划量 + 本次计划量 ≤ 购买证数量</li>
- </ul>
- <div class="formula danger">
- 占用合计 = Σ归档实际量 + Σ已安排已确认未归档计划量 + 本次计划量 ≤ 证面数量
- </div>
- </div>
- <div class="card warn-card">
- <h2>软比对(展示差异,点确定 / 取消)</h2>
- <ul>
- <li><strong>销售单位</strong> ↔ 计划装货客户(示意)</li>
- <li><strong>购买单位或个人</strong> ↔ 计划送货客户(示意)</li>
- <li><strong>购买物品</strong> ↔ 计划产品品名</li>
- </ul>
- <div class="formula warn">
- 有出入时仍可点「确定」完成关联(Demo 映射待业务确认)
- </div>
- </div>
- </div>
- <div class="scenario-tabs" role="tablist">
- <button type="button" class="scenario-tab active" data-scene="ok">场景 A · 全部通过</button>
- <button type="button" class="scenario-tab" data-scene="soft">场景 B · 单位/品名有出入</button>
- <button type="button" class="scenario-tab" data-scene="qty">场景 C · 数量超限</button>
- <button type="button" class="scenario-tab" data-scene="date">场景 D · 超出有效期</button>
- </div>
- <div class="stage">
- <div class="dialog" id="dialog">
- <div class="dialog-hd">
- <h3>关联待确认计划</h3>
- <button type="button" class="x" aria-label="关闭">×</button>
- </div>
- <div class="dialog-bd">
- <label class="field-label">待确认计划</label>
- <div class="select-like">
- <span id="planLabel">YS-20261009-018 · 陕A·D8821</span>
- <span class="chev">▾</span>
- </div>
- <div class="plan-meta" id="planMeta">
- 车牌 <strong>陕A·D8821</strong>;送货日期 <strong>2026-10-12</strong>;
- 每行易制毒产品须绑定 1 张购买证 + 1 张运输证。
- </div>
- <div class="link-row">
- <div class="link-row-title">
- <span class="name" id="prodName">丙酮</span>
- <span class="tag" id="prodQtyTag">计划量 32 吨</span>
- </div>
- <div class="link-row-fields">
- <div>
- <label class="field-label">购买证</label>
- <div class="select-like" id="purchaseSelect">
- <span>购备〔2026〕0831 · 丙酮 · 余 118</span>
- <span class="chev">▾</span>
- </div>
- </div>
- <div>
- <label class="field-label">运输证</label>
- <div class="select-like" id="transportSelect">
- <span>运备〔2026〕2104 · 车陕A·D8821 · 余 40</span>
- <span class="chev">▾</span>
- </div>
- </div>
- </div>
- <!-- 硬门禁 -->
- <div class="gate-panel" id="hardGate">
- <div class="gate-hd">
- <span id="hardGateTitle">硬门禁校验</span>
- <span class="tag" id="hardGateTag">通过</span>
- </div>
- <div class="gate-bd">
- <div class="gate-row header">
- <div>校验项</div>
- <div>计划侧</div>
- <div>购买证侧</div>
- <div>结果</div>
- </div>
- <div class="gate-row" id="rowDate">
- <div class="col-label">有效期限</div>
- <div class="col-plan" id="datePlan">送货日 2026-10-12</div>
- <div class="col-cert" id="dateCert">2026-09-01 ~ 2026-12-31</div>
- <div class="result" id="dateResult">通过</div>
- </div>
- <div class="gate-row" id="rowQty">
- <div class="col-label">数量占用</div>
- <div class="col-plan" id="qtyPlan">本次 32 吨</div>
- <div class="col-cert" id="qtyCert">证面 170 吨</div>
- <div class="result" id="qtyResult">通过</div>
- </div>
- <div class="qty-breakdown" id="qtyBreakdown"></div>
- </div>
- </div>
- <!-- 软比对 -->
- <div class="gate-panel" id="softGate">
- <div class="gate-hd">
- <span id="softGateTitle">单位 / 品名比对</span>
- <span class="tag" id="softGateTag">一致</span>
- </div>
- <div class="gate-bd">
- <div class="gate-row header">
- <div>比对项</div>
- <div>计划侧</div>
- <div>购买证侧</div>
- <div>结果</div>
- </div>
- <div class="gate-row" id="rowSeller">
- <div class="col-label">销售单位</div>
- <div class="col-plan" id="sellerPlan">—</div>
- <div class="col-cert" id="sellerCert">—</div>
- <div class="result" id="sellerResult">—</div>
- </div>
- <div class="gate-row" id="rowBuyer">
- <div class="col-label">购买单位</div>
- <div class="col-plan" id="buyerPlan">—</div>
- <div class="col-cert" id="buyerCert">—</div>
- <div class="result" id="buyerResult">—</div>
- </div>
- <div class="gate-row" id="rowProduct">
- <div class="col-label">购买物品</div>
- <div class="col-plan" id="productPlan">—</div>
- <div class="col-cert" id="productCert">—</div>
- <div class="result" id="productResult">—</div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="dialog-ft">
- <button type="button" class="btn" id="btnCancel">取消</button>
- <button type="button" class="btn btn-primary" id="btnOk">确定</button>
- </div>
- </div>
- </div>
- <p class="note">
- Demo 说明:装货客户 ↔ 销售单位、送货客户 ↔ 购买单位为示意映射,落地前需业务确认。
- 文件路径:<code>docs/fresh-mint-pl-purchase-cert-link-compare-demo.html</code>
- </p>
- </div>
- <div class="toast" id="toast"></div>
- <script>
- const SCENES = {
- ok: {
- label: '全部通过',
- planNo: 'YS-20261009-018 · 陕A·D8821',
- deliveryDate: '2026-10-12',
- product: '丙酮',
- planQty: 32,
- purchaseLabel: '购备〔2026〕0831 · 丙酮 · 余 118',
- transportLabel: '运备〔2026〕2104 · 车陕A·D8821 · 余 40',
- validFrom: '2026-09-01',
- validTo: '2026-12-31',
- certTotal: 170,
- archivedActual: 20,
- occupiedPlan: 32,
- loadCustomer: '陕西某某化工有限公司',
- deliveryCustomer: '西安某某制药有限公司',
- sellerName: '陕西某某化工有限公司',
- buyerName: '西安某某制药有限公司',
- certProduct: '丙酮',
- },
- soft: {
- label: '单位/品名有出入',
- planNo: 'YS-20261009-022 · 陕A·D8821',
- deliveryDate: '2026-10-12',
- product: '丙酮(工业级)',
- planQty: 28,
- purchaseLabel: '购备〔2026〕0831 · 丙酮 · 余 118',
- transportLabel: '运备〔2026〕2104 · 车陕A·D8821 · 余 40',
- validFrom: '2026-09-01',
- validTo: '2026-12-31',
- certTotal: 170,
- archivedActual: 20,
- occupiedPlan: 32,
- loadCustomer: '陕西某某化工(销售)有限公司',
- deliveryCustomer: '西安某某制药股份有限公司',
- sellerName: '陕西某某化工有限公司',
- buyerName: '西安某某制药有限公司',
- certProduct: '丙酮',
- },
- qty: {
- label: '数量超限',
- planNo: 'YS-20261009-031 · 陕B·F1908',
- deliveryDate: '2026-10-15',
- product: '丙酮',
- planQty: 90,
- purchaseLabel: '购备〔2026〕0831 · 丙酮 · 余 118',
- transportLabel: '运备〔2026〕2110 · 车陕B·F1908 · 余 100',
- validFrom: '2026-09-01',
- validTo: '2026-12-31',
- certTotal: 170,
- archivedActual: 52,
- occupiedPlan: 40,
- loadCustomer: '陕西某某化工有限公司',
- deliveryCustomer: '西安某某制药有限公司',
- sellerName: '陕西某某化工有限公司',
- buyerName: '西安某某制药有限公司',
- certProduct: '丙酮',
- },
- date: {
- label: '超出有效期',
- planNo: 'YS-20261009-040 · 陕A·D8821',
- deliveryDate: '2027-01-05',
- product: '丙酮',
- planQty: 20,
- purchaseLabel: '购备〔2026〕0831 · 丙酮 · 余 118',
- transportLabel: '运备〔2026〕2104 · 车陕A·D8821 · 余 40',
- validFrom: '2026-09-01',
- validTo: '2026-12-31',
- certTotal: 170,
- archivedActual: 20,
- occupiedPlan: 32,
- loadCustomer: '陕西某某化工有限公司',
- deliveryCustomer: '西安某某制药有限公司',
- sellerName: '陕西某某化工有限公司',
- buyerName: '西安某某制药有限公司',
- certProduct: '丙酮',
- },
- };
- function norm(s) {
- return String(s || '')
- .replace(/\s+/g, '')
- .replace(/(/g, '(')
- .replace(/)/g, ')')
- .toLowerCase();
- }
- function softMatch(a, b) {
- const na = norm(a);
- const nb = norm(b);
- if (!na || !nb) return false;
- if (na === nb) return true;
- return na.includes(nb) || nb.includes(na);
- }
- function setRow(el, state) {
- el.classList.remove('match', 'mismatch', 'block');
- if (state) el.classList.add(state);
- }
- function setGate(panel, tag, level, title) {
- panel.classList.remove('ok', 'warn', 'danger');
- panel.classList.add(level);
- tag.className = 'tag ' + (level === 'ok' ? 'ok' : level === 'warn' ? 'warn' : 'danger');
- tag.textContent = title;
- }
- function render(sceneKey) {
- const s = SCENES[sceneKey];
- const used = s.archivedActual + s.occupiedPlan + s.planQty;
- const remainAfter = s.certTotal - used;
- const dateOk = s.deliveryDate >= s.validFrom && s.deliveryDate <= s.validTo;
- const qtyOk = used <= s.certTotal + 1e-9;
- const hardOk = dateOk && qtyOk;
- const sellerOk = softMatch(s.loadCustomer, s.sellerName);
- const buyerOk = softMatch(s.deliveryCustomer, s.buyerName);
- const productOk = softMatch(s.product, s.certProduct);
- const softOk = sellerOk && buyerOk && productOk;
- document.getElementById('planLabel').textContent = s.planNo;
- document.getElementById('planMeta').innerHTML =
- '车牌 <strong>' + s.planNo.split('·').slice(1).join('·').trim() + '</strong>;送货日期 <strong>' +
- s.deliveryDate + '</strong>;每行易制毒产品须绑定 1 张购买证 + 1 张运输证。';
- document.getElementById('prodName').textContent = s.product;
- document.getElementById('prodQtyTag').textContent = '计划量 ' + s.planQty + ' 吨';
- document.getElementById('purchaseSelect').querySelector('span').textContent = s.purchaseLabel;
- document.getElementById('transportSelect').querySelector('span').textContent = s.transportLabel;
- // hard
- document.getElementById('datePlan').textContent = '送货日 ' + s.deliveryDate;
- document.getElementById('dateCert').textContent = s.validFrom + ' ~ ' + s.validTo;
- document.getElementById('dateResult').textContent = dateOk ? '通过' : '超出有效期';
- setRow(document.getElementById('rowDate'), dateOk ? 'match' : 'block');
- document.getElementById('qtyPlan').textContent = '本次 ' + s.planQty + ' 吨';
- document.getElementById('qtyCert').textContent = '证面 ' + s.certTotal + ' 吨';
- document.getElementById('qtyResult').textContent = qtyOk ? '通过' : '超限';
- setRow(document.getElementById('rowQty'), qtyOk ? 'match' : 'block');
- document.getElementById('qtyBreakdown').innerHTML =
- '<div class="line"><span>已归档实际数量</span><span class="num">' + s.archivedActual + ' 吨</span></div>' +
- '<div class="line"><span>已安排已确认未归档计划量</span><span class="num">' + s.occupiedPlan + ' 吨</span></div>' +
- '<div class="line"><span>本次计划数量</span><span class="num">' + s.planQty + ' 吨</span></div>' +
- '<div class="line total' + (qtyOk ? '' : ' over') + '"><span>合计占用 / 证面</span><span class="num">' +
- used + ' / ' + s.certTotal + ' 吨' + (qtyOk ? '(剩余 ' + remainAfter + ')' : '(超 ' + Math.abs(remainAfter) + ')') +
- '</span></div>';
- setGate(
- document.getElementById('hardGate'),
- document.getElementById('hardGateTag'),
- hardOk ? 'ok' : 'danger',
- hardOk ? '通过' : '拦截'
- );
- document.getElementById('hardGateTitle').textContent = hardOk ? '硬门禁校验 · 通过' : '硬门禁校验 · 不可确认';
- // soft
- function fillSoft(rowId, planId, certId, resultId, planVal, certVal, ok) {
- document.getElementById(planId).textContent = planVal;
- document.getElementById(certId).textContent = certVal;
- document.getElementById(resultId).textContent = ok ? '一致' : '有出入';
- setRow(document.getElementById(rowId), ok ? 'match' : 'mismatch');
- }
- fillSoft('rowSeller', 'sellerPlan', 'sellerCert', 'sellerResult', s.loadCustomer, s.sellerName, sellerOk);
- fillSoft('rowBuyer', 'buyerPlan', 'buyerCert', 'buyerResult', s.deliveryCustomer, s.buyerName, buyerOk);
- fillSoft('rowProduct', 'productPlan', 'productCert', 'productResult', s.product, s.certProduct, productOk);
- setGate(
- document.getElementById('softGate'),
- document.getElementById('softGateTag'),
- softOk ? 'ok' : 'warn',
- softOk ? '一致' : '有出入'
- );
- document.getElementById('softGateTitle').textContent = softOk
- ? '单位 / 品名比对 · 一致'
- : '单位 / 品名比对 · 请确认后继续';
- const btnOk = document.getElementById('btnOk');
- btnOk.disabled = !hardOk;
- btnOk.textContent = hardOk
- ? (softOk ? '确定' : '确认仍要关联')
- : '确定(已拦截)';
- btnOk.dataset.softWarn = softOk ? '0' : '1';
- btnOk.dataset.hardOk = hardOk ? '1' : '0';
- }
- function toast(msg) {
- const el = document.getElementById('toast');
- el.textContent = msg;
- el.classList.add('show');
- clearTimeout(toast._t);
- toast._t = setTimeout(() => el.classList.remove('show'), 2200);
- }
- document.querySelectorAll('.scenario-tab').forEach((btn) => {
- btn.addEventListener('click', () => {
- document.querySelectorAll('.scenario-tab').forEach((b) => b.classList.remove('active'));
- btn.classList.add('active');
- render(btn.dataset.scene);
- });
- });
- document.getElementById('btnCancel').addEventListener('click', () => {
- toast('已取消,未保存关联');
- });
- document.getElementById('btnOk').addEventListener('click', (e) => {
- const btn = e.currentTarget;
- if (btn.disabled) return;
- if (btn.dataset.softWarn === '1') {
- toast('已确认差异并保存关联(Demo)');
- } else {
- toast('关联已保存(Demo)');
- }
- });
- render('ok');
- </script>
- </body>
- </html>
|