docs(design): 新增 UI demo 页面,供 UI 精修评审
- docs/design/ui-demo/:控件总览、表单、卡片、列表与表格,以及工作台、读标两个组合页 - 只用设计规范的变量和组件;新增组件样式放在 demo.css,清单见 index - index 列出 UI 精修待定问题 Q1–Q12 - design/README 与 AGENTS.md 进度同步 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
300
docs/design/ui-demo/forms.html
Normal file
300
docs/design/ui-demo/forms.html
Normal file
@@ -0,0 +1,300 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>表单 · 标博士 UI demo</title>
|
||||
<link rel="icon" href="../logo/favicon.svg">
|
||||
<link rel="stylesheet" href="../system/tokens.css">
|
||||
<link rel="stylesheet" href="../system/fonts-local.css">
|
||||
<link rel="stylesheet" href="../system/components.css">
|
||||
<link rel="stylesheet" href="demo.css">
|
||||
<style>
|
||||
/* 只属于本页的排版 */
|
||||
.lot-radios{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-3)}
|
||||
.f-card{max-width:none}
|
||||
.hint-warn{font-size:var(--fs-caption);line-height:var(--lh-caption);color:var(--warn-text);display:flex;gap:6px;align-items:flex-start}
|
||||
.hint-warn .ico{width:14px;height:14px;font-size:10px;margin:3px 0 0}
|
||||
</style>
|
||||
</head>
|
||||
<body class="demo">
|
||||
<header data-demo-top></header>
|
||||
<main class="d-page">
|
||||
<div class="d-head">
|
||||
<h1>② 表单</h1>
|
||||
<p>三张真实业务表单:新建项目、资质录入、处理问题时的「忽略并注明原因」。标签在上,必填写「(必填)」,错误用赭色边框 + 下方赭色小字 + 「!」图标,离开输入框时校验、提交时汇总。</p>
|
||||
<nav class="d-toc" aria-label="本页目录"><a href="#s-new">01 新建项目</a><a href="#s-states">02 状态对照</a><a href="#s-qual">03 资质录入</a><a href="#s-ignore">04 忽略并注明原因 · 致命确认说明</a></nav>
|
||||
</div>
|
||||
|
||||
<!-- 01 新建项目 -->
|
||||
<section class="d-sec" id="s-new">
|
||||
<div class="d-sec-h"><span class="no">01</span><h2>新建项目</h2><span class="ref">规范 §7.13 · §8.3 · FR-M2-01</span></div>
|
||||
<div class="d-grid c-side">
|
||||
<form class="card f-card" novalidate data-new>
|
||||
<div class="alert warn err-sum" data-errsum hidden><span class="ico w">!</span><div><p><b>有 <span data-errn>2</span> 处需要修改</b></p><ul data-errlist></ul></div></div>
|
||||
|
||||
<fieldset class="form-sec">
|
||||
<legend>项目信息<small>招标文件解析后会自动补全,可以先只填名称</small></legend>
|
||||
<div class="form">
|
||||
<div class="field span2" id="f-name"><label for="n-name">项目名称 <small>(必填)</small></label><input class="input" id="n-name" placeholder="例如:某市政务服务中心智慧大厅建设项目"><span class="msg">只在你的工作台里显示,可以用简称</span></div>
|
||||
<div class="field"><label for="n-no">项目编号</label><input class="input" id="n-no" placeholder="招标文件封面上的编号"></div>
|
||||
<div class="field"><label for="n-buyer">采购人</label><input class="input" id="n-buyer" placeholder="例如:某市政务服务管理办公室"></div>
|
||||
<div class="field span2"><label id="l-regime">法律体系</label>
|
||||
<div class="lot-radios" role="radiogroup" aria-labelledby="l-regime">
|
||||
<label class="choice-card"><input type="radio" class="ck" name="regime" checked><span><b>让标博士识别</b><small>按招标文件的依据和格式判断</small></span></label>
|
||||
<label class="choice-card"><input type="radio" class="ck" name="regime"><span><b>政府采购</b><small>结论用「投标无效」</small></span></label>
|
||||
<label class="choice-card"><input type="radio" class="ck" name="regime"><span><b>招标投标</b><small>结论用「否决投标」</small></span></label>
|
||||
</div></div>
|
||||
<div class="field"><label>采购方式</label>
|
||||
<div class="pop" data-select><button type="button" class="select" aria-haspopup="listbox" aria-expanded="false"><span class="val"><span class="ph">解析后识别</span></span><i data-ic="chev-down"></i></button>
|
||||
<ul class="menu" role="listbox"><li role="option" aria-selected="true" data-label='<span class="ph">解析后识别</span>'>解析后识别</li><li class="grp">政府采购</li><li role="option">公开招标</li><li role="option">邀请招标</li><li role="option">竞争性磋商</li><li role="option">竞争性谈判</li><li role="option">询价</li></ul></div></div>
|
||||
<div class="field" id="f-due"><label>投标截止 <small>(必填)</small></label>
|
||||
<div class="dt-pair"><div class="pop" data-date data-marks="2026-11-20" data-new-date><button type="button" class="select date-trigger" aria-haspopup="dialog" aria-expanded="false"><span class="val"><span class="ph">选择日期</span></span><i data-ic="calendar"></i></button><div class="cal"></div></div><input class="input date-trigger" value="09:30" aria-label="截止时间"></div>
|
||||
<span class="msg">用于工作台的倒计时;补遗更正后会提示你核对</span></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="form-sec">
|
||||
<legend>招标文件<small>PDF、Word 或扫描件;补遗可以以后追加</small></legend>
|
||||
<div class="field fill" id="f-file">
|
||||
<div class="drop" tabindex="0" role="button" aria-label="上传招标文件" data-drop><i data-ic="upload" class="lg"></i><b>拖入或点击上传招标文件</b><span>单个文件不超过 200 MB · 扩展名不可信时以文件内容为准</span></div>
|
||||
<div data-files style="margin-top:var(--sp-3)"></div>
|
||||
</div>
|
||||
<div class="field fill" style="margin-top:var(--sp-5)"><label for="n-note">备注 <small>(选填)</small></label><textarea class="input" id="n-note" placeholder="例如:只投采购包 1,联合体伙伴待定"></textarea></div>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-foot">
|
||||
<span class="cost">扣 1 次解析 · 剩 <span class="fig">37</span> 次 · 解析失败、超时自动退回</span>
|
||||
<button type="button" class="btn">取消</button>
|
||||
<button type="submit" class="btn primary swap" data-submit><span class="idle">创建并开始解析</span><span class="busy">正在创建…</span></button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="d-stack">
|
||||
<div class="d-box">
|
||||
<h3>试一试</h3>
|
||||
<ol class="d-rules" style="border:0;padding-top:0;margin-top:0">
|
||||
<li>什么都不填,直接点「创建并开始解析」:顶部汇总 + 每个字段下方说明,点汇总里的链接跳到字段。</li>
|
||||
<li>在项目名称里输入再清空,离开输入框时就会校验。</li>
|
||||
<li>点上传区,会加入两个示意文件,其中一个扩展名和内容不符。</li>
|
||||
<li>全部填好后提交:按钮变成「正在创建…」,宽度不变,表单整体禁用。</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="d-box">
|
||||
<h3>规则</h3>
|
||||
<ul class="d-rules" style="border:0;padding-top:0;margin-top:0">
|
||||
<li>必填写「(必填)」,不用红色星号;选填项多的表单反过来写「(选填)」。</li>
|
||||
<li>错误说明写清楚怎么改,不写「格式错误」。</li>
|
||||
<li>会扣点的提交按钮,左侧直接写扣多少、还剩多少。</li>
|
||||
<li>文件扩展名和内容不符只提醒,不拦截(样本分析 07 的结论)。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 02 状态对照 -->
|
||||
<section class="d-sec" id="s-states">
|
||||
<div class="d-sec-h"><span class="no">02</span><h2>同一字段的状态对照</h2><span class="ref">规范 §7.13</span></div>
|
||||
<div class="d-box">
|
||||
<div class="d-states wide">
|
||||
<div class="d-state"><small>正常</small><div class="field"><label>证书编号 <small>(必填)</small></label><input class="input" value="01226IS0458"></div></div>
|
||||
<div class="d-state"><small>聚焦</small><div class="field"><label>证书编号 <small>(必填)</small></label><input class="input is-focus" value="01226IS04"></div></div>
|
||||
<div class="d-state"><small>错误</small><div class="field err"><label>证书编号 <small>(必填)</small></label><input class="input" value="" aria-invalid="true"><span class="msg"><span class="ico w">!</span>请填写证书编号,查标时用它核对附件</span></div></div>
|
||||
<div class="d-state"><small>禁用</small><div class="field dis"><label>证书编号</label><input class="input" value="01226IS0458" disabled><span class="msg">已被 2 个已递交项目引用,不能修改</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-grid c2" style="margin-top:var(--sp-6)">
|
||||
<div class="card">
|
||||
<div class="card-h"><h3>填写中</h3><span class="more cap muted">正常状态</span></div>
|
||||
<div class="form">
|
||||
<div class="field"><label>名称 <small>(必填)</small></label><input class="input" value="ISO 9001 质量管理体系"></div>
|
||||
<div class="field"><label>证书编号 <small>(必填)</small></label><input class="input" value="01226Q31877"></div>
|
||||
</div>
|
||||
<div class="form-foot"><span class="cost">不扣额度</span><button class="btn">取消</button><button class="btn primary swap"><span class="idle">保存资质</span><span class="busy">正在保存…</span></button></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-h"><h3>提交中</h3><span class="more cap muted">整表禁用,按钮换成「正在…」,宽度不变</span></div>
|
||||
<fieldset disabled style="border:0;margin:0;padding:0;min-width:0">
|
||||
<div class="form">
|
||||
<div class="field dis"><label>名称 <small>(必填)</small></label><input class="input" value="ISO 9001 质量管理体系" disabled></div>
|
||||
<div class="field dis"><label>证书编号 <small>(必填)</small></label><input class="input" value="01226Q31877" disabled></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-foot"><span class="cost">不扣额度</span><button class="btn" disabled>取消</button><button class="btn primary swap is-loading" aria-busy="true"><span class="idle">保存资质</span><span class="busy">正在保存…</span></button></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 03 资质录入 -->
|
||||
<section class="d-sec" id="s-qual">
|
||||
<div class="d-sec-h"><span class="no">03</span><h2>资质录入</h2><span class="ref">FR-M6 最小资质库 · 红线 5 不编造</span></div>
|
||||
<div class="d-grid c-side">
|
||||
<div class="dialog wide static" role="dialog" aria-labelledby="q-t" style="width:auto">
|
||||
<h2 id="q-t">添加资质</h2>
|
||||
<div class="body">
|
||||
<p class="muted">查标时用来核对证书有没有过期、等级够不够。数据只来自你录入的内容,系统不从外部补数据。</p>
|
||||
<div class="form">
|
||||
<div class="field span2"><label for="q-name">名称 <small>(必填)</small></label><input class="input" id="q-name" value="ISO/IEC 27001 信息安全管理体系认证"></div>
|
||||
<div class="field"><label>类型 <small>(必填)</small></label>
|
||||
<div class="pop" data-select><button type="button" class="select" aria-haspopup="listbox" aria-expanded="false"><span class="val">体系认证</span><i data-ic="chev-down"></i></button>
|
||||
<ul class="menu" role="listbox"><li role="option">资质证书</li><li role="option" aria-selected="true">体系认证</li><li role="option">软件著作权</li><li role="option">其他</li></ul></div></div>
|
||||
<div class="field"><label for="q-lv">等级 <small>(选填)</small></label><input class="input" id="q-lv" placeholder="例如:CS3、二级"></div>
|
||||
<div class="field"><label for="q-no">证书编号 <small>(必填)</small></label><input class="input" id="q-no" value="01226IS0458"></div>
|
||||
<div class="field"><label for="q-org">发证机构</label><input class="input" id="q-org" value="某认证中心"></div>
|
||||
<div class="field"><label>发证日期</label><div class="pop" data-date data-value="2023-11-16" data-month="2023-11"><button type="button" class="select date-trigger" aria-haspopup="dialog" aria-expanded="false"><span class="val">2023-11-16</span><i data-ic="calendar"></i></button><div class="cal"></div></div></div>
|
||||
<div class="field"><label>有效期至 <small>(必填)</small></label><div class="pop" data-date data-value="2026-11-15" data-marks="2026-11-20"><button type="button" class="select date-trigger" aria-haspopup="dialog" aria-expanded="false"><span class="val">2026-11-15</span><i data-ic="calendar"></i></button><div class="cal"></div></div>
|
||||
<span class="hint-warn"><span class="ico w">!</span><span>早于进行中项目「智慧大厅建设项目」的投标截止日 11月20日</span></span></div>
|
||||
<div class="field span2"><div class="d-row" style="gap:var(--sp-3)"><span id="q-long">长期有效</span><button type="button" class="switch" role="switch" aria-checked="false" aria-labelledby="q-long"><span class="track"></span><span class="st"></span></button><span class="cap muted">打开后不检查有效期</span></div></div>
|
||||
<div class="field span2"><label>证书扫描件</label>
|
||||
<div class="file-row"><span class="ext">PDF</span><div><b>ISO27001 证书 2023.pdf</b><span class="cap muted">2 页 · 1.2 MB</span></div><span class="acts"><button type="button" class="btn sm text">替换</button><button type="button" class="icon-btn sm" aria-label="移除附件" data-tip="移除附件"><i data-ic="x"></i></button></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot"><span class="left cap muted">保存后,进行中项目的查标会用新信息复查</span><button class="btn">取消</button><button class="btn primary">保存资质</button></div>
|
||||
</div>
|
||||
<div class="d-stack">
|
||||
<div class="d-box">
|
||||
<h3>打开真实对话框 <small>可以点</small></h3>
|
||||
<button class="btn primary" data-qadd><i data-ic="plus"></i>添加资质</button>
|
||||
<p class="note">空表单直接保存会看到错误状态;「附件」可以稍后补录,列表里显示「待补录」占位,不生成内容。</p>
|
||||
</div>
|
||||
<div class="d-box">
|
||||
<h3>提醒和错误的区别</h3>
|
||||
<ul class="d-rules" style="border:0;padding-top:0;margin-top:0">
|
||||
<li><b>错误</b>(赭色边框):必须改了才能保存,例如漏填证书编号。</li>
|
||||
<li><b>提醒</b>(只有赭色小字,边框不变):可以保存,但查标会提示,例如证书在投标截止日前到期。</li>
|
||||
<li>到期判断以每个项目的投标截止日为准,不以今天为准。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 04 忽略并注明原因 -->
|
||||
<section class="d-sec" id="s-ignore">
|
||||
<div class="d-sec-h"><span class="no">04</span><h2>忽略并注明原因 · 致命问题的确认说明</h2><span class="ref">规范 §7.4 · §7.13 · U4</span></div>
|
||||
<div class="results">
|
||||
<article class="finding">
|
||||
<div>
|
||||
<div class="f-head"><span class="sev major">重要</span><span class="f-title">开标一览表与分项价格表合计不一致</span></div>
|
||||
<p class="f-text">开标一览表 287.60 万元,分项价格表合计 286.80 万元,相差 0.80 万元。按招标文件规定,两者不一致时以开标一览表为准,不作无效处理;但会影响价格评审。</p>
|
||||
<div class="u4" data-ign>
|
||||
<div class="field err">
|
||||
<label for="ig1">忽略原因 <small>(必填,至少 5 个字)</small></label>
|
||||
<div class="chips"><button type="button" class="btn" data-chip>招标文件允许</button><button type="button" class="btn" data-chip>已在其他分册响应</button><button type="button" class="btn" data-chip>与本项目无关</button></div>
|
||||
<textarea class="input" id="ig1" maxlength="200" aria-invalid="true">已核对</textarea>
|
||||
<div class="msg-row"><span class="msg"><span class="ico w">!</span>至少写 5 个字,说明为什么不处理</span><span class="count"><span data-n>3</span> / 200</span></div>
|
||||
</div>
|
||||
<div class="row"><button class="btn primary" data-ign-ok>忽略这一项</button><button class="btn text" data-ign-cancel>取消</button><span class="cap muted">「已忽略」不等于确认无误,报告里单独列出</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<aside>
|
||||
<div class="cite"><a class="cite-src" href="#">报价册 · <span class="fig">第 1 页</span></a><q>投标总价(小写):<mark>2876000.00 元</mark></q></div>
|
||||
<div class="cite"><a class="cite-src" href="#">报价册 · <span class="fig">第 3 页</span></a><q><mark>合计:2868000.00 元</mark></q></div>
|
||||
</aside>
|
||||
</article>
|
||||
<article class="finding is-fatal">
|
||||
<div>
|
||||
<div class="f-head"><span class="sev fatal">致命</span><span class="f-title">授权委托书的单位签章位置未发现盖章</span><span class="flag box">新增</span></div>
|
||||
<p class="f-text">商务册第 5 页《法定代表人授权委托书》的「投标人(电子签章)」位置是空的。本检查只看有无,不鉴定真伪。</p>
|
||||
<div class="u4">
|
||||
<div class="field">
|
||||
<label for="ig2">确认无误的说明 <small>(必填)</small></label>
|
||||
<textarea class="input" id="ig2">电子签章在递交时由交易平台统一加盖,Word 稿里本来就是空的。</textarea>
|
||||
<div class="msg-row"><span class="msg">对致命问题说「没问题」,需要写一句说明;说明会同时作为误报反馈提交。</span><span class="count"><span>30</span> / 200</span></div>
|
||||
</div>
|
||||
<div class="row"><button class="btn primary swap" data-loading="已确认无误 · 说明已作为反馈提交"><span class="idle">确认无误</span><span class="busy">正在保存…</span></button><button class="btn text">取消</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<aside>
|
||||
<div class="cite"><a class="cite-src" href="#">招标文件 · <span class="fig">第 24 页</span></a><q>4.《法定代表人授权委托书》(法定代表人签字或盖章并<mark>加盖单位电子签章</mark>)。</q></div>
|
||||
<div class="cite"><a class="cite-src" href="#">商务册 · <span class="fig">第 5 页</span></a><q>法定代表人(签字或盖章):李某某 <mark>投标人(电子签章):(签章位置为空)</mark></q></div>
|
||||
</aside>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script src="demo.js"></script>
|
||||
<script>
|
||||
const { $, $$, toast, dialog, icon, esc } = Demo;
|
||||
Demo.demoTop("forms.html");
|
||||
|
||||
/* ---------- 新建项目 ---------- */
|
||||
const F = $("[data-new]");
|
||||
let files = [], dateVal = "";
|
||||
$("[data-new-date]").addEventListener("change", (e) => { dateVal = e.detail; setErr("f-due", ""); });
|
||||
function setErr(id, msg) {
|
||||
const f = document.getElementById(id);
|
||||
f.classList.toggle("err", !!msg);
|
||||
let m = $(":scope > .msg.e", f);
|
||||
if (msg) {
|
||||
if (!m) { m = document.createElement("span"); m.className = "msg e"; f.appendChild(m); }
|
||||
m.innerHTML = `<span class="ico w">!</span>${msg}`;
|
||||
$$(":scope > .msg:not(.e)", f).forEach((x) => x.hidden = true);
|
||||
} else { if (m) m.remove(); $$(":scope > .msg", f).forEach((x) => x.hidden = false); }
|
||||
}
|
||||
function checkName() { setErr("f-name", $("#n-name").value.trim() ? "" : "请填写项目名称,可以先写简称,之后再改"); }
|
||||
$("#n-name").addEventListener("blur", checkName);
|
||||
function renderFiles() {
|
||||
$("[data-files]").innerHTML = files.map((f, i) => `<div class="file-row"><span class="ext">${f.ext}</span><div><b>${esc(f.name)}</b>${f.warn ? `<span class="hint-warn"><span class="ico w">!</span><span>${f.warn}</span></span>` : `<span class="cap muted">${f.meta}</span>`}</div><span class="acts"><button type="button" class="icon-btn sm" aria-label="移除" data-tip="移除" data-rm="${i}">${icon("x")}</button></span></div>`).join("");
|
||||
}
|
||||
$("[data-drop]").addEventListener("click", () => {
|
||||
files = [{ ext: "PDF", name: "ZC-2026-0418 采购文件.pdf", meta: "186 页 · 8.4 MB" }, { ext: "DOC", name: "关于 ZC-2026-0418 的更正公告.pdf", warn: "扩展名是 .pdf,内容是 Word 文档,会按 Word 解析" }];
|
||||
renderFiles(); setErr("f-file", "");
|
||||
});
|
||||
$("[data-files]").addEventListener("click", (e) => { const b = e.target.closest("[data-rm]"); if (b) { files.splice(+b.dataset.rm, 1); renderFiles(); } });
|
||||
F.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
checkName();
|
||||
setErr("f-due", dateVal ? "" : "请选择投标截止日期,用于倒计时");
|
||||
setErr("f-file", files.length ? "" : "请上传招标文件,至少一份");
|
||||
const errs = $$(".field.err", F);
|
||||
const sum = $("[data-errsum]");
|
||||
if (errs.length) {
|
||||
$("[data-errn]").textContent = errs.length;
|
||||
$("[data-errlist]").innerHTML = errs.map((f) => `<li><a href="#${f.id}">${$("label", f)?.firstChild.textContent.trim() || "招标文件"}</a>:${$(".msg.e", f).textContent.replace(/^!/, "")}</li>`).join("");
|
||||
sum.hidden = false; sum.scrollIntoView({ block: "center", behavior: "smooth" });
|
||||
return;
|
||||
}
|
||||
sum.hidden = true;
|
||||
const b = $("[data-submit]");
|
||||
b.classList.add("is-loading"); b.setAttribute("aria-busy", "true");
|
||||
$$("input, textarea, button:not([data-submit]), .drop", F).forEach((x) => { x.disabled = true; x.closest(".field")?.classList.add("dis"); });
|
||||
setTimeout(() => { b.classList.remove("is-loading"); b.removeAttribute("aria-busy"); $$("input, textarea, button", F).forEach((x) => x.disabled = false); $$(".field.dis", F).forEach((x) => x.classList.remove("dis")); toast("项目已创建,正在解析招标文件 · 可以离开本页"); }, 2400);
|
||||
});
|
||||
|
||||
/* ---------- 资质对话框 ---------- */
|
||||
$("[data-qadd]").onclick = () => dialog({
|
||||
title: "添加资质", wide: true, ok: "保存资质",
|
||||
footLeft: '<span class="cap muted">不扣额度</span>',
|
||||
body: `<p class="muted">数据只来自你录入的内容,系统不从外部补数据。</p><div class="form">
|
||||
<div class="field span2" id="qd-name"><label for="qdn">名称 <small>(必填)</small></label><input class="input" id="qdn" placeholder="例如:信息系统建设和服务能力等级证书"></div>
|
||||
<div class="field"><label>类型 <small>(必填)</small></label><div class="pop" data-select><button type="button" class="select" aria-haspopup="listbox" aria-expanded="false"><span class="val">资质证书</span>${icon("chev-down")}</button><ul class="menu" role="listbox"><li role="option" aria-selected="true">资质证书</li><li role="option">体系认证</li><li role="option">软件著作权</li><li role="option">其他</li></ul></div></div>
|
||||
<div class="field"><label for="qdl">等级 <small>(选填)</small></label><input class="input" id="qdl"></div>
|
||||
<div class="field" id="qd-no"><label for="qdo">证书编号 <small>(必填)</small></label><input class="input" id="qdo"></div>
|
||||
<div class="field"><label>有效期至</label><div class="pop" data-date><button type="button" class="select date-trigger" aria-haspopup="dialog" aria-expanded="false"><span class="val"><span class="ph">选择日期</span></span>${icon("calendar")}</button><div class="cal"></div></div></div>
|
||||
<div class="field span2"><label>证书扫描件 <small>(可以稍后补录)</small></label><div class="drop" style="padding:var(--sp-4)">${icon("upload")}<span>拖入或点击上传 PDF / 图片</span></div></div></div>`,
|
||||
onOk: (s) => {
|
||||
let bad = 0;
|
||||
[["qd-name", "#qdn", "请填写资质名称,和证书上的写法一致"], ["qd-no", "#qdo", "请填写证书编号,查标时用它核对附件"]].forEach(([id, sel, msg]) => {
|
||||
const f = $("#" + id, s), v = $(sel, s).value.trim();
|
||||
f.classList.toggle("err", !v); $(".msg", f)?.remove();
|
||||
if (!v) { bad++; f.insertAdjacentHTML("beforeend", `<span class="msg"><span class="ico w">!</span>${msg}</span>`); }
|
||||
});
|
||||
if (bad) return false;
|
||||
toast("已保存资质");
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- 忽略原因 ---------- */
|
||||
const ig = $("[data-ign]"), ta = $("#ig1", ig), fld = $(".field", ig);
|
||||
const validate = (show) => { const n = ta.value.trim().length; $("[data-n]", ig).textContent = ta.value.length; const bad = n < 5; if (show || !bad) { fld.classList.toggle("err", bad); $(".msg", fld).innerHTML = bad ? '<span class="ico w">!</span>至少写 5 个字,说明为什么不处理' : "报告和处理记录里会显示这段原因"; } return !bad; };
|
||||
ta.addEventListener("input", () => validate(false));
|
||||
ta.addEventListener("blur", () => validate(true));
|
||||
$$("[data-chip]", ig).forEach((c) => c.onclick = () => { ta.value = c.textContent; validate(true); ta.focus(); });
|
||||
$("[data-ign-ok]").onclick = () => { if (validate(true)) toast("已忽略 · 原因已记录", { undo: () => toast("已撤销", { ok: false }) }); };
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user