forked from liweijie/education
326 lines
8.9 KiB
SCSS
326 lines
8.9 KiB
SCSS
// ============================================================
|
||
// 全局设计系统(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;
|
||
} |