feat: update audit platform workspace
This commit is contained in:
@@ -0,0 +1,971 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>评查详情纵向抽屉原型</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary: #00684a;
|
||||
--primary-soft: rgba(0, 104, 74, 0.08);
|
||||
--border: #d9e1e7;
|
||||
--text: #172033;
|
||||
--muted: #64748b;
|
||||
--bg: #eef2f5;
|
||||
--panel: #ffffff;
|
||||
--danger: #dc2626;
|
||||
--warn: #d97706;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", sans-serif;
|
||||
color: var(--text);
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
height: 52px;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 0 18px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--panel);
|
||||
}
|
||||
|
||||
.title {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.title strong {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.title span {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.mode-switch {
|
||||
display: inline-flex;
|
||||
padding: 3px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 7px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.mode-switch button,
|
||||
.top-action {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.mode-switch button {
|
||||
height: 28px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mode-switch button.active {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.top-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.top-action {
|
||||
height: 32px;
|
||||
padding: 0 11px;
|
||||
border: 1px solid var(--border);
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.top-action.primary {
|
||||
border-color: var(--primary);
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.workspace {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 260px minmax(0, 1fr) 58px;
|
||||
gap: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.rules {
|
||||
min-width: 0;
|
||||
border-right: 1px solid var(--border);
|
||||
background: #fbfcfd;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.rules-head {
|
||||
flex: 0 0 auto;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 14px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.rules-list {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.rule-item {
|
||||
width: 100%;
|
||||
min-height: 46px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
margin-bottom: 6px;
|
||||
padding: 8px 9px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 7px;
|
||||
background: transparent;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rule-item.active {
|
||||
border-color: rgba(0, 104, 74, 0.22);
|
||||
background: var(--primary-soft);
|
||||
}
|
||||
|
||||
.rule-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.rule-dot.error {
|
||||
background: var(--danger);
|
||||
}
|
||||
|
||||
.rule-dot.warn {
|
||||
background: var(--warn);
|
||||
}
|
||||
|
||||
.rule-text {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.rule-text strong {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.rule-text span {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
font-size: 10.5px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.preview {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
position: relative;
|
||||
background: #dfe6ec;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.preview-toolbar {
|
||||
height: 40px;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid #cbd5df;
|
||||
background: #f8fafc;
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.pages {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 24px 0 80px;
|
||||
}
|
||||
|
||||
.page {
|
||||
width: min(760px, calc(100% - 64px));
|
||||
min-height: 900px;
|
||||
margin: 0 auto 22px;
|
||||
padding: 52px 58px;
|
||||
background: #fff;
|
||||
box-shadow: 0 14px 42px rgba(15, 23, 42, 0.12);
|
||||
line-height: 1.8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.page h2 {
|
||||
margin: 0 0 28px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: rgba(0, 104, 74, 0.13);
|
||||
outline: 1px solid rgba(0, 104, 74, 0.45);
|
||||
}
|
||||
|
||||
.rail {
|
||||
border-left: 1px solid var(--border);
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 8px 6px;
|
||||
gap: 6px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.rail-button {
|
||||
width: 44px;
|
||||
min-height: 48px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 7px;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.rail-button:hover,
|
||||
.rail-button.active {
|
||||
border-color: rgba(0, 104, 74, 0.18);
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.rail-button .icon {
|
||||
font-size: 17px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.rail-button .label {
|
||||
font-size: 10px;
|
||||
writing-mode: vertical-rl;
|
||||
letter-spacing: 0;
|
||||
line-height: 1.1;
|
||||
max-height: 54px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 999px;
|
||||
background: var(--danger);
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.drawer-backdrop {
|
||||
position: fixed;
|
||||
inset: 52px 58px 0 0;
|
||||
background: rgba(15, 23, 42, 0.18);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 160ms ease;
|
||||
z-index: 25;
|
||||
}
|
||||
|
||||
.drawer-backdrop.open {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.drawer {
|
||||
position: fixed;
|
||||
top: 52px;
|
||||
right: 58px;
|
||||
bottom: 0;
|
||||
width: 460px;
|
||||
max-width: calc(100vw - 120px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-left: 1px solid var(--border);
|
||||
background: #fff;
|
||||
box-shadow: -18px 0 36px rgba(15, 23, 42, 0.18);
|
||||
transform: translateX(calc(100% + 24px));
|
||||
transition: transform 180ms ease;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.drawer.open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.drawer.wide {
|
||||
width: min(980px, calc(100vw - 116px));
|
||||
}
|
||||
|
||||
.drawer-head {
|
||||
height: 48px;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 14px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.drawer-title {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.drawer-title strong {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.drawer-title span {
|
||||
display: block;
|
||||
margin-top: 1px;
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drawer-body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.drawer-foot {
|
||||
flex: 0 0 auto;
|
||||
min-height: 52px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
border-top: 1px solid var(--border);
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.btn {
|
||||
height: 34px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 0 12px;
|
||||
background: #fff;
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
border-color: var(--primary);
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn.ghost-primary {
|
||||
border-color: rgba(0, 104, 74, 0.35);
|
||||
color: var(--primary);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.card-head {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 12px;
|
||||
font-size: 12px;
|
||||
color: #334155;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.status-row {
|
||||
display: grid;
|
||||
grid-template-columns: 90px 1fr;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.status-row span:first-child {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.field-item,
|
||||
.opinion-item {
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
}
|
||||
|
||||
.field-item:last-child,
|
||||
.opinion-item:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.field-item strong,
|
||||
.opinion-item strong {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.field-item span,
|
||||
.opinion-item span {
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.compare-grid {
|
||||
min-height: calc(100vh - 180px);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.compare-pane {
|
||||
min-width: 0;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.compare-pane + .compare-pane {
|
||||
border-left: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.compare-pane h4 {
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.compare-text {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.8;
|
||||
white-space: pre-wrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.diff-del {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.diff-add {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 22px;
|
||||
transform: translateX(-50%) translateY(20px);
|
||||
min-width: 220px;
|
||||
padding: 9px 12px;
|
||||
border-radius: 7px;
|
||||
background: #172033;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 160ms ease, transform 160ms ease;
|
||||
z-index: 50;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.workspace {
|
||||
grid-template-columns: 0 minmax(0, 1fr) 54px;
|
||||
}
|
||||
|
||||
.rules {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.drawer-backdrop {
|
||||
inset: 52px 54px 0 0;
|
||||
}
|
||||
|
||||
.drawer,
|
||||
.drawer.wide {
|
||||
right: 54px;
|
||||
width: calc(100vw - 54px);
|
||||
max-width: calc(100vw - 54px);
|
||||
}
|
||||
|
||||
.topbar {
|
||||
gap: 8px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.top-actions {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
<header class="topbar">
|
||||
<div class="title">
|
||||
<strong id="pageTitle">合同评查详情 - 采购合同示例.docx</strong>
|
||||
<span id="pageMeta">合同编号:HT-2026-0523 | DOCX | 18页 | 当前布局为预览原型</span>
|
||||
</div>
|
||||
<div class="mode-switch" aria-label="切换页面模式">
|
||||
<button id="normalMode" class="active" type="button">普通评查</button>
|
||||
<button id="crossMode" type="button">交叉评查</button>
|
||||
</div>
|
||||
<div class="top-actions">
|
||||
<button class="top-action" type="button" data-toast="返回上一页">返回</button>
|
||||
<button class="top-action" type="button" data-toast="开始下载文档">下载</button>
|
||||
<button id="confirmButton" class="top-action primary" type="button" data-toast="确认评查结果">确认评查结果</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="workspace">
|
||||
<aside class="rules">
|
||||
<div class="rules-head">
|
||||
<span>评查点目录</span>
|
||||
<span style="font-size: 11px; color: var(--muted);">29</span>
|
||||
</div>
|
||||
<div class="rules-list">
|
||||
<button class="rule-item active" type="button">
|
||||
<span class="rule-dot error"></span>
|
||||
<span class="rule-text"><strong>合同主体信息不完整</strong><span>第 2 页 | 风险项</span></span>
|
||||
</button>
|
||||
<button class="rule-item" type="button">
|
||||
<span class="rule-dot warn"></span>
|
||||
<span class="rule-text"><strong>付款节点表述不一致</strong><span>第 5 页 | 待复核</span></span>
|
||||
</button>
|
||||
<button class="rule-item" type="button">
|
||||
<span class="rule-dot"></span>
|
||||
<span class="rule-text"><strong>违约责任条款完整</strong><span>第 8 页 | 通过</span></span>
|
||||
</button>
|
||||
<button class="rule-item" type="button">
|
||||
<span class="rule-dot warn"></span>
|
||||
<span class="rule-text"><strong>争议解决方式需确认</strong><span>第 12 页 | 待复核</span></span>
|
||||
</button>
|
||||
<button class="rule-item" type="button">
|
||||
<span class="rule-dot"></span>
|
||||
<span class="rule-text"><strong>签章区域格式符合要求</strong><span>第 18 页 | 通过</span></span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section class="preview">
|
||||
<div class="preview-toolbar">
|
||||
<span>文档预览</span>
|
||||
<span>缩放 100% | 当前页 2 / 18</span>
|
||||
</div>
|
||||
<div class="pages">
|
||||
<article class="page">
|
||||
<h2>采购合同</h2>
|
||||
<p>甲方:某某烟草公司</p>
|
||||
<p>乙方:某某供应商有限公司</p>
|
||||
<p class="highlight">经评查发现,乙方统一社会信用代码未在合同主体信息中完整展示,建议补充完整后再提交确认。</p>
|
||||
<p>双方根据相关法律法规,经友好协商,就采购事项达成本合同。</p>
|
||||
<p>付款方式:合同签订后支付 30%,验收通过后支付 60%,质保期满后支付 10%。</p>
|
||||
<p>违约责任:任一方违反本合同约定,应承担相应违约责任。</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<nav id="rail" class="rail" aria-label="业务功能"></nav>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="backdrop" class="drawer-backdrop"></div>
|
||||
<aside id="drawer" class="drawer" aria-live="polite">
|
||||
<header class="drawer-head">
|
||||
<div class="drawer-title">
|
||||
<strong id="drawerTitle">评查结果</strong>
|
||||
<span id="drawerSubtitle">查看当前选中评查点的详情</span>
|
||||
</div>
|
||||
<button id="drawerClose" class="icon-button" type="button" aria-label="关闭">×</button>
|
||||
</header>
|
||||
<div id="drawerBody" class="drawer-body"></div>
|
||||
<footer id="drawerFoot" class="drawer-foot"></footer>
|
||||
</aside>
|
||||
|
||||
<div id="toast" class="toast"></div>
|
||||
|
||||
<script>
|
||||
const state = {
|
||||
mode: "normal",
|
||||
activeTab: null,
|
||||
hasTemplate: false,
|
||||
};
|
||||
|
||||
const rail = document.getElementById("rail");
|
||||
const drawer = document.getElementById("drawer");
|
||||
const backdrop = document.getElementById("backdrop");
|
||||
const drawerTitle = document.getElementById("drawerTitle");
|
||||
const drawerSubtitle = document.getElementById("drawerSubtitle");
|
||||
const drawerBody = document.getElementById("drawerBody");
|
||||
const drawerFoot = document.getElementById("drawerFoot");
|
||||
const toast = document.getElementById("toast");
|
||||
|
||||
const normalTabs = [
|
||||
{ key: "result", label: "评查结果", icon: "✓", subtitle: "查看当前选中评查点的详情" },
|
||||
{ key: "fields", label: "抽取字段", icon: "▦", subtitle: "查看文档字段抽取结果" },
|
||||
{ key: "compare", label: "结构比对", icon: "⇄", subtitle: "对比原文和模板合同结构", wide: true },
|
||||
{ key: "fileinfo", label: "文件信息", icon: "i", subtitle: "查看文件基础信息和评查信息" },
|
||||
];
|
||||
|
||||
const crossTabs = [
|
||||
{ key: "result", label: "评查结果", icon: "✓", subtitle: "查看当前选中评查点的详情" },
|
||||
{ key: "fields", label: "抽取字段", icon: "▦", subtitle: "查看文档字段抽取结果" },
|
||||
{ key: "compare", label: "结构比对", icon: "⇄", subtitle: "对比原文和模板合同结构", wide: true },
|
||||
{ key: "crossOpinions", label: "交叉意见", icon: "☰", subtitle: "查看和提交评查点意见", badge: 3 },
|
||||
{ key: "supplementOpinions", label: "补充意见", icon: "+", subtitle: "查看和提交补充意见", badge: 1 },
|
||||
{ key: "fileinfo", label: "文件信息", icon: "i", subtitle: "查看文件基础信息和评查信息" },
|
||||
];
|
||||
|
||||
function getTabs() {
|
||||
return state.mode === "cross" ? crossTabs : normalTabs;
|
||||
}
|
||||
|
||||
function showToast(message) {
|
||||
toast.textContent = message;
|
||||
toast.classList.add("show");
|
||||
window.clearTimeout(showToast.timer);
|
||||
showToast.timer = window.setTimeout(() => toast.classList.remove("show"), 1600);
|
||||
}
|
||||
|
||||
function renderRail() {
|
||||
rail.innerHTML = "";
|
||||
getTabs().forEach((tab) => {
|
||||
const button = document.createElement("button");
|
||||
button.className = `rail-button ${state.activeTab === tab.key ? "active" : ""}`;
|
||||
button.type = "button";
|
||||
button.title = tab.label;
|
||||
button.innerHTML = `
|
||||
<span class="icon">${tab.icon}</span>
|
||||
<span class="label">${tab.label}</span>
|
||||
${tab.badge ? `<span class="badge">${tab.badge}</span>` : ""}
|
||||
`;
|
||||
button.addEventListener("click", () => openTab(tab.key));
|
||||
rail.appendChild(button);
|
||||
});
|
||||
}
|
||||
|
||||
function openTab(key) {
|
||||
const tab = getTabs().find((item) => item.key === key);
|
||||
if (!tab) return;
|
||||
state.activeTab = key;
|
||||
drawerTitle.textContent = tab.label;
|
||||
drawerSubtitle.textContent = tab.subtitle;
|
||||
drawer.classList.toggle("wide", Boolean(tab.wide));
|
||||
drawerBody.innerHTML = renderDrawerBody(key);
|
||||
drawerFoot.innerHTML = renderDrawerFoot(key);
|
||||
drawer.classList.add("open");
|
||||
backdrop.classList.add("open");
|
||||
renderRail();
|
||||
bindDrawerActions();
|
||||
}
|
||||
|
||||
function closeDrawer() {
|
||||
state.activeTab = null;
|
||||
drawer.classList.remove("open");
|
||||
backdrop.classList.remove("open");
|
||||
renderRail();
|
||||
}
|
||||
|
||||
function renderDrawerBody(key) {
|
||||
if (key === "result") {
|
||||
return `
|
||||
<section class="card">
|
||||
<div class="card-head">合同主体信息不完整</div>
|
||||
<div class="card-body">
|
||||
<div class="status-row"><span>评查状态</span><strong style="color: var(--danger);">不通过</strong></div>
|
||||
<div class="status-row"><span>定位页码</span><span>第 2 页</span></div>
|
||||
<div class="status-row"><span>扣分</span><span>-3</span></div>
|
||||
<p>乙方主体信息缺少统一社会信用代码,建议补齐主体身份信息。</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<div class="card-head">AI 建议</div>
|
||||
<div class="card-body">请补充乙方统一社会信用代码,并与营业执照信息保持一致。</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
if (key === "fields") {
|
||||
return `
|
||||
<section class="card">
|
||||
<div class="card-head">抽取字段 29</div>
|
||||
<div class="card-body">
|
||||
<div class="field-item"><strong>甲方名称</strong><span>某某烟草公司 | 置信度 96% | 第 1 页</span></div>
|
||||
<div class="field-item"><strong>乙方名称</strong><span>某某供应商有限公司 | 置信度 94% | 第 1 页</span></div>
|
||||
<div class="field-item"><strong>乙方统一社会信用代码</strong><span style="color: var(--danger);">缺失 | 未定位</span></div>
|
||||
<div class="field-item"><strong>合同金额</strong><span>1,580,000.00 元 | 置信度 91% | 第 4 页</span></div>
|
||||
<div class="field-item"><strong>付款方式</strong><span>分阶段付款 | 置信度 88% | 第 5 页</span></div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
if (key === "compare") {
|
||||
const uploadLabel = state.hasTemplate ? "重新上传对比" : "上传模板对比";
|
||||
return `
|
||||
<section class="card">
|
||||
<div class="card-body" style="display:flex; align-items:center; justify-content:space-between; gap:12px;">
|
||||
<span>${state.hasTemplate ? "已上传模板合同,当前显示结构差异。" : "当前文档类型暂未上传模板合同,可先上传模板后再对比。"}</span>
|
||||
<button class="btn ghost-primary" type="button" data-action="upload-template">${uploadLabel}</button>
|
||||
</div>
|
||||
</section>
|
||||
${state.hasTemplate ? `
|
||||
<div class="compare-grid">
|
||||
<section class="compare-pane">
|
||||
<h4>原始版本</h4>
|
||||
<div class="compare-text">第一条 合同主体
|
||||
甲方:某某烟草公司
|
||||
乙方:某某供应商有限公司
|
||||
<span class="diff-del">乙方信用代码:未填写</span>
|
||||
|
||||
第二条 付款方式
|
||||
合同签订后支付 30%。</div>
|
||||
</section>
|
||||
<section class="compare-pane">
|
||||
<h4>模板版本</h4>
|
||||
<div class="compare-text">第一条 合同主体
|
||||
甲方:某某烟草公司
|
||||
乙方:某某供应商有限公司
|
||||
<span class="diff-add">乙方信用代码:应填写统一社会信用代码</span>
|
||||
|
||||
第二条 付款方式
|
||||
合同签订后支付 30%。</div>
|
||||
</section>
|
||||
</div>
|
||||
` : `
|
||||
<section class="card">
|
||||
<div class="card-body" style="text-align:center; padding:48px 20px;">
|
||||
<div style="font-size:34px; color:#94a3b8;">⇄</div>
|
||||
<strong style="display:block; margin-top:10px;">暂无可用模板,无法进行结构比对</strong>
|
||||
<p style="margin:8px auto 0; max-width:420px; color:var(--muted);">上传模板后,这里会展示原始文档和模板合同的结构差异。</p>
|
||||
</div>
|
||||
</section>
|
||||
`}
|
||||
`;
|
||||
}
|
||||
|
||||
if (key === "crossOpinions") {
|
||||
return `
|
||||
<section class="card">
|
||||
<div class="card-head">交叉意见 3</div>
|
||||
<div class="card-body">
|
||||
<div class="opinion-item"><strong>梅州评查员</strong><span>建议将该项从“不通过”调整为“待复核”。</span></div>
|
||||
<div class="opinion-item"><strong>省级复核员</strong><span>主体信息缺失属实,维持不通过。</span></div>
|
||||
<div class="opinion-item"><strong>系统汇总</strong><span>当前 2 人赞同,1 人待投票。</span></div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
if (key === "supplementOpinions") {
|
||||
return `
|
||||
<section class="card">
|
||||
<div class="card-head">补充意见 1</div>
|
||||
<div class="card-body">
|
||||
<div class="opinion-item"><strong>补充风险</strong><span>建议额外检查供应商资质附件是否齐全。</span></div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<section class="card">
|
||||
<div class="card-head">文件信息</div>
|
||||
<div class="card-body">
|
||||
<div class="status-row"><span>文件名称</span><span>采购合同示例.docx</span></div>
|
||||
<div class="status-row"><span>文件类型</span><span>合同</span></div>
|
||||
<div class="status-row"><span>上传时间</span><span>2026/5/23 10:18:22</span></div>
|
||||
<div class="status-row"><span>评查模型</span><span>LeAudit 默认模型</span></div>
|
||||
<div class="status-row"><span>评查结果</span><span>存在风险项</span></div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderDrawerFoot(key) {
|
||||
if (key === "compare") {
|
||||
return `
|
||||
<button class="btn" type="button" data-action="close">关闭</button>
|
||||
<button class="btn ghost-primary" type="button" data-action="upload-template">${state.hasTemplate ? "重新上传对比" : "上传模板对比"}</button>
|
||||
`;
|
||||
}
|
||||
|
||||
if (key === "crossOpinions" || key === "supplementOpinions") {
|
||||
return `
|
||||
<button class="btn" type="button" data-action="close">关闭</button>
|
||||
<button class="btn primary" type="button" data-toast="提交意见弹窗">提交意见</button>
|
||||
`;
|
||||
}
|
||||
|
||||
if (key === "result") {
|
||||
return `
|
||||
<button class="btn" type="button" data-toast="开始下载文档">下载</button>
|
||||
<button class="btn primary" type="button" data-toast="${state.mode === "cross" ? "完成当前交叉评查" : "确认评查结果"}">${state.mode === "cross" ? "完成评查" : "确认评查结果"}</button>
|
||||
`;
|
||||
}
|
||||
|
||||
return `<button class="btn" type="button" data-action="close">关闭</button>`;
|
||||
}
|
||||
|
||||
function bindDrawerActions() {
|
||||
drawer.querySelectorAll("[data-action='close']").forEach((button) => {
|
||||
button.addEventListener("click", closeDrawer);
|
||||
});
|
||||
|
||||
drawer.querySelectorAll("[data-action='upload-template']").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
state.hasTemplate = true;
|
||||
showToast("模拟上传成功,已切换为重新上传对比");
|
||||
openTab("compare");
|
||||
});
|
||||
});
|
||||
|
||||
drawer.querySelectorAll("[data-toast]").forEach((button) => {
|
||||
button.addEventListener("click", () => showToast(button.dataset.toast));
|
||||
});
|
||||
}
|
||||
|
||||
function setMode(mode) {
|
||||
state.mode = mode;
|
||||
state.activeTab = null;
|
||||
document.getElementById("normalMode").classList.toggle("active", mode === "normal");
|
||||
document.getElementById("crossMode").classList.toggle("active", mode === "cross");
|
||||
document.getElementById("pageTitle").textContent = mode === "cross"
|
||||
? "交叉评查详情 - 采购合同示例.docx"
|
||||
: "合同评查详情 - 采购合同示例.docx";
|
||||
document.getElementById("pageMeta").textContent = mode === "cross"
|
||||
? "任务:梅州地区交叉评查 | DOCX | 18页 | 当前布局为预览原型"
|
||||
: "合同编号:HT-2026-0523 | DOCX | 18页 | 当前布局为预览原型";
|
||||
document.getElementById("confirmButton").textContent = mode === "cross" ? "完成评查" : "确认评查结果";
|
||||
closeDrawer();
|
||||
renderRail();
|
||||
}
|
||||
|
||||
document.getElementById("normalMode").addEventListener("click", () => setMode("normal"));
|
||||
document.getElementById("crossMode").addEventListener("click", () => setMode("cross"));
|
||||
document.getElementById("drawerClose").addEventListener("click", closeDrawer);
|
||||
backdrop.addEventListener("click", closeDrawer);
|
||||
document.querySelectorAll("[data-toast]").forEach((button) => {
|
||||
button.addEventListener("click", () => showToast(button.dataset.toast));
|
||||
});
|
||||
|
||||
document.querySelectorAll(".rule-item").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
document.querySelectorAll(".rule-item").forEach((item) => item.classList.remove("active"));
|
||||
button.classList.add("active");
|
||||
showToast("已切换评查点");
|
||||
if (state.activeTab === "result") openTab("result");
|
||||
});
|
||||
});
|
||||
|
||||
renderRail();
|
||||
openTab("result");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user