diff --git a/clinical-web/src/components/PagePlaceholder.vue b/clinical-web/src/components/PagePlaceholder.vue
new file mode 100644
index 0000000..cf2b14a
--- /dev/null
+++ b/clinical-web/src/components/PagePlaceholder.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
{{ icon }}
+
{{ group }}
+
{{ title }}
+
{{ description }}
+
+
+
+
+
diff --git a/clinical-web/src/components/layout/Container.vue b/clinical-web/src/components/layout/Container.vue
index 4689a1e..57e9849 100644
--- a/clinical-web/src/components/layout/Container.vue
+++ b/clinical-web/src/components/layout/Container.vue
@@ -3,3 +3,18 @@
+
+
diff --git a/clinical-web/src/components/layout/Header.vue b/clinical-web/src/components/layout/Header.vue
index 4beb964..be5ea95 100644
--- a/clinical-web/src/components/layout/Header.vue
+++ b/clinical-web/src/components/layout/Header.vue
@@ -30,3 +30,74 @@ const pageGroup = computed(() => String(route.meta.group ?? '工作台'))
{{ appStore.environment }}
+
+
diff --git a/clinical-web/src/components/layout/Menu.vue b/clinical-web/src/components/layout/Menu.vue
index c4cc8bd..2274a85 100644
--- a/clinical-web/src/components/layout/Menu.vue
+++ b/clinical-web/src/components/layout/Menu.vue
@@ -94,3 +94,159 @@ function handleLogout() {
+
+
diff --git a/clinical-web/src/layouts/ClinicalLayout.vue b/clinical-web/src/layouts/ClinicalLayout.vue
index 84ffaed..5494abc 100644
--- a/clinical-web/src/layouts/ClinicalLayout.vue
+++ b/clinical-web/src/layouts/ClinicalLayout.vue
@@ -17,3 +17,20 @@ import Menu from '@/components/layout/Menu.vue'
+
+
diff --git a/clinical-web/src/styles/index.css b/clinical-web/src/styles/index.css
index b92185e..225ade4 100644
--- a/clinical-web/src/styles/index.css
+++ b/clinical-web/src/styles/index.css
@@ -61,464 +61,8 @@ a {
background: transparent;
}
-/* 主框架:侧边菜单 + 顶部 header + 内容 container */
-.clinical-layout {
- display: flex;
- width: 100%;
- min-height: 100vh;
- background: var(--bg);
-}
-
-.clinical-main {
- display: flex;
- flex: 1;
- flex-direction: column;
- min-width: 0;
- min-height: 100vh;
-}
-
-.clinical-menu {
- display: flex;
- flex: 0 0 var(--sidebar-width);
- flex-direction: column;
- width: var(--sidebar-width);
- color: #c8dde6;
- background: var(--side);
-}
-
-.menu-brand {
- display: flex;
- flex-shrink: 0;
- gap: 10px;
- align-items: center;
- padding: 18px 16px 16px;
- border-bottom: 1px solid rgb(255 255 255 / 8%);
-}
-
-.menu-brand-icon {
- display: grid;
- flex-shrink: 0;
- width: 34px;
- height: 34px;
- place-items: center;
- border-radius: 9px;
- background: linear-gradient(135deg, #18a0c0, var(--brand));
-}
-
-.menu-brand-copy strong,
-.menu-brand-copy span {
- display: block;
-}
-
-.menu-brand-copy strong {
- color: #fff;
- font-size: 16px;
- letter-spacing: 1px;
-}
-
-.menu-brand-copy span {
- color: #8fb3c2;
- font-size: 10px;
- letter-spacing: 1px;
-}
-
-.menu-nav {
- flex: 1;
- padding: 12px 10px;
- overflow-y: auto;
-}
-
-.menu-group-title {
- padding: 10px 10px 6px;
- color: #7ba2b3;
- font-size: 11px;
- letter-spacing: 1px;
-}
-
-.menu-item {
- display: flex;
- gap: 10px;
- align-items: center;
- margin-bottom: 2px;
- padding: 10px 12px;
- color: #c8dde6;
- font-size: 13.5px;
- text-decoration: none;
- border-radius: 8px;
- transition:
- color 0.15s ease,
- background 0.15s ease;
-}
-
-.menu-item:hover {
- color: #fff;
- background: rgb(255 255 255 / 7%);
-}
-
-.menu-item.is-active {
- color: #fff;
- font-weight: 700;
- background: var(--brand);
-}
-
-.menu-dot {
- flex-shrink: 0;
- width: 6px;
- height: 6px;
- background: transparent;
- border-radius: 50%;
-}
-
-.menu-item.is-active .menu-dot {
- background: #5ee0a8;
-}
-
-.menu-profile {
- display: flex;
- flex-shrink: 0;
- gap: 10px;
- align-items: center;
- padding: 14px 16px;
- border-top: 1px solid rgb(255 255 255 / 8%);
-}
-
-.menu-profile-avatar {
- display: grid;
- flex-shrink: 0;
- width: 34px;
- height: 34px;
- color: #fff;
- font-size: 14px;
- font-weight: 700;
- place-items: center;
- border-radius: 50%;
- background: #18a0c0;
-}
-
-.menu-profile-copy {
- min-width: 0;
-}
-
-.menu-profile-copy strong,
-.menu-profile-copy span {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.menu-profile-copy strong {
- color: #fff;
- font-size: 13px;
-}
-
-.menu-profile-copy span {
- margin-top: 2px;
- color: #8fb3c2;
- font-size: 11px;
-}
-
-.menu-logout {
- flex-shrink: 0;
- margin-left: auto;
- padding: 0;
- color: #8fb3c2;
- font-size: 11px;
- background: transparent;
-}
-
-.menu-logout:hover {
- color: #fff;
-}
-
-/* 原型中的顶部 header */
-.clinical-header {
- display: flex;
- flex-shrink: 0;
- gap: 14px;
- align-items: center;
- height: var(--header-height);
- padding: 0 20px;
- background: #fff;
- border-bottom: 1px solid var(--line);
-}
-
-.header-page {
- display: flex;
- gap: 14px;
- align-items: baseline;
- min-width: 0;
-}
-
-.header-title {
- flex-shrink: 0;
- color: var(--ink);
- font-size: 16px;
- font-weight: 700;
-}
-
-.header-breadcrumb {
- overflow: hidden;
- color: var(--mut);
- font-size: 12px;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.header-spacer {
- flex: 1;
-}
-
-.campus-selector {
- display: flex;
- flex-shrink: 0;
- gap: 6px;
- align-items: center;
-}
-
-.campus-label {
- color: var(--mut);
- font-size: 12px;
-}
-
-.campus-selector select {
- width: auto;
- padding: 4px 8px;
- color: var(--brand-d);
- font-size: 12.5px;
- font-weight: 700;
- background: var(--brand-l);
- border: 1px solid var(--brand);
- border-radius: 6px;
-}
-
-.environment-badge {
- flex-shrink: 0;
- padding: 3px 8px;
- color: var(--warn);
- font-size: 11px;
- background: var(--warn-l);
- border-radius: 20px;
-}
-
-/* container 只负责滚动和内边距,页面内容由各 View 提供 */
-.clinical-container {
- flex: 1;
- min-height: 0;
- padding: 18px 20px;
- overflow-y: auto;
-}
-
-.page-section {
- width: 100%;
- max-width: 1440px;
- margin: 0 auto;
-}
-
-.page-placeholder {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- min-height: 380px;
- padding: 48px 32px;
- text-align: center;
- background: var(--card);
- border-radius: var(--r);
- box-shadow: var(--sh);
-}
-
-.placeholder-mark {
- display: grid;
- width: 54px;
- height: 54px;
- margin-bottom: 18px;
- color: var(--brand);
- font-size: 24px;
- place-items: center;
- background: var(--brand-l);
- border-radius: 14px;
-}
-
-.eyebrow {
- margin-bottom: 6px;
- color: var(--brand);
- font-size: 11px;
- font-weight: 700;
- letter-spacing: 1px;
-}
-
-.placeholder-title {
- margin: 0;
- color: var(--ink);
- font-size: 22px;
-}
-
-.placeholder-copy {
- margin-top: 10px;
- color: var(--mut);
- font-size: 13px;
-}
-
-@media (max-width: 1200px) {
- .clinical-container {
- padding: 16px;
- }
-}
-
-/* 原型登录页 */
-.login-page {
- position: fixed;
- inset: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- background: var(--login-gradient);
-}
-
-.login-card {
- width: 380px;
- padding: 30px 36px;
- background: #fff;
- border-radius: 14px;
- box-shadow: var(--sh-login);
-}
-
-.login-brand {
- display: flex;
- gap: 12px;
- align-items: center;
- justify-content: center;
- margin-bottom: 8px;
-}
-
-.login-brand-icon {
- display: grid;
- width: 46px;
- height: 46px;
- place-items: center;
- border-radius: 12px;
- background: linear-gradient(135deg, var(--brand), #18a0c0);
-}
-
-.login-brand h1 {
- margin: 0;
- color: var(--ink);
- font-size: 22px;
- letter-spacing: 1px;
-}
-
-.login-brand p {
- margin: 2px 0 0;
- color: #8aa7b3;
- font-size: 11px;
- letter-spacing: 2px;
-}
-
-.login-subtitle {
- margin: 0 0 20px;
- color: var(--mut);
- font-size: 12px;
- text-align: center;
-}
-
-.login-field {
- margin-bottom: 10px;
-}
-
-.login-field label {
- display: block;
- margin-bottom: 6px;
- color: var(--mut);
- font-size: 12px;
-}
-
-.login-field input {
- width: 100%;
- padding: 7px 10px;
- color: var(--ink);
- font-size: 13px;
- background: #fff;
- border: 1px solid var(--line);
- border-radius: 6px;
- outline: none;
-}
-
-.login-field input:focus {
- border-color: var(--brand);
-}
-
-.login-captcha-row {
- display: flex;
- gap: 8px;
- align-items: center;
-}
-
-.login-captcha-row input {
- flex: 1;
-}
-
-.login-captcha-image {
- flex-shrink: 0;
- padding: 8px 14px;
- color: #5c7d8a;
- font-size: 13px;
- font-style: italic;
- font-weight: 700;
- letter-spacing: 6px;
- user-select: none;
- background: linear-gradient(120deg, #dfeef3, #c8dfe8);
- border-radius: 6px;
-}
-
-.login-error {
- margin: -4px 0 10px;
- color: var(--err);
- font-size: 12px;
-}
-
-.login-submit {
- width: 100%;
- margin-top: 6px;
- padding: 9px;
- color: #fff;
- font-size: 13px;
- font-weight: 700;
- background: var(--brand);
- border-radius: 7px;
-}
-
-.login-submit:hover {
- background: var(--brand-d);
-}
-
-.login-tip {
- margin: 12px 0 0;
- padding: 7px;
- color: var(--mut);
- font-size: 12px;
- text-align: center;
- background: var(--brand-l);
- border-radius: 8px;
-}
-
-.login-footer {
- position: absolute;
- bottom: 18px;
- width: 100%;
- margin: 0;
- color: rgb(255 255 255 / 55%);
- font-size: 12px;
- text-align: center;
-}
-
@media (max-width: 520px) {
body {
min-width: 0;
}
-
- .login-card {
- width: calc(100% - 32px);
- padding: 32px 24px;
- }
}
diff --git a/clinical-web/src/views/auth/LoginView.vue b/clinical-web/src/views/auth/LoginView.vue
index dc75414..df853a1 100644
--- a/clinical-web/src/views/auth/LoginView.vue
+++ b/clinical-web/src/views/auth/LoginView.vue
@@ -111,3 +111,157 @@ function handleLogin() {
+
+
diff --git a/clinical-web/src/views/consent-tasks/ConsentTasksView.vue b/clinical-web/src/views/consent-tasks/ConsentTasksView.vue
index 73d5557..d233180 100644
--- a/clinical-web/src/views/consent-tasks/ConsentTasksView.vue
+++ b/clinical-web/src/views/consent-tasks/ConsentTasksView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
✍
-
工作台
-
签署工作台
-
签署工作台页面占位,待根据 Web 端需求实现。
-
-
+
diff --git a/clinical-web/src/views/dashboard/DashboardView.vue b/clinical-web/src/views/dashboard/DashboardView.vue
index 6fe0773..fb93302 100644
--- a/clinical-web/src/views/dashboard/DashboardView.vue
+++ b/clinical-web/src/views/dashboard/DashboardView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
⌂
-
工作台
-
首页
-
首页页面占位,待根据 Web 端需求实现。
-
-
+
diff --git a/clinical-web/src/views/document-permissions/DocumentPermissionsView.vue b/clinical-web/src/views/document-permissions/DocumentPermissionsView.vue
index cd4b4d9..a916892 100644
--- a/clinical-web/src/views/document-permissions/DocumentPermissionsView.vue
+++ b/clinical-web/src/views/document-permissions/DocumentPermissionsView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
⊞
-
管理
-
文档权限
-
文档权限页面占位,待根据 Web 端需求实现。
-
-
+
diff --git a/clinical-web/src/views/documents/DocumentsView.vue b/clinical-web/src/views/documents/DocumentsView.vue
index add5060..707c6de 100644
--- a/clinical-web/src/views/documents/DocumentsView.vue
+++ b/clinical-web/src/views/documents/DocumentsView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
▤
-
管理
-
文档库管理
-
文档库管理页面占位,待根据 Web 端需求实现。
-
-
+
diff --git a/clinical-web/src/views/reports/ReportsView.vue b/clinical-web/src/views/reports/ReportsView.vue
index 27e9bd8..afacc51 100644
--- a/clinical-web/src/views/reports/ReportsView.vue
+++ b/clinical-web/src/views/reports/ReportsView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
↗
-
管理
-
报表分析
-
报表分析页面占位,待根据 Web 端需求实现。
-
-
+
diff --git a/clinical-web/src/views/settings/SettingsView.vue b/clinical-web/src/views/settings/SettingsView.vue
index fd71f50..77f5ede 100644
--- a/clinical-web/src/views/settings/SettingsView.vue
+++ b/clinical-web/src/views/settings/SettingsView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
⚙
-
管理
-
系统设置
-
系统设置页面占位,待根据 Web 端需求实现。
-
-
+
diff --git a/clinical-web/src/views/users/UserPermissionsView.vue b/clinical-web/src/views/users/UserPermissionsView.vue
index 46b8276..b01dedf 100644
--- a/clinical-web/src/views/users/UserPermissionsView.vue
+++ b/clinical-web/src/views/users/UserPermissionsView.vue
@@ -1,10 +1,12 @@
+
+
-
-
-
◉
-
管理
-
用户与权限
-
用户与权限页面占位,待根据 Web 端需求实现。
-
-
+