Files
shanxia2.0/docs/fresh-mint-pl-plan-stop-product-display-demo.html
T
2026-08-27 14:23:18 +08:00

499 lines
23 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.0" />
<title>运输计划 · 段内产品「双行展示」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;
--table-head: #f8fafc;
--bg-page: #f1f5f9;
--shadow: 0 1px 3px rgba(0,0,0,.05);
--shadow-lg: 0 12px 40px rgba(15,23,42,.14);
--radius: 10px;
--warn: #d97706;
--warn-bg: #fffbeb;
--danger: #dc2626;
--danger-bg: #fef2f2;
--readonly-bg: #f8fafc;
--edit-bg: #fff;
}
* { box-sizing: border-box; }
body {
margin: 0; min-height: 100vh;
font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 14px; line-height: 1.5; color: var(--text); background: var(--bg-page);
}
.page { max-width: 1440px; margin: 0 auto; padding: 24px 20px 80px; }
.hero {
background: linear-gradient(135deg, #ecfdf5 0%, #fff 50%, #f0f9ff 100%);
border: 1px solid var(--border); border-radius: var(--radius);
padding: 22px 24px; margin-bottom: 18px; box-shadow: var(--shadow);
}
.hero h1 { margin: 0 0 8px; font-size: 22px; font-weight: 700; }
.hero h1 em { font-style: normal; color: var(--primary-dark); }
.hero p { margin: 0; color: var(--text-muted); max-width: 980px; }
.idea-box {
margin-top: 14px; padding: 12px 14px; border-radius: 8px; font-size: 13px;
background: var(--primary-bg); border: 1px solid #a7f3d0; color: var(--primary-dark);
}
.idea-box strong { display: block; margin-bottom: 4px; font-size: 14px; }
.pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.pill {
padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 500;
background: #fff; color: var(--text-muted); border: 1px solid var(--border);
}
.scheme-tabs {
display: flex; flex-wrap: wrap; gap: 6px;
background: #fff; border: 1px solid var(--border);
border-radius: var(--radius) var(--radius) 0 0; padding: 10px 12px 0;
}
.scheme-tab {
border: none; background: transparent; cursor: pointer;
padding: 10px 14px; font-size: 13px; font-weight: 600;
color: var(--text-muted); border-bottom: 2px solid transparent; font-family: inherit;
}
.scheme-tab.active { color: var(--primary-dark); border-bottom-color: var(--primary); }
.scheme-tab.recommended::after {
content: "推荐"; margin-left: 6px; font-size: 10px; font-weight: 700;
color: #fff; background: var(--primary-dark); padding: 1px 6px; border-radius: 999px;
}
.scheme-panel {
display: none; background: #fff; border: 1px solid var(--border); border-top: none;
border-radius: 0 0 var(--radius) var(--radius); padding: 16px 18px 22px; box-shadow: var(--shadow);
}
.scheme-panel.active { display: block; }
.scheme-desc {
margin: 0 0 14px; padding: 10px 12px; border-radius: 8px; font-size: 12px;
border: 1px solid #bae6fd; background: #f0f9ff; color: #0369a1;
}
.scheme-desc.ok { border-color: #a7f3d0; background: var(--primary-bg); color: var(--primary-dark); }
.scheme-desc.warn { border-color: rgba(217,119,6,.3); background: var(--warn-bg); color: #92400e; }
.dialog-sim {
border: 1px solid var(--border); border-radius: var(--radius);
background: #fff; box-shadow: var(--shadow-lg); overflow: hidden; max-width: 580px; margin: 0 auto;
}
.dialog-sim__hd {
padding: 12px 14px; border-bottom: 1px solid var(--border); font-weight: 700; font-size: 13px;
background: linear-gradient(180deg, #ecfdf5, #f8fffc);
}
.dialog-sim__bd { padding: 12px; }
.products-head {
display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;
}
.products-head__title { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.btn {
height: 26px; padding: 0 8px; border: 1px solid var(--border); border-radius: 6px;
background: #fff; font: inherit; font-size: 12px; cursor: pointer; color: var(--text-muted);
}
.btn.link { border: none; background: transparent; color: var(--danger); padding: 0; height: auto; }
.tag {
display: inline-flex; padding: 1px 6px; border-radius: 4px;
font-size: 10px; font-weight: 600; vertical-align: middle;
}
.tag.danger { background: var(--danger); color: #fff; }
input, select {
width: 100%; height: 32px; border: 1px solid var(--border); border-radius: 8px;
padding: 0 8px; font: inherit; font-size: 12px;
}
.field label {
display: block; font-size: 10px; font-weight: 600; color: var(--text-muted); margin-bottom: 3px;
}
/* ===== 现状:单行表格 ===== */
.single-row-table { border: 1px solid var(--border); border-radius: 8px; overflow-x: auto; }
.single-row-table table { width: 100%; min-width: 720px; border-collapse: collapse; font-size: 11px; }
.single-row-table th, .single-row-table td { border-bottom: 1px solid var(--border); padding: 6px; white-space: nowrap; }
.single-row-table th { background: var(--table-head); color: var(--text-muted); font-weight: 600; }
.scroll-hint {
text-align: center; font-size: 10px; color: var(--warn); padding: 4px;
background: var(--warn-bg); border-top: 1px dashed rgba(217,119,6,.3);
}
/* ===== 双行表:通用结构 ===== */
.dual-row-list { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.dual-row-list__thead {
display: grid; grid-template-columns: 1fr;
padding: 7px 10px; background: var(--table-head);
border-bottom: 1px solid var(--border);
font-size: 11px; font-weight: 600; color: var(--text-muted);
}
.dual-item { border-bottom: 1px solid var(--border); }
.dual-item:last-child { border-bottom: none; }
/* 第 1 行:只读信息带 */
.dual-item__row1 {
display: grid; gap: 8px; padding: 8px 10px;
background: var(--readonly-bg);
border-bottom: 1px dashed var(--border);
}
.dual-item__row1.layout-a { grid-template-columns: 1.4fr repeat(4, minmax(0, 1fr)); align-items: start; }
.dual-item__row1.layout-b { grid-template-columns: 1fr 100px; align-items: center; }
.dual-item__row1.layout-c { grid-template-columns: 1fr; }
.product-cell__name { font-size: 13px; font-weight: 700; line-height: 1.35; min-width: 0; }
.product-cell__name .model { display: block; font-size: 11px; font-weight: 500; color: var(--text-muted); margin-top: 2px; }
.ro-cell { min-width: 0; }
.ro-cell label {
display: block; font-size: 10px; font-weight: 600; color: var(--text-muted); margin-bottom: 2px;
}
.ro-cell span { font-size: 12px; color: var(--text); word-break: break-all; }
.ro-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.ro-chip {
font-size: 11px; padding: 2px 8px; border-radius: 6px;
background: #fff; border: 1px solid #e2e8f0;
}
.ro-chip b { color: var(--text-muted); font-weight: 600; margin-right: 4px; }
.qty-inline { text-align: right; }
.qty-inline input { text-align: right; height: 34px; font-weight: 700; color: var(--primary-dark); }
/* 第 2 行:可编辑带 */
.dual-item__row2 {
display: grid; gap: 8px; padding: 8px 10px;
background: var(--edit-bg);
}
.dual-item__row2.layout-edit-4 {
grid-template-columns: 100px 1fr 1fr 1fr 36px; align-items: end;
}
.dual-item__row2.layout-edit-3 {
grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end;
}
.dual-item__row2.layout-edit-2 {
grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: end;
}
.dual-item__row2 .remark-full { grid-column: 1 / -1; }
.dual-item__row2 .act-cell { display: flex; align-items: flex-end; justify-content: center; padding-bottom: 4px; }
.row-label {
font-size: 10px; font-weight: 700; letter-spacing: 0.04em;
color: var(--text-muted); margin-bottom: 6px;
}
.row-label.readonly::before { content: "① "; color: #94a3b8; }
.row-label.editable::before { content: "② "; color: var(--primary); }
/* 结构示意 */
.structure-diagram {
margin: 14px 0; padding: 12px; border-radius: 8px;
background: #f8fafc; border: 1px dashed var(--border); font-size: 12px;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; line-height: 1.7; color: var(--text-muted);
}
.structure-diagram em { color: var(--primary-dark); font-style: normal; font-weight: 600; }
.pros-cons {
display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 14px;
}
@media (max-width: 640px) {
.pros-cons { grid-template-columns: 1fr; }
.dual-item__row1.layout-a { grid-template-columns: 1fr 1fr; }
.dual-item__row2.layout-edit-4 { grid-template-columns: 1fr 1fr; }
}
.pros-cons > div {
border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; font-size: 12px;
}
.pros-cons h4 { margin: 0 0 6px; font-size: 12px; }
.pros-cons ul { margin: 0; padding-left: 18px; color: var(--text-muted); }
</style>
</head>
<body>
<div class="page">
<header class="hero">
<h1>段内产品 · <em>双行展示</em> Demo</h1>
<p>
装货 / 送货 pane 约 580px 宽,<strong>一行平铺 9 列</strong>必然挤压或横滑。
核心思路:<strong>每条产品占两行</strong>——纵向换空间,横向仍保持可读宽度。
</p>
<div class="idea-box">
<strong>你的思路 → 双行表</strong>
仍保留「列表 / 表格」扫读习惯;不改成卡片、Tab 或折叠。
第 1 行放<strong>识别 + 只读</strong>,第 2 行放<strong>段级可编辑</strong>,两行视觉上属于同一条产品。
</div>
<div class="pills">
<span class="pill">~580px 栏宽</span>
<span class="pill">1 条产品 = 2 行</span>
<span class="pill">无横向滚动</span>
</div>
</header>
<div class="scheme-tabs">
<button class="scheme-tab" data-scheme="current" type="button">现状 · 单行(问题)</button>
<button class="scheme-tab recommended active" data-scheme="a" type="button">双行 A · 上行只读 / 下行编辑</button>
<button class="scheme-tab" data-scheme="b" type="button">双行 B · 上行产品+数量</button>
<button class="scheme-tab" data-scheme="c" type="button">双行 C · 上行名称 / 下行全字段</button>
<button class="scheme-tab" data-scheme="impl" type="button">实现说明</button>
</div>
<!-- 现状 -->
<section class="scheme-panel" id="panel-current">
<p class="scheme-desc warn">
<strong>现状:</strong>9 列挤在一行 → 别名/品牌/下拉被截断,或整表横向滚动。
</p>
<div class="dialog-sim">
<div class="dialog-sim__hd">装货产品 · 单行表格</div>
<div class="dialog-sim__bd">
<div class="single-row-table">
<table>
<thead>
<tr>
<th>产品</th><th>别名</th><th>品牌</th><th>单位</th>
<th>数量</th><th>包装</th><th>送货</th><th>备注</th><th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>97%硫酸</td><td>工业…</td><td>不限…</td><td>吨</td>
<td>30</td><td>槽罐</td><td>一票…</td><td>—</td><td>删</td>
</tr>
</tbody>
</table>
<div class="scroll-hint">← 需横向滚动,字段显示不全 →</div>
</div>
</div>
</div>
</section>
<!-- 双行 A:推荐 -->
<section class="scheme-panel active" id="panel-a">
<p class="scheme-desc ok">
<strong>推荐 · 双行 A(已实现):</strong>
<em>第 1 行</em> = 产品名(只读)+ <strong>别名 / 品牌 / 单位(可编辑)</strong>;
<em>第 2 行</em> = 计划数量 + 包装 + 送货 + 备注 + 删除。
别名/品牌交互与上方「产品信息」表一致(下拉 + 维护入口)。
</p>
<div class="structure-diagram">
每条产品:<br />
┌─ <em>行1</em> ─ 产品名 │ <strong>别名▼</strong> │ <strong>品牌▼</strong> │ <strong>单位▼</strong> ─┐<br />
└─ <em>行2</em> ─ 数量 │ 包装规格 │ 送货方式 │ 备注 │ 删 ─┘
</div>
<div class="dialog-sim">
<div class="dialog-sim__hd">装货产品 · 双行 A</div>
<div class="dialog-sim__bd">
<div class="products-head">
<span class="products-head__title">2 条产品</span>
<button class="btn" type="button">从计划同步</button>
</div>
<div class="dual-row-list">
<div class="dual-row-list__thead">装货产品(每条占两行)</div>
<article class="dual-item">
<div class="row-label editable">产品属性(可编辑)</div>
<div class="dual-item__row1 layout-a">
<div class="product-cell__name">
97% 精制硫酸 <span class="tag danger">易制毒</span>
<span class="model">型号/规格:CP级</span>
</div>
<div class="edit-field"><label>别名</label><select><option>工业硫酸</option></select></div>
<div class="edit-field"><label>品牌</label><select><option>不限品牌</option></select></div>
<div class="edit-field"><label>单位</label><select><option>吨</option></select></div>
</div>
<div class="row-label editable">段级数量与物流</div>
<div class="dual-item__row2 layout-edit-4">
<div class="field"><label>计划数量</label><input value="30.000" /></div>
<div class="field"><label>包装规格</label><select><option>槽罐</option></select></div>
<div class="field"><label>送货方式</label><select><option>一票制送货</option></select></div>
<div class="field"><label>备注</label><input placeholder="段内备注" /></div>
<div class="act-cell"><button class="btn link" type="button">删</button></div>
</div>
</article>
<article class="dual-item">
<div class="dual-item__row1 layout-a">
<div class="product-cell__name">
30% 液碱
<span class="model">型号/规格:国标</span>
</div>
<div class="edit-field"><label>别名</label><input placeholder="—" /></div>
<div class="edit-field"><label>品牌</label><select><option>指定 · 天原化工</option></select></div>
<div class="edit-field"><label>单位</label><select><option>吨</option></select></div>
</div>
<div class="dual-item__row2 layout-edit-4">
<div class="field"><label>计划数量</label><input value="10.000" /></div>
<div class="field"><label>包装规格</label><select><option>散装</option></select></div>
<div class="field"><label>送货方式</label><select><option>山峡自提</option></select></div>
<div class="field"><label>备注</label><input value="含量30%" /></div>
<div class="act-cell"><button class="btn link" type="button">删</button></div>
</div>
</article>
</div>
</div>
</div>
<div class="pros-cons">
<div>
<h4>优点</h4>
<ul>
<li>仍是「表格式列表」,多条产品纵向排列</li>
<li>只读字段 5 列全宽,长文本不截断</li>
<li>可编辑下拉各自 ~120px+,选项可读</li>
<li>两行底色区分(灰 / 白),不用点展开</li>
</ul>
</div>
<div>
<h4>注意</h4>
<ul>
<li>比单行略高,段内 1–3 条可接受</li>
<li>规格可在行1名称副行与独立列二选一(避免重复)</li>
</ul>
</div>
</div>
</section>
<!-- 双行 B -->
<section class="scheme-panel" id="panel-b">
<p class="scheme-desc">
<strong>双行 B:</strong><em>第 1 行</em>只保留「产品名 + 计划数量」(扫数量最快);
<em>第 2 行</em>再排别名/品牌/单位 + 包装/送货/备注。适合<strong>改数频繁</strong>的场景。
</p>
<div class="dialog-sim">
<div class="dialog-sim__hd">装货产品 · 双行 B</div>
<div class="dialog-sim__bd">
<div class="dual-row-list">
<article class="dual-item">
<div class="dual-item__row1 layout-b">
<div class="product-cell__name">
97% 精制硫酸 <span class="tag danger">毒</span>
<div class="ro-chips">
<span class="ro-chip"><b>别名</b>工业硫酸</span>
<span class="ro-chip"><b>品牌</b>不限</span>
<span class="ro-chip"><b>单位</b>吨</span>
</div>
</div>
<div class="qty-inline field">
<label>计划数量</label>
<input value="30.000" />
</div>
</div>
<div class="dual-item__row2 layout-edit-3">
<div class="field"><label>包装规格</label><select><option>槽罐</option></select></div>
<div class="field"><label>送货方式</label><select><option>一票制</option></select></div>
<div class="field"><label>备注</label><input /></div>
</div>
</article>
<article class="dual-item">
<div class="dual-item__row1 layout-b">
<div class="product-cell__name">
30% 液碱
<div class="ro-chips">
<span class="ro-chip"><b>品牌</b>天原</span>
<span class="ro-chip"><b>单位</b>吨</span>
</div>
</div>
<div class="qty-inline field"><label>计划数量</label><input value="10.000" /></div>
</div>
<div class="dual-item__row2 layout-edit-3">
<div class="field"><label>包装规格</label><select><option>散装</option></select></div>
<div class="field"><label>送货方式</label><select><option>自提</option></select></div>
<div class="field"><label>备注</label><input value="含量30%" /></div>
</div>
</article>
</div>
</div>
</div>
<div class="pros-cons">
<div><h4>优点</h4><ul><li>数量与产品名同一视线,改数最快</li><li>第 2 行 3 列更宽</li></ul></div>
<div><h4>注意</h4><ul><li>只读字段用 chip,不如 A 的列对齐整齐</li></ul></div>
</div>
</section>
<!-- 双行 C -->
<section class="scheme-panel" id="panel-c">
<p class="scheme-desc">
<strong>双行 C:</strong><em>第 1 行</em>仅产品名 + 危化标识 + chip 摘要;
<em>第 2 行</em>用 2×3 栅格排<strong>全部 6 个字段</strong>(含只读与可编辑)。
结构最简,但第 2 行字段较多时略挤。
</p>
<div class="dialog-sim">
<div class="dialog-sim__hd">装货产品 · 双行 C</div>
<div class="dialog-sim__bd">
<div class="dual-row-list">
<article class="dual-item">
<div class="dual-item__row1 layout-c">
<div class="product-cell__name">
97% 精制硫酸 <span class="tag danger">毒</span>
<div class="ro-chips" style="margin-top:6px">
<span class="ro-chip"><b>别名</b>工业硫酸</span>
<span class="ro-chip"><b>品牌</b>不限</span>
<span class="ro-chip"><b>CP级</b></span>
<span class="ro-chip"><b>吨</b></span>
</div>
</div>
</div>
<div class="dual-item__row2 layout-edit-2">
<div class="field"><label>计划数量</label><input value="30" /></div>
<div class="field"><label>包装规格</label><select><option>槽罐</option></select></div>
<div class="field"><label>送货方式</label><select><option>一票制</option></select></div>
<div class="field"><label>单位</label><input value="吨" readonly style="background:#f8fafc" /></div>
<div class="field remark-full"><label>备注</label><input /></div>
</div>
</article>
</div>
</div>
</div>
</section>
<!-- 实现说明 -->
<section class="scheme-panel" id="panel-impl">
<p class="scheme-desc ok">
<strong>落地建议(双行 A):</strong>改造 <code>PlPlanStopProductTable</code> 的 compact 模式——
不用 <code>el-table</code> 多列,改为 <code>v-for</code> 渲染「双行块」列表;
或用 <code>el-table</code> 的 <code>span-method</code> 合并为每组 2 行(实现稍复杂)。
</p>
<div class="structure-diagram">
Vue 结构示意:<br /><br />
&lt;div class="pl-stop-product-dual-list"&gt;<br />
&nbsp;&nbsp;&lt;article v-for="row in products" class="pl-stop-product-dual-item"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="pl-stop-product-dual-item__readonly"&gt;...5 列只读&lt;/div&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;div class="pl-stop-product-dual-item__editable"&gt;...数量/包装/送货/备注/删&lt;/div&gt;<br />
&nbsp;&nbsp;&lt;/article&gt;<br />
&lt;/div&gt;
</div>
<div class="pros-cons">
<div>
<h4>与单行表对比</h4>
<ul>
<li>列数不变,只是<strong>换行承载</strong></li>
<li>用户心智:「还是一张产品表,只是每条高一点」</li>
<li>装货 / 送货 pane 复用同一组件</li>
</ul>
</div>
<div>
<h4>推荐 A 而非 B/C</h4>
<ul>
<li>A 只读/编辑<strong>物理分行</strong>,与业务语义一致</li>
<li>B 数量提前适合「只改数」但只读字段弱化</li>
<li>C 第 2 行仍偏挤</li>
</ul>
</div>
</div>
</section>
</div>
<script>
document.querySelectorAll('.scheme-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.scheme-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.scheme-panel').forEach(p => p.classList.remove('active'));
tab.classList.add('active');
document.getElementById('panel-' + tab.dataset.scheme).classList.add('active');
});
});
</script>
</body>
</html>