From fd6177d479db5bb889470fdee3d97a4992e53ede Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Wed, 4 Mar 2026 16:23:31 +0800 Subject: [PATCH 1/9] chore(ui): add enterprise ui contract checks --- frontend/package.json | 3 ++- frontend/scripts/verify-ui-contract.mjs | 31 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 frontend/scripts/verify-ui-contract.mjs diff --git a/frontend/package.json b/frontend/package.json index 0bd25545..9621bd0c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "vite build", "preview": "vite preview", - "type-check": "vue-tsc --noEmit" + "type-check": "vue-tsc --noEmit", + "ui:contract": "node scripts/verify-ui-contract.mjs" }, "dependencies": { "axios": "^1.6.8", diff --git a/frontend/scripts/verify-ui-contract.mjs b/frontend/scripts/verify-ui-contract.mjs new file mode 100644 index 00000000..60743884 --- /dev/null +++ b/frontend/scripts/verify-ui-contract.mjs @@ -0,0 +1,31 @@ +import { readFileSync } from "node:fs"; + +const main = readFileSync("src/styles/main.css", "utf8"); +const unified = readFileSync("src/styles/unified-page.css", "utf8"); + +const requiredMainTokens = [ + "--ctms-primary", + "--ctms-text-main", + "--ctms-bg-base", + "--ctms-radius", + "--ctms-shadow" +]; + +const requiredUnifiedTokens = [ + "--unified-shell-bg", + "--unified-shell-radius", + ".unified-action-bar", + ".unified-section" +]; + +const missing = [ + ...requiredMainTokens.filter((t) => !main.includes(t)), + ...requiredUnifiedTokens.filter((t) => !unified.includes(t)) +]; + +if (missing.length) { + console.error("UI contract check failed. Missing:", missing.join(", ")); + process.exit(1); +} + +console.log("UI contract check passed"); From f7e867c2bd8a89d4d8e818e481798d594a1f800e Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Wed, 4 Mar 2026 16:25:05 +0800 Subject: [PATCH 2/9] feat(ui): add enterprise token baseline --- frontend/scripts/verify-ui-contract.mjs | 7 ++++++- frontend/src/styles/main.css | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/scripts/verify-ui-contract.mjs b/frontend/scripts/verify-ui-contract.mjs index 60743884..33b5713f 100644 --- a/frontend/scripts/verify-ui-contract.mjs +++ b/frontend/scripts/verify-ui-contract.mjs @@ -8,7 +8,12 @@ const requiredMainTokens = [ "--ctms-text-main", "--ctms-bg-base", "--ctms-radius", - "--ctms-shadow" + "--ctms-shadow", + "--ctms-brand-900", + "--ctms-brand-700", + "--ctms-neutral-100", + "--ctms-neutral-300", + "--ctms-focus-ring" ]; const requiredUnifiedTokens = [ diff --git a/frontend/src/styles/main.css b/frontend/src/styles/main.css index 95eb666a..882e1afc 100644 --- a/frontend/src/styles/main.css +++ b/frontend/src/styles/main.css @@ -11,6 +11,8 @@ --ctms-primary-hover: #365067; --ctms-primary-active: #2b4356; --ctms-primary-light: #e6edf2; + --ctms-brand-900: #13243a; + --ctms-brand-700: #24496f; /* 语义色 */ --ctms-success: #3f8f6b; @@ -28,6 +30,8 @@ --ctms-bg-base: #f9fafb; --ctms-bg-card: #ffffff; --ctms-bg-muted: #f3f4f6; + --ctms-neutral-100: #f5f7fa; + --ctms-neutral-300: #d5dce5; --ctms-border-color: #e5e7eb; --ctms-border-color-hover: #cbd5e1; @@ -51,6 +55,7 @@ /* 动画 */ --ctms-transition: all 0.25s cubic-bezier(0.22, 1, 0.36, 1); + --ctms-focus-ring: 0 0 0 3px rgba(36, 73, 111, 0.2); /* Element Plus 主色适配 */ --el-color-primary: var(--ctms-primary); From 80d98301393fde8bebee3a9439d35d451d5dc9ec Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Wed, 4 Mar 2026 16:26:17 +0800 Subject: [PATCH 3/9] feat(ui): enforce shared page shell contract --- frontend/scripts/verify-ui-contract.mjs | 5 ++++- frontend/src/components/Layout.vue | 8 +++++++- frontend/src/styles/unified-page.css | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/frontend/scripts/verify-ui-contract.mjs b/frontend/scripts/verify-ui-contract.mjs index 33b5713f..0a19f1a0 100644 --- a/frontend/scripts/verify-ui-contract.mjs +++ b/frontend/scripts/verify-ui-contract.mjs @@ -20,7 +20,10 @@ const requiredUnifiedTokens = [ "--unified-shell-bg", "--unified-shell-radius", ".unified-action-bar", - ".unified-section" + ".unified-section", + ".ctms-page-shell", + ".ctms-page-header-row", + ".ctms-page-content-grid" ]; const missing = [ diff --git a/frontend/src/components/Layout.vue b/frontend/src/components/Layout.vue index 7fb743d1..377466b7 100644 --- a/frontend/src/components/Layout.vue +++ b/frontend/src/components/Layout.vue @@ -195,7 +195,9 @@
- +
+ +
@@ -704,6 +706,10 @@ const onCommand = (cmd: string) => { background: #f7f8fb; } +.ctms-route-shell { + min-height: 100%; +} + /* 过渡动画 */ .fade-transform-enter-active, .fade-transform-leave-active { diff --git a/frontend/src/styles/unified-page.css b/frontend/src/styles/unified-page.css index f985b8c2..507f9373 100644 --- a/frontend/src/styles/unified-page.css +++ b/frontend/src/styles/unified-page.css @@ -9,6 +9,22 @@ --unified-muted-color: #6f84a8; } +.ctms-page-shell { + padding: 16px 20px 20px; +} + +.ctms-page-header-row { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; +} + +.ctms-page-content-grid { + display: grid; + gap: 12px; +} + .unified-shell { background: var(--unified-shell-bg); border: 0; From 1b920520d6aca0fcf27703fc62a3ec2c9e02b9f2 Mon Sep 17 00:00:00 2001 From: Cheng Zhou Date: Wed, 4 Mar 2026 16:28:41 +0800 Subject: [PATCH 4/9] feat(ui): unify list-page enterprise visual pattern --- frontend/scripts/verify-ui-contract.mjs | 23 +++++++++++++++++++ frontend/src/views/ia/ProjectMilestones.vue | 11 +++++---- .../views/ia/RiskIssueMonitoringVisits.vue | 4 ++-- frontend/src/views/ia/RiskIssuePd.vue | 4 ++-- frontend/src/views/ia/RiskIssueSae.vue | 4 ++-- frontend/src/views/ia/SubjectManagement.vue | 4 ++-- 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/frontend/scripts/verify-ui-contract.mjs b/frontend/scripts/verify-ui-contract.mjs index 0a19f1a0..52d3c5fa 100644 --- a/frontend/scripts/verify-ui-contract.mjs +++ b/frontend/scripts/verify-ui-contract.mjs @@ -31,6 +31,29 @@ const missing = [ ...requiredUnifiedTokens.filter((t) => !unified.includes(t)) ]; +const pageContractChecks = [ + "src/views/ia/ProjectMilestones.vue", + "src/views/ia/SubjectManagement.vue", + "src/views/ia/RiskIssueSae.vue", + "src/views/ia/RiskIssuePd.vue", + "src/views/ia/RiskIssueMonitoringVisits.vue" +]; + +const requiredPageClasses = [ + "ctms-page-shell", + "unified-action-bar", + "ctms-table-card" +]; + +for (const file of pageContractChecks) { + const content = readFileSync(file, "utf8"); + for (const className of requiredPageClasses) { + if (!content.includes(className)) { + missing.push(`${file}:${className}`); + } + } +} + if (missing.length) { console.error("UI contract check failed. Missing:", missing.join(", ")); process.exit(1); diff --git a/frontend/src/views/ia/ProjectMilestones.vue b/frontend/src/views/ia/ProjectMilestones.vue index 01472fdd..9837e4d2 100644 --- a/frontend/src/views/ia/ProjectMilestones.vue +++ b/frontend/src/views/ia/ProjectMilestones.vue @@ -1,8 +1,8 @@