diff --git a/frontend/src/assets/styles/design-system.scss b/frontend/src/assets/styles/design-system.scss
new file mode 100644
index 00000000..5aa75813
--- /dev/null
+++ b/frontend/src/assets/styles/design-system.scss
@@ -0,0 +1,326 @@
+// ============================================================
+// 全局设计系统(Design System)
+// 收敛 Element 基元 + 统一页面结构基线 + 工具类
+// 依赖 design-tokens.scss 中的 $token 与 --token
+//
+// 用途:业务页面优先复用以下区块/工具类,删除各自 scoped 中重复定义,
+// 实现全站风格、排版、按钮统一。仅需在 index.scss 末尾引入一次。
+// ============================================================
+
+// ------------------------- 1. Element 基元收敛 -------------------------
+
+// 1.1 按钮——统一主色、尺寸、圆角、hover/active 反馈与外光晕
+.el-button {
+ --el-button-primary-text: #fff;
+ border-radius: var(--token-radius-md, 4px);
+ transition: background-color 0.2s, border-color 0.2s, color 0.2s,
+ box-shadow 0.2s;
+
+ // 主按钮统一教育绿
+ &.el-button--primary {
+ background-color: var(--token-color-primary, #00875a);
+ border-color: var(--token-color-primary, #00875a);
+ color: #fff;
+
+ &:hover,
+ &:focus {
+ background-color: var(--token-color-primary-hover, #0b9e6c);
+ border-color: var(--token-color-primary-hover, #0b9e6c);
+ }
+
+ &:active {
+ background-color: var(--token-color-primary-active, #006b47);
+ border-color: var(--token-color-primary-active, #006b47);
+ }
+
+ &.is-plain {
+ color: var(--token-color-primary, #00875a);
+ background-color: var(--token-color-primary-lighter, #f0f9f4);
+ border-color: var(--token-color-primary, #00875a);
+
+ &:hover,
+ &:focus {
+ color: #fff;
+ background-color: var(--token-color-primary, #00875a);
+ }
+ }
+
+ &.is-disabled {
+ background-color: #a0cfb8;
+ border-color: #a0cfb8;
+ color: rgba(255, 255, 255, 0.9);
+ }
+ }
+
+ // 危险按钮
+ &.el-button--danger {
+ background-color: var(--token-color-danger, #ff4949);
+ border-color: var(--token-color-danger, #ff4949);
+ &:hover,
+ &:focus {
+ background-color: #ff6b6b;
+ border-color: #ff6b6b;
+ }
+ }
+
+ // 聚焦外光晕(键盘可访问性),除 text 按钮外
+ &:focus-visible {
+ outline: none;
+ box-shadow: 0 0 0 3px var(--token-color-primary-ring, rgba(0, 135, 90, 0.35));
+ }
+
+ // 表格内文字操作按钮保持紧凑
+ &.el-button--text {
+ font-size: var(--token-font-size-sm, 13px);
+ padding: 0 4px;
+
+ &.danger-link {
+ color: var(--token-color-danger, #ff4949);
+ }
+ }
+}
+
+// 1.2 卡片——统一无内阴影、body 内边距
+.el-card {
+ border-color: var(--token-color-border-lighter, #ebeef5);
+ &.is-always-shadow {
+ box-shadow: var(--token-shadow-card, 0 1px 4px rgba(0, 0, 0, 0.06));
+ }
+}
+
+// 1.3 表格——统一表头背景与居中、行 hover、斑马
+.el-table {
+ th.el-table__cell {
+ background-color: var(--token-color-fill, #f5f7fa);
+ color: var(--token-color-text-main, #303133);
+ font-weight: 600;
+ }
+
+ th.el-table__cell > .cell {
+ text-align: center;
+ }
+
+ .el-table__body tr.hover-row > td.el-table__cell,
+ .el-table__body tr:hover > td.el-table__cell {
+ background-color: var(--token-color-primary-lighter, #f0f9f4);
+ }
+
+ &.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell {
+ background-color: var(--token-color-fill-light, #f0f2f5);
+ }
+}
+
+// 1.4 表单——统一 label 对齐与错误/必填语义
+.el-form {
+ .el-form-item {
+ .el-form-item__label {
+ color: var(--token-color-text-regular, #606266);
+ }
+ .el-form-item__error {
+ color: var(--token-color-danger, #ff4949);
+ }
+ }
+}
+
+// 1.5 分页——统一置于底部右侧
+.el-pagination {
+ color: var(--token-color-text-regular, #606266);
+ &.pagination-right {
+ justify-content: flex-end;
+ }
+}
+
+// ------------------------- 2. 页面结构基线 -------------------------
+// 说明:这些类名与历史业务页 scoped 中的自定义类名保持同名,
+// 统一后应删除页面内的 scoped 重复定义,避免覆盖。
+
+// 2.1 基础页面容器
+.page-shell {
+ padding: var(--token-space-xl, 20px);
+ box-sizing: border-box;
+}
+
+// 2.2 页面标题
+.page-title {
+ font-size: var(--token-font-size-xl, 20px);
+ font-weight: 600;
+ color: var(--token-color-text-main, #303133);
+ margin-bottom: var(--token-space-lg, 16px);
+}
+
+// 2.3 区块/卡片容器——统一白底 + 圆角 + 轻阴影 + 内边距
+.section-card {
+ background: #fff;
+ border-radius: var(--token-radius-xl, 8px);
+ box-shadow: var(--token-shadow-light, 0 1px 4px rgba(0, 0, 0, 0.08));
+ padding: var(--token-space-lg, 16px) var(--token-space-xl, 20px);
+ margin-bottom: var(--token-space-lg, 16px);
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+// 兼容:el-card 封装的查询/表格卡
+.search-card.el-card,
+.table-card.el-card {
+ border-radius: var(--token-radius-xl, 8px);
+}
+.search-card,
+.table-card {
+ margin-bottom: var(--token-space-lg, 16px);
+}
+
+.search-card {
+ .search-form {
+ .el-form-item {
+ margin-bottom: 0;
+ }
+ }
+
+ // 底部操作区(右侧对齐)
+ .search-actions,
+ .search-footer {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: var(--token-space-md, 12px);
+ }
+
+ // 仅明确标记为页脚的操作区才带轻分割线(避免误伤页面自有分割结构)
+ .search-footer {
+ margin-top: var(--token-space-md, 12px);
+ padding-top: var(--token-space-md, 12px);
+ border-top: 1px solid var(--token-color-border-lighter, #ebeef5);
+ }
+}
+
+.table-card {
+ .pagination-wrap,
+ .pagination-wrapper,
+ .pagination {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: var(--token-space-md, 12px);
+ }
+}
+
+// 2.4 查询控件——统一纵向排列的表单:标签右对齐 + 控件自适应
+.query-field {
+ display: flex;
+ align-items: center;
+ margin-bottom: var(--token-space-sm, 8px);
+ min-height: 32px;
+
+ .q-label {
+ width: 120px;
+ flex-shrink: 0;
+ font-size: var(--token-font-size-sm, 13px);
+ color: var(--token-color-text-main, #303133);
+ text-align: right;
+ margin-right: var(--token-space-sm, 8px);
+ white-space: nowrap;
+
+ &.no-check {
+ margin-left: var(--token-space-2xl, 24px);
+ }
+ }
+
+ .q-control {
+ flex: 1;
+ min-width: 0;
+ }
+}
+
+// 2.5 操作/导出按钮行——统一 flex + 等比间距 + 自动换行
+.action-row,
+.export-bar {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--token-space-md, 12px);
+}
+
+.action-row + .action-row {
+ margin-top: var(--token-space-md, 12px);
+}
+
+// 2.6 列表工具栏——左右分组
+.list-toolbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--token-space-md, 12px);
+ flex-wrap: wrap;
+ margin-bottom: var(--token-space-lg, 16px);
+
+ .left-group,
+ .right-group {
+ display: flex;
+ align-items: center;
+ gap: var(--token-space-md, 12px);
+ flex-wrap: wrap;
+ }
+}
+
+// 列表标题
+.list-title,
+.section-title {
+ font-size: var(--token-font-size-lg, 16px);
+ font-weight: 600;
+ color: var(--token-color-text-main, #303133);
+ margin-bottom: var(--token-space-md, 12px);
+}
+
+// 2.7 危险文字(删除/停用等)
+.text-danger,
+.danger-text,
+.danger-link {
+ color: var(--token-color-danger, #ff4949);
+}
+
+// ------------------------- 3. 工具类 -------------------------
+// 字体
+.text-center { text-align: center; }
+.text-left { text-align: left; }
+.text-right { text-align: right; }
+.text-primary { color: var(--token-color-primary, #00875a); }
+.text-regular { color: var(--token-color-text-regular, #606266); }
+.text-secondary { color: var(--token-color-text-secondary, #909399); }
+
+.font-sm { font-size: var(--token-font-size-sm, 13px); }
+.font-lg { font-size: var(--token-font-size-lg, 16px); }
+
+// 布局
+.flex { display: flex; align-items: center; }
+.flex-center { display: flex; align-items: center; justify-content: center; }
+.flex-between { display: flex; align-items: center; justify-content: space-between; }
+.flex-end { display: flex; align-items: center; justify-content: flex-end; }
+.flex-wrap { flex-wrap: wrap; }
+.flex-1 { flex: 1; min-width: 0; }
+.w-full { width: 100%; }
+
+// 间距(上/下)
+.mt-0 { margin-top: 0; }
+.mt-xs { margin-top: var(--token-space-xs, 4px); }
+.mt-sm { margin-top: var(--token-space-sm, 8px); }
+.mt-md { margin-top: var(--token-space-md, 12px); }
+.mt-lg { margin-top: var(--token-space-lg, 16px); }
+.mt-xl { margin-top: var(--token-space-xl, 20px); }
+.mb-0 { margin-bottom: 0; }
+.mb-xs { margin-bottom: var(--token-space-xs, 4px); }
+.mb-sm { margin-bottom: var(--token-space-sm, 8px); }
+.mb-md { margin-bottom: var(--token-space-md, 12px); }
+.mb-lg { margin-bottom: var(--token-space-lg, 16px); }
+.mb-xl { margin-bottom: var(--token-space-xl, 20px); }
+
+// 圆角/阴影
+.radius-sm { border-radius: var(--token-radius-sm, 2px); }
+.radius-md { border-radius: var(--token-radius-md, 4px); }
+.radius-lg { border-radius: var(--token-radius-lg, 6px); }
+.radius-xl { border-radius: var(--token-radius-xl, 8px); }
+.shadow-light { box-shadow: var(--token-shadow-light, 0 1px 4px rgba(0, 0, 0, 0.08)); }
+
+// 等宽
+.mono {
+ font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
+}
\ No newline at end of file
diff --git a/frontend/src/assets/styles/design-tokens.scss b/frontend/src/assets/styles/design-tokens.scss
new file mode 100644
index 00000000..3349142f
--- /dev/null
+++ b/frontend/src/assets/styles/design-tokens.scss
@@ -0,0 +1,147 @@
+// ============================================================
+// 设计 Token 体系(Design Tokens)
+// 全站统一颜色 / 字体 / 间距 / 圆角 / 阴影 / 边框 / 层级 / 断点
+// 约定:
+// 1. 业务代码禁止散落魔法数字,一律引用下方 $token / --token
+// 2. SCSS 变量供样式内使用,:root 自定义属性供内联/动态样式使用
+// ============================================================
+@import './variables.scss';
+
+// ------------------------- 色彩 Token -------------------------
+// 主色:教育绿
+$token-color-primary: #00875a; // 主色
+$token-color-primary-hover: #0b9e6c; // hover
+$token-color-primary-active: #006b47; // active
+$token-color-primary-light: #e6f4ea; // 浅底(标签/选中背景)
+$token-color-primary-lighter: #f0f9f4; // 更浅(hover 背景/斑马)
+$token-color-primary-ring: rgba(0, 135, 90, 0.35); // 聚焦外光晕
+
+// 语义色
+$token-color-danger: #ff4949; // 危险
+$token-color-success: #13ce66; // 成功
+$token-color-warning: #ffba00; // 警告
+$token-color-info: #909399; // 中性信息
+
+// 中性灰阶(对齐 Element 三级文字)
+$token-color-text-main: #303133; // 主要文字
+$token-color-text-regular: #606266; // 常规文字
+$token-color-text-secondary: #909399; // 次要文字
+$token-color-text-placeholder: #c0c4cc; // 占位
+$token-color-border: #dcdfe6; // 边框
+$token-color-border-light: #e4e7ed; // 浅边框
+$token-color-border-lighter: #ebeef5; // 极浅边框(分割线)
+$token-color-fill: #f5f7fa; // 填充/底灰
+$token-color-fill-light: #f0f2f5; // 更浅填充
+
+// ------------------------- 字体 Token -------------------------
+$token-font-family: 'Helvetica Neue', Helvetica, 'PingFang SC',
+ 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
+$token-font-size-xs: 12px;
+$token-font-size-sm: 13px;
+$token-font-size-base: 14px;
+$token-font-size-lg: 16px;
+$token-font-size-xl: 20px;
+
+// ------------------------- 间距 Token -------------------------
+$token-space-xs: 4px;
+$token-space-sm: 8px;
+$token-space-md: 12px;
+$token-space-lg: 16px;
+$token-space-xl: 20px;
+$token-space-2xl: 24px;
+
+// ------------------------- 圆角 Token -------------------------
+$token-radius-sm: 2px;
+$token-radius-md: 4px;
+$token-radius-lg: 6px;
+$token-radius-xl: 8px;
+$token-radius-circle: 50%;
+
+// ------------------------- 阴影 Token -------------------------
+$token-shadow-light: 0 1px 4px rgba(0, 0, 0, 0.08);
+$token-shadow-card: 0 1px 4px rgba(0, 0, 0, 0.06);
+$token-shadow-popup: 0 2px 12px rgba(0, 0, 0, 0.12);
+
+// ------------------------- 层级 Token -------------------------
+$token-z-index-dropdown: 2000; // 下拉/气泡
+$token-z-index-mask: 2001; // 遮罩
+$token-z-index-modal: 2002; // 弹窗
+$token-z-index-toast: 3000; // 消息/通知
+
+// ------------------------- 断点 Token -------------------------
+$token-breakpoint-xs: 480px;
+$token-breakpoint-sm: 768px;
+$token-breakpoint-md: 992px;
+$token-breakpoint-lg: 1200px;
+$token-breakpoint-xl: 1920px;
+
+// ------------------------- 暴露给运行时(CSS 变量) -------------------------
+:root {
+ --token-color-primary: #{$token-color-primary};
+ --token-color-primary-hover: #{$token-color-primary-hover};
+ --token-color-primary-active: #{$token-color-primary-active};
+ --token-color-primary-light: #{$token-color-primary-light};
+ --token-color-primary-lighter: #{$token-color-primary-lighter};
+ --token-color-primary-ring: #{$token-color-primary-ring};
+
+ --token-color-danger: #{$token-color-danger};
+ --token-color-success: #{$token-color-success};
+ --token-color-warning: #{$token-color-warning};
+ --token-color-info: #{$token-color-info};
+
+ --token-color-text-main: #{$token-color-text-main};
+ --token-color-text-regular: #{$token-color-text-regular};
+ --token-color-text-secondary: #{$token-color-text-secondary};
+ --token-color-text-placeholder: #{$token-color-text-placeholder};
+ --token-color-border: #{$token-color-border};
+ --token-color-border-light: #{$token-color-border-light};
+ --token-color-border-lighter: #{$token-color-border-lighter};
+ --token-color-fill: #{$token-color-fill};
+ --token-color-fill-light: #{$token-color-fill-light};
+
+ --token-font-family: #{$token-font-family};
+ --token-font-size-xs: #{$token-font-size-xs};
+ --token-font-size-sm: #{$token-font-size-sm};
+ --token-font-size-base: #{$token-font-size-base};
+ --token-font-size-lg: #{$token-font-size-lg};
+ --token-font-size-xl: #{$token-font-size-xl};
+
+ --token-space-xs: #{$token-space-xs};
+ --token-space-sm: #{$token-space-sm};
+ --token-space-md: #{$token-space-md};
+ --token-space-lg: #{$token-space-lg};
+ --token-space-xl: #{$token-space-xl};
+ --token-space-2xl: #{$token-space-2xl};
+
+ --token-radius-sm: #{$token-radius-sm};
+ --token-radius-md: #{$token-radius-md};
+ --token-radius-lg: #{$token-radius-lg};
+ --token-radius-xl: #{$token-radius-xl};
+
+ --token-shadow-light: #{$token-shadow-light};
+ --token-shadow-card: #{$token-shadow-card};
+ --token-shadow-popup: #{$token-shadow-popup};
+
+ --token-z-index-dropdown: #{$token-z-index-dropdown};
+ --token-z-index-mask: #{$token-z-index-mask};
+ --token-z-index-modal: #{$token-z-index-modal};
+ --token-z-index-toast: #{$token-z-index-toast};
+}
+
+// ------------------------- 暴露给 JS 模块 -------------------------
+:export {
+ colorPrimary: $token-color-primary;
+ colorPrimaryHover: $token-color-primary-hover;
+ colorPrimaryActive: $token-color-primary-active;
+ colorPrimaryLight: $token-color-primary-light;
+ colorPrimaryLighter: $token-color-primary-lighter;
+ colorDanger: $token-color-danger;
+ colorSuccess: $token-color-success;
+ colorWarning: $token-color-warning;
+ fontFamily: $token-font-family;
+ breakpointXs: $token-breakpoint-xs;
+ breakpointSm: $token-breakpoint-sm;
+ breakpointMd: $token-breakpoint-md;
+ breakpointLg: $token-breakpoint-lg;
+ breakpointXl: $token-breakpoint-xl;
+}
\ No newline at end of file
diff --git a/frontend/src/assets/styles/index.scss b/frontend/src/assets/styles/index.scss
index 27d028ab..f1344433 100644
--- a/frontend/src/assets/styles/index.scss
+++ b/frontend/src/assets/styles/index.scss
@@ -245,3 +245,9 @@ aside {
margin-bottom: 10px;
}
}
+
+/* ================= 全局设计系统 =================
+ 居于最末加载,收敛 Element 基元与页面结构基线
+ (Token 体系在 design-tokens.scss,页面统一类名在 design-system.scss) */
+@import './design-tokens.scss';
+@import './design-system.scss';
diff --git a/frontend/src/views/classHour/jointTraining/index.vue b/frontend/src/views/classHour/jointTraining/index.vue
index 40e74a7f..9515adbf 100644
--- a/frontend/src/views/classHour/jointTraining/index.vue
+++ b/frontend/src/views/classHour/jointTraining/index.vue
@@ -455,13 +455,7 @@ export default {
// ==================== 1. 查询条件区域 ====================
.search-card {
- margin-bottom: 16px;
-
.search-form {
- .w-full {
- width: 100%;
- }
-
.search-actions {
display: flex;
justify-content: flex-end;
@@ -473,8 +467,6 @@ export default {
// ==================== 2. 操作区域 ====================
.upload-card {
- margin-bottom: 16px;
-
.upload-row {
display: flex;
align-items: center;
@@ -501,24 +493,12 @@ export default {
// ==================== 3. 数据表格 ====================
.table-card {
- margin-bottom: 16px;
-
.table-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
}
-
- .pagination {
- display: flex;
- justify-content: flex-end;
- margin-top: 12px;
- }
-
- .text-danger {
- color: #f56c6c;
- }
}
// ==================== 4. 新增/修改表单 ====================
diff --git a/frontend/src/views/classHour/plan/index.vue b/frontend/src/views/classHour/plan/index.vue
index 626e0e2e..c366fda4 100644
--- a/frontend/src/views/classHour/plan/index.vue
+++ b/frontend/src/views/classHour/plan/index.vue
@@ -641,30 +641,6 @@ export default {
margin-bottom: 12px;
}
- // ==================== 1. 查询区域 ====================
- .search-card {
- margin-bottom: 16px;
-
- .search-form {
- .el-form-item {
- margin-bottom: 0;
- }
- }
- }
-
- // ==================== 2. 数据表格 ====================
- .table-card {
- .pagination {
- display: flex;
- justify-content: flex-end;
- margin-top: 12px;
- }
-
- .text-danger {
- color: #f56c6c;
- }
- }
-
// ==================== 3. 新增/修改表单 ====================
.add-form {
max-height: 62vh;
diff --git a/frontend/src/views/classHour/subsidy/index.vue b/frontend/src/views/classHour/subsidy/index.vue
index b4a16d84..6ce1e7af 100644
--- a/frontend/src/views/classHour/subsidy/index.vue
+++ b/frontend/src/views/classHour/subsidy/index.vue
@@ -251,22 +251,9 @@ export default {
diff --git a/frontend/src/views/schedule/planImport/index.vue b/frontend/src/views/schedule/planImport/index.vue
index d86c285a..401ddc26 100644
--- a/frontend/src/views/schedule/planImport/index.vue
+++ b/frontend/src/views/schedule/planImport/index.vue
@@ -327,10 +327,6 @@ export default {
diff --git a/frontend/src/views/student/score/index.vue b/frontend/src/views/student/score/index.vue
index fa2acd7e..bf1804de 100644
--- a/frontend/src/views/student/score/index.vue
+++ b/frontend/src/views/student/score/index.vue
@@ -218,18 +218,6 @@ export default {
\ No newline at end of file
diff --git a/frontend/src/views/student/shiftTeam/index.vue b/frontend/src/views/student/shiftTeam/index.vue
index 9a93fd30..08069f41 100644
--- a/frontend/src/views/student/shiftTeam/index.vue
+++ b/frontend/src/views/student/shiftTeam/index.vue
@@ -627,31 +627,14 @@ export default {
diff --git a/frontend/src/views/subjectMajor/discipline/index.vue b/frontend/src/views/subjectMajor/discipline/index.vue
index 14213bc6..a77d6a0a 100644
--- a/frontend/src/views/subjectMajor/discipline/index.vue
+++ b/frontend/src/views/subjectMajor/discipline/index.vue
@@ -494,15 +494,7 @@ export default {
diff --git a/frontend/src/views/textbook/index.vue b/frontend/src/views/textbook/index.vue
index b5115772..1826f180 100644
--- a/frontend/src/views/textbook/index.vue
+++ b/frontend/src/views/textbook/index.vue
@@ -1468,10 +1468,6 @@ export default {