Archived
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>数据工单 · PN 主数据创建(类型驱动 Demo) · SS02 ACT-WORK-05 差异评估</title>
|
||||
<style>
|
||||
:root{
|
||||
--ink:#1f2329; --ink-2:#41464e; --ink-3:#646a73; --ink-4:#8f959e;
|
||||
--line:#dee0e3; --line-soft:#e8eaed; --soft:#f8f9fb;
|
||||
--brand:#3370ff; --brand-deep:#245bdb;
|
||||
--data:#3370ff; --data-deep:#245bdb; --data-soft:#e1eaff; --data-line:#c3d6ff; --data-wash:#f0f4ff;
|
||||
--ok:#278717; --ok-soft:#e8f8e4; --danger:#d83931; --danger-soft:#feeae9;
|
||||
--amber:#8f6a12; --amber-soft:#fdf3d7; --amber-line:#ecd9a0;
|
||||
--mono:"SF Mono",Menlo,Consolas,monospace;
|
||||
/* 8px 间距节奏(dense) */
|
||||
--s1:8px; --s2:16px; --s3:24px; --s4:32px;
|
||||
--r-sm:8px; --r-md:12px;
|
||||
--tr:.22s cubic-bezier(.2,.7,.3,1);
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body{margin:0;padding:0}
|
||||
body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:#fff;color:var(--ink);font-size:14px;line-height:1.7;-webkit-font-smoothing:antialiased}
|
||||
.page{margin:0;padding:0}
|
||||
.card{background:#fff;overflow:hidden;border:0;border-radius:0;box-shadow:none}
|
||||
|
||||
/* ===== 卡头 ===== */
|
||||
.card-head{display:flex;align-items:center;gap:14px;padding:20px 24px;border-bottom:1px solid var(--line-soft);background:linear-gradient(120deg,#f0f4ff 0%,#fff 55%,#eef3ff 100%)}
|
||||
.badge{flex:none;width:44px;height:44px;border-radius:11px;display:grid;place-items:center;background:var(--data);color:#fff;font-weight:800;font-size:13px;box-shadow:0 6px 16px rgba(51,112,255,.28)}
|
||||
.tit{flex:1;min-width:0}
|
||||
.tit .kick{font-size:11px;letter-spacing:.08em;color:var(--ink-4);font-weight:700}
|
||||
.tit h1{margin:2px 0 0;font-size:20px;font-weight:800;line-height:1.3;letter-spacing:-.01em}
|
||||
.tit .sub{font-size:12px;color:var(--ink-3);margin-top:3px}
|
||||
.side{display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex:none}
|
||||
.tag{font-size:11px;font-weight:800;padding:2px 10px;border-radius:999px;color:var(--data-deep);background:var(--data-soft);border:1px solid var(--data-line)}
|
||||
.step{font-size:12px;color:var(--ink-3)}
|
||||
.deadline{font-size:12px;color:var(--ink-3)}
|
||||
.deadline b{color:var(--danger)}
|
||||
.card-bd{padding:var(--s3) 24px var(--s4)}
|
||||
|
||||
/* ===== 区标 / 说明带 ===== */
|
||||
.zone{font-size:11px;font-weight:800;letter-spacing:.12em;color:var(--ink-4);margin:0 0 var(--s1)}
|
||||
.zone b{color:var(--ink-3)}
|
||||
.note{border:1px solid var(--line);border-left:3px solid var(--data);border-radius:var(--r-sm);background:var(--soft);padding:14px 16px;margin-bottom:var(--s2)}
|
||||
.note p{margin:0;font-size:13px;color:var(--ink-2)}
|
||||
.note p+p{margin-top:6px}
|
||||
.note b{color:var(--ink)}
|
||||
.note .need{color:var(--data-deep);font-weight:700}
|
||||
.mono{font-family:var(--mono);font-size:12px;color:var(--ink-2)}
|
||||
.st{display:inline-block;font-size:11px;font-weight:700;padding:1px 8px;border-radius:999px;border:1px solid transparent;white-space:nowrap}
|
||||
.st.ok{color:var(--ok);background:var(--ok-soft);border-color:#c9ecc2}
|
||||
.st.new{color:var(--data-deep);background:var(--data-soft);border-color:var(--data-line)}
|
||||
.st.lock{color:var(--ink-3);background:#eef1f6;border-color:var(--line)}
|
||||
|
||||
/* ===== 编辑闸 + 必填进度 ===== */
|
||||
.jc-editgate{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 var(--s2);padding:10px 14px;border-radius:10px;background:var(--soft);border:1px solid var(--line-soft);font-size:12px;color:var(--ink-3);transition:background var(--tr),border-color var(--tr)}
|
||||
.jc-editgate-t{flex:1 1 auto;min-width:0}
|
||||
.jc-editgate-t b{color:var(--ink-2);font-weight:700}
|
||||
.gateprog{flex:1 1 100%;display:flex;align-items:center;gap:10px;margin-top:6px}
|
||||
.gateprog .track{flex:1;height:5px;border-radius:3px;background:var(--line-soft);overflow:hidden}
|
||||
.gateprog .fill{display:block;height:100%;width:0;border-radius:3px;background:linear-gradient(90deg,var(--data),var(--data-deep));transition:width .35s cubic-bezier(.2,.7,.3,1)}
|
||||
.gateprog .pct{font-family:var(--mono);font-size:11px;color:var(--ink-4);min-width:64px;text-align:right}
|
||||
.jc-egbtn{flex:none;display:inline-flex;align-items:center;gap:5px;cursor:pointer;border:1px solid var(--line);border-radius:8px;padding:7px 14px;font:inherit;font-size:12px;font-weight:700;color:var(--ink-2);background:#fff;transition:border-color var(--tr),color var(--tr),background var(--tr),transform .12s}
|
||||
.jc-egbtn:hover{border-color:var(--data);color:var(--data)}
|
||||
.jc-egbtn:active{transform:scale(.97)}
|
||||
.jc-egbtn.save{color:#fff;background:var(--data);border-color:var(--data)}
|
||||
.jc-egbtn.save:hover{filter:brightness(1.06);color:#fff}
|
||||
.jc-egbtn:focus-visible{outline:2px solid var(--data-deep);outline-offset:2px}
|
||||
.jc-editgate .eg-cancel,.jc-editgate .eg-save{display:none}
|
||||
.jc-editgate.on{background:var(--data-wash);border-color:var(--data-line);color:#1e40af}
|
||||
.jc-editgate.on .eg-open{display:none}
|
||||
.jc-editgate.on .eg-cancel,.jc-editgate.on .eg-save{display:inline-flex}
|
||||
|
||||
/* ===== 渲染态:档案卡 ===== */
|
||||
.idcard{border:1px solid var(--line-soft);border-radius:var(--r-md);margin-bottom:var(--s2);background:linear-gradient(150deg,#fff 60%,var(--data-wash));display:grid;grid-template-columns:1.2fr 1fr;overflow:hidden}
|
||||
.idcard .cell{padding:18px 22px}
|
||||
.idcard .cell+.cell{border-left:1px solid var(--line-soft);background:rgba(255,255,255,.55)}
|
||||
.idcard .lab{font-size:11.5px;font-weight:800;color:var(--ink-3);letter-spacing:.08em;display:flex;align-items:center;gap:6px}
|
||||
.idcard .lab::before{content:"";width:8px;height:8px;border-radius:2.5px;background:var(--data)}
|
||||
.idcard .val{margin-top:8px;font-size:24px;font-weight:800;font-family:var(--mono);letter-spacing:-.01em;line-height:1.25;color:var(--ink)}
|
||||
.idcard .val.empty{font-size:14px;font-family:inherit;font-weight:400;color:var(--ink-4)}
|
||||
.idcard .val .tpill{display:inline-block;font-family:inherit;font-size:15px;font-weight:800;color:var(--data-deep);background:var(--data-soft);border:1px solid var(--data-line);border-radius:999px;padding:4px 14px;vertical-align:2px}
|
||||
.idcard .val .st{margin-left:8px;vertical-align:3px}
|
||||
|
||||
/* ===== 参数表(渲染态) ===== */
|
||||
.tbl-wrap{border:1px solid var(--line-soft);border-radius:10px;overflow:hidden}
|
||||
table{width:100%;border-collapse:collapse;font-size:12.5px}
|
||||
th{text-align:left;background:var(--soft);font-size:11px;letter-spacing:.04em;font-weight:800;color:var(--ink-3);padding:10px 14px;border-bottom:1px solid var(--line)}
|
||||
td{padding:10px 14px;border-bottom:1px solid var(--line-soft);vertical-align:middle}
|
||||
tr:last-child td{border-bottom:0}
|
||||
tbody tr{transition:background .15s}
|
||||
tbody tr:hover{background:var(--data-wash)}
|
||||
.empty-row td{color:var(--ink-4);text-align:center;padding:22px}
|
||||
.empty-row td:hover{background:#fff}
|
||||
|
||||
/* ===== 编辑态:步骤轨道 ===== */
|
||||
.editarea{display:none}
|
||||
body.editing .editarea{display:block}
|
||||
body.editing .viewarea{display:none}
|
||||
.steps{position:relative}
|
||||
.steps::before{content:"";position:absolute;left:12px;top:20px;bottom:20px;width:2px;background:var(--line-soft);border-radius:1px}
|
||||
.stepbox{position:relative;padding-left:36px;margin-bottom:var(--s3)}
|
||||
.stepbox:last-child{margin-bottom:0}
|
||||
.sdot{position:absolute;left:0;top:0;width:26px;height:26px;border-radius:50%;background:#fff;border:2px solid var(--data-line);color:var(--data-deep);font-size:12px;font-weight:800;display:grid;place-items:center;transition:background var(--tr),border-color var(--tr),color var(--tr)}
|
||||
.stepbox.done .sdot{background:var(--data);border-color:var(--data);color:#fff}
|
||||
.scard{border:1px solid var(--line-soft);border-radius:var(--r-md);background:#fff;transition:border-color var(--tr),box-shadow var(--tr)}
|
||||
.stepbox.done .scard{border-color:var(--data-line)}
|
||||
.scard .sh{display:flex;align-items:center;gap:10px;padding:12px 16px;border-bottom:1px solid var(--line-soft);font-size:13.5px;font-weight:800;letter-spacing:-.01em}
|
||||
.scard .sh .req-note{margin-left:auto;font-size:11px;color:var(--ink-4);font-weight:400}
|
||||
.scard .sb{padding:16px}
|
||||
.fld{display:flex;align-items:flex-start;gap:12px;font-size:12.5px}
|
||||
.fld .fk{width:88px;flex:none;color:var(--ink-3);font-weight:700;font-size:12px;padding-top:9px}
|
||||
.fld .fk.req::after{content:" *";color:var(--danger)}
|
||||
.fld .fv{flex:1;min-width:0}
|
||||
.fld input,.fld select{width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 11px;font:inherit;font-size:13px;color:var(--ink);background:#fff;transition:border-color var(--tr),box-shadow var(--tr)}
|
||||
.fld input:focus,.fld select:focus{border-color:var(--data);box-shadow:0 0 0 3px var(--data-wash);outline:none}
|
||||
.hint{font-size:11.5px;color:var(--ink-4);margin-top:6px}
|
||||
|
||||
/* ===== 新增类型面板 ===== */
|
||||
.newtype{display:none;margin-top:12px;border:1px dashed var(--data-line);border-radius:10px;background:var(--data-wash);padding:14px 16px}
|
||||
.newtype.show{display:block;animation:rise .25s cubic-bezier(.2,.7,.3,1)}
|
||||
@keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
|
||||
.newtype h4{margin:0 0 10px;font-size:12.5px;color:var(--data-deep)}
|
||||
.prow{display:flex;gap:8px;align-items:center;margin-top:8px;animation:rise .2s cubic-bezier(.2,.7,.3,1)}
|
||||
.prow input{flex:1;border:1px solid var(--line);border-radius:7px;padding:8px 10px;font:inherit;font-size:12.5px;background:#fff;transition:border-color var(--tr),box-shadow var(--tr)}
|
||||
.prow input:focus{border-color:var(--data);box-shadow:0 0 0 3px rgba(51,112,255,.12);outline:none}
|
||||
.prow .del{flex:none;width:28px;height:28px;cursor:pointer;border:1px solid var(--line);border-radius:7px;background:#fff;color:var(--ink-3);font-size:14px;line-height:1;transition:border-color var(--tr),color var(--tr),background var(--tr)}
|
||||
.prow .del:hover{border-color:var(--danger);color:var(--danger);background:var(--danger-soft)}
|
||||
.nt-actions{display:flex;gap:8px;margin-top:12px;align-items:center}
|
||||
.btn{cursor:pointer;border:1px solid var(--data-line);border-radius:8px;padding:7px 14px;font:inherit;font-size:12px;font-weight:700;color:var(--data-deep);background:#fff;transition:background var(--tr),transform .12s}
|
||||
.btn:hover{background:var(--data-soft)}
|
||||
.btn:active{transform:scale(.97)}
|
||||
.btn.primary{color:#fff;background:var(--data);border-color:var(--data)}
|
||||
.btn.primary:hover{filter:brightness(1.07)}
|
||||
.btn:focus-visible{outline:2px solid var(--data-deep);outline-offset:2px}
|
||||
|
||||
/* ===== 参数值瓷贴 ===== */
|
||||
.pvgrid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
|
||||
.pv{border:1px solid var(--line-soft);border-radius:10px;padding:10px 12px;background:#fff;transition:border-color var(--tr),box-shadow var(--tr)}
|
||||
.pv:focus-within{border-color:var(--data-line);box-shadow:0 0 0 3px rgba(51,112,255,.08)}
|
||||
.pv .pn2{font-size:12px;font-weight:800;color:var(--ink-2);margin-bottom:6px;display:flex;align-items:baseline;gap:6px}
|
||||
.pv .pn2::after{content:"*";color:var(--danger);font-size:11px}
|
||||
.pv input{width:100%;border:1px solid var(--line);border-radius:7px;padding:7px 10px;font:inherit;font-size:12.5px;background:#fff;transition:border-color var(--tr),box-shadow var(--tr)}
|
||||
.pv input:focus{border-color:var(--data);box-shadow:0 0 0 3px rgba(51,112,255,.12);outline:none}
|
||||
.pv-empty{border:1px dashed var(--line);border-radius:10px;padding:20px;text-align:center;color:var(--ink-4);font-size:12px}
|
||||
|
||||
/* ===== 底 ===== */
|
||||
.flow{margin-top:var(--s2);padding:10px 14px;border-radius:var(--r-sm);background:var(--soft);border:1px dashed var(--line);font-size:12px;color:var(--ink-3)}
|
||||
.flow b{color:var(--ink)}
|
||||
.card-foot{padding:14px 24px;border-top:1px solid var(--line-soft);font-size:11.5px;color:var(--ink-4);display:flex;justify-content:space-between;flex-wrap:wrap;gap:8px}
|
||||
@media(max-width:760px){.pvgrid{grid-template-columns:1fr}.card-head{flex-wrap:wrap}.side{align-items:flex-start}.idcard{grid-template-columns:1fr}.idcard .cell+.cell{border-left:0;border-top:1px solid var(--line-soft)}}
|
||||
@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="card">
|
||||
|
||||
<header class="card-head">
|
||||
<div class="badge">数据</div>
|
||||
<div class="tit">
|
||||
<div class="kick">SS02 · ACT-WORK-05 差异评估 · 数据工单 · 类型驱动 Demo</div>
|
||||
<h1>PN 主数据创建</h1>
|
||||
<div class="sub">收件人:<span data-slot="meta.task.owner">FAE · 李工</span> · 关联任务:<span data-slot="meta.task.id">TASK-BT02-20260828-003</span></div>
|
||||
</div>
|
||||
<div class="side">
|
||||
<span class="tag">数据工单</span>
|
||||
<span class="step" data-slot="meta.phase">步骤 2/5 · 读取并标准化资料(读 P-08 查无触发)</span>
|
||||
<span class="deadline">最迟交回:<b data-slot="card.deadline">1 个工作日</b></span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="card-bd">
|
||||
|
||||
<p class="zone"><b>【触发原因】</b>—— 系统查 P-08 芯片主数据无该 PN 记录(完全没有,非字段缺失)</p>
|
||||
<div class="note">
|
||||
<p><b>流程</b>:填 PN 名称 → 选 PN 类型(下拉首行「+新增类型」)→ 按类型自动加载该类型的核心参数名 → 逐项填值。找不到类型就现场新建:填类型名称 + 它的核心参数名,保存后参数名自动加载成输入框。</p>
|
||||
<p><span class="need">AI 预填情况</span>:未提供 datasheet → 本单全手填(合法路径)。<b>纪律</b>:确认即正式入库(无草稿、无审核),确认人 = 数据责任人并留痕;只创建主数据/资料类记录。</p>
|
||||
</div>
|
||||
|
||||
<div class="jc-editgate" id="editgate">
|
||||
<span class="jc-editgate-t"><b>必填未完成</b>:PN 名称、PN 类型、全部核心参数值为必填;点「编辑」进入编辑态</span>
|
||||
<button class="jc-egbtn eg-open" type="button">编辑</button>
|
||||
<button class="jc-egbtn eg-cancel" type="button">取消</button>
|
||||
<button class="jc-egbtn eg-save" type="button">保存</button>
|
||||
<span class="gateprog"><span class="track"><span class="fill" id="gp-fill"></span></span><span class="pct" id="gp-pct">0 / 3 项</span></span>
|
||||
</div>
|
||||
|
||||
<!-- 渲染态 -->
|
||||
<div class="viewarea">
|
||||
<div class="idcard">
|
||||
<div class="cell">
|
||||
<div class="lab">PN 名称</div>
|
||||
<div class="val empty" id="v-pn">(未填写)</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="lab">PN 类型</div>
|
||||
<div class="val empty" id="v-type">(未选择)</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="zone"><b>核心参数</b>(由 PN 类型决定参数名)</p>
|
||||
<div class="tbl-wrap">
|
||||
<table>
|
||||
<thead><tr><th style="width:220px">参数名</th><th>参数值</th></tr></thead>
|
||||
<tbody id="v-params" data-rows="in.PN核心参数">
|
||||
<tr class="empty-row"><td colspan="2">未选择 PN 类型,暂无参数</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑态 -->
|
||||
<div class="editarea">
|
||||
<div class="steps">
|
||||
|
||||
<div class="stepbox" id="sb1">
|
||||
<span class="sdot">1</span>
|
||||
<div class="scard">
|
||||
<div class="sh">PN 名称<span class="req-note">必填 · 内部料号</span></div>
|
||||
<div class="sb">
|
||||
<div class="fld"><span class="fk req">PN 名称</span><div class="fv"><input id="e-pn" data-field="PN名称" placeholder="如 SGM6132-5.0"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stepbox" id="sb2">
|
||||
<span class="sdot">2</span>
|
||||
<div class="scard">
|
||||
<div class="sh">PN 类型<span class="req-note">必填 · 类型决定第 3 步加载哪些核心参数</span></div>
|
||||
<div class="sb">
|
||||
<div class="fld"><span class="fk req">PN 类型</span><div class="fv">
|
||||
<select id="e-type" data-field="PN类型">
|
||||
<option value="__new__">+ 新增类型</option>
|
||||
<option>DCDC 降压稳压器</option>
|
||||
<option>LDO 线性稳压器</option>
|
||||
<option>运算放大器</option>
|
||||
</select>
|
||||
<div class="hint">类型库里没有的类型,选首行「+ 新增类型」现场定义。</div>
|
||||
</div></div>
|
||||
|
||||
<div class="newtype" id="newtype">
|
||||
<h4>新增 PN 类型</h4>
|
||||
<div class="fld"><span class="fk req">类型名称</span><div class="fv"><input id="nt-name" data-field="新类型名称" placeholder="如 负载开关"></div></div>
|
||||
<div class="fld" style="margin-top:10px"><span class="fk req">核心参数名</span><div class="fv">
|
||||
<div id="nt-params"></div>
|
||||
<div class="nt-actions">
|
||||
<button type="button" class="btn" id="nt-addrow">+ 加一行参数名</button>
|
||||
<button type="button" class="btn primary" id="nt-save">保存类型并加载参数</button>
|
||||
</div>
|
||||
<div class="hint">保存后:类型进入下拉库(本单生效),下方自动加载这些参数名的输入框。</div>
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stepbox" id="sb3">
|
||||
<span class="sdot">3</span>
|
||||
<div class="scard">
|
||||
<div class="sh">核心参数值<span class="req-note" id="pv-note">先选类型</span></div>
|
||||
<div class="sb">
|
||||
<div class="pv-empty" id="pv-empty">已在第 2 步选择类型后,这里按类型列出核心参数输入框</div>
|
||||
<div class="pvgrid" id="pv-grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow"><b>审批 / 提交:</b>本工单只承载内容;「确认」请在对话区的【数据卡】中进行。<b>确认后去向:</b>PN 主数据正式入库 P-08(无草稿、无审核),活动从断点续跑;本单不复用。<b>留痕:</b>确认人 / 本单编号 / 所属活动随记录入库。</div>
|
||||
|
||||
</div>
|
||||
|
||||
<footer class="card-foot">
|
||||
<span>SS02 · ACT-WORK-05 差异评估 · 数据工单 · PN 主数据创建(类型驱动 Demo)</span>
|
||||
<span style="font-family:var(--mono)">工单类型:数据 · <span data-slot="card.id">WO-ACT-WORK-05-D02</span></span>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
// ===== 类型库:类型名 → 核心参数名列表 =====
|
||||
var PN_TYPES = {
|
||||
"DCDC 降压稳压器": ["输入电压范围","输出电压","输出电流","开关频率","静态电流","工作温度","使能阈值","反馈网络"],
|
||||
"LDO 线性稳压器": ["输入电压范围","输出电压","输出电流","压差电压","静态电流","工作温度"],
|
||||
"运算放大器": ["供电电压范围","增益带宽积","压摆率","输入失调电压","静态电流","工作温度"]
|
||||
};
|
||||
var BUILTIN = {"DCDC 降压稳压器":1,"LDO 线性稳压器":1,"运算放大器":1};
|
||||
|
||||
var body = document.body;
|
||||
var gate = document.getElementById('editgate');
|
||||
var ePn = document.getElementById('e-pn');
|
||||
var eType = document.getElementById('e-type');
|
||||
var newtype = document.getElementById('newtype');
|
||||
var ntName = document.getElementById('nt-name');
|
||||
var ntParams = document.getElementById('nt-params');
|
||||
var pvGrid = document.getElementById('pv-grid');
|
||||
var pvEmpty = document.getElementById('pv-empty');
|
||||
var pvNote = document.getElementById('pv-note');
|
||||
var gpFill = document.getElementById('gp-fill');
|
||||
var gpPct = document.getElementById('gp-pct');
|
||||
var values = {}; // 参数名 → 值(编辑态暂存,切类型时保留同名值)
|
||||
var snap = null; // 取消用快照
|
||||
|
||||
// ===== 必填完成度 =====
|
||||
function progress(){
|
||||
var total = 2, done = 0; // PN 名称 + PN 类型
|
||||
if(ePn.value.trim()) done++;
|
||||
var names = (eType.value && eType.value !== '__new__') ? PN_TYPES[eType.value] : null;
|
||||
if(names){ done++; total += names.length; names.forEach(function(pn){ if(values[pn] && values[pn].trim()) done++; }); }
|
||||
var pct = total ? Math.round(done/total*100) : 0;
|
||||
gpFill.style.width = pct + '%';
|
||||
gpPct.textContent = done + ' / ' + total + ' 项';
|
||||
document.getElementById('sb1').classList.toggle('done', !!ePn.value.trim());
|
||||
document.getElementById('sb2').classList.toggle('done', !!names);
|
||||
document.getElementById('sb3').classList.toggle('done', !!names && names.every(function(pn){ return values[pn] && values[pn].trim(); }));
|
||||
}
|
||||
|
||||
// ===== 编辑态:参数值区渲染 =====
|
||||
function clearParams(msg, note){
|
||||
pvGrid.innerHTML = '';
|
||||
pvEmpty.textContent = msg;
|
||||
pvEmpty.style.display = 'block';
|
||||
pvNote.textContent = note || '待类型确定';
|
||||
}
|
||||
function renderParams(typeName){
|
||||
pvGrid.innerHTML = '';
|
||||
var names = PN_TYPES[typeName];
|
||||
if(!names){ clearParams('先选类型','先选类型'); progress(); return; }
|
||||
pvEmpty.style.display='none';
|
||||
pvNote.textContent = typeName + ' · ' + names.length + ' 项核心参数';
|
||||
names.forEach(function(pn){
|
||||
var div = document.createElement('div');
|
||||
div.className = 'pv';
|
||||
div.innerHTML = '<div class="pn2"></div><input data-field="参数值" placeholder="填写 ' + pn + '">';
|
||||
div.querySelector('.pn2').textContent = pn;
|
||||
var inp = div.querySelector('input');
|
||||
inp.value = values[pn] || '';
|
||||
inp.addEventListener('input', function(){ values[pn] = inp.value; progress(); });
|
||||
pvGrid.appendChild(div);
|
||||
});
|
||||
progress();
|
||||
}
|
||||
|
||||
// 类型下拉:选中即加载参数;选「+新增类型」展开新建面板并清空参数区(等保存后按新类型重渲染)
|
||||
eType.addEventListener('change', function(){
|
||||
if(eType.value === '__new__'){
|
||||
newtype.classList.add('show'); ntName.focus();
|
||||
clearParams('正在新增类型——保存后这里按新类型的参数名加载输入框');
|
||||
progress();
|
||||
return;
|
||||
}
|
||||
newtype.classList.remove('show');
|
||||
renderParams(eType.value);
|
||||
});
|
||||
ePn.addEventListener('input', progress);
|
||||
|
||||
// 新增类型:参数名行动态增删
|
||||
function addNtRow(v){
|
||||
var row = document.createElement('div');
|
||||
row.className = 'prow';
|
||||
row.innerHTML = '<input data-field="新类型参数名" placeholder="参数名,如 导通电阻"><button type="button" class="del" title="删除">×</button>';
|
||||
row.querySelector('input').value = v || '';
|
||||
row.querySelector('.del').addEventListener('click', function(){ row.remove(); });
|
||||
ntParams.appendChild(row);
|
||||
}
|
||||
document.getElementById('nt-addrow').addEventListener('click', function(){ addNtRow(''); });
|
||||
|
||||
// 保存类型:入库(本单生效)→ 进下拉并选中 → 加载参数名
|
||||
document.getElementById('nt-save').addEventListener('click', function(){
|
||||
var name = ntName.value.trim();
|
||||
var names = Array.prototype.map.call(ntParams.querySelectorAll('input'), function(i){ return i.value.trim(); }).filter(Boolean);
|
||||
if(!name){ ntName.focus(); return; }
|
||||
if(names.length === 0){ addNtRow(''); return; }
|
||||
PN_TYPES[name] = names;
|
||||
var opt = document.createElement('option');
|
||||
opt.textContent = name; opt.value = name;
|
||||
eType.insertBefore(opt, eType.children[1]); // 首行固定为「+新增类型」,新类型插到其后
|
||||
eType.value = name;
|
||||
newtype.classList.remove('show');
|
||||
renderParams(name);
|
||||
});
|
||||
|
||||
// ===== 渲染态回写 =====
|
||||
function paint(){
|
||||
var vPn = document.getElementById('v-pn');
|
||||
var vType = document.getElementById('v-type');
|
||||
vPn.textContent = ePn.value.trim() || '(未填写)';
|
||||
vPn.classList.toggle('empty', !ePn.value.trim());
|
||||
vType.innerHTML = '';
|
||||
if(eType.value && eType.value !== '__new__'){
|
||||
var pill = document.createElement('span'); pill.className = 'tpill'; pill.textContent = eType.value;
|
||||
vType.appendChild(pill);
|
||||
if(!BUILTIN[eType.value]){ var s=document.createElement('span'); s.className='st new'; s.textContent='本单新建类型'; vType.appendChild(s); }
|
||||
vType.classList.remove('empty');
|
||||
} else { vType.textContent='(未选择)'; vType.classList.add('empty'); }
|
||||
var tb = document.getElementById('v-params');
|
||||
tb.innerHTML = '';
|
||||
var names = PN_TYPES[eType.value] || [];
|
||||
if(names.length === 0){
|
||||
tb.innerHTML = '<tr class="empty-row"><td colspan="2">未选择 PN 类型,暂无参数</td></tr>';
|
||||
} else {
|
||||
names.forEach(function(pn){
|
||||
var tr = document.createElement('tr');
|
||||
tr.setAttribute('data-field','参数名');
|
||||
var val = values[pn] && values[pn].trim() ? values[pn] : '(未填写)';
|
||||
tr.innerHTML = '<td><b></b></td><td class="mono"></td>';
|
||||
tr.children[0].querySelector('b').textContent = pn;
|
||||
tr.children[1].textContent = val;
|
||||
if(val === '(未填写)'){ tr.children[1].style.color = 'var(--ink-4)'; tr.children[1].classList.remove('mono'); }
|
||||
tb.appendChild(tr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 编辑闸 =====
|
||||
gate.querySelector('.eg-open').addEventListener('click', function(){
|
||||
snap = { pn: ePn.value, type: eType.value, values: JSON.parse(JSON.stringify(values)) };
|
||||
body.classList.add('editing'); gate.classList.add('on');
|
||||
if(eType.value && eType.value !== '__new__'){ renderParams(eType.value); }
|
||||
else { clearParams('先选类型','先选类型'); }
|
||||
progress();
|
||||
});
|
||||
gate.querySelector('.eg-cancel').addEventListener('click', function(){
|
||||
if(snap){ ePn.value = snap.pn; eType.value = snap.type; values = snap.values; }
|
||||
newtype.classList.remove('show');
|
||||
body.classList.remove('editing'); gate.classList.remove('on');
|
||||
progress();
|
||||
});
|
||||
gate.querySelector('.eg-save').addEventListener('click', function(){
|
||||
paint();
|
||||
body.classList.remove('editing'); gate.classList.remove('on');
|
||||
});
|
||||
|
||||
// 初始:新增类型面板预置 3 行参数名输入
|
||||
addNtRow(''); addNtRow(''); addNtRow('');
|
||||
progress();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user