feat: integrate govdoc platform updates

This commit is contained in:
wren
2026-05-18 14:35:25 +08:00
parent a73826dc1d
commit 1bacfe41b7
10 changed files with 2151 additions and 92 deletions
@@ -0,0 +1,513 @@
# 内部公文前端拆分实施清单
## 1. 文档目的
本文档只解决一个问题:
- 在不改变“内部公文”业务语义的前提下,如何把当前前端实现拆成一套与“交叉评查”同级的独立页面架构
本文档关注的是:
- 页面编排边界
- 组件职责边界
- `govdoc``reviews / cross-checking` 的复用边界
- 分阶段实施顺序
本文档不做以下事情:
- 不改后端业务语义
- 不要求照搬旧项目代码
- 不把 `Collabora` 当成整个中栏预览架构
---
## 2. 结论先行
内部公文前端应按以下原则重构:
> **像交叉评查一样独立成页,但复用 reviews 的定位型预览能力。**
准确解释如下:
- 内部公文应有自己独立的页面 orchestrator
- 内部公文应有自己独立的业务组件层
- 内部公文应有自己独立的 TS service / adapter 层
- 中栏 PDF / DOCX 预览不应重新发明一套,而应优先复用 `reviews` 已有能力
- `Collabora` 只应作为 DOCX viewer,不应承担“问题定位主架构”
因此,目标不是:
- 把当前 `govdoc-audit` 页面继续补丁式扩写
而是:
- 把内部公文前端收敛为“独立页面编排 + 统一预览协议 + 独立业务壳”的平台化实现
---
## 3. 当前实现现状
## 3.1 当前内部公文前端入口
当前内部公文详情页主入口为:
- [components/govdoc-audit/audit.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/govdoc-audit/audit.tsx:1)
当前内部公文列表页主入口为:
- [components/govdoc-audit/audits.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/govdoc-audit/audits.tsx:1)
当前路由入口为:
- [app/(audit)/govdoc/audits/page.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/app/(audit)/govdoc/audits/page.tsx:1)
- [app/(audit)/govdoc/detail/[documentId]/page.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/app/(audit)/govdoc/detail/[documentId]/page.tsx:1)
当前详情页已经具备:
- 顶部摘要与报告下载操作
- 评查 / 结构 / 大纲 / 实体 tab
- 中栏文档视图
- 右栏 findings / checked rules 展示
问题不在于“没有功能”,而在于“页面职责混装”。
---
## 3.2 当前详情页耦合点
当前 [audit.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/govdoc-audit/audit.tsx:1) 同时承担了以下职责:
- 页面数据加载
- 顶部操作区渲染
- tab 状态切换
- 结果统计条渲染
- 中栏文档视图调度
- 右栏问题面板调度
- 规则弹窗调度
这会带来三个问题:
- 页面 orchestrator 和业务组件未分层
- 中栏预览协议没有向平台现有 `reviews` 能力对齐
- 右栏问题区与 `reviews / cross-checking` 的定位交互无法复用
---
## 3.3 当前中栏预览为什么不应继续沿现状扩写
当前内部公文中栏主要使用:
- [components/govdoc-audit/doc-view.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/govdoc-audit/doc-view.tsx:1)
而平台现有成熟的“定位型预览”能力在:
- [components/reviews/previewComponents/PdfPreviewTest.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/reviews/previewComponents/PdfPreviewTest.tsx:1)
- [components/reviews/previewComponents/DocxPreviewTest.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/reviews/previewComponents/DocxPreviewTest.tsx:1)
- [app/(audit)/reviews-test/ReviewsTestClient.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/app/(audit)/reviews-test/ReviewsTestClient.tsx:1)
- [app/(audit)/cross-checking/result/CrossCheckingResultClient.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/app/(audit)/cross-checking/result/CrossCheckingResultClient.tsx:1)
必须明确:
- PDF 中栏定位主能力不是 `Collabora`
- DOCX 中栏当前虽然使用 `CollaboraViewer`,但它承担的是文档渲染,不是完整的问题定位架构
如果内部公文要做到:
- 点击问题点后定位到对应页
- 对问题字段/段落做高亮
- 为后续“问题行定位”保留升级空间
则中栏必须对齐现有平台预览输入协议,而不是继续把 `DocView` 做成一套孤岛实现。
---
## 4. 目标架构
## 4.1 总体原则
前端目标架构应满足以下四条:
- 内部公文页面独立编排
- 中栏预览能力平台复用
- 业务面板 govdoc 自治
- 数据适配集中在 adapter 层
可以概括为:
> **govdoc 自己负责业务壳,platform 负责通用预览能力。**
---
## 4.2 目标目录结构
建议拆分为以下结构:
```text
legal-platform-frontend/
app/(audit)/govdoc/
audits/page.tsx
detail/[documentId]/page.tsx
components/govdoc-audit/
GovdocAuditListPage.tsx
GovdocAuditResultPage.tsx
GovdocSummaryHeader.tsx
GovdocFindingPanel.tsx
GovdocStructurePanel.tsx
GovdocOutlinePanel.tsx
GovdocEntityPanel.tsx
GovdocReportActions.tsx
lib/api/govdoc-audit/
api.ts
types.ts
adapters.ts
govdoc-routes.ts
```
说明如下:
- `page.tsx` 只保留路由入口职责
- `GovdocAuditResultPage.tsx` 负责详情页 orchestrator
- `GovdocAuditListPage.tsx` 负责列表页 orchestrator
- `Govdoc*Panel` 负责内部公文独有业务视图
- `adapters.ts` 负责把 govdoc 后端返回结果转成前端视图模型
---
## 4.3 页面编排职责
### 详情页 orchestrator
建议新增:
- `components/govdoc-audit/GovdocAuditResultPage.tsx`
该组件只负责:
- 读取 `documentId / runId`
- 调用 govdoc API
- 维护 tab 状态
- 维护当前激活问题点
- 维护当前预览定位目标
- 组装中栏与右栏
它不应承担:
- 具体 finding 卡片渲染细节
- 实体/结构/大纲具体 UI 细节
- 预览底层渲染逻辑
这部分应当参照:
- [CrossCheckingResultClient.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/app/(audit)/cross-checking/result/CrossCheckingResultClient.tsx:1)
---
### 列表页 orchestrator
建议新增:
- `components/govdoc-audit/GovdocAuditListPage.tsx`
该组件负责:
- 列表数据加载
- 筛选状态
- 批量操作状态
- 导出与删除
- 跳转详情页
它应继续保持内部公文自己的筛选语义,但 UI 节奏应向平台文档列表页靠拢。
列表页设计参照:
- [DocumentsListClient.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/app/(audit)/documents/list/DocumentsListClient.tsx:1)
---
## 5. 与 reviews / cross-checking 的复用边界
## 5.1 应复用的能力
内部公文应复用以下能力:
- PDF 中栏预览组件
- DOCX 中栏预览组件
- 问题点点击后的预览定位协议
- 页码跳转、高亮、bbox / charPositions 定位能力
优先复用对象:
- [PdfPreviewTest.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/reviews/previewComponents/PdfPreviewTest.tsx:1)
- [DocxPreviewTest.tsx](/home/wren-dev/Porject/leaudit-platform/legal-platform-frontend/components/reviews/previewComponents/DocxPreviewTest.tsx:1)
复用的是:
- 预览能力
- 定位协议
- 用户交互模型
不是:
- 合同业务语义
- 卷宗业务命名
- 旧页面外壳
---
## 5.2 不应复用的部分
以下部分不应直接复用:
- `reviews-test` 自身的业务标题、业务字段命名
- 合同/卷宗专有的右栏业务解释
- `cross-checking` 的评分协同、提议投票、交叉意见面板
原因是:
- 这些属于业务壳,而不是平台通用能力
内部公文应保留自己的:
- findings 口径
- checked rules 口径
- 结构 / 大纲 / 实体口径
- 报告下载口径
---
## 5.3 Collabora 的正确定位
`CollaboraViewer` 的边界必须明确:
- 它是 DOCX viewer
- 它可以承担跳页、文本高亮、编辑/只读查看
- 它不是内部公文详情页的业务 orchestrator
- 它也不是“问题行精确定位”的完整方案
因此:
- `Collabora` 只能留在 `DocxPreviewTest` 这一层
- 不应让 govdoc 页面继续直接围绕 `Collabora` 自己长出一套完整详情页体系
---
## 6. 必须新增的 adapter 层
## 6.1 为什么必须有 adapters.ts
当前 `lib/api/govdoc-audit` 下已有:
- `api.ts`
- `types.ts`
- `govdoc-routes.ts`
但还缺一层:
- `adapters.ts`
这层必须存在,因为它承担的是“业务结果语义 -> 预览与页面视图语义”的转换。
如果没有这层,后果会是:
- govdoc 页面自己维护一套 findings 展示模型
- reviews 页面自己维护一套 preview target 模型
- 同类定位交互会出现两套不兼容实现
---
## 6.2 adapters.ts 建议职责
`adapters.ts` 建议至少提供以下能力:
-`govdoc` 结果对象转换为结果页 view model
-`finding / checked_rule` 转换为右栏展示项
-`finding / paragraph / entity` 转换为中栏跳转目标
- 根据文件类型产出统一 preview target
- 将后端报告产物状态转换为按钮展示状态
建议输出的数据语义包括:
- `previewKind`
- `previewPath`
- `activeTarget`
- `findingItems`
- `summaryCards`
- `reportActions`
- `structureItems`
- `outlineItems`
- `entityItems`
这样后续页面层只编排,不解释后端字段细节。
---
## 7. 分阶段实施顺序
## 7.1 第一阶段:补 adapter,不改页面语义
目标:
- 先把数据适配层补齐
动作:
- 新增 `lib/api/govdoc-audit/adapters.ts`
- 收敛 `audit.tsx` 里对原始接口字段的直接解释
- 把 preview target 语义统一为:
- `page`
- `highlightValue`
- `bboxHighlight`
- `charPositions`
本阶段收益:
- 不改用户可见业务逻辑
- 为后续替换中栏和右栏做稳定基础
---
## 7.2 第二阶段:拆详情页 orchestrator
目标:
- 让 govdoc 详情页像 `cross-checking` 一样拥有独立 orchestrator
动作:
- 新增 `GovdocAuditResultPage.tsx`
- 将现有 `audit.tsx` 逻辑迁入新组件
- 路由入口改为挂载新组件
- 顶部摘要、下载操作、tab 切换拆成子组件
本阶段收益:
- 页面职责清晰
- 后续中栏和右栏可以独立演进
---
## 7.3 第三阶段:切换中栏到定位型预览
目标:
- 内部公文详情页中栏不再以 `DocView` 为核心
动作:
- 根据文件类型切换到 `PdfPreviewTest / DocxPreviewTest`
- 从 govdoc adapter 输出统一 preview target
- 让右栏点击直接驱动中栏定位
本阶段注意:
- PDF 定位优先支持 `bboxHighlight / charPositions`
- DOCX 优先支持 `targetPage + highlightValue`
- 不承诺此阶段立即做到“DOCX 行级精确定位”
---
## 7.4 第四阶段:重构右栏与 tab 业务壳
目标:
- 保留 govdoc 自己的业务面板,但交互模型对齐平台
动作:
- 将当前 `RightPanel` 重构为 `GovdocFindingPanel`
- 将结构、大纲、实体分面板组件化
- 收敛旧的孤立交互状态
本阶段收益:
- govdoc 保持业务独立
- 同时具备平台统一的交互体验
---
## 7.5 第五阶段:样式与布局收口
目标:
- govdoc 页面在视觉上向平台现有绿色主题和通用 panel 节奏靠齐
动作:
- 减少 `.govdoc-audit-scope` 中重复定义
- 优先复用 `layout-primitives.css`
- 保留必要的 govdoc 业务样式命名空间
本阶段原则:
- 先统一布局和交互节奏
- 再减少样式重复
- 不先做“大改视觉”
---
## 8. 风险点与前置条件
## 8.1 最大风险不在前端组件,而在定位数据颗粒度
内部公文要实现“定位到哪一行有问题”,前端只是承载层,真正决定上限的是后端给的数据。
前端能稳定消费的数据类型分为两类:
- PDF
- `page`
- `bbox`
- `page_box`
- `char_positions`
- DOCX
- `targetPage`
- `highlightValue`
- 未来如果需要更高精度,还需要更细粒度锚点
如果后端只给:
- 问题描述
- 规则结果
而不给定位数据,那么前端最多只能做到:
- 页级定位
- 文本关键字高亮
不能承诺做到稳定的“行级定位”。
---
## 8.2 不应在这一阶段做的事情
以下动作不建议和本次拆分同时进行:
- 重写 govdoc 全部视觉设计
- 把 govdoc 规则语义改造成合同/卷宗语义
- 试图把所有 `reviews` 业务组件直接搬进 govdoc
- 在没有 adapter 的情况下直接大规模替换页面
原因很简单:
- 这些动作会把“前端分层重构”和“业务改动”混在一起,增加回归风险
---
## 9. 最终边界结论
内部公文前端的正确实现边界应锁定为:
- **像交叉评查一样,独立成页**
- **像 reviews 一样,复用定位型预览能力**
- **像平台模块一样,数据解释集中在 adapter 层**
- **像内部公文自己一样,保留 findings / checked rules / structure / outline / entities 的业务语义**
更直白地说:
- `Govdoc 页面` 负责业务编排
- `reviews 预览组件` 负责中栏定位能力
- `Collabora` 只负责 DOCX 渲染
- `adapters.ts` 负责把 govdoc 后端结果翻译成前端可复用语义
这就是内部公文前端后续实施的固定边界。
+654
View File
@@ -0,0 +1,654 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>内部公文报告 UI 样例</title>
<style>
:root {
--bg: #f8fafc;
--panel: #ffffff;
--panel-soft: #f1f5f9;
--line: #e2e8f0;
--text: #0f172a;
--muted: #64748b;
--primary: #00684a;
--primary-soft: #e8f3ef;
--danger: #dc2626;
--danger-soft: #fef2f2;
--warn: #b45309;
--warn-soft: #fffbeb;
--info: #1d4ed8;
--info-soft: #eff6ff;
--shadow: 0 10px 30px rgba(15, 23, 42, 0.08);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background:
radial-gradient(circle at top left, rgba(0, 104, 74, 0.06), transparent 22%),
linear-gradient(180deg, #fbfdff 0%, var(--bg) 100%);
color: var(--text);
font: 14px/1.6 "PingFang SC", "Microsoft YaHei", sans-serif;
}
.page {
max-width: 1360px;
margin: 0 auto;
padding: 32px 24px 56px;
}
.hero {
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
gap: 20px;
align-items: stretch;
margin-bottom: 20px;
}
.card {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 18px;
box-shadow: var(--shadow);
}
.score-card {
padding: 24px 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
background:
linear-gradient(180deg, rgba(0, 104, 74, 0.05) 0%, rgba(255, 255, 255, 0.96) 36%),
var(--panel);
}
.score-ring {
width: 132px;
height: 132px;
margin: 0 auto 18px;
border-radius: 50%;
background: conic-gradient(var(--primary) 0%, #dbe4ea 0%);
display: grid;
place-items: center;
}
.score-ring::before {
content: "";
width: 102px;
height: 102px;
border-radius: 50%;
background: #fff;
box-shadow: inset 0 0 0 1px rgba(226, 232, 240, 0.9);
grid-area: 1 / 1;
}
.score-value {
grid-area: 1 / 1;
position: relative;
z-index: 1;
text-align: center;
}
.score-value strong {
display: block;
font-size: 34px;
line-height: 1;
letter-spacing: -0.04em;
}
.score-value span {
display: block;
margin-top: 6px;
font-size: 12px;
color: var(--muted);
}
.score-caption {
text-align: center;
color: var(--muted);
font-size: 12px;
}
.hero-main {
padding: 24px 26px;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 18px;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 28px;
padding: 0 12px;
border-radius: 999px;
background: var(--primary-soft);
color: var(--primary);
font-size: 12px;
font-weight: 600;
}
h1 {
margin: 10px 0 8px;
font-size: 30px;
line-height: 1.2;
}
.doc-meta {
color: var(--muted);
font-size: 13px;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
}
.metric {
border: 1px solid var(--line);
border-radius: 14px;
background: linear-gradient(180deg, #fff, #f8fafc);
padding: 14px 16px;
}
.metric-label {
color: var(--muted);
font-size: 12px;
}
.metric-value {
margin-top: 6px;
display: flex;
align-items: baseline;
gap: 6px;
}
.metric-value strong {
font-size: 26px;
line-height: 1;
letter-spacing: -0.04em;
}
.metric-value span {
color: var(--muted);
font-size: 12px;
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.chip {
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 30px;
padding: 0 12px;
border-radius: 999px;
border: 1px solid transparent;
font-size: 12px;
font-weight: 600;
}
.chip.error {
color: var(--danger);
background: var(--danger-soft);
border-color: #fecaca;
}
.chip.warning {
color: var(--warn);
background: var(--warn-soft);
border-color: #fde68a;
}
.chip.info {
color: var(--info);
background: var(--info-soft);
border-color: #bfdbfe;
}
.content {
display: grid;
grid-template-columns: 320px minmax(0, 1fr);
gap: 20px;
align-items: start;
}
.sidebar {
padding: 18px;
position: sticky;
top: 20px;
}
.section-title {
margin: 0 0 14px;
font-size: 13px;
font-weight: 700;
}
.stat-list {
display: grid;
gap: 10px;
}
.stat-item {
border: 1px solid var(--line);
border-radius: 12px;
background: #fff;
padding: 12px 14px;
}
.stat-item strong {
display: block;
font-size: 20px;
line-height: 1;
margin-bottom: 6px;
}
.stat-item span {
color: var(--muted);
font-size: 12px;
}
.legend {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--line);
}
.legend-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 8px 0;
color: var(--muted);
font-size: 12px;
}
.legend-row b {
color: var(--text);
font-size: 13px;
}
.table-card {
overflow: hidden;
}
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 16px 18px;
border-bottom: 1px solid var(--line);
background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}
.toolbar h2 {
margin: 0;
font-size: 15px;
}
.toolbar span {
color: var(--muted);
font-size: 12px;
}
.filters {
display: flex;
gap: 8px;
}
.filter {
min-height: 30px;
padding: 0 12px;
border-radius: 999px;
border: 1px solid var(--line);
background: #fff;
color: var(--muted);
font-size: 12px;
font-weight: 600;
}
.filter.active {
color: var(--primary);
background: var(--primary-soft);
border-color: rgba(0, 104, 74, 0.2);
}
table {
width: 100%;
border-collapse: collapse;
}
thead th {
padding: 12px 14px;
text-align: left;
background: #f8fafc;
color: var(--muted);
font-size: 12px;
font-weight: 700;
border-bottom: 1px solid var(--line);
white-space: nowrap;
}
tbody td {
padding: 14px;
border-bottom: 1px solid #edf2f7;
vertical-align: top;
}
tbody tr:hover {
background: #fcfdfd;
}
.finding-id {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
color: var(--muted);
font-size: 12px;
}
.rule-cell strong {
display: block;
font-size: 13px;
}
.rule-cell span {
display: block;
margin-top: 4px;
color: var(--muted);
font-size: 12px;
}
.severity-tag {
display: inline-flex;
align-items: center;
min-height: 26px;
padding: 0 10px;
border-radius: 999px;
border: 1px solid transparent;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
}
.severity-tag.error {
color: var(--danger);
background: var(--danger-soft);
border-color: #fecaca;
}
.severity-tag.warning {
color: var(--warn);
background: var(--warn-soft);
border-color: #fde68a;
}
.location {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
color: #334155;
font-size: 12px;
}
.msg {
min-width: 360px;
}
.msg-main {
font-size: 13px;
color: var(--text);
}
.context {
margin-top: 8px;
padding: 10px 12px;
border-radius: 12px;
background: #f8fafc;
color: var(--muted);
font-size: 12px;
}
.suggestion {
margin-top: 8px;
padding: 10px 12px;
border-radius: 12px;
background: #eff6ff;
color: #0f4c81;
font-size: 12px;
}
@media (max-width: 1080px) {
.hero,
.content {
grid-template-columns: 1fr;
}
.summary-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sidebar {
position: static;
}
}
@media (max-width: 720px) {
.page {
padding: 18px 14px 32px;
}
.summary-grid {
grid-template-columns: 1fr;
}
.toolbar {
align-items: flex-start;
flex-direction: column;
}
.msg {
min-width: 0;
}
}
</style>
</head>
<body>
<div class="page">
<section class="hero">
<div class="card score-card">
<div class="score-ring">
<div class="score-value">
<strong>0</strong>
<span>综合得分</span>
</div>
</div>
<div class="score-caption">当前样例沿用你提供的实际报告数据,不改业务语义</div>
</div>
<div class="card hero-main">
<div>
<div class="eyebrow">统一报告样式锚点</div>
<h1>公文格式审核报告</h1>
<div class="doc-meta">买卖合同 (1).docx · 共 123 项问题 · 样例用于确认 UI / 配色方向</div>
</div>
<div class="summary-grid">
<div class="metric">
<div class="metric-label">错误项</div>
<div class="metric-value"><strong>31</strong><span>error</span></div>
</div>
<div class="metric">
<div class="metric-label">警告项</div>
<div class="metric-value"><strong>92</strong><span>warning</span></div>
</div>
<div class="metric">
<div class="metric-label">提示项</div>
<div class="metric-value"><strong>0</strong><span>info</span></div>
</div>
<div class="metric">
<div class="metric-label">问题类别</div>
<div class="metric-value"><strong>4</strong><span>标题 / 发文 / 格式 / 其他</span></div>
</div>
</div>
<div class="chips">
<span class="chip error">错误 31</span>
<span class="chip warning">警告 92</span>
<span class="chip info">提示 0</span>
</div>
</div>
</section>
<section class="content">
<aside class="card sidebar">
<h2 class="section-title">报告摘要</h2>
<div class="stat-list">
<div class="stat-item">
<strong>GW-F-003</strong>
<span>当前命中最多的规则,二级标题用楷体三号</span>
</div>
<div class="stat-item">
<strong>P35 - P83</strong>
<span>问题主要集中在正文中段的二级标题样式</span>
</div>
<div class="stat-item">
<strong>标题 / 发文</strong>
<span>顶部实体未识别,标题文种与发文字号前置规则同时触发</span>
</div>
</div>
<div class="legend">
<div class="legend-row">
<span>设计基调</span>
<b>贴合系统统一工作台</b>
</div>
<div class="legend-row">
<span>信息组织</span>
<b>摘要 + 问题表格</b>
</div>
<div class="legend-row">
<span>配色策略</span>
<b>Slate + 平台绿</b>
</div>
</div>
</aside>
<div class="card table-card">
<div class="toolbar">
<div>
<h2>问题明细</h2>
<span>保留当前报告语义,只收敛版式和视觉层级</span>
</div>
<div class="filters">
<button class="filter active" type="button">全部</button>
<button class="filter" type="button">错误</button>
<button class="filter" type="button">警告</button>
</div>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>规则</th>
<th>严重度</th>
<th>类别</th>
<th>位置</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td class="finding-id">F-c0dfd361</td>
<td class="rule-cell">
<strong>GW-T-001</strong>
<span>标题文种合规性</span>
</td>
<td><span class="severity-tag error">error</span></td>
<td>标题</td>
<td class="location">P-1 ()</td>
<td class="msg">
<div class="msg-main">目标实体「title」未识别到</div>
<div class="context">原文:未识别到标题内容,无法继续执行标题文种合规校验。</div>
<div class="suggestion">建议:补全标题并确保标题文种符合规则要求。</div>
</td>
</tr>
<tr>
<td class="finding-id">F-a896eaa4</td>
<td class="rule-cell">
<strong>GW-N-001</strong>
<span>发文字号必须用六角括号</span>
</td>
<td><span class="severity-tag error">error</span></td>
<td>发文</td>
<td class="location">P-1 ()</td>
<td class="msg">
<div class="msg-main">目标实体「doc_number」未识别到</div>
<div class="context">原文:未识别到发文字号,年份括号规则无法匹配。</div>
<div class="suggestion">建议:发文字号年份应用六角括号〔〕,不得使用方括号或圆括号。</div>
</td>
</tr>
<tr>
<td class="finding-id">F-087a4841</td>
<td class="rule-cell">
<strong>GW-F-003</strong>
<span>二级标题用楷体三号</span>
</td>
<td><span class="severity-tag error">error</span></td>
<td>格式</td>
<td class="location">P35 (heading_2)</td>
<td class="msg">
<div class="msg-main">字体或字号不符合(实际 仿宋 Nonept,期望 楷体 16pt</div>
<div class="context">原文:(一)甲方从乙方处购买:</div>
<div class="suggestion">建议:二级标题应使用楷体三号,保持同级标题样式一致。</div>
</td>
</tr>
<tr>
<td class="finding-id">F-37b4bb81</td>
<td class="rule-cell">
<strong>GW-F-003</strong>
<span>二级标题用楷体三号</span>
</td>
<td><span class="severity-tag error">error</span></td>
<td>格式</td>
<td class="location">P39 (heading_2)</td>
<td class="msg">
<div class="msg-main">字体或字号不符合(实际 仿宋 Nonept,期望 楷体 16pt</div>
<div class="context">原文:(二)质量要求:</div>
<div class="suggestion">建议:这一类同级标题可在正式版中支持折叠聚合同规则项。</div>
</td>
</tr>
<tr>
<td class="finding-id">F-b2140a78</td>
<td class="rule-cell">
<strong>GW-F-003</strong>
<span>二级标题用楷体三号</span>
</td>
<td><span class="severity-tag warning">warning</span></td>
<td>格式</td>
<td class="location">P62 (heading_2)</td>
<td class="msg">
<div class="msg-main">格式接近但未完全满足规则要求</div>
<div class="context">原文:(一)交付时间: 。</div>
<div class="suggestion">建议:保留原有规则说明内容,只把告警与错误的视觉层级拉开。</div>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</body>
</html>