This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-TMP-REPO/docs/ss02-act-05-new/ACT-WORK-05-数据工单-PN主数据创建.html
T

445 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>