|
|
@@ -0,0 +1,470 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8" />
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
|
+ <title>协议单审核 · 列表模式(已定稿预览)</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;
|
|
|
+ --bg-page: #f8fafc;
|
|
|
+ --panel: #ffffff;
|
|
|
+ --text: #0f172a;
|
|
|
+ --text-secondary: #334155;
|
|
|
+ --text-muted: #64748b;
|
|
|
+ --border: #e2e8f0;
|
|
|
+ --radius: 10px;
|
|
|
+ --radius-sm: 8px;
|
|
|
+ --warning: #d97706;
|
|
|
+ --warning-bg: #fffbeb;
|
|
|
+ --danger: #dc2626;
|
|
|
+ --danger-bg: #fef2f2;
|
|
|
+ }
|
|
|
+ * { box-sizing: border-box; }
|
|
|
+ body {
|
|
|
+ margin: 0;
|
|
|
+ font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: var(--text);
|
|
|
+ background: var(--bg-page);
|
|
|
+ }
|
|
|
+ .page { max-width: 100%; margin: 0 auto; padding: 24px 20px 80px; }
|
|
|
+ .hero { max-width: 1100px; margin-bottom: 18px; }
|
|
|
+ .hero h1 {
|
|
|
+ margin: 0 0 8px;
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 700;
|
|
|
+ letter-spacing: -0.02em;
|
|
|
+ }
|
|
|
+ .hero h1::before {
|
|
|
+ content: "";
|
|
|
+ display: inline-block;
|
|
|
+ width: 4px;
|
|
|
+ height: 1.1em;
|
|
|
+ margin-right: 10px;
|
|
|
+ vertical-align: -0.15em;
|
|
|
+ border-radius: 2px;
|
|
|
+ background: var(--primary);
|
|
|
+ }
|
|
|
+ .hero p { margin: 0 0 8px; color: var(--text-muted); max-width: 920px; }
|
|
|
+ .context-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
|
|
|
+ .pill {
|
|
|
+ display: inline-flex; align-items: center;
|
|
|
+ padding: 4px 10px; border-radius: 999px; font-size: 12px;
|
|
|
+ background: var(--primary-bg); color: var(--primary-dark); border: 1px solid #a7f3d0;
|
|
|
+ }
|
|
|
+ .pill.muted { background: #f1f5f9; color: var(--text-muted); border-color: var(--border); }
|
|
|
+
|
|
|
+ .decisions {
|
|
|
+ max-width: 1100px;
|
|
|
+ margin: 0 0 18px;
|
|
|
+ padding: 14px 16px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: var(--radius);
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+ .decisions h3 { margin: 0 0 8px; font-size: 14px; }
|
|
|
+ .decisions ul { margin: 0; padding-left: 18px; color: var(--text-secondary); }
|
|
|
+ .decisions li { margin: 4px 0; }
|
|
|
+
|
|
|
+ .panel {
|
|
|
+ background: var(--panel);
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: var(--radius);
|
|
|
+ box-shadow: 0 1px 3px rgba(15, 23, 42, 0.05);
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .panel-top { padding: 14px 18px 10px; border-bottom: 1px solid var(--border); }
|
|
|
+ .panel-top h2 { margin: 0; font-size: 15px; font-weight: 600; }
|
|
|
+ .panel-top h2::before {
|
|
|
+ content: "";
|
|
|
+ display: inline-block;
|
|
|
+ width: 3px;
|
|
|
+ height: 1em;
|
|
|
+ margin-right: 8px;
|
|
|
+ vertical-align: -0.1em;
|
|
|
+ border-radius: 2px;
|
|
|
+ background: var(--primary);
|
|
|
+ }
|
|
|
+ .panel-top .sub { margin: 6px 0 0; font-size: 13px; color: var(--text-muted); }
|
|
|
+
|
|
|
+ .filter-block { padding: 12px 18px 8px; border-bottom: 1px solid var(--border); }
|
|
|
+ .filter-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
+ gap: 10px;
|
|
|
+ }
|
|
|
+ .field label {
|
|
|
+ display: block;
|
|
|
+ font-size: 11px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+ .field .ctrl {
|
|
|
+ height: 36px;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: var(--radius-sm);
|
|
|
+ background: #fff;
|
|
|
+ padding: 0 12px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ color: var(--text-muted);
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+ .filter-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 8px;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .toolbar {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 10px 18px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ }
|
|
|
+ .sel { font-size: 13px; color: var(--text-secondary); margin-right: 4px; }
|
|
|
+ .sel b { color: var(--primary-dark); }
|
|
|
+
|
|
|
+ .btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ height: 32px;
|
|
|
+ padding: 0 12px;
|
|
|
+ border-radius: var(--radius-sm);
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ background: #fff;
|
|
|
+ color: var(--text-secondary);
|
|
|
+ }
|
|
|
+ .btn.main {
|
|
|
+ background: var(--primary);
|
|
|
+ border-color: var(--primary);
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-scroll { overflow-x: auto; }
|
|
|
+ table.list {
|
|
|
+ width: 100%;
|
|
|
+ border-collapse: collapse;
|
|
|
+ font-size: 12px;
|
|
|
+ min-width: 1540px;
|
|
|
+ }
|
|
|
+ table.list th,
|
|
|
+ table.list td {
|
|
|
+ padding: 8px 10px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ text-align: center;
|
|
|
+ vertical-align: middle;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ table.list th {
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text-muted);
|
|
|
+ background: #f8fafc;
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
+ table.list td.left { text-align: left; }
|
|
|
+ table.list tr.batch-a td { background: #fff; }
|
|
|
+ table.list tr.batch-b td { background: #fafbfc; }
|
|
|
+ table.list tr:hover td { background: #f1f5f9 !important; }
|
|
|
+ table.list tr.group-a { box-shadow: inset 3px 0 0 #10b981; }
|
|
|
+ table.list tr.group-b { box-shadow: inset 3px 0 0 #94a3b8; }
|
|
|
+ table.list tr.alert-row td { color: var(--danger); }
|
|
|
+
|
|
|
+ .mono {
|
|
|
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ .muted { color: var(--text-muted); }
|
|
|
+ .name-strong { font-weight: 600; }
|
|
|
+
|
|
|
+ .tag {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 1px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 1.6;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ }
|
|
|
+ .tag.success { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
|
|
|
+ .tag.warning { background: #fffbeb; color: #b45309; border-color: #fde68a; }
|
|
|
+ .tag.info { background: #f1f5f9; color: #64748b; border-color: var(--border); }
|
|
|
+
|
|
|
+ .op-row { display: inline-flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
|
|
|
+ .op {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 26px;
|
|
|
+ padding: 0 8px;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: 6px;
|
|
|
+ background: #fff;
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-secondary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .pager {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 12px 18px;
|
|
|
+ border-top: 1px solid var(--border);
|
|
|
+ font-size: 13px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .callout {
|
|
|
+ margin-top: 16px;
|
|
|
+ max-width: 1100px;
|
|
|
+ padding: 12px 14px;
|
|
|
+ border-radius: var(--radius-sm);
|
|
|
+ background: var(--primary-bg);
|
|
|
+ border: 1px solid #a7f3d0;
|
|
|
+ font-size: 13px;
|
|
|
+ color: var(--primary-dark);
|
|
|
+ }
|
|
|
+ .note {
|
|
|
+ margin-top: 10px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-muted);
|
|
|
+ max-width: 1100px;
|
|
|
+ }
|
|
|
+ .pay-multi {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 2px;
|
|
|
+ line-height: 1.35;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ <div class="page">
|
|
|
+ <div class="hero">
|
|
|
+ <h1>协议单审核 · 列表模式(已定稿预览)</h1>
|
|
|
+ <p>
|
|
|
+ 将 <code>/#/market/cell-storage/protocol-audit?tab=cell_storage</code> 从卡片改为
|
|
|
+ <strong>纯扁平行列表</strong>(一行一样本,协议字段重复),列对齐客户 Excel。
|
|
|
+ </p>
|
|
|
+ <div class="context-bar">
|
|
|
+ <span class="pill">纯扁平行 · 已确认</span>
|
|
|
+ <span class="pill">年月日 → 采集日期 · 已确认</span>
|
|
|
+ <span class="pill">是否同存 = 样本数 ≥ 2</span>
|
|
|
+ <span class="pill muted">P02 · Fresh Mint</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="decisions">
|
|
|
+ <h3>已确认决策</h3>
|
|
|
+ <ul>
|
|
|
+ <li><strong>行粒度:</strong>一行一样本;同一协议多样本占多行,协议字段重复显示(不做 rowspan)。</li>
|
|
|
+ <li><strong>采集日期:</strong>原 Excel「年 / 月 / 日」合并为一列,取值自 <code>sampleCollectTime</code> 的日期部分(如 2025-09-15)。</li>
|
|
|
+ <li><strong>采集时间:</strong>保留完整时间列(含时分)。</li>
|
|
|
+ <li><strong>是否同存:</strong>计算列,不落库;同协议样本数 ≥ 2 →「是」,否则「否」(同协议各行相同)。</li>
|
|
|
+ <li><strong>操作列:</strong>保留审核 / 查看 / 编辑 / 删除(Excel 无,系统需要);批量操作按协议 ID 去重。</li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="panel">
|
|
|
+ <div class="panel-top">
|
|
|
+ <h2>列表预览 · 纯扁平行</h2>
|
|
|
+ <p class="sub">
|
|
|
+ 郭梦朵协议 ZKZX34000849 含 2 个样本 → 占两行,是否同存均为「是」;左侧绿条仅作示意分组(实现可不加)。
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="filter-block">
|
|
|
+ <div class="filter-grid">
|
|
|
+ <div class="field"><label>关键词</label><div class="ctrl">姓名/身份证号/电话/入库编码</div></div>
|
|
|
+ <div class="field"><label>协议状态</label><div class="ctrl">全部</div></div>
|
|
|
+ <div class="field"><label>创建时间</label><div class="ctrl">开始日期 至 结束日期</div></div>
|
|
|
+ <div class="field"><label>样本采集时间</label><div class="ctrl">开始日期 至 结束日期</div></div>
|
|
|
+ </div>
|
|
|
+ <div class="filter-actions">
|
|
|
+ <span class="btn">重置</span>
|
|
|
+ <span class="btn main">搜索</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="toolbar">
|
|
|
+ <span class="sel">已选 <b>0</b> 项</span>
|
|
|
+ <span class="btn main">新增</span>
|
|
|
+ <span class="btn">退费登记</span>
|
|
|
+ <span class="btn">审核</span>
|
|
|
+ <span class="btn">协议生效</span>
|
|
|
+ <span class="btn">协议过期</span>
|
|
|
+ <span class="btn">协议作废</span>
|
|
|
+ <span class="btn">协议转科研</span>
|
|
|
+ <span class="btn">批量删除</span>
|
|
|
+ </div>
|
|
|
+ <div class="table-scroll">
|
|
|
+ <table class="list">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>选</th>
|
|
|
+ <th>序号</th>
|
|
|
+ <th>采集日期</th>
|
|
|
+ <th>实验室流转编号</th>
|
|
|
+ <th>母亲姓名</th>
|
|
|
+ <th>协议编号</th>
|
|
|
+ <th>样本类型</th>
|
|
|
+ <th>是否同存</th>
|
|
|
+ <th>采集地区</th>
|
|
|
+ <th>采集医院</th>
|
|
|
+ <th>采集时间</th>
|
|
|
+ <th>缴费方式</th>
|
|
|
+ <th>首期缴费时间</th>
|
|
|
+ <th>市场专员</th>
|
|
|
+ <th>地区经理</th>
|
|
|
+ <th>运输方式</th>
|
|
|
+ <th>操作</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr class="batch-a group-a">
|
|
|
+ <td><input type="checkbox" /></td>
|
|
|
+ <td>1</td>
|
|
|
+ <td>2025-09-15</td>
|
|
|
+ <td class="mono left">B0000004</td>
|
|
|
+ <td class="name-strong">郭梦朵</td>
|
|
|
+ <td class="mono left">ZKZX34000849</td>
|
|
|
+ <td class="left">围产期造血干细胞</td>
|
|
|
+ <td><span class="tag warning">是</span></td>
|
|
|
+ <td>亳州区域</td>
|
|
|
+ <td class="left">涡阳县人民医院</td>
|
|
|
+ <td class="left">2025-09-15 08:51</td>
|
|
|
+ <td><span class="tag success">趸交</span></td>
|
|
|
+ <td class="left">2025-09-15 09:20</td>
|
|
|
+ <td>马丽</td>
|
|
|
+ <td>张颖</td>
|
|
|
+ <td>专线车</td>
|
|
|
+ <td>
|
|
|
+ <div class="op-row">
|
|
|
+ <span class="op">审核</span>
|
|
|
+ <span class="op">查看</span>
|
|
|
+ <span class="op">编辑</span>
|
|
|
+ <span class="op">删除</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr class="batch-a group-a">
|
|
|
+ <td><input type="checkbox" /></td>
|
|
|
+ <td>2</td>
|
|
|
+ <td>2025-09-15</td>
|
|
|
+ <td class="mono left">B0000004A</td>
|
|
|
+ <td class="name-strong">郭梦朵</td>
|
|
|
+ <td class="mono left">ZKZX34000849</td>
|
|
|
+ <td class="left">围产期间充质干细胞</td>
|
|
|
+ <td><span class="tag warning">是</span></td>
|
|
|
+ <td>亳州区域</td>
|
|
|
+ <td class="left">涡阳县人民医院</td>
|
|
|
+ <td class="left">2025-09-15 08:51</td>
|
|
|
+ <td><span class="tag warning">分期</span></td>
|
|
|
+ <td class="left">
|
|
|
+ <div class="pay-multi">
|
|
|
+ <span>2025-09-15 09:20</span>
|
|
|
+ <span>2025-10-15 10:05</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ <td>马丽</td>
|
|
|
+ <td>张颖</td>
|
|
|
+ <td>专线车</td>
|
|
|
+ <td>
|
|
|
+ <div class="op-row">
|
|
|
+ <span class="op">审核</span>
|
|
|
+ <span class="op">查看</span>
|
|
|
+ <span class="op">编辑</span>
|
|
|
+ <span class="op">删除</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr class="batch-b group-b alert-row">
|
|
|
+ <td><input type="checkbox" /></td>
|
|
|
+ <td>3</td>
|
|
|
+ <td>2025-10-10</td>
|
|
|
+ <td class="mono left muted">—</td>
|
|
|
+ <td class="name-strong">邵悦</td>
|
|
|
+ <td class="mono left">ZKZX34000861</td>
|
|
|
+ <td class="left">围产期造血干细胞</td>
|
|
|
+ <td><span class="tag info">否</span></td>
|
|
|
+ <td>亳州区域</td>
|
|
|
+ <td class="left">涡阳县中医院</td>
|
|
|
+ <td class="left">2025-10-10 14:22</td>
|
|
|
+ <td><span class="tag warning">分期</span></td>
|
|
|
+ <td class="left">
|
|
|
+ <div class="pay-multi">
|
|
|
+ <span>2025-10-10 15:01</span>
|
|
|
+ <span>2025-11-10 09:18</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ <td>张慧茹</td>
|
|
|
+ <td>张颖</td>
|
|
|
+ <td>专线车</td>
|
|
|
+ <td>
|
|
|
+ <div class="op-row">
|
|
|
+ <span class="op">审核</span>
|
|
|
+ <span class="op">查看</span>
|
|
|
+ <span class="op">编辑</span>
|
|
|
+ <span class="op">删除</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr class="batch-a group-b">
|
|
|
+ <td><input type="checkbox" /></td>
|
|
|
+ <td>4</td>
|
|
|
+ <td>2025-10-12</td>
|
|
|
+ <td class="mono left">B0000007</td>
|
|
|
+ <td class="name-strong">尹璐</td>
|
|
|
+ <td class="mono left">ZKZX34000870</td>
|
|
|
+ <td class="left">围产期造血干细胞</td>
|
|
|
+ <td><span class="tag info">否</span></td>
|
|
|
+ <td>亳州区域</td>
|
|
|
+ <td class="left">利辛县人民医院</td>
|
|
|
+ <td class="left">2025-10-12 11:05</td>
|
|
|
+ <td><span class="tag success">趸交</span></td>
|
|
|
+ <td class="left">2025-10-12 11:40</td>
|
|
|
+ <td>马丽</td>
|
|
|
+ <td>张颖</td>
|
|
|
+ <td>专线车</td>
|
|
|
+ <td>
|
|
|
+ <div class="op-row">
|
|
|
+ <span class="op">审核</span>
|
|
|
+ <span class="op">查看</span>
|
|
|
+ <span class="op">编辑</span>
|
|
|
+ <span class="op">删除</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ <div class="pager">共 3 条协议 / 4 行样本 · 接口分页仍按协议 · 前端 flatten · < 1 ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="callout">
|
|
|
+ <strong>实现要点:</strong>接口仍返回协议列表(含 <code>sampleItems[]</code>);前端 flatten 成样本行;无样本时仍保留 1 行(流转编号等为空)。
|
|
|
+ 勾选多样本行时,批量审核/删除按 <code>protocolId</code> 去重。
|
|
|
+ </div>
|
|
|
+ <p class="note">
|
|
|
+ 文件:<code>docs/demos/2026-10-09-protocol-audit-list-mode-demo.html</code>
|
|
|
+ · 若本预览 OK,回复「设计没问题」或指出要改的点,我再写正式设计文档并进入实现计划。
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+</body>
|
|
|
+</html>
|