admin-tokens.css 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /**
  2. * Admin 后台管理页面样式规范
  3. *
  4. * 设计原则:
  5. * - 基于 Element UI 的默认风格进行扩展
  6. * - 统一间距和尺寸标准
  7. * - 减少内联样式使用,改为 class 复用
  8. */
  9. /* ========================
  10. CSS 自定义属性 (设计令牌)
  11. ======================== */
  12. :root {
  13. /* 主色调 */
  14. --color-primary: #409EFF;
  15. --color-primary-light: #66b1ff;
  16. --color-primary-dark: #337ecc;
  17. /* 成功/警告/危险 */
  18. --color-success: #67C23A;
  19. --color-warning: #E6A23C;
  20. --color-danger: #F56C6C;
  21. --color-info: #909399;
  22. /* 文字色 */
  23. --color-text-primary: #303133;
  24. --color-text-regular: #606266;
  25. --color-text-secondary: #909399;
  26. --color-text-placeholder: #C0C4CC;
  27. /* 边框色 */
  28. --color-border-base: #DCDFE6;
  29. --color-border-light: #E4E7ED;
  30. --color-border-lighter: #EBEEF5;
  31. --color-border-extra-light: #F2F6FC;
  32. /* 背景色 */
  33. --color-bg-page: #f0f2f5;
  34. --color-bg-card: #ffffff;
  35. --color-bg-overlay: rgba(0, 0, 0, 0.5);
  36. /* 字体 */
  37. --font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
  38. --font-size-base: 14px;
  39. --font-size-small: 13px;
  40. --font-size-mini: 12px;
  41. /* 间距 (8px 基准) */
  42. --spacing-xs: 4px;
  43. --spacing-sm: 8px;
  44. --spacing-md: 12px;
  45. --spacing-base: 16px;
  46. --spacing-lg: 20px;
  47. --spacing-xl: 24px;
  48. --spacing-xxl: 32px;
  49. /* 圆角 */
  50. --border-radius-base: 4px;
  51. --border-radius-small: 2px;
  52. --border-radius-large: 8px;
  53. /* 阴影 */
  54. --box-shadow-base: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  55. --box-shadow-light: 0 2px 4px 0 rgba(0, 0, 0, 0.08);
  56. /* 宽度标准 */
  57. --width-search-input: 220px;
  58. --width-select-sm: 120px;
  59. --width-select-base: 150px;
  60. --width-select-lg: 180px;
  61. --width-select-xl: 200px;
  62. /* 高度标准 */
  63. --height-table-max: calc(100vh - 280px);
  64. --height-table-with-filter: calc(100vh - 340px);
  65. }
  66. /* ========================
  67. 全局重置
  68. ======================== */
  69. .admin-page {
  70. padding: var(--spacing-base);
  71. background: var(--color-bg-page);
  72. min-height: calc(100vh - 60px);
  73. }
  74. /* page-container:所有<el-card>包裹的列表页使用此 class */
  75. .page-container {
  76. flex: 1;
  77. display: flex;
  78. flex-direction: column;
  79. min-height: 0;
  80. padding: 20px;
  81. }
  82. .page-container > .el-card {
  83. flex: 1;
  84. display: flex;
  85. flex-direction: column;
  86. min-height: 0;
  87. }
  88. .page-container > .el-card .el-card__body {
  89. flex: 1;
  90. display: flex;
  91. flex-direction: column;
  92. min-height: 0;
  93. padding: 20px;
  94. }
  95. .page-container > .el-card .el-card__body > .el-form:first-child {
  96. flex-shrink: 0;
  97. }
  98. .page-container > .el-card .el-card__body > .el-pagination {
  99. flex-shrink: 0;
  100. margin-top: auto;
  101. padding-top: 20px;
  102. text-align: right;
  103. }
  104. /* ========================
  105. 页面头部标题栏
  106. ======================== */
  107. .admin-page-header {
  108. display: flex;
  109. align-items: center;
  110. justify-content: space-between;
  111. margin-bottom: var(--spacing-base);
  112. }
  113. .admin-page-title {
  114. font-size: 16px;
  115. font-weight: 600;
  116. color: var(--color-text-primary);
  117. }
  118. .admin-page-actions {
  119. display: flex;
  120. align-items: center;
  121. gap: 8px;
  122. }
  123. /* ========================
  124. 筛选器 / 搜索栏
  125. ======================== */
  126. .filter-bar {
  127. display: flex;
  128. align-items: center;
  129. flex-wrap: wrap;
  130. gap: var(--spacing-sm);
  131. margin-bottom: var(--spacing-base);
  132. padding: var(--spacing-base);
  133. background: var(--color-bg-card);
  134. border-radius: var(--border-radius-base);
  135. box-shadow: var(--box-shadow-light);
  136. }
  137. .filter-bar .el-select {
  138. width: var(--width-select-base);
  139. }
  140. .filter-bar .el-input {
  141. width: var(--width-search-input);
  142. }
  143. .filter-bar .el-input--small {
  144. width: var(--width-search-input);
  145. }
  146. .filter-bar .el-input--mini {
  147. width: 160px;
  148. }
  149. /* ========================
  150. 状态标签栏 (ArticleManage 等)
  151. ======================== */
  152. .status-tabs {
  153. display: flex;
  154. align-items: center;
  155. flex-wrap: wrap;
  156. gap: var(--spacing-xs);
  157. margin-bottom: var(--spacing-md);
  158. }
  159. .status-tabs .el-button + .el-button {
  160. margin-left: 0;
  161. }
  162. /* ========================
  163. 表格容器 (滚动)
  164. ======================== */
  165. .table-scroll-wrap {
  166. overflow: auto;
  167. max-height: var(--height-table-max);
  168. border-radius: var(--border-radius-base);
  169. }
  170. .table-scroll-wrap-sm {
  171. overflow: auto;
  172. max-height: calc(100vh - 300px);
  173. border-radius: var(--border-radius-base);
  174. }
  175. .table-scroll-wrap-lg {
  176. overflow: auto;
  177. max-height: var(--height-table-with-filter);
  178. border-radius: var(--border-radius-base);
  179. }
  180. /* ========================
  181. 卡片
  182. ======================== */
  183. .admin-card {
  184. background: var(--color-bg-card);
  185. border-radius: var(--border-radius-base);
  186. box-shadow: var(--box-shadow-light);
  187. margin-bottom: var(--spacing-base);
  188. }
  189. .admin-card .el-card__header {
  190. padding: var(--spacing-base);
  191. border-bottom: 1px solid var(--color-border-lighter);
  192. }
  193. .admin-card .el-card__body {
  194. padding: var(--spacing-base);
  195. }
  196. /* ========================
  197. 操作按钮区 (分页上方/下方)
  198. ======================== */
  199. .table-actions {
  200. display: flex;
  201. align-items: center;
  202. justify-content: space-between;
  203. margin-top: var(--spacing-base);
  204. }
  205. .table-actions-right {
  206. text-align: right;
  207. margin-top: var(--spacing-base);
  208. }
  209. /* ========================
  210. 对话框表单
  211. ======================== */
  212. .admin-form-dialog .el-form-item {
  213. margin-bottom: var(--spacing-base);
  214. }
  215. .admin-form-dialog .el-form-item__label {
  216. color: var(--color-text-regular);
  217. }
  218. /* ========================
  219. 搜索结果统计
  220. ======================== */
  221. .search-result-count {
  222. font-size: var(--font-size-small);
  223. color: var(--color-text-secondary);
  224. margin-bottom: var(--spacing-sm);
  225. }
  226. /* ========================
  227. 空状态
  228. ======================== */
  229. .empty-state {
  230. display: flex;
  231. flex-direction: column;
  232. align-items: center;
  233. justify-content: center;
  234. padding: var(--spacing-xxl) 0;
  235. color: var(--color-text-placeholder);
  236. }
  237. .empty-state i {
  238. font-size: 48px;
  239. margin-bottom: var(--spacing-sm);
  240. }
  241. /* ========================
  242. 分页器
  243. ======================== */
  244. .pagination-wrap {
  245. display: flex;
  246. justify-content: flex-end;
  247. margin-top: var(--spacing-base);
  248. padding: var(--spacing-sm) 0;
  249. }
  250. /* ========================
  251. 详情页布局
  252. ======================== */
  253. .detail-section {
  254. margin-bottom: var(--spacing-lg);
  255. }
  256. .detail-section-title {
  257. font-size: 15px;
  258. font-weight: 600;
  259. color: var(--color-text-primary);
  260. margin-bottom: var(--spacing-md);
  261. padding-bottom: var(--spacing-sm);
  262. border-bottom: 1px solid var(--color-border-lighter);
  263. }
  264. /* ========================
  265. 编辑页通用样式
  266. ======================== */
  267. .edit-form {
  268. max-width: 800px;
  269. }
  270. .edit-form .el-form-item__label {
  271. font-weight: 500;
  272. }
  273. .edit-form-footer {
  274. margin-top: var(--spacing-xl);
  275. padding-top: var(--spacing-base);
  276. border-top: 1px solid var(--color-border-lighter);
  277. text-align: right;
  278. }
  279. /* ========================
  280. 富文本编辑器容器
  281. ======================== */
  282. .rich-editor {
  283. border: 1px solid var(--color-border-base);
  284. border-radius: var(--border-radius-base);
  285. position: relative;
  286. overflow: visible;
  287. }
  288. .rich-editor /deep/ .w-e-toolbar {
  289. flex-wrap: wrap;
  290. padding: var(--spacing-sm);
  291. }
  292. .rich-editor /deep/ .w-e-text-container {
  293. min-height: 300px;
  294. }
  295. .rich-editor /deep/ .w-e-panel-container {
  296. z-index: 5000;
  297. }
  298. /* ========================
  299. Element UI 组件覆盖样式
  300. ======================== */
  301. /* 表格 */
  302. .el-table {
  303. font-size: var(--font-size-small);
  304. }
  305. .el-table th {
  306. background-color: var(--color-bg-page) !important;
  307. color: var(--color-text-regular);
  308. font-weight: 600;
  309. }
  310. .el-table td {
  311. padding: 8px 0;
  312. }
  313. /* 按钮 */
  314. .el-button--small {
  315. padding: 9px 15px;
  316. }
  317. /* 卡片 */
  318. .el-card {
  319. border-radius: var(--border-radius-base);
  320. box-shadow: var(--box-shadow-light);
  321. }
  322. .el-card__header {
  323. padding: var(--spacing-base);
  324. font-weight: 600;
  325. border-bottom: 1px solid var(--color-border-lighter);
  326. }
  327. .el-card__body {
  328. padding: var(--spacing-base);
  329. }
  330. /* 输入框 */
  331. .el-input--small {
  332. font-size: var(--font-size-small);
  333. }
  334. /* 表单项 */
  335. .el-form-item--small .el-form-item__label {
  336. font-size: var(--font-size-small);
  337. }
  338. /* 标签 */
  339. .el-tag {
  340. border-radius: var(--border-radius-small);
  341. }
  342. /* 分页 */
  343. .el-pagination {
  344. font-weight: normal;
  345. }
  346. /* 对话框 */
  347. .el-dialog__header {
  348. padding: var(--spacing-base);
  349. border-bottom: 1px solid var(--color-border-lighter);
  350. }
  351. .el-dialog__body {
  352. padding: var(--spacing-lg);
  353. }
  354. .el-dialog__footer {
  355. padding: var(--spacing-base);
  356. border-top: 1px solid var(--color-border-lighter);
  357. }
  358. /* ========================
  359. 工具类
  360. ======================== */
  361. /* 文本 */
  362. .text-muted {
  363. color: var(--color-text-placeholder);
  364. }
  365. .text-secondary {
  366. color: var(--color-text-secondary);
  367. }
  368. .text-primary {
  369. color: var(--color-text-primary);
  370. }
  371. .text-success {
  372. color: var(--color-success);
  373. }
  374. .text-warning {
  375. color: var(--color-warning);
  376. }
  377. .text-danger {
  378. color: var(--color-danger);
  379. }
  380. /* 间距 */
  381. .mt-sm { margin-top: var(--spacing-sm); }
  382. .mt-base { margin-top: var(--spacing-base); }
  383. .mt-lg { margin-top: var(--spacing-lg); }
  384. .mb-sm { margin-bottom: var(--spacing-sm); }
  385. .mb-base { margin-bottom: var(--spacing-base); }
  386. .mb-lg { margin-bottom: var(--spacing-lg); }
  387. /* Flex */
  388. .flex { display: flex; }
  389. .flex-wrap { flex-wrap: wrap; }
  390. .items-center { align-items: center; }
  391. .justify-between { justify-content: space-between; }
  392. .gap-sm { gap: var(--spacing-sm); }
  393. .gap-base { gap: var(--spacing-base); }
  394. /* 浮动 */
  395. .pull-right { float: right; }
  396. .clearfix::after { content: ""; display: table; clear: both; }
  397. /* ==== 企业级设计系统(Ant Design 5 规范,对齐 design-tokens.md) ==== */
  398. /* 作用域:.admin-page 及其后代 —— 覆盖全部 B 端管理页(admin / teacher / 顶层共享页) */
  399. /* 原则:克制、干净、留白分区、状态色仅承载语义、主色覆盖率 < 5% */
  400. :root {
  401. --adm-primary: #1677FF;
  402. --adm-primary-hover: #4096FF;
  403. --adm-primary-active: #0958D9;
  404. --adm-success: #52C41A;
  405. --adm-success-text: #389E0D;
  406. --adm-warning: #FAAD14;
  407. --adm-warning-text: #D48806;
  408. --adm-error: #FF4D4F;
  409. --adm-error-text: #CF1322;
  410. --adm-info: #1677FF;
  411. --adm-info-text: #0958D9;
  412. --adm-text-88: rgba(0, 0, 0, 0.88);
  413. --adm-text-65: rgba(0, 0, 0, 0.65);
  414. --adm-text-45: rgba(0, 0, 0, 0.45);
  415. --adm-text-25: rgba(0, 0, 0, 0.25);
  416. --adm-border-base: #D9D9D9;
  417. --adm-border-split: #F0F0F0;
  418. --adm-fill: #F5F5F5;
  419. --adm-bg-container: #FFFFFF;
  420. --adm-bg-header: #FAFAFA;
  421. --adm-radius-sm: 2px;
  422. --adm-radius-control: 6px;
  423. --adm-radius-card: 8px;
  424. --adm-shadow-card: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
  425. }
  426. /* 主色按钮统一为 Ant 蓝(覆盖 Element 默认 #409EFF) */
  427. .admin-page .el-button--primary { background-color: var(--adm-primary); border-color: var(--adm-primary); color: #fff; }
  428. .admin-page .el-button--primary:hover,
  429. .admin-page .el-button--primary:focus { background-color: var(--adm-primary-hover); border-color: var(--adm-primary-hover); }
  430. .admin-page .el-button--primary:active { background-color: var(--adm-primary-active); border-color: var(--adm-primary-active); }
  431. .admin-page .el-button--primary.is-disabled,
  432. .admin-page .el-button--primary.is-disabled:hover { background-color: #A0C4FF; border-color: #A0C4FF; color: #fff; }
  433. /* 卡片:1px 描边 + 极轻阴影,替代重投影 */
  434. .admin-page .el-card { border: 1px solid var(--adm-border-split); border-radius: var(--adm-radius-card); box-shadow: var(--adm-shadow-card); }
  435. .admin-page .el-card__header { padding: 20px 24px; border-bottom: 1px solid var(--adm-border-split); }
  436. .admin-page .el-card__body { padding: 24px; }
  437. /* 页面标题区:唯一主操作居右 */
  438. .admin-page .admin-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; flex-shrink: 0; }
  439. .admin-page .admin-page-title { font-size: 20px; font-weight: 600; line-height: 1.4; color: var(--adm-text-88); }
  440. .admin-page .admin-page-subtitle { font-size: 12px; color: var(--adm-text-45); margin-left: 12px; }
  441. .admin-page .admin-page-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
  442. /* 筛选区:去卡片化,改底部 1px 分割线分区 */
  443. .admin-page .filter-bar {
  444. display: flex; align-items: flex-end; flex-wrap: wrap; gap: 16px;
  445. padding: 0 0 16px; margin-bottom: 16px;
  446. background: transparent; border-radius: 0; box-shadow: none;
  447. border-bottom: 1px solid var(--adm-border-split);
  448. }
  449. /* 区块标题:3px 主色竖条 */
  450. .admin-page .admin-section-title {
  451. font-size: 14px; font-weight: 500; color: var(--adm-text-88);
  452. padding-left: 8px; border-left: 3px solid var(--adm-primary);
  453. margin: 24px 0 12px; line-height: 1.2;
  454. }
  455. /* 表格:表头浅底、行高舒适、单元格留白 */
  456. .admin-page .el-table { font-size: 14px; border-radius: var(--adm-radius-card); }
  457. .admin-page .el-table th { background-color: var(--adm-bg-header) !important; color: var(--adm-text-88); font-weight: 500; height: 46px; padding: 0; }
  458. .admin-page .el-table td { padding: 12px 0; }
  459. .admin-page .el-table .cell { padding-left: 16px; padding-right: 16px; }
  460. .admin-page .el-table--border, .admin-page .el-table--group { border-color: var(--adm-border-split); }
  461. .admin-page .el-table td, .admin-page .el-table th.is-leaf { border-color: var(--adm-border-split); }
  462. /* 数值列:右对齐 + 等宽数字 */
  463. .admin-page .el-table .cell-num,
  464. .admin-page .el-table .is-right .cell { text-align: right; font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
  465. /* 状态标签:浅底 + 深字 + 同色描边(语义化,替代纯文字着色) */
  466. .admin-page .el-tag { border-radius: var(--adm-radius-sm); }
  467. .admin-page .el-tag--success { background: #F6FFED; border-color: #B7EB8F; color: var(--adm-success-text); }
  468. .admin-page .el-tag--warning { background: #FFFBE6; border-color: #FFE58F; color: var(--adm-warning-text); }
  469. .admin-page .el-tag--info { background: #E6F4FF; border-color: #91CAFF; color: var(--adm-info-text); }
  470. .admin-page .el-tag--danger { background: #FFF1F0; border-color: #FFCCC7; color: var(--adm-error-text); }
  471. /* 标准化状态徽标(自定义 span,替代纯文字着色) */
  472. .admin-page .adm-status { display: inline-flex; align-items: center; gap: 6px; padding: 2px 8px; font-size: 12px; line-height: 20px; border-radius: var(--adm-radius-sm); white-space: nowrap; }
  473. .admin-page .adm-status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
  474. .admin-page .adm-status--success { background: #F6FFED; color: var(--adm-success-text); }
  475. .admin-page .adm-status--info { background: #E6F4FF; color: var(--adm-info-text); }
  476. .admin-page .adm-status--warning { background: #FFFBE6; color: var(--adm-warning-text); }
  477. .admin-page .adm-status--error { background: #FFF1F0; color: var(--adm-error-text); }
  478. .admin-page .adm-status--default { background: var(--adm-fill); color: var(--adm-text-65); }
  479. /* 对话框 */
  480. .admin-page .el-dialog__header { padding: 16px 24px; border-bottom: 1px solid var(--adm-border-split); }
  481. .admin-page .el-dialog__title { font-size: 16px; font-weight: 500; color: var(--adm-text-88); }
  482. .admin-page .el-dialog__body { padding: 24px; }
  483. .admin-page .el-dialog__footer { padding: 12px 24px; border-top: 1px solid var(--adm-border-split); }
  484. /* 分页 */
  485. .admin-page .el-pagination { padding: 16px 0 0; text-align: right; font-weight: normal; flex-shrink: 0; }
  486. /* 表单 */
  487. .admin-page .el-form-item__label { font-size: 14px; color: var(--adm-text-65); font-weight: 500; }
  488. .admin-page .el-divider__text { font-size: 14px; font-weight: 500; color: var(--adm-text-88); }
  489. .admin-page .el-divider--horizontal { margin: 24px 0; }
  490. /* 表格容器:弹性撑满(替代 JS 计算 max-height),仅表格自身滚动 */
  491. .admin-page .adm-table-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  492. .admin-page .adm-table-wrap > .el-table { flex: 1; min-height: 0; height: 100%; }
  493. /* 通用辅助 */
  494. .admin-page .text-muted { color: var(--adm-text-45); }
  495. .admin-page .adm-num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
  496. .admin-page > .header { flex-shrink: 0; }