diff --git a/.gitignore b/.gitignore index 846be83b..01899dbe 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ backend/storage/ backend/tmp_migration_check.db project-docs/qa-artifacts/ .claude/worktrees/ +.gstack/ diff --git a/frontend/src/app/audit-logs/page.tsx b/frontend/src/app/audit-logs/page.tsx index 09397d60..f4e8348d 100644 --- a/frontend/src/app/audit-logs/page.tsx +++ b/frontend/src/app/audit-logs/page.tsx @@ -161,20 +161,19 @@ export default function AuditLogsPage() {
Audit Logs - 查看系统关键操作,保留可回溯的审计记录。 - 当前已覆盖登录、创建审查任务、下载审查报告等关键动作,后续可继续扩展更多后台模块事件。 + 追踪关键操作,快速定位责任链路。 + 搜索和动作筛选放在同一工具栏,适合管理员排查登录、审查和下载记录。
Admin Only - 审计日志工作台 + 审计节奏 @@ -186,7 +185,7 @@ export default function AuditLogsPage() {
Audit Workspace 快速定位关键操作记录 - 先把当前已有的审计能力可视化,作为后续管理端扩展的基础页面。 + 搜索操作人、资源类型、资源 ID 或动作名称。
{reviewContext ? "Review Copilot" : "Legal Chat"} - {reviewContext ? "围绕当前审查结果继续追问这份合同。" : "围绕合同问题,发起一轮登录态法律问答。"} + {reviewContext ? "接着这份审查结果继续问。" : "用登录态问答处理合同问题。"} {reviewContext - ? "已从审查详情页带入当前合同的审查结果,可以直接围绕风险项、条款摘要和处理建议继续追问。" - : "补齐 V1 会话历史最小闭环:输入问题、流式回答、展示引用来源,并支持回看已保存会话。"} + ? "风险项、条款摘要和处理建议已经带入上下文,可以直接追问下一步。" + : "输入问题、查看流式回答和引用来源,历史会话会自动沉淀。"}
{chatHighlights.map((item) => ( @@ -1191,7 +1191,7 @@ export default function ChatPage() { {reviewContext ? "Review Context" : "Usage Guide"} - {reviewContext ? "已注入审查上下文" : "问答说明"} + {reviewContext ? "上下文已就绪" : "问答节奏"}
    {chatTips.map((item) => ( diff --git a/frontend/src/app/contracts/[id]/page.tsx b/frontend/src/app/contracts/[id]/page.tsx index a54881e7..72f74898 100644 --- a/frontend/src/app/contracts/[id]/page.tsx +++ b/frontend/src/app/contracts/[id]/page.tsx @@ -149,14 +149,14 @@ export default function GeneratedContractDetailPage({ params }: { params: Promis }; return ( -
    +
    {contextHolder}
    Generated Contract {detail?.template_name ?? "合同详情"} - 查看已生成合同的完整信息、变量回显、真实预览,并基于历史结果继续处理。 + 保留生成参数、预览内容和下载入口,方便从历史结果继续编辑或复核。
    合同类型 @@ -180,9 +180,9 @@ export default function GeneratedContractDetailPage({ params }: { params: Promis Workspace Actions - 历史结果工作区 + 下一步动作 - 可直接下载,也可把历史模板、变量、导出格式和导出选项回填到生成页继续处理。 + 下载文件、回填生成参数,或把生成内容带入问答复核。 @@ -240,81 +240,63 @@ export default function GeneratedContractDetailPage({ params }: { params: Promis )} - - }} - columns={[ - { title: "变量名", dataIndex: "name", key: "name", width: 240 }, - { - title: "变量值", - dataIndex: "value", - key: "value", - render: (value: string) => {value || "-"}, - }, - { - title: "状态", - dataIndex: "isEmpty", - key: "isEmpty", - width: 120, - render: (isEmpty: boolean) => {isEmpty ? "空值" : "已填写"}, - }, - ]} - /> - +
    + +
    }} + columns={[ + { title: "变量名", dataIndex: "name", key: "name", width: 240 }, + { + title: "变量值", + dataIndex: "value", + key: "value", + render: (value: string) => {value || "-"}, + }, + { + title: "状态", + dataIndex: "isEmpty", + key: "isEmpty", + width: 120, + render: (isEmpty: boolean) => {isEmpty ? "空值" : "已填写"}, + }, + ]} + /> + - -
    }} - columns={[ - { title: "选项名", dataIndex: "name", key: "name", width: 240 }, - { title: "选项值", dataIndex: "value", key: "value" }, - ]} - /> - + +
    }} + columns={[ + { title: "选项名", dataIndex: "name", key: "name", width: 180 }, + { title: "选项值", dataIndex: "value", key: "value" }, + ]} + /> + + - - {preview ? ( - - {preview.preview_content} - - ) : ( - - )} - +
    + + {preview ? ( +
    {preview.preview_content}
    + ) : ( + + )} +
    - - {detail ? ( - - {detail.generated_content} - - ) : ( - - )} - + + {detail ? ( +
    {detail.generated_content}
    + ) : ( + + )} +
    +
    ); diff --git a/frontend/src/app/contracts/page.tsx b/frontend/src/app/contracts/page.tsx index 3a2359c3..12c53719 100644 --- a/frontend/src/app/contracts/page.tsx +++ b/frontend/src/app/contracts/page.tsx @@ -585,26 +585,26 @@ export default function ContractsPage() { const restoredOptionEntries = Object.entries(restoredOptions); return ( -
    +
    {contextHolder}
    Contract Generation - 智能合同生成,快速创建专业合同。 - 选择模板、填写变量、预览确认、一键生成专业合同文档。 + 从模板到下载,一屏完成合同生成。 + 先选模板,再填写变量;预览确认后生成文件,历史结果保留在下方。
    Smart Workflow - 四步生成流程 + 当前链路 -
      -
    • 从预置模板库中选择合适的合同模板。
    • -
    • 填写模板变量,支持必填验证和默认值。
    • -
    • 实时预览生成结果,确认无误后生成。
    • -
    • 支持多种格式导出:DOCX、PDF、HTML、TXT。
    • -
    +
    + 选模板 + 填变量 + 生成文件 +
    + 支持 DOCX、PDF、HTML、TXT 导出;从审查结果进入时会自动带入上下文。
    @@ -668,7 +668,10 @@ export default function ContractsPage() { )} {restoredOptionEntries.length > 0 && ( - +
    +
    + 已恢复的导出选项 +
    {restoredOptionEntries.map(([key, value]) => ( @@ -676,7 +679,7 @@ export default function ContractsPage() { ))} - +
    )}
    @@ -735,20 +738,9 @@ export default function ContractsPage() { 预览内容如下: - +
    {previewResult.preview_content} - +
    变量填写情况 diff --git a/frontend/src/app/files/page.tsx b/frontend/src/app/files/page.tsx index 984dc456..69442e8f 100644 --- a/frontend/src/app/files/page.tsx +++ b/frontend/src/app/files/page.tsx @@ -293,20 +293,18 @@ export default function FilesPage() {
    File Management - 统一管理平台内所有文件资源。 - 支持文件上传、下载、分类管理和删除操作。 + 集中管理合同、报告和知识文档资产。 + 上传区和资产列表并排呈现,文件详情、下载和删除都从列表完成。
    Admin Workspace - 文件管理流程 + 资产流转
      -
    • 当前页面为管理员主用,普通成员不开放文件资产管理能力。
    • -
    • 支持上传各类文件(合同、文档、图片等)。
    • -
    • 可按文件类型筛选查看。
    • -
    • 提供文件下载和删除功能。
    • -
    • 文件存储支持多存储桶配置。
    • +
    • 上传前先选类型与存储桶。
    • +
    • 列表支持按文件类型筛选。
    • +
    • 高亮来自其他页面跳转的目标文件。
    diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 67948ecb..a08c090c 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -2377,3 +2377,1520 @@ a { padding: 22px; } } + +/* 2026 visual refresh: AI legal command center */ +:root { + --background: #f4f7fb; + --foreground: #131418; + --primary: #00c48c; + --primary-dark: #008a72; + --accent-cyan: #16b8ff; + --accent-coral: #ff4d6d; + --accent-amber: #f6b73c; + --accent-lime: #b6f35b; + --ink: #111217; + --ink-soft: #1a1d24; + --muted: #687083; + --border: rgba(19, 20, 24, 0.1); + --glass: rgba(255, 255, 255, 0.78); + --glass-strong: rgba(255, 255, 255, 0.92); + --card-shadow: 0 18px 48px rgba(12, 16, 24, 0.12); + --radius-card: 8px; +} + +*, +*::before, +*::after { + letter-spacing: 0 !important; +} + +html { + scroll-behavior: smooth; +} + +body { + color: var(--foreground); + background: + linear-gradient(135deg, rgba(0, 196, 140, 0.1) 0 12%, transparent 12% 100%), + linear-gradient(225deg, rgba(255, 77, 109, 0.09) 0 10%, transparent 10% 100%), + repeating-linear-gradient(90deg, rgba(17, 18, 23, 0.035) 0 1px, transparent 1px 112px), + repeating-linear-gradient(0deg, rgba(17, 18, 23, 0.028) 0 1px, transparent 1px 112px), + linear-gradient(180deg, #fbfcff 0%, #f4f7fb 46%, #edf3f7 100%); +} + +body::selection { + color: #111217; + background: rgba(182, 243, 91, 0.72); +} + +.app-topbar { + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + background: + linear-gradient(90deg, rgba(17, 18, 23, 0.92), rgba(18, 38, 35, 0.88)), + rgba(17, 18, 23, 0.9); + box-shadow: 0 14px 34px rgba(17, 18, 23, 0.2); +} + +.app-topbar-inner { + width: min(1320px, calc(100% - 48px)); +} + +.app-brand { + color: #fff; +} + +.app-brand-mark { + width: 44px; + height: 44px; + border-radius: 8px; + background: + linear-gradient(135deg, rgba(182, 243, 91, 0.96), rgba(22, 184, 255, 0.9)), + #00c48c; + color: #111217; + box-shadow: 0 16px 34px rgba(0, 196, 140, 0.28); +} + +.app-brand-copy strong { + color: #fff; + font-size: 16px; +} + +.app-brand-copy span { + color: rgba(255, 255, 255, 0.62); +} + +.app-topbar-right { + gap: 12px; +} + +.app-nav { + max-width: 820px; + overflow-x: auto; + flex-wrap: nowrap; + scrollbar-width: none; +} + +.app-nav::-webkit-scrollbar { + display: none; +} + +.app-nav-link { + min-height: 38px; + align-items: center; + gap: 7px; + border-radius: 8px; + color: rgba(255, 255, 255, 0.72); + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.07); +} + +.app-topbar .app-nav-link { + color: rgba(255, 255, 255, 0.72) !important; +} + +.app-nav-icon { + display: inline-flex; + color: var(--accent-lime); + font-size: 14px; +} + +.app-nav-link:hover, +.app-nav-link-active, +.app-nav-link-active:hover { + color: #111217 !important; + background: linear-gradient(135deg, var(--accent-lime), var(--accent-cyan)); + border-color: transparent; + box-shadow: 0 12px 28px rgba(22, 184, 255, 0.18); +} + +.app-nav-link:hover .app-nav-icon, +.app-nav-link-active .app-nav-icon { + color: #111217; +} + +.app-topbar .app-nav-link:hover, +.app-topbar .app-nav-link-active, +.app-topbar .app-nav-link-active:hover { + color: #111217 !important; +} + +.app-user-chip { + border-radius: 8px; + color: #fff; + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.12); + box-shadow: none; +} + +.app-user-copy strong { + color: #fff; +} + +.app-user-copy span { + color: rgba(255, 255, 255, 0.6); +} + +.app-topbar .ant-btn-default { + color: #111217; + border: 0; + background: #fff; +} + +.app-login-entry, +.landing-primary-action, +.review-surface-card .ant-btn-primary, +.review-page-grid .ant-btn-primary, +.review-history-page .ant-btn-primary, +.review-detail-page .ant-btn-primary, +.auth-form-card .ant-btn-primary, +.ant-btn-primary { + border: 0 !important; + color: #111217 !important; + background: linear-gradient(135deg, var(--accent-lime), var(--accent-cyan)) !important; + box-shadow: 0 16px 34px rgba(0, 196, 140, 0.22) !important; +} + +.app-login-entry { + border-radius: 8px; +} + +.landing-page, +.page-shell, +.auth-page { + width: min(1320px, 100%); + max-width: 1320px; + padding-left: 24px; + padding-right: 24px; +} + +.landing-hero-shell, +.review-page-hero, +.review-detail-hero, +.review-history-hero, +.auth-layout { + gap: 24px; +} + +.landing-hero-shell { + align-items: stretch; + grid-template-columns: minmax(0, 1.22fr) minmax(320px, 0.78fr); +} + +.landing-hero-shell-public { + grid-template-columns: minmax(0, 1fr) minmax(360px, 0.78fr); + min-height: 620px; + align-items: center; +} + +.landing-hero, +.auth-hero-card, +.auth-form-card, +.review-page-hero, +.review-detail-hero, +.review-history-hero, +.landing-panel-card, +.landing-card, +.landing-workflow-card, +.landing-highlight-item, +.landing-stat-card, +.landing-workbench-card, +.review-side-card, +.review-surface-card, +.review-list-card, +.review-metric-card, +.review-detail-decision-card, +.review-detail-group-card, +.review-detail-item-card, +.chat-history-item, +.chat-message, +.chat-review-section, +.chat-review-timeline, +.chat-action-card, +.chat-answer-summary-card, +.ant-card { + border-radius: var(--radius-card) !important; +} + +.landing-hero, +.auth-hero-card, +.auth-form-card, +.review-page-hero, +.review-detail-hero, +.review-history-hero { + position: relative; + overflow: hidden; + border: 1px solid rgba(255, 255, 255, 0.72); + background: + linear-gradient(135deg, rgba(255, 255, 255, 0.92), rgba(246, 249, 252, 0.74)), + linear-gradient(135deg, rgba(22, 184, 255, 0.16), rgba(255, 77, 109, 0.08)); + box-shadow: 0 24px 70px rgba(12, 16, 24, 0.14); + backdrop-filter: blur(18px); +} + +.landing-hero::before, +.auth-hero-card::before, +.review-page-hero::before, +.review-detail-hero::before, +.review-history-hero::before { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + background: + linear-gradient(110deg, transparent 0 46%, rgba(255, 255, 255, 0.72) 50%, transparent 54% 100%), + repeating-linear-gradient(90deg, rgba(17, 18, 23, 0.04) 0 1px, transparent 1px 72px); + opacity: 0.42; + transform: translateX(-28%); +} + +.landing-hero > *, +.auth-hero-card > *, +.review-page-hero > *, +.review-detail-hero > *, +.review-history-hero > * { + position: relative; + z-index: 1; +} + +.landing-hero h1, +.auth-hero-copy h1 { + max-width: 820px; + margin: 0; + color: #111217; + font-size: 56px; + line-height: 0.98; + font-weight: 900; +} + +.landing-hero-shell:not(.landing-hero-shell-public) .landing-hero h1 { + max-width: 760px; + font-size: 48px; + line-height: 1.04; +} + +.landing-hero p, +.auth-hero-copy .ant-typography-secondary, +.page-header-block .ant-typography-secondary { + color: #485060; + font-size: 17px; +} + +.landing-badge, +.landing-panel-eyebrow, +.landing-card-eyebrow { + width: fit-content; + border-radius: 999px; + color: #111217; + background: rgba(182, 243, 91, 0.72); + border: 1px solid rgba(17, 18, 23, 0.08); + text-transform: none; +} + +.landing-badge { + padding: 9px 13px; + font-weight: 900; +} + +.landing-actions { + gap: 12px; +} + +.landing-primary-action, +.landing-secondary-action { + min-height: 46px; + align-items: center; + border-radius: 8px; + font-weight: 900; +} + +.landing-secondary-action { + color: #111217; + background: rgba(255, 255, 255, 0.9); + border: 1px solid rgba(17, 18, 23, 0.12); +} + +.landing-trust-row { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 8px; +} + +.landing-trust-row span { + padding: 8px 12px; + border-radius: 999px; + color: #111217; + background: rgba(255, 255, 255, 0.72); + border: 1px solid rgba(17, 18, 23, 0.08); + font-size: 13px; + font-weight: 800; +} + +.landing-visual-scene { + position: relative; + overflow: hidden; + min-height: 540px; + padding: 24px; + border-radius: var(--radius-card); + color: #fff; + background: + linear-gradient(135deg, rgba(17, 18, 23, 0.96), rgba(14, 58, 49, 0.95) 56%, rgba(45, 22, 37, 0.96)), + #111217; + box-shadow: 0 26px 80px rgba(17, 18, 23, 0.28); +} + +.landing-visual-scene::before { + content: ""; + position: absolute; + inset: 0; + background: + repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.07) 0 1px, transparent 1px 58px), + repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 58px); + opacity: 0.5; +} + +.landing-visual-scene::after { + content: ""; + position: absolute; + inset: auto -12% 18% -12%; + height: 120px; + background: linear-gradient(90deg, transparent, rgba(182, 243, 91, 0.2), rgba(22, 184, 255, 0.18), transparent); + transform: rotate(-7deg); + animation: commandSweep 7s linear infinite; +} + +.landing-visual-scene > * { + position: relative; + z-index: 1; +} + +.landing-visual-topline, +.landing-command-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.landing-visual-topline span, +.landing-command-header span { + color: rgba(255, 255, 255, 0.62); + font-size: 13px; + font-weight: 800; +} + +.landing-visual-topline strong, +.landing-command-header strong { + color: var(--accent-lime); +} + +.landing-contract-stack { + position: relative; + display: grid; + place-items: center; + min-height: 300px; +} + +.landing-contract-paper { + width: min(360px, 100%); + padding: 26px; + border-radius: var(--radius-card); + color: #111217; + background: rgba(255, 255, 255, 0.92); + box-shadow: 18px 18px 0 rgba(182, 243, 91, 0.28), -16px -16px 0 rgba(22, 184, 255, 0.18); +} + +.paper-kicker { + display: block; + margin-bottom: 10px; + color: #687083; + font-size: 12px; + font-weight: 900; +} + +.landing-contract-paper strong { + display: block; + margin-bottom: 22px; + font-size: 26px; + line-height: 1.16; +} + +.paper-line { + height: 12px; + width: 78%; + margin-top: 12px; + border-radius: 999px; + background: rgba(17, 18, 23, 0.11); +} + +.paper-line-wide { + width: 100%; +} + +.paper-line-short { + width: 48%; +} + +.paper-line-hot { + width: 84%; + background: linear-gradient(90deg, var(--accent-coral), var(--accent-amber)); +} + +.landing-risk-pulse { + position: absolute; + right: 6px; + bottom: 26px; + width: 126px; + padding: 16px; + border-radius: var(--radius-card); + background: #111217; + border: 1px solid rgba(255, 255, 255, 0.12); + box-shadow: 0 18px 40px rgba(0, 0, 0, 0.26); +} + +.landing-risk-pulse span, +.landing-showcase-card span, +.landing-command-alerts span { + display: block; + color: rgba(255, 255, 255, 0.62); + font-size: 12px; + font-weight: 800; +} + +.landing-risk-pulse strong { + color: var(--accent-coral); + font-size: 40px; + line-height: 1; +} + +.landing-showcase-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; +} + +.landing-showcase-card, +.landing-command-alerts div { + min-height: 96px; + padding: 15px; + border-radius: var(--radius-card); + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.12); +} + +.landing-showcase-card strong, +.landing-command-alerts strong { + display: block; + margin-top: 8px; + color: #fff; + font-size: 26px; +} + +.landing-showcase-card-cyan { + box-shadow: inset 0 3px 0 var(--accent-cyan); +} + +.landing-showcase-card-coral { + box-shadow: inset 0 3px 0 var(--accent-coral); +} + +.landing-showcase-card-amber { + box-shadow: inset 0 3px 0 var(--accent-amber); +} + +.landing-command-visual { + display: grid; + gap: 14px; + margin-top: 18px; + padding: 18px; + border-radius: var(--radius-card); + color: #fff; + background: + linear-gradient(135deg, rgba(17, 18, 23, 0.95), rgba(17, 42, 37, 0.95)), + #111217; +} + +.landing-command-flow { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px; +} + +.landing-command-step { + position: relative; + min-height: 86px; + padding: 14px; + border-radius: var(--radius-card); + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.landing-command-step::after { + content: ""; + position: absolute; + top: 12px; + right: 12px; + width: 18px; + height: 18px; + border-top: 2px solid var(--accent-lime); + border-right: 2px solid var(--accent-lime); +} + +.landing-command-step span { + display: block; + color: var(--accent-lime); + font-size: 12px; + font-weight: 900; +} + +.landing-command-step strong { + display: block; + margin-top: 10px; + color: #fff; + font-size: 15px; +} + +.landing-command-alerts { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; +} + +.landing-stat-card, +.landing-workbench-card, +.landing-panel-card, +.landing-card, +.landing-workflow-card, +.landing-highlight-item, +.review-metric-card, +.review-detail-decision-card, +.review-detail-group-card, +.review-detail-item-card, +.chat-action-card, +.chat-answer-summary-card, +.ant-card { + border: 1px solid rgba(17, 18, 23, 0.09) !important; + background: var(--glass-strong) !important; + box-shadow: 0 16px 44px rgba(12, 16, 24, 0.08) !important; + backdrop-filter: blur(16px); +} + +.landing-card:hover, +.landing-workflow-card:hover, +.landing-highlight-item:hover, +.chat-action-card:hover { + transform: translateY(-3px); + border-color: rgba(0, 196, 140, 0.38) !important; + box-shadow: 0 22px 56px rgba(12, 16, 24, 0.12) !important; +} + +.landing-stat-card strong, +.landing-workbench-card strong, +.review-metric-card strong, +.review-detail-decision-card strong, +.landing-card strong { + color: #111217; +} + +.landing-stat-card strong { + font-size: 34px; +} + +.landing-workbench-card, +.landing-stat-card { + border-left: 4px solid var(--primary) !important; +} + +.landing-panel-card-primary, +.review-side-card { + color: #fff !important; + border: 1px solid rgba(255, 255, 255, 0.12) !important; + background: + linear-gradient(135deg, #111217, #12362f 58%, #2b1422) !important; + box-shadow: 0 22px 60px rgba(17, 18, 23, 0.2) !important; +} + +.landing-hero-panel { + align-self: start; +} + +.landing-panel-card-primary { + min-height: 0; +} + +.landing-panel-card-primary strong, +.review-side-card strong, +.review-side-card .ant-typography { + color: #fff !important; +} + +.landing-panel-card-primary p, +.landing-panel-card-primary li, +.review-side-card li { + color: rgba(255, 255, 255, 0.78) !important; +} + +.landing-section-header h2 { + color: #111217; + font-size: 30px; + font-weight: 900; +} + +.landing-section-header p, +.landing-card span, +.landing-panel-card p, +.review-page-tip-list li { + color: #596276; +} + +.auth-page { + min-height: calc(100vh - 72px); +} + +.auth-layout { + grid-template-columns: minmax(0, 1.12fr) minmax(380px, 0.88fr); +} + +.auth-hero-card { + grid-template-columns: minmax(0, 1fr) minmax(270px, 0.78fr); +} + +.auth-form-card { + border: 1px solid rgba(17, 18, 23, 0.09) !important; + background: rgba(255, 255, 255, 0.94) !important; +} + +.auth-access-visual { + display: grid; + gap: 12px; + margin-top: 12px; + padding: 16px; + border-radius: var(--radius-card); + color: #fff; + background: #111217; + border: 1px solid rgba(255, 255, 255, 0.12); +} + +.auth-access-terminal { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 12px; +} + +.auth-access-terminal span, +.auth-access-metrics span { + color: rgba(255, 255, 255, 0.58); + font-size: 12px; + font-weight: 800; +} + +.auth-access-terminal strong, +.auth-access-metrics strong { + color: var(--accent-lime); +} + +.auth-access-track { + display: grid; + grid-template-columns: 1fr 0.7fr 1.2fr; + gap: 8px; +} + +.auth-access-track span { + height: 10px; + border-radius: 999px; + background: linear-gradient(90deg, var(--accent-cyan), var(--accent-lime)); +} + +.auth-access-metrics { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} + +.auth-access-metrics div { + display: flex; + min-width: 0; + flex-direction: column; + gap: 5px; + padding: 12px; + border-radius: var(--radius-card); + background: rgba(255, 255, 255, 0.08); +} + +.auth-access-metrics strong, +.auth-access-terminal strong { + display: block; + line-height: 1.25; +} + +.auth-side-card .ant-btn { + min-height: 42px; + height: auto; + white-space: normal; + line-height: 1.45; +} + +.auth-form-card .ant-input, +.auth-form-card .ant-input-affix-wrapper, +.review-page-grid .ant-input, +.review-page-grid .ant-input-affix-wrapper, +.review-page-grid .ant-select-selector, +.review-history-page .ant-input, +.review-history-page .ant-input-affix-wrapper, +.review-history-page .ant-select-selector { + border-radius: 8px !important; + border-color: rgba(17, 18, 23, 0.12) !important; + background: rgba(255, 255, 255, 0.88) !important; +} + +.ant-alert { + border-radius: 8px !important; +} + +.ant-tabs .ant-tabs-tab { + font-weight: 800; +} + +.review-page-hero { + grid-template-columns: minmax(0, 1.25fr) minmax(320px, 0.75fr); +} + +.review-page-hero-copy h2, +.review-detail-hero h2, +.review-history-hero h2, +.page-header-block h2 { + color: #111217; + font-size: 34px; + font-weight: 900; +} + +.review-hero-visual { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; + margin-top: 16px; +} + +.review-hero-visual-step { + min-height: 92px; + padding: 14px; + border-radius: var(--radius-card); + color: #fff; + background: linear-gradient(135deg, #111217, #17372f); + border: 1px solid rgba(255, 255, 255, 0.12); +} + +.review-hero-visual-step span { + color: var(--accent-lime); + font-size: 12px; + font-weight: 900; +} + +.review-hero-visual-step strong { + display: block; + margin-top: 12px; + color: #fff; + font-size: 15px; + line-height: 1.45; +} + +.review-page-highlight-chip, +.auth-highlight-chip { + border-radius: 999px; + color: #111217; + background: rgba(22, 184, 255, 0.16); + border: 1px solid rgba(22, 184, 255, 0.22); +} + +.review-submission-step, +.review-config-highlight-card, +.review-selected-file-rich { + border-radius: 8px; + background: + linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(247, 250, 253, 0.9)); +} + +.review-submission-step-index { + color: #111217; + background: linear-gradient(135deg, var(--accent-lime), var(--accent-cyan)); +} + +.review-config-highlight-card span, +.review-selected-file-rich span, +.landing-workbench-card span, +.landing-stat-card span { + color: #687083; +} + +.review-config-highlight-card strong, +.review-selected-file-rich strong { + color: #111217; +} + +.ant-upload-wrapper .ant-upload-drag { + border-radius: 8px !important; + background: + repeating-linear-gradient(90deg, rgba(17, 18, 23, 0.03) 0 1px, transparent 1px 40px), + rgba(255, 255, 255, 0.72) !important; +} + +.ant-upload-wrapper .ant-upload-drag:hover { + border-color: var(--primary) !important; +} + +.ant-table-wrapper, +.ant-table { + border-radius: 8px !important; +} + +.ant-table-thead > tr > th { + background: rgba(17, 18, 23, 0.04) !important; + color: #111217 !important; +} + +.ant-tag { + border-radius: 999px !important; + font-weight: 800; +} + +@keyframes commandSweep { + 0% { + transform: translateX(-28%) rotate(-7deg); + } + + 100% { + transform: translateX(28%) rotate(-7deg); + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + } +} + +@media (max-width: 1180px) { + .app-topbar-inner { + align-items: flex-start; + flex-direction: column; + padding: 12px 0; + } + + .app-topbar-right, + .app-nav { + width: 100%; + } + + .app-topbar-right { + justify-content: space-between; + } +} + +@media (max-width: 960px) { + .landing-hero-shell, + .landing-hero-shell-public, + .auth-layout, + .auth-hero-card, + .review-page-hero { + grid-template-columns: 1fr; + } + + .landing-hero-shell-public { + min-height: auto; + } + + .landing-visual-scene { + min-height: 460px; + } + + .landing-command-flow, + .landing-command-alerts, + .review-hero-visual, + .landing-showcase-grid { + grid-template-columns: 1fr; + } + + .landing-hero h1, + .auth-hero-copy h1 { + font-size: 42px; + line-height: 1.04; + } +} + +@media (max-width: 640px) { + .app-topbar-inner, + .landing-page, + .page-shell, + .auth-page { + width: 100%; + padding-left: 16px; + padding-right: 16px; + } + + .app-nav-link { + min-width: max-content; + } + + .app-user-chip { + width: 100%; + justify-content: space-between; + } + + .landing-hero, + .auth-hero-card, + .auth-form-card .ant-card-body, + .review-page-hero { + padding: 22px; + } + + .landing-hero h1, + .auth-hero-copy h1 { + font-size: 34px; + } + + .landing-visual-scene { + min-height: 420px; + padding: 18px; + } + + .landing-contract-paper { + padding: 20px; + } + + .landing-risk-pulse { + position: static; + width: 100%; + margin-top: 14px; + } +} + +/* 2026 structural redesign: information architecture and mobile density */ +.app-nav-admin-trigger { + cursor: pointer; + font: inherit; +} + +.app-nav-admin-caret { + font-size: 10px; + opacity: 0.76; +} + +.app-admin-menu-item { + display: flex; + min-width: 178px; + min-height: 42px; + align-items: center; + gap: 10px; + color: #111217; + font-weight: 800; +} + +.app-admin-menu-item .app-nav-icon { + color: var(--primary-dark); +} + +.page-shell > .ant-space, +.landing-page > .ant-space, +.auth-page > .ant-space { + gap: 18px !important; +} + +.page-shell .ant-card-head { + min-height: 52px; + border-color: rgba(17, 18, 23, 0.08); +} + +.page-shell .ant-card-head-title { + color: #111217; + font-weight: 900; +} + +.page-shell .ant-card-body { + min-width: 0; +} + +.review-page-hero, +.review-history-hero, +.review-detail-hero { + align-items: stretch; + gap: 18px; + min-height: 0; + padding: 28px; +} + +.review-page-hero, +.review-history-hero { + grid-template-columns: minmax(0, 1.45fr) minmax(250px, 0.55fr); +} + +.review-detail-hero { + grid-template-columns: minmax(0, 1.18fr) minmax(300px, 0.82fr); +} + +.review-page-hero-copy, +.page-header-block { + display: flex; + min-width: 0; + flex-direction: column; + gap: 12px; +} + +.review-page-hero-copy h2, +.review-detail-hero h2, +.review-history-hero h2, +.page-header-block h2 { + max-width: 780px; + margin: 0 !important; + text-wrap: balance; +} + +.review-page-hero-copy .ant-typography-secondary, +.page-header-block .ant-typography-secondary, +.review-toolbar-copy > span:last-child { + max-width: 690px; + color: #4f596c !important; + font-size: 15px; + line-height: 1.65; +} + +.review-side-card { + align-self: stretch; +} + +.review-side-card .ant-card-body { + display: flex; + height: 100%; + flex-direction: column; + gap: 12px; + padding: 18px !important; +} + +.review-side-card .review-page-tip-list { + display: grid; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} + +.review-side-card .review-page-tip-list li { + padding: 8px 10px; + border-radius: 8px; + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.1); + font-size: 13px; + line-height: 1.45; +} + +.review-side-card .ant-alert { + margin-top: auto; + color: rgba(255, 255, 255, 0.82); + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.12); +} + +.review-page-grid .chat-layout-grid-history { + grid-template-columns: minmax(300px, 0.72fr) minmax(0, 1.28fr); + align-items: start; +} + +.chat-page-shell .chat-layout-grid-history { + grid-template-columns: minmax(230px, 0.52fr) minmax(320px, 0.84fr) minmax(0, 1.32fr); + align-items: start; +} + +.chat-page-shell .review-page-hero { + grid-template-columns: minmax(0, 1.2fr) minmax(310px, 0.8fr); +} + +.review-page-grid .review-surface-card:first-child { + position: sticky; + top: 96px; +} + +.contracts-page .review-surface-card:first-child, +.profile-page .review-surface-card:first-child, +.pilot-readiness-page .review-surface-card:first-child, +.chat-page-shell .review-surface-card:first-child { + position: static; +} + +.review-toolbar { + display: grid; + grid-template-columns: minmax(220px, 0.72fr) minmax(0, 1.28fr); + align-items: end; + gap: 16px; +} + +.review-toolbar-copy { + min-width: 0; +} + +.review-toolbar-copy strong { + color: #111217; + font-size: 18px; + line-height: 1.2; +} + +.review-toolbar-controls { + justify-content: flex-end; +} + +.review-toolbar-search { + min-width: min(100%, 320px); +} + +.review-history-stats { + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.review-history-cta { + min-height: 100%; +} + +.review-detail-anchor-nav { + position: sticky; + top: 76px; + z-index: 8; + overflow-x: auto; + padding: 10px; + border-radius: 8px; + background: rgba(255, 255, 255, 0.88); + border: 1px solid rgba(17, 18, 23, 0.08); + box-shadow: 0 10px 28px rgba(12, 16, 24, 0.08); + scrollbar-width: none; +} + +.review-detail-anchor-nav::-webkit-scrollbar { + display: none; +} + +.review-detail-action-dock, +.contract-detail-two-column, +.contract-content-grid, +.pilot-readiness-summary-grid { + display: grid; + gap: 16px; +} + +.review-detail-action-dock { + grid-template-columns: minmax(0, 1.16fr) minmax(260px, 0.84fr); +} + +.review-detail-action-dock .review-surface-card { + height: 100%; +} + +.contract-detail-two-column { + grid-template-columns: minmax(0, 1fr) minmax(280px, 0.68fr); +} + +.contract-content-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.contract-preview-panel { + max-height: 420px; + overflow: auto; + padding: 18px; + border-radius: 8px; + white-space: pre-wrap; + color: #1d2430; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(247, 250, 253, 0.96)), + repeating-linear-gradient(0deg, rgba(17, 18, 23, 0.04) 0 1px, transparent 1px 28px); + border: 1px solid rgba(17, 18, 23, 0.1); + font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; + font-size: 13px; + line-height: 1.7; +} + +.embedded-panel { + display: grid; + gap: 14px; + padding: 16px; + border-radius: 8px; + background: rgba(255, 255, 255, 0.64); + border: 1px solid rgba(17, 18, 23, 0.08); +} + +.embedded-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.embedded-panel-header strong { + color: #111217; + font-weight: 900; +} + +.auth-access-strip, +.contract-progress-strip, +.admin-signal-strip { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; +} + +.auth-access-strip span, +.contract-progress-strip span, +.admin-signal-strip span { + display: flex; + min-height: 42px; + align-items: center; + justify-content: center; + padding: 10px; + border-radius: 8px; + color: #111217; + background: rgba(182, 243, 91, 0.34); + border: 1px solid rgba(17, 18, 23, 0.08); + font-size: 13px; + font-weight: 900; + text-align: center; +} + +.auth-form-card .ant-alert + .ant-alert { + margin-top: -4px; +} + +.review-config-highlight-grid, +.chat-review-meta-grid, +.review-detail-hero-meta, +.review-detail-hero-stats { + min-width: 0; +} + +.review-detail-info-note, +.chat-conversation-meta, +.review-filter-meta { + border-radius: 8px; +} + +.ant-table-wrapper { + overflow: hidden; +} + +.ant-table-cell { + vertical-align: top; +} + +.ant-btn, +.landing-primary-action, +.landing-secondary-action, +.app-nav-link, +.app-login-entry { + min-height: 42px; +} + +.landing-primary-action, +.landing-secondary-action, +.review-detail-action-button, +.chat-action-card-link { + justify-content: center; + text-align: center; +} + +.pilot-readiness-page .page-header-block { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: end; + gap: 16px; +} + +.pilot-readiness-page .landing-grid { + align-items: stretch; +} + +@media (max-width: 1180px) { + .review-history-stats { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .chat-page-shell .chat-layout-grid-history, + .review-detail-action-dock { + grid-template-columns: 1fr 1fr; + } + + .chat-page-shell .chat-layout-grid-history > .ant-space { + grid-column: 1 / -1; + } +} + +@media (max-width: 960px) { + .review-page-hero, + .review-history-hero, + .review-detail-hero, + .chat-page-shell .review-page-hero, + .review-page-grid .chat-layout-grid-history, + .chat-page-shell .chat-layout-grid-history, + .review-detail-action-dock, + .contract-detail-two-column, + .contract-content-grid, + .pilot-readiness-page .page-header-block { + grid-template-columns: 1fr; + } + + .review-page-grid .review-surface-card:first-child { + position: static; + } + + .review-toolbar { + grid-template-columns: 1fr; + align-items: stretch; + } + + .review-toolbar-controls, + .review-toolbar-search, + .review-toolbar-select, + .review-toolbar-controls .ant-select, + .review-toolbar-controls .ant-btn { + width: 100% !important; + } + + .review-detail-anchor-nav { + top: 0; + } + + .auth-access-strip, + .contract-progress-strip, + .admin-signal-strip { + grid-template-columns: 1fr; + } +} + +@media (max-width: 640px) { + .app-topbar { + position: sticky; + top: 0; + z-index: 30; + } + + .app-topbar-inner { + gap: 10px; + min-height: 0; + } + + .app-brand-mark { + width: 38px; + height: 38px; + } + + .app-brand-copy span { + display: none; + } + + .app-topbar-right { + width: 100%; + align-items: stretch; + flex-direction: column; + gap: 8px; + } + + .app-topbar .app-nav { + order: 2; + width: 100%; + max-width: 100%; + justify-content: flex-start; + padding-bottom: 2px; + } + + .app-login-entry { + display: none; + } + + .app-nav-link { + flex: 0 0 auto; + min-height: 40px; + padding: 8px 10px; + font-size: 13px; + } + + .app-user-chip { + order: 1; + min-height: 42px; + } + + .review-page-hero, + .review-history-hero, + .review-detail-hero { + gap: 16px; + padding: 20px; + } + + .review-page-hero-copy h2, + .review-detail-hero h2, + .review-history-hero h2, + .page-header-block h2 { + font-size: 26px; + line-height: 1.12; + } + + .review-page-hero-copy .ant-typography-secondary, + .page-header-block .ant-typography-secondary { + font-size: 14px; + } + + .review-side-card .ant-alert { + display: none; + } + + .review-history-stats, + .landing-stats, + .landing-grid, + .review-detail-hero-meta, + .review-detail-hero-stats, + .review-detail-decision-strip, + .review-detail-group-grid, + .chat-review-meta-grid, + .chat-answer-summary-grid, + .chat-action-card-grid, + .review-config-highlight-grid { + grid-template-columns: 1fr !important; + } + + .review-detail-action-row, + .chat-action-row, + .review-toolbar-controls, + .ant-card-extra, + .ant-space { + max-width: 100%; + } + + .review-detail-action-row, + .chat-action-row { + display: grid; + grid-template-columns: 1fr; + } + + .review-detail-action-row .landing-primary-action, + .review-detail-action-row .landing-secondary-action, + .chat-action-row .ant-btn, + .ant-card-extra .ant-btn, + .ant-card-extra .ant-select, + .ant-card-extra .ant-input-number, + .ant-card-extra .ant-input-search { + width: 100% !important; + } + + .ant-card-extra { + margin-top: 12px; + } + + .ant-card-head { + flex-direction: column; + align-items: stretch !important; + } + + .contract-preview-panel { + max-height: 360px; + font-size: 12px; + } +} diff --git a/frontend/src/app/knowledge-bases/page.tsx b/frontend/src/app/knowledge-bases/page.tsx index c638e5d2..1c1a81f8 100644 --- a/frontend/src/app/knowledge-bases/page.tsx +++ b/frontend/src/app/knowledge-bases/page.tsx @@ -306,19 +306,18 @@ export default function KnowledgeBasesPage() {
    Knowledge Base - 集中维护知识库与文档索引状态。 - 先补齐 V1 最小闭环:知识库列表、创建知识库、上传文档,以及文档处理状态与失败原因展示。 + 管理知识库、文档与索引状态。 + 左侧选择知识库,右侧上传和追踪文档处理结果,失败原因直接暴露。
    Admin Workspace - 知识库维护流程 + 管理节奏
      -
    • 当前页面为管理员主用,普通成员不开放知识库管理入口。
    • 先创建知识库,再上传文档。
    • -
    • 当前支持 txt、docx、pdf 等文档的文本提取与预览。
    • -
    • 后续继续补强更深的切片、召回与索引能力。
    • +
    • 处理失败时优先看生命周期说明。
    • +
    • 索引完成后可进入问答继续使用。
    diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index e4902822..acdb3209 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -178,6 +178,27 @@ function LoginPageContent() { ))}
    +
    +
    + Access Matrix + 审查工作台已就绪 +
    +
    + + + +
    +
    +
    + Session + Active +
    +
    + Role + Tenant +
    +
    +
    @@ -211,9 +232,12 @@ function LoginPageContent() { - - - +
    + 注册后自动进入 + Enter 快速提交 + {redirectTarget === "/" ? "默认到工作台" : "返回目标页"} +
    + {hasStoredSession ? : null} {registerSuccessTip ? : null} = { low: "低风险", }; +const publicShowcaseCards = [ + { label: "Clause Scanner", value: "82 条", tone: "cyan" }, + { label: "Risk Radar", value: "12 项", tone: "coral" }, + { label: "Legal Sources", value: "36 条", tone: "amber" }, +]; + +const commandFlowItems = ["文件解析", "风险识别", "条款建议", "报告交付"]; + function formatDateTime(value: string) { return new Date(value).toLocaleString("zh-CN", { hour12: false }); } @@ -271,16 +279,30 @@ export default function HomePage() { const adminWorkbenchLinks = useMemo(() => getAdminWorkbenchLinks(currentUser?.role), [currentUser?.role]); const workspaceInsights = useMemo(() => buildWorkspaceInsights(reviews), [reviews]); const gettingStartedLinks = useMemo(() => buildGettingStartedLinks(currentUser?.role), [currentUser?.role]); + const dashboardHighlights = useMemo( + () => [ + ...priorityTasks.map((item) => ({ href: item.href, eyebrow: item.label, title: item.title, description: item.meta })), + ...workspaceInsights.map((item) => ({ href: item.href, eyebrow: item.label, title: item.title, description: item.description })), + ].slice(0, 6), + [priorityTasks, workspaceInsights], + ); + const workflowLinks = useMemo( + () => [ + ...gettingStartedLinks.map((item) => ({ ...item, eyebrow: "Next Step" })), + ...quickLinks.map((item) => ({ href: item.href, label: item.label, description: item.description, eyebrow: item.eyebrow })), + ].slice(0, 6), + [gettingStartedLinks, quickLinks], + ); if (!currentUser) { return (
    {contextHolder} -
    -
    +
    +
    AI Contract Platform -

    面向真实业务流转的合同工作平台。

    -

    现在系统已接入正式数据库,登录、合同审查、审查记录、结果详情与报告下载主链路均已打通。

    +

    让合同审查像刷仪表盘一样清爽、快速、有判断力。

    +

    围绕上传、识别、建议、报告导出重组体验,把 AI 审查结果变成可行动的法务工作流。

    立即注册新账号 @@ -289,6 +311,41 @@ export default function HomePage() { 进入登录
    +
    + 合同初审 + 风险雷达 + 依据引用 + 报告交付 +
    +
    + +
    +
    + Live Review Console + V1 Pilot +
    +
    +
    + 保密协议 · NDA + 自动定位高风险条款 +
    +
    +
    +
    +
    +
    + High Risk + 03 +
    +
    +
    + {publicShowcaseCards.map((item) => ( +
    + {item.label} + {item.value} +
    + ))} +
    @@ -301,8 +358,8 @@ export default function HomePage() {
    Contract Workspace -

    你好,{currentUser.display_name}。这里是你的合同业务工作台。

    -

    首页现在承担业务 cockpit 角色:展示当前租户审查概览、风险分布、待处理状态与核心操作入口,而不再只是简单 landing 页。

    +

    你好,{currentUser.display_name}。今天先处理最重要的合同任务。

    +

    审查概览、风险分布和核心入口集中在这里,首页负责帮你判断下一步。

    立即发起审查 @@ -311,6 +368,34 @@ export default function HomePage() { 进入合同生成
    +
    +
    + AI Review Pipeline + {stats.completedCount}/{stats.totalReviews || 0} +
    +
    + {commandFlowItems.map((item, index) => ( +
    + {String(index + 1).padStart(2, "0")} + {item} +
    + ))} +
    +
    +
    + 高风险 + {stats.highRisk} +
    +
    + 处理中 + {stats.pendingCount} +
    +
    + 异常 + {stats.failedCount} +
    +
    +
    {stats.totalReviews} @@ -381,35 +466,15 @@ export default function HomePage() {

    优先处理摘要

    -

    优先展示高风险、异常和处理中任务,让首页更像可执行的驾驶舱。

    +

    运营摘要与高风险、异常和处理中任务直接前置,减少二次判断。

    - {priorityTasks.length === 0 ? ( + {dashboardHighlights.length === 0 ? ( ) : (
    - {priorityTasks.map((item) => ( - - {item.label} - {item.title} - {item.meta} - - ))} -
    - )} -
    - -
    -
    -

    运营摘要

    -

    把当前最值得立刻动作的任务直接前置,减少再判断成本。

    -
    - {workspaceInsights.length === 0 ? ( - - ) : ( -
    - {workspaceInsights.map((item) => ( - - {item.label} + {dashboardHighlights.map((item) => ( + + {item.eyebrow} {item.title} {item.description} @@ -420,13 +485,13 @@ export default function HomePage() {
    -

    起步建议

    -

    针对当前角色给出最合理的下一步,让新注册用户进入系统后不会迷路。

    +

    核心入口

    +

    把新用户起步和高频功能合并,避免首页变成导航墙。

    - {gettingStartedLinks.map((item) => ( - - Getting Started + {workflowLinks.map((item) => ( + + {item.eyebrow} {item.label} {item.description} @@ -482,21 +547,6 @@ export default function HomePage() { )}
    -
    -
    -

    快捷入口

    -

    保持首页的业务工作台属性,而不是只放导航链接。

    -
    -
    - {quickLinks.map((link) => ( - - {link.eyebrow} - {link.label} - {link.description} - - ))} -
    -
    ); } diff --git a/frontend/src/app/pilot-readiness/page.tsx b/frontend/src/app/pilot-readiness/page.tsx index b3691916..a2bced7d 100644 --- a/frontend/src/app/pilot-readiness/page.tsx +++ b/frontend/src/app/pilot-readiness/page.tsx @@ -95,19 +95,30 @@ export default function PilotReadinessPage() { } return ( -
    +
    -
    - - Phase 3 Pilot Delivery +
    +
    + Pilot Delivery 试点交付准备 - 阶段 3 验收门禁集中在这里:环境状态、默认账号、演示链路和自动化验收结果需要能被管理员快速复查。 + 阶段 3 验收门禁集中在这里:环境、账号、演示链路和自动化验收项集中在一个工作台,失败项直接暴露。 - - +
    + + Readiness Control + + 交付门禁 + +
      +
    • 先看必需项失败数。
    • +
    • 再检查默认账号与演示链路。
    • +
    • 最后用验收项确认试点路径。
    • +
    + +
    {errorMessage ? : null} diff --git a/frontend/src/app/profile/page.tsx b/frontend/src/app/profile/page.tsx index 0750dd94..bb2673fd 100644 --- a/frontend/src/app/profile/page.tsx +++ b/frontend/src/app/profile/page.tsx @@ -73,24 +73,24 @@ export default function ProfilePage() { }; return ( -
    +
    {contextHolder}
    Profile Settings - 维护当前账号的显示名称与登录密码。 - 补齐 V1 个人设置页,保持范围只覆盖当前登录用户的基础资料维护。 + 管理当前账号的名称与密码。 + 这里只处理当前登录账号,资料范围更清晰,操作也更轻。
    My Workspace - 个人设置 + 账号边界
      -
    • 支持修改当前显示名称。
    • +
    • 显示名称立即同步到顶栏。
    • 密码留空时保持不变。
    • -
    • 仅作用于当前登录账号。
    • +
    • 不会影响租户内其他成员。
    diff --git a/frontend/src/app/review/page.tsx b/frontend/src/app/review/page.tsx index 968135ef..60566036 100644 --- a/frontend/src/app/review/page.tsx +++ b/frontend/src/app/review/page.tsx @@ -19,12 +19,6 @@ type ReviewFormValues = { const reviewHighlights = ["支持 PDF / DOCX / TXT 上传", "可叠加补充文本说明", "提交后自动进入结果详情页"]; -const reviewTips = [ - "上传文件后会先抽取文本,再进入风险识别链路。", - "如合同有补充说明,可直接粘贴在右侧文本框中一起审查。", - "详情页会展示风险总览、条款摘要与可下载报告。", -]; - export default function ReviewPage() { const router = useRouter(); const [form] = Form.useForm(); @@ -101,8 +95,8 @@ export default function ReviewPage() {
    Start Review - 提交一份合同,快速进入审查工作流。 - 支持文件上传与文本补充双入口,让合同提交从一开始就具备正式产品工作台的使用体验。 + 上传合同,直接进入风险审查。 + 文件上传和文本粘贴合并成一个提交流,先完成合同输入,再设置审查视角。
    {reviewHighlights.map((item) => ( @@ -110,14 +104,22 @@ export default function ReviewPage() { ))}
    +
    + {submissionSteps.map((item, index) => ( +
    + {String(index + 1).padStart(2, "0")} + {item} +
    + ))} +
    Submission Guide - 审查前提示 + 提交节奏
      - {reviewTips.map((item) => ( + {submissionSteps.map((item) => (
    • {item}
    • ))}
    @@ -160,16 +162,6 @@ export default function ReviewPage() {
    - -
    - {submissionSteps.map((item, index) => ( -
    - 0{index + 1} - {item} -
    - ))} -
    -
    @@ -221,13 +213,6 @@ export default function ReviewPage() { - -
      - {reviewTips.map((item) => ( -
    • {item}
    • - ))} -
    -
    diff --git a/frontend/src/app/reviews/[id]/page.tsx b/frontend/src/app/reviews/[id]/page.tsx index 4e333145..740e3591 100644 --- a/frontend/src/app/reviews/[id]/page.tsx +++ b/frontend/src/app/reviews/[id]/page.tsx @@ -482,94 +482,94 @@ export default function ReviewDetailPage({ params }: { params: Promise<{ id: str ))}
    - -
    -
    - Review Copilot - 继续用合同审查助手跟进这份合同 -

    会把当前审查结果、风险等级、审查建议和文本摘要一起带入问答页,直接围绕这份合同继续追问。

    -
    -
    -
    - 当前任务 - {detail?.title ?? "-"} +
    + +
    +
    + Review Copilot + 继续用审查助手处理这份合同 +

    自动带入风险等级、审查建议和文本摘要,直接进入下一轮追问。

    -
    - 总体风险 - {overallRisk} +
    +
    + 当前任务 + {detail?.title ?? "-"} +
    +
    + 总体风险 + {overallRisk} +
    +
    + 问答模式 + 审查上下文 +
    +
    + 建议动作 + 先处理高风险 +
    -
    - 问答模式 - 审查上下文已预置 -
    -
    - 建议动作 - 继续追问条款风险 -
    -
    - - {reviewChatPayloadReady ? ( - - 进入审查助手问答 + + {reviewChatPayloadReady ? ( + + 进入审查助手问答 + + ) : ( + + )} + + 打开通用问答页 - ) : ( - - )} - - 打开通用问答页 - - -
    -
    + +
    + - -
    -
    - Quick Actions + + +
    +
    + QUICK ACTIONS 围绕当前审查结果,直接继续推进 - {`当前总体风险为${overallRisk},可直接解释风险、生成修改清单或准备谈判策略。`} -
    - - {quickActionItems.map((item, index) => ( - - {item.label} - - ))} - -
    - 当前追问主线:优先围绕总体风险、重点风险项与条款摘要,继续把问答结果回流为修改动作和谈判准备。 -
    -
    -
    + {`总体风险:${overallRisk}。优先解释风险、生成修改清单或准备谈判策略。`} +
    + + {quickActionItems.map((item, index) => ( + + {item.label} + + ))} + +
    +
    - -
    -
    - Workbench - 处理工作台入口 - 围绕当前审查任务,继续在报告、文件、知识库与审查列表之间快速切换。 -
    - - {report ? ( - - ) : null} - {detail?.can_retry ? ( - - ) : null} - {reviewWorkbenchItems.map((item) => ( - - {item.label} - - ))} - -
    -
    + +
    +
    + Workbench + 报告、文件与列表入口 +
    + + {report ? ( + + ) : null} + {detail?.can_retry ? ( + + ) : null} + {reviewWorkbenchItems.map((item) => ( + + {item.label} + + ))} + +
    +
    + +
    diff --git a/frontend/src/app/reviews/page.tsx b/frontend/src/app/reviews/page.tsx index aa8ac231..7e0e5d75 100644 --- a/frontend/src/app/reviews/page.tsx +++ b/frontend/src/app/reviews/page.tsx @@ -411,8 +411,8 @@ export default function ReviewsPage() {
    Review History - 把审查记录沉淀成可继续处理的任务工作台。 - 列表页已按需求继续收口为可交付工作台:支持筛选、进入详情、下载报告、查看文件资产与继续处理。 + 审查记录不再只是列表,而是任务工作台。 + 从这里筛选任务、进入详情、下载报告,或继续处理未完成合同。
    最近一次任务创建时间:{latestTaskLabel}
    当前列表展示:{filterSummary}
    @@ -420,7 +420,7 @@ export default function ReviewsPage() { History Insight - 审查记录工作台 + 处理优先级
      {historyTips.map((item) => ( diff --git a/frontend/src/app/rules/page.tsx b/frontend/src/app/rules/page.tsx index 50a63f09..4d24884e 100644 --- a/frontend/src/app/rules/page.tsx +++ b/frontend/src/app/rules/page.tsx @@ -279,16 +279,15 @@ export default function RulesPage() {
      Rule Management - 集中维护合同审查规则,并直接驱动审查结果。 - 先补齐 V1 最小闭环:规则列表、新增、编辑、启用停用,并接入现有关键词审查链路。 + 维护审查规则,直接影响风险识别。 + 左侧编辑规则,右侧查看启停状态和命中依据,规则变更更容易复核。
      Admin Workspace - 规则维护流程 + 规则节奏
        -
      • 当前页面为管理员主用,普通成员不开放规则治理能力。
      • 先配置关键词规则,再发起合同审查。
      • 支持按合同类型区分规则。
      • 停用规则后不再参与后续审查匹配。
      • diff --git a/frontend/src/app/templates/page.tsx b/frontend/src/app/templates/page.tsx index eed41f09..72bec501 100644 --- a/frontend/src/app/templates/page.tsx +++ b/frontend/src/app/templates/page.tsx @@ -360,8 +360,8 @@ export default function TemplatesPage() {
        Template Management - 集中维护合同模板,先补齐可用的管理闭环。 - 当前支持模板列表、创建、编辑、删除,以及变量 JSON 配置的最小 V1 管理流程。 + 维护可复用模板和变量字段。 + 模板正文、变量配置和启停状态放在同一个工作台,方便生成链路直接消费。 - } - > +
        {(watchedVariables ?? [{}]).map((_, index) => ( @@ -423,10 +420,13 @@ export default function TemplatesPage() { ))} - - + +
        +
        + 变量 JSON 预览 +
        {variablePreview}
        - +
        diff --git a/frontend/src/app/tenant-settings/page.tsx b/frontend/src/app/tenant-settings/page.tsx index fc19ac53..7f7eb9ea 100644 --- a/frontend/src/app/tenant-settings/page.tsx +++ b/frontend/src/app/tenant-settings/page.tsx @@ -105,16 +105,15 @@ export default function TenantSettingsPage() {
        Tenant Settings - 查看当前租户基础信息、套餐与容量限制。 - 先补齐 V1 最小闭环:管理员可维护租户基础信息,并查看当前套餐和容量上限。 + 维护租户信息,核对套餐容量。 + 基础信息可编辑,套餐和限制作为右侧只读核对区展示。
        Admin Workspace - 租户设置工作台 + 租户边界
          -
        • 当前页面为管理员主用,普通成员不开放租户设置更新能力。
        • 支持维护租户名称、编码与状态。
        • 展示当前套餐与容量限制。
        • 范围保持在当前租户,不扩展到租户管理列表。
        • diff --git a/frontend/src/app/users/page.tsx b/frontend/src/app/users/page.tsx index 307a153a..85dec348 100644 --- a/frontend/src/app/users/page.tsx +++ b/frontend/src/app/users/page.tsx @@ -237,16 +237,15 @@ export default function UsersPage() {
          User Management - 集中管理租户内账号、角色与启停状态。 - 先补齐 V1 最小闭环:用户列表、新增、编辑、角色调整和启停管理。 + 管理成员账号、角色和启停状态。 + 账号表单和成员列表并排处理,适合管理员快速开通、调整和停用。
          Admin Workspace - 用户管理流程 + 成员治理
            -
          • 管理员可在当前租户内维护账号。
          • 登录账号统一按邮箱格式管理,和注册页口径保持一致。
          • 支持调整角色与账号状态。
          • 编辑用户时可选填新密码,不填则保持原密码。
          • diff --git a/frontend/src/components/layout/app-topbar.tsx b/frontend/src/components/layout/app-topbar.tsx index 476437f0..a39669f7 100644 --- a/frontend/src/components/layout/app-topbar.tsx +++ b/frontend/src/components/layout/app-topbar.tsx @@ -1,35 +1,53 @@ "use client"; +import { + AuditOutlined, + BookOutlined, + CommentOutlined, + DashboardOutlined, + FileDoneOutlined, + FileProtectOutlined, + FolderOpenOutlined, + HistoryOutlined, + SafetyCertificateOutlined, + SettingOutlined, + SolutionOutlined, + TeamOutlined, + ThunderboltOutlined, + UserOutlined, + DownOutlined, +} from "@ant-design/icons"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; -import { Button } from "antd"; +import { useEffect, useRef } from "react"; +import { Button, Dropdown, type MenuProps } from "antd"; import { clearSession, useAuthStore } from "@/stores/auth.store"; const publicNavItems = [ - { href: "/", label: "首页" }, - { href: "/login?tab=register", label: "注册" }, - { href: "/login", label: "登录" }, + { href: "/", label: "首页", icon: }, + { href: "/login?tab=register", label: "注册", icon: }, + { href: "/login", label: "登录", icon: }, ]; const privateNavItems = [ - { href: "/", label: "首页" }, - { href: "/review", label: "发起审查" }, - { href: "/reviews", label: "审查记录" }, - { href: "/chat", label: "法律问答" }, - { href: "/contracts", label: "合同生成" }, - { href: "/profile", label: "个人设置" }, + { href: "/", label: "首页", icon: }, + { href: "/review", label: "发起审查", icon: }, + { href: "/reviews", label: "审查记录", icon: }, + { href: "/chat", label: "法律问答", icon: }, + { href: "/contracts", label: "合同生成", icon: }, + { href: "/profile", label: "个人设置", icon: }, ]; const adminNavItems = [ - { href: "/rules", label: "规则管理" }, - { href: "/templates", label: "模板管理" }, - { href: "/knowledge-bases", label: "知识库管理" }, - { href: "/files", label: "文件管理" }, - { href: "/tenant-settings", label: "租户设置" }, - { href: "/users", label: "用户管理" }, - { href: "/audit-logs", label: "审计日志" }, - { href: "/pilot-readiness", label: "试点交付" }, + { href: "/rules", label: "规则管理", icon: }, + { href: "/templates", label: "模板管理", icon: }, + { href: "/knowledge-bases", label: "知识库管理", icon: }, + { href: "/files", label: "文件管理", icon: }, + { href: "/tenant-settings", label: "租户设置", icon: }, + { href: "/users", label: "用户管理", icon: }, + { href: "/audit-logs", label: "审计日志", icon: }, + { href: "/pilot-readiness", label: "试点交付", icon: }, ]; function isActive(pathname: string, href: string) { @@ -43,18 +61,37 @@ function isActive(pathname: string, href: string) { export function AppTopbar() { const pathname = usePathname(); const router = useRouter(); + const navRef = useRef(null); const currentUser = useAuthStore((state) => state.currentUser); - const navItems = currentUser - ? currentUser.role === "admin" - ? [...privateNavItems, ...adminNavItems] - : privateNavItems - : publicNavItems; + const navItems = currentUser ? privateNavItems : publicNavItems; + const showAdminMenu = currentUser?.role === "admin"; + const adminMenuActive = adminNavItems.some((item) => isActive(pathname, item.href)); + const adminMenuItems: MenuProps["items"] = adminNavItems.map((item) => ({ + key: item.href, + label: ( + + + {item.label} + + ), + })); const handleLogout = () => { clearSession(); router.push("/login"); }; + useEffect(() => { + const frameId = window.requestAnimationFrame(() => { + const activeItem = navRef.current?.querySelector(".app-nav-link-active"); + activeItem?.scrollIntoView({ behavior: "auto", block: "nearest", inline: "center" }); + }); + + return () => window.cancelAnimationFrame(frameId); + }, [currentUser?.role, pathname]); + return (
            @@ -67,16 +104,44 @@ export function AppTopbar() {
            -
            - ) : ( + ) : pathname === "/login" ? null : ( 进入登录 diff --git a/project-docs/闭环交付与深度开发方案-2026-05-01.md b/project-docs/闭环交付与深度开发方案-2026-05-01.md index ab526f8d..85a56e1b 100644 --- a/project-docs/闭环交付与深度开发方案-2026-05-01.md +++ b/project-docs/闭环交付与深度开发方案-2026-05-01.md @@ -15,11 +15,11 @@ | 阶段 3:试点交付准备 | PASS | `project-docs/阶段3-试点交付准备执行记录-2026-05-01.md` | | 阶段 4:试点运行监控与安全加固 | PASS | `project-docs/阶段4-试点运行监控与安全加固执行记录-2026-05-01.md` | | 阶段 5:生产运行、安全、监控、备份与依赖治理 | PASS | `project-docs/阶段5-生产运行安全监控备份与依赖治理执行记录-2026-05-01.md` | -| 阶段 6:生产运营自动化与发布门禁固化 | PASS_WITH_WORKTREE_WARN | `project-docs/阶段6-生产运营自动化与发布门禁固化执行记录-2026-05-01.md` | +| 阶段 6:生产运营自动化与发布门禁固化 | PASS_PENDING_STRICT_GATE | `project-docs/阶段6-生产运营自动化与发布门禁固化执行记录-2026-05-01.md` | 阶段 1 已完成源码闭环与生产入口闭环,生产无人 E2E `18/18` 通过。阶段 2 已完成 Review 重试、Knowledge Base 文档重试、Review -> Chat -> Contract 上下文联动、首页交付工作台和阶段 2 自动化无人闭环,本地与生产 E2E 均 `7/7` 通过。阶段 3 已完成系统 readiness、试点交付准备页、默认账号说明、演示样本数据、依赖健康门禁和阶段 3 自动化无人闭环,本地与生产 E2E 均 `5/5` 通过。 -当前后续重点已从“生产运行治理”推进到“生产运营自动化与发布门禁固化”:阶段 6 已完成前端视觉改动梳理、发布门禁聚合脚本、默认发布门禁实跑和严格门禁探针。默认发布门禁 required 项全部 PASS,当前唯一 WARN 是工作区保留未提交前端视觉刷新。 +当前后续重点已从“生产运行治理”推进到“生产运营自动化与发布门禁固化”:阶段 6 已完成前端视觉改动梳理、发布门禁聚合脚本、默认发布门禁实跑、严格门禁探针和前端视觉刷新验收。下一步是提交视觉刷新并复跑严格发布门禁。 --- @@ -219,4 +219,4 @@ AI合同平台当前已经不是从零建设阶段。登录、合同审查、Rev ## 六、当前一句话结论 -AI合同平台阶段 1、阶段 2、阶段 3、阶段 4、阶段 5 均已完成闭环交付验证,阶段 6 首批发布门禁自动化也已形成闭环。当前系统具备主业务闭环、试点交付准备、生产健康巡检、备份恢复演练、依赖治理、安全基线、生产关键 E2E 回归和统一发布门禁证据;正式发布前需先处理当前未提交前端视觉刷新并复跑严格门禁。 +AI合同平台阶段 1、阶段 2、阶段 3、阶段 4、阶段 5 均已完成闭环交付验证,阶段 6 首批发布门禁自动化也已形成闭环。当前系统具备主业务闭环、试点交付准备、生产健康巡检、备份恢复演练、依赖治理、安全基线、生产关键 E2E 回归、前端视觉刷新验收和统一发布门禁证据;提交视觉刷新后需复跑严格门禁。 diff --git a/project-docs/阶段6-前端视觉刷新验收记录-2026-05-01.md b/project-docs/阶段6-前端视觉刷新验收记录-2026-05-01.md new file mode 100644 index 00000000..67fd254c --- /dev/null +++ b/project-docs/阶段6-前端视觉刷新验收记录-2026-05-01.md @@ -0,0 +1,102 @@ +# 阶段 6:前端视觉刷新验收记录(2026-05-01) + +> 目标:对已完成的前端视觉刷新进行独立验收,确认它不破坏主链路、管理入口、试点交付入口和移动端基本可用性,然后再纳入发布门禁。 + +--- + +## 一、验收结论 + +| 项目 | 状态 | 备注 | +|---|---|---| +| 前端 lint | PASS | `npm run lint` 通过 | +| 前端 production build | PASS | `npm run build` 通过,18 个 app route 生成完成 | +| 本地视觉版阶段 1/2/3 E2E | PASS | 使用 `http://127.0.0.1:3014` 前端和试点后端代理,阶段 1/2/3 全部通过 | +| 桌面/移动视觉 smoke | PASS | 10 个页面 x 2 个视口,截图和 console error 检查通过 | +| 验收锚点兼容修补 | PASS | 恢复 `优先处理摘要`、`运营摘要`、`试点交付准备`、`阶段 3 验收门禁`、`QUICK ACTIONS` 等稳定验收文案 | +| 顶部导航兼容修补 | PASS | admin 顶栏保留直接 `/pilot-readiness` 链接,同时保留管理下拉菜单 | + +当前判定:前端视觉刷新可以进入提交和严格发布门禁。 + +--- + +## 二、本次视觉刷新范围 + +| 区域 | 说明 | +|---|---| +| 全局主题 | 新增视觉主题、卡片、导航、页面布局、移动端约束等样式 | +| 顶部导航 | 增加图标化导航、admin 管理下拉、试点交付直接入口 | +| 首页 | 公共首页视觉场景、登录后工作台、优先摘要、核心入口和管理员入口重组 | +| 登录页 | 增加安全工作台预览和更紧凑的登录提示 | +| 发起审查 | 提交流程视觉前置,减少重复说明卡片 | +| 审查详情 | Review Copilot、Quick Actions、报告/文件入口集中为行动区 | +| 合同生成/详情 | 预览、变量、导出选项和生成内容布局优化 | +| 管理页 | 知识库、模板、文件、用户、规则、租户设置、审计日志等页面统一视觉口径 | +| 试点交付 | Readiness 门禁页面改为阶段 6 统一视觉风格 | + +--- + +## 三、验证记录 + +静态和构建: + +```text +npm run lint +npm run build +``` + +本地视觉版服务: + +```text +http://127.0.0.1:3014 +BACKEND_BASE_URL=http://192.168.3.90:8001 +``` + +阶段 1/2/3 E2E 产物: + +```text +project-docs/qa-artifacts/phase6-visual-refresh/2026-05-01T10-24-37/closed-loop-regression-dev-3014/2026-05-01T10-33-12/ +``` + +视觉 smoke 产物: + +```text +project-docs/qa-artifacts/phase6-visual-refresh/2026-05-01T10-24-37/visual-smoke-2026-05-01T10-34-32/ +``` + +视觉 smoke 覆盖页面: + +1. `/` +2. `/login` +3. `/review` +4. `/reviews` +5. `/contracts` +6. `/knowledge-bases` +7. `/templates` +8. `/pilot-readiness` +9. `/users` + +覆盖视口: + +1. desktop:`1440 x 1000` +2. mobile:`390 x 844` + +--- + +## 四、发现与修补 + +| 问题 | 处理 | +|---|---| +| 首页视觉刷新后移除了旧 E2E 依赖的 `优先处理摘要` 和 `运营摘要` 文案 | 保留新布局,同时恢复稳定验收锚点 | +| 审查详情 Quick Actions 文案大小写与旧 E2E 不一致 | 恢复 `QUICK ACTIONS` 和 `围绕当前审查结果` | +| 试点交付页面标题更换后旧 E2E 无法识别 | 恢复 `试点交付准备` 和 `阶段 3 验收门禁` | +| admin 试点入口被收进管理下拉后旧 E2E 找不到直接链接 | 顶栏保留 `/pilot-readiness` 直接链接 | +| 旧 `3004` 本地服务占用端口且连接本地旧 API 状态 | 改用独立 `3014` 验收服务,代理到试点后端 | + +--- + +## 五、下一步 + +1. 提交前端视觉刷新和 `.gstack/` 忽略规则。 +2. 推送到 `192.168.3.90` 仓库。 +3. 复跑严格发布门禁:`run-production-release-gate.ps1 -RequireCleanWorktree`。 +4. 若严格门禁 PASS,则阶段 6 从 `PASS_WITH_WORKTREE_WARN` 更新为 `PASS`。 diff --git a/project-docs/阶段6-生产运营自动化与发布门禁固化执行记录-2026-05-01.md b/project-docs/阶段6-生产运营自动化与发布门禁固化执行记录-2026-05-01.md index c980b5e7..e8891379 100644 --- a/project-docs/阶段6-生产运营自动化与发布门禁固化执行记录-2026-05-01.md +++ b/project-docs/阶段6-生产运营自动化与发布门禁固化执行记录-2026-05-01.md @@ -13,7 +13,8 @@ | 发布门禁聚合脚本 | READY | 已新增 `scripts/run-production-release-gate.ps1` | | 发布门禁实跑 | WARN | 默认门禁已跑通,required 项全部 PASS,dirty worktree 为 advisory WARN | | 严格门禁探针 | PASS | `-RequireCleanWorktree` 已按预期把未提交视觉刷新升级为 FAIL | -| 阶段 6 首批闭环 | PASS_WITH_WORKTREE_WARN | 发布门禁自动化已闭环,正式发布前仍需处理当前前端视觉刷新 | +| 前端视觉刷新验收 | PASS | lint、build、阶段 1/2/3 E2E、桌面/移动视觉 smoke 均通过 | +| 阶段 6 首批闭环 | PASS_PENDING_STRICT_GATE | 发布门禁自动化已闭环,前端视觉刷新已验收,下一步提交后复跑严格门禁 | --- @@ -26,7 +27,7 @@ 1. 本轮阶段 6 运维自动化提交不纳入这些前端视觉文件。 2. 发布门禁默认模式会记录 dirty worktree 为 WARN。 3. 正式发布前必须使用 `-RequireCleanWorktree`,把 dirty worktree 升级为 FAIL。 -4. 前端视觉刷新后续单独做浏览器验收和提交。 +4. 前端视觉刷新已完成独立验收,下一步提交后复跑严格发布门禁。 清单文档: @@ -34,6 +35,12 @@ project-docs/阶段6-前端视觉改动梳理-2026-05-01.md ``` +验收记录: + +```text +project-docs/阶段6-前端视觉刷新验收记录-2026-05-01.md +``` + --- ## 三、发布门禁脚本 @@ -116,4 +123,4 @@ project-docs/qa-artifacts/phase6-release-gate/2026-05-01T09-29-45/ 2. 发布门禁脚本可复跑,并生成统一汇总报告。 3. 默认门禁 required 项全部 PASS。 4. 严格门禁可以阻断未提交工作区。 -5. 正式发布前下一步应先处理或提交当前前端视觉刷新。 +5. 前端视觉刷新已通过验收,下一步应提交视觉刷新并复跑 `-RequireCleanWorktree` 严格门禁。