@kine-design/crud 0.0.1-beta.2 → 0.0.1-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.vlaude/last-session-id +1 -0
  2. package/components/crudPage/KCrudPage.tsx +178 -0
  3. package/components/crudPage/crudPage.css +64 -0
  4. package/components/crudPage/index.ts +10 -0
  5. package/components/editableTable/KEditableTable.tsx +281 -0
  6. package/components/editableTable/editableTable.css +268 -0
  7. package/components/editableTable/index.ts +10 -0
  8. package/components/formPage/KApprovalDialog.tsx +142 -0
  9. package/components/formPage/KFormCard.tsx +65 -0
  10. package/components/formPage/KFormPage.tsx +128 -0
  11. package/components/formPage/KMasterDetailPage.tsx +205 -0
  12. package/components/formPage/KStickyActionBar.tsx +33 -0
  13. package/components/formPage/formPage.css +629 -0
  14. package/components/formPage/index.ts +14 -0
  15. package/components/layout/KContent.tsx +20 -0
  16. package/components/layout/KHeader.tsx +37 -0
  17. package/components/layout/KLayout.tsx +82 -0
  18. package/components/layout/KSider.tsx +80 -0
  19. package/components/layout/index.ts +18 -0
  20. package/components/layout/layout.css +262 -0
  21. package/components/login/KLoginPage.tsx +129 -0
  22. package/components/login/index.ts +10 -0
  23. package/components/login/login.css +118 -0
  24. package/components/navMenu/KNavMenu.tsx +175 -0
  25. package/components/navMenu/index.ts +2 -0
  26. package/components/navMenu/navMenu.css +197 -0
  27. package/components/pageHeader/KPageHeader.tsx +85 -0
  28. package/components/pageHeader/index.ts +9 -0
  29. package/components/pageHeader/pageHeader.css +93 -0
  30. package/components/searchTable/KSearchTable.tsx +138 -0
  31. package/components/searchTable/index.ts +10 -0
  32. package/components/searchTable/searchTable.css +121 -0
  33. package/components/upload/KFileList.tsx +95 -0
  34. package/components/upload/KImageUpload.tsx +286 -0
  35. package/components/upload/KUpload.tsx +206 -0
  36. package/components/upload/index.ts +13 -0
  37. package/components/upload/types.ts +26 -0
  38. package/components/upload/upload.css +345 -0
  39. package/composables/auth/authGuard.ts +128 -0
  40. package/composables/auth/index.ts +23 -0
  41. package/composables/auth/types.ts +109 -0
  42. package/composables/auth/useAuth.ts +278 -0
  43. package/composables/auth/vCan.ts +95 -0
  44. package/composables/defineRepository.ts +224 -0
  45. package/composables/error/createErrorHandler.ts +46 -0
  46. package/composables/error/defaultFeedbackHandler.ts +76 -0
  47. package/composables/error/dispatchError.ts +70 -0
  48. package/composables/error/index.ts +32 -0
  49. package/composables/error/types.ts +57 -0
  50. package/composables/error/useErrorHandler.ts +41 -0
  51. package/composables/form/index.ts +18 -0
  52. package/composables/form/renderFormField.tsx +119 -0
  53. package/composables/form/types.ts +129 -0
  54. package/composables/form/useFormPage.ts +183 -0
  55. package/composables/index.ts +62 -0
  56. package/composables/page/index.ts +11 -0
  57. package/composables/page/types.ts +62 -0
  58. package/composables/page/useCrudPage.ts +88 -0
  59. package/composables/request/composables.ts +206 -0
  60. package/composables/request/controlGate.ts +143 -0
  61. package/composables/request/createRequest.ts +173 -0
  62. package/composables/request/index.ts +71 -0
  63. package/composables/request/orchestrator.ts +145 -0
  64. package/composables/request/requestBuilder.ts +418 -0
  65. package/composables/request/transport/fetchTransport.ts +79 -0
  66. package/composables/request/transport/xhrTransport.ts +100 -0
  67. package/composables/request/types.ts +226 -0
  68. package/composables/request/upload.ts +146 -0
  69. package/composables/router/createRouterGuard.ts +134 -0
  70. package/composables/router/defineCrudRoutes.ts +116 -0
  71. package/composables/router/index.ts +22 -0
  72. package/composables/router/types.ts +128 -0
  73. package/composables/router/useMenuFromRoutes.ts +109 -0
  74. package/composables/router/useTabStore.ts +183 -0
  75. package/composables/search/index.ts +11 -0
  76. package/composables/search/useAutoCompleteSearch.ts +161 -0
  77. package/composables/setupCrud.ts +43 -0
  78. package/composables/storage/createStorageAdapter.ts +72 -0
  79. package/composables/storage/index.ts +13 -0
  80. package/composables/storage/types.ts +30 -0
  81. package/composables/storage/useStorage.ts +108 -0
  82. package/composables/store/defineUserStore.ts +122 -0
  83. package/composables/store/index.ts +11 -0
  84. package/composables/types.ts +118 -0
  85. package/dist/components/crudPage/KCrudPage.d.ts +14 -0
  86. package/dist/components/crudPage/index.d.ts +9 -0
  87. package/dist/components/editableTable/KEditableTable.d.ts +146 -0
  88. package/dist/components/editableTable/index.d.ts +10 -0
  89. package/dist/components/formPage/KApprovalDialog.d.ts +99 -0
  90. package/dist/components/formPage/KFormCard.d.ts +49 -0
  91. package/dist/components/formPage/KFormPage.d.ts +14 -0
  92. package/dist/components/formPage/KMasterDetailPage.d.ts +14 -0
  93. package/dist/components/formPage/KStickyActionBar.d.ts +16 -0
  94. package/dist/components/formPage/index.d.ts +14 -0
  95. package/dist/components/layout/KLayout.d.ts +7 -4
  96. package/dist/composables/auth/useAuth.d.ts +5 -5
  97. package/dist/composables/error/types.d.ts +2 -1
  98. package/dist/composables/form/index.d.ts +12 -0
  99. package/dist/composables/form/renderFormField.d.ts +11 -0
  100. package/dist/composables/form/types.d.ts +104 -0
  101. package/dist/composables/form/useFormPage.d.ts +38 -0
  102. package/dist/composables/index.d.ts +2 -0
  103. package/dist/composables/page/index.d.ts +10 -0
  104. package/dist/composables/page/types.d.ts +61 -0
  105. package/dist/composables/page/useCrudPage.d.ts +14 -0
  106. package/dist/composables/request/createRequest.d.ts +2 -0
  107. package/dist/composables/request/requestBuilder.d.ts +2 -0
  108. package/dist/composables/search/index.d.ts +10 -0
  109. package/dist/composables/search/useAutoCompleteSearch.d.ts +50 -0
  110. package/dist/crud.css +2499 -663
  111. package/dist/crud.js +11512 -2910
  112. package/dist/index.d.ts +11 -0
  113. package/dist/setup.d.ts +2 -2
  114. package/index.ts +144 -0
  115. package/package.json +20 -19
  116. package/setup.ts +288 -0
  117. package/tsconfig.json +12 -0
  118. package/vite.config.build.ts +52 -0
package/dist/crud.css CHANGED
@@ -26,13 +26,13 @@
26
26
  color: var(--kine-color-text-primary);
27
27
  border-right: 1px solid var(--kine-color-border-default);
28
28
  /* 折叠/展开宽度过渡 */
29
- transition: width 0.3s ease;
29
+ transition: width 0.3s var(--kine-motion-easing-default);
30
30
  will-change: width;
31
31
  box-sizing: border-box;
32
32
  }
33
33
 
34
34
  /* Logo 区域 */
35
- .k-crud-sider__logo {
35
+ .k-crud-sider-logo {
36
36
  display: flex;
37
37
  align-items: center;
38
38
  justify-content: center;
@@ -45,7 +45,7 @@
45
45
  }
46
46
 
47
47
  /* 菜单主体,占满剩余高度 */
48
- .k-crud-sider__body {
48
+ .k-crud-sider-body {
49
49
  display: flex;
50
50
  flex-direction: column;
51
51
  flex: 1;
@@ -55,7 +55,7 @@
55
55
  }
56
56
 
57
57
  /* 折叠触发器(底部) */
58
- .k-crud-sider__trigger {
58
+ .k-crud-sider-trigger {
59
59
  display: flex;
60
60
  align-items: center;
61
61
  justify-content: center;
@@ -65,7 +65,7 @@
65
65
  }
66
66
 
67
67
  /* 默认折叠按钮 */
68
- .k-crud-sider__trigger-btn {
68
+ .k-crud-sider-trigger-btn {
69
69
  display: flex;
70
70
  align-items: center;
71
71
  justify-content: center;
@@ -82,24 +82,24 @@
82
82
  padding: 0;
83
83
  }
84
84
 
85
- .k-crud-sider__trigger-btn:hover {
85
+ .k-crud-sider-trigger-btn:hover {
86
86
  background-color: var(--kine-color-bg-hover);
87
87
  color: var(--kine-color-text-primary);
88
88
  }
89
89
 
90
90
  /* 折叠箭头图标:展开时朝左,折叠时朝右 */
91
- .k-crud-sider__trigger-icon {
91
+ .k-crud-sider-trigger-icon {
92
92
  display: inline-flex;
93
93
  align-items: center;
94
- font-size: 20px;
94
+ font-size: var(--kine-font-size-3xl);
95
95
  line-height: 1;
96
96
  font-style: normal;
97
- transition: transform 0.3s ease;
97
+ transition: transform 0.3s var(--kine-motion-easing-default);
98
98
  /* 默认(展开态):‹ 指向左侧,表示可以收起 */
99
99
  transform: rotate(0deg);
100
100
  }
101
101
 
102
- .k-crud-sider__trigger-icon--collapsed {
102
+ .k-crud-sider-trigger-icon--collapsed {
103
103
  /* 折叠态:旋转 180deg,‹ 变成朝右,表示可以展开 */
104
104
  transform: rotate(180deg);
105
105
  }
@@ -112,13 +112,13 @@
112
112
  flex-shrink: 0;
113
113
  height: 56px;
114
114
  min-height: 56px;
115
- padding: 0 16px;
115
+ padding: 0 var(--kine-spacing-8);
116
116
  box-sizing: border-box;
117
117
  background-color: var(--kine-color-bg-primary);
118
118
  border-bottom: 1px solid var(--kine-color-border-default);
119
119
  }
120
120
 
121
- .k-crud-header__main {
121
+ .k-crud-header-main {
122
122
  display: flex;
123
123
  flex-direction: row;
124
124
  align-items: center;
@@ -126,12 +126,12 @@
126
126
  min-width: 0;
127
127
  }
128
128
 
129
- .k-crud-header__extra {
129
+ .k-crud-header-extra {
130
130
  display: flex;
131
131
  flex-direction: row;
132
132
  align-items: center;
133
133
  flex-shrink: 0;
134
- gap: 8px;
134
+ gap: var(--kine-spacing-4);
135
135
  }
136
136
 
137
137
  /* ===== KContent ===== */
@@ -144,9 +144,122 @@
144
144
  overflow-y: auto;
145
145
  overflow-x: hidden;
146
146
  background-color: var(--kine-color-bg-primary);
147
- padding: 16px;
147
+ padding: var(--kine-spacing-8);
148
148
  box-sizing: border-box;
149
149
  }
150
+
151
+ /* ===== 遮罩层(桌面端隐藏) ===== */
152
+ .k-crud-sider-overlay {
153
+ display: none;
154
+ position: fixed;
155
+ inset: 0;
156
+ z-index: 999;
157
+ background: rgba(0, 0, 0, 0);
158
+ pointer-events: none;
159
+ transition: background 0.3s var(--kine-motion-easing-default);
160
+ }
161
+
162
+ .k-crud-sider-overlay--visible {
163
+ background: rgba(0, 0, 0, 0.45);
164
+ pointer-events: auto;
165
+ }
166
+
167
+ /* ===== 汉堡按钮 ===== */
168
+ .k-crud-header-hamburger {
169
+ display: none; /* 桌面端隐藏 */
170
+ flex-direction: column;
171
+ justify-content: center;
172
+ align-items: center;
173
+ width: 36px;
174
+ height: 36px;
175
+ flex-shrink: 0;
176
+ margin-right: var(--kine-spacing-4);
177
+ background: none;
178
+ border: none;
179
+ cursor: pointer;
180
+ padding: var(--kine-spacing-2);
181
+ border-radius: var(--kine-radius-xs);
182
+ color: var(--kine-color-text-secondary);
183
+ transition: background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
184
+ }
185
+
186
+ .k-crud-header-hamburger:hover {
187
+ background: var(--kine-color-bg-hover);
188
+ color: var(--kine-color-text-primary);
189
+ }
190
+
191
+ /* 三条横线图标 */
192
+ .k-crud-header-hamburger-icon,
193
+ .k-crud-header-hamburger-icon::before,
194
+ .k-crud-header-hamburger-icon::after {
195
+ display: block;
196
+ width: 18px;
197
+ height: 2px;
198
+ background: currentColor;
199
+ border-radius: 1px;
200
+ }
201
+
202
+ .k-crud-header-hamburger-icon {
203
+ position: relative;
204
+ }
205
+
206
+ .k-crud-header-hamburger-icon::before,
207
+ .k-crud-header-hamburger-icon::after {
208
+ content: '';
209
+ position: absolute;
210
+ left: 0;
211
+ }
212
+
213
+ .k-crud-header-hamburger-icon::before { top: -5px; }
214
+ .k-crud-header-hamburger-icon::after { top: 5px; }
215
+
216
+ /* ================================================================
217
+ 移动端(<768px)
218
+ ================================================================ */
219
+
220
+ @media (max-width: 767px) {
221
+ /* 汉堡按钮显示 */
222
+ .k-crud-header-hamburger {
223
+ display: flex;
224
+ }
225
+
226
+ /* 侧边栏变为 fixed 抽屉,默认隐藏 */
227
+ .k-crud-sider {
228
+ position: fixed;
229
+ top: 0;
230
+ left: 0;
231
+ height: 100%;
232
+ width: 240px !important; /* 覆盖 inline style */
233
+ z-index: 1000;
234
+ transform: translateX(-100%);
235
+ transition:
236
+ transform 0.3s var(--kine-motion-easing-default),
237
+ box-shadow 0.3s var(--kine-motion-easing-default);
238
+ box-shadow: none;
239
+ border-right: none;
240
+ }
241
+
242
+ /* 抽屉打开 */
243
+ .k-crud-sider--drawer-open {
244
+ transform: translateX(0);
245
+ box-shadow: 4px 0 24px rgba(0, 0, 0, 0.18);
246
+ }
247
+
248
+ /* 遮罩层 */
249
+ .k-crud-sider-overlay {
250
+ display: block;
251
+ }
252
+
253
+ /* 底部折叠 trigger 在移动端隐藏 */
254
+ .k-crud-sider-trigger {
255
+ display: none;
256
+ }
257
+
258
+ /* 内容区 padding 缩减 */
259
+ .k-crud-content {
260
+ padding: var(--kine-spacing-4);
261
+ }
262
+ }
150
263
  /**
151
264
  * @description kine-ui table 样式 — Phosphor 主题
152
265
  * @author 阿怪
@@ -179,9 +292,9 @@
179
292
 
180
293
  /* 表头单元格 */
181
294
  .k-th {
182
- padding: 8px 12px;
295
+ padding: var(--kine-spacing-4) var(--kine-spacing-6);
183
296
  color: var(--kine-color-text-secondary);
184
- font-weight: 500;
297
+ font-weight: var(--kine-font-weight-medium);
185
298
  font-size: var(--kine-font-size-sm);
186
299
  text-align: left;
187
300
  white-space: nowrap;
@@ -189,7 +302,7 @@
189
302
 
190
303
  /* 数据单元格 */
191
304
  .k-td {
192
- padding: 8px 12px;
305
+ padding: var(--kine-spacing-4) var(--kine-spacing-6);
193
306
  border-bottom: 1px solid var(--kine-color-border-default);
194
307
  font-size: var(--kine-font-size-sm);
195
308
  color: var(--kine-color-text-primary);
@@ -211,7 +324,7 @@
211
324
 
212
325
  /* 空数据占位 */
213
326
  .k-table-empty th {
214
- padding: 24px;
327
+ padding: var(--kine-spacing-12);
215
328
  text-align: center;
216
329
  color: var(--kine-color-text-muted);
217
330
  font-size: var(--kine-font-size-sm);
@@ -246,6 +359,16 @@
246
359
  @keyframes k-table-spin {
247
360
  to { transform: rotate(360deg); }
248
361
  }
362
+
363
+ /* ================================================================
364
+ 移动端(<768px)— 表格横向滚动保护
365
+ ================================================================ */
366
+
367
+ @media (max-width: 767px) {
368
+ .k-table-inner {
369
+ min-width: 600px;
370
+ }
371
+ }
249
372
  /**
250
373
  * @description kine-ui pagination 样式 — Phosphor 主题
251
374
  * @author 阿怪
@@ -259,7 +382,7 @@
259
382
  font-family: var(--kine-font-family-mono);
260
383
  font-size: var(--kine-font-size-md);
261
384
  color: var(--kine-color-text-secondary);
262
- gap: 4px;
385
+ gap: var(--kine-spacing-2);
263
386
  user-select: none;
264
387
  }
265
388
 
@@ -315,7 +438,7 @@
315
438
  border-radius: var(--kine-radius-sm);
316
439
  border: 1px solid var(--kine-color-border-default);
317
440
  color: var(--kine-color-text-secondary);
318
- font-size: 16px;
441
+ font-size: var(--kine-font-size-2xl);
319
442
  cursor: pointer;
320
443
  transition: background var(--kine-motion-duration-fast), color var(--kine-motion-duration-fast);
321
444
  }
@@ -337,12 +460,215 @@
337
460
  .k-page-total {
338
461
  font-size: var(--kine-font-size-sm);
339
462
  color: var(--kine-color-text-muted);
340
- padding: 0 4px;
463
+ padding: 0 var(--kine-spacing-2);
341
464
  }
342
465
 
343
466
  .k-page-total span {
344
467
  color: var(--kine-color-text-secondary);
345
468
  }
469
+ /**
470
+ * @description kine-ui button 样式 — Phosphor 主题
471
+ * @author 阿怪
472
+ * @date 2026/2/27
473
+ * @version v1.1.0
474
+ */
475
+
476
+ .k-button {
477
+ font-family: var(--kine-font-family-mono);
478
+ font-size: var(--kine-control-font-size-md);
479
+ font-weight: var(--kine-font-weight-medium);
480
+ height: var(--kine-control-height-md);
481
+ padding: 0 var(--kine-control-padding-x-md);
482
+ border: 1px solid var(--kine-control-border-color);
483
+ border-radius: var(--kine-control-radius);
484
+ background: var(--kine-control-bg);
485
+ color: var(--kine-color-text-primary);
486
+ cursor: pointer;
487
+ outline: none;
488
+ transition: all var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
489
+ user-select: none;
490
+ display: inline-flex;
491
+ align-items: center;
492
+ gap: var(--kine-spacing-3);
493
+ }
494
+
495
+ /* === default hover/active === */
496
+ .k-button:hover {
497
+ background: var(--kine-color-bg-hover);
498
+ border-color: var(--kine-color-text-secondary);
499
+ color: #ffffff;
500
+ }
501
+
502
+ .k-button:active {
503
+ background: var(--kine-color-border-subtle);
504
+ }
505
+
506
+ /* === primary === */
507
+ .k-button-primary {
508
+ background: color-mix(in srgb, var(--kine-color-accent-default) 10%, var(--kine-color-bg-tertiary));
509
+ border-color: var(--kine-color-accent-default);
510
+ color: var(--kine-color-accent-default);
511
+ }
512
+
513
+ .k-button-primary:hover {
514
+ background: color-mix(in srgb, var(--kine-color-accent-default) 18%, var(--kine-color-bg-primary));
515
+ border-color: var(--kine-color-accent-hover);
516
+ color: var(--kine-color-accent-hover);
517
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-accent-default) 50%, transparent);
518
+ }
519
+
520
+ .k-button-primary:active {
521
+ background: color-mix(in srgb, var(--kine-color-accent-default) 25%, var(--kine-color-bg-primary));
522
+ }
523
+
524
+ /* === success === */
525
+ .k-button-success {
526
+ border-color: var(--kine-color-semantic-success);
527
+ color: var(--kine-color-semantic-success);
528
+ }
529
+
530
+ .k-button-success:hover {
531
+ background: color-mix(in srgb, var(--kine-color-semantic-success) 12%, var(--kine-color-bg-primary));
532
+ border-color: var(--kine-color-semantic-success-hover);
533
+ color: var(--kine-color-semantic-success-hover);
534
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-success) 50%, transparent);
535
+ }
536
+
537
+ .k-button-success:active {
538
+ background: color-mix(in srgb, var(--kine-color-semantic-success) 20%, var(--kine-color-bg-primary));
539
+ }
540
+
541
+ /* === warning === */
542
+ .k-button-warning {
543
+ border-color: var(--kine-color-semantic-warning);
544
+ color: var(--kine-color-semantic-warning);
545
+ }
546
+
547
+ .k-button-warning:hover {
548
+ background: color-mix(in srgb, var(--kine-color-semantic-warning) 12%, var(--kine-color-bg-primary));
549
+ border-color: var(--kine-color-semantic-warning-hover);
550
+ color: var(--kine-color-semantic-warning-hover);
551
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-warning) 50%, transparent);
552
+ }
553
+
554
+ .k-button-warning:active {
555
+ background: color-mix(in srgb, var(--kine-color-semantic-warning) 20%, var(--kine-color-bg-primary));
556
+ }
557
+
558
+ /* === danger === */
559
+ .k-button-danger {
560
+ border-color: var(--kine-color-semantic-error);
561
+ color: var(--kine-color-semantic-error);
562
+ }
563
+
564
+ .k-button-danger:hover {
565
+ background: color-mix(in srgb, var(--kine-color-semantic-error) 12%, var(--kine-color-bg-primary));
566
+ border-color: var(--kine-color-semantic-error-hover);
567
+ color: var(--kine-color-semantic-error-hover);
568
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-error) 50%, transparent);
569
+ }
570
+
571
+ .k-button-danger:active {
572
+ background: color-mix(in srgb, var(--kine-color-semantic-error) 20%, var(--kine-color-bg-primary));
573
+ }
574
+
575
+ /* === info === */
576
+ .k-button-info {
577
+ border-color: var(--kine-color-semantic-info, #64748b);
578
+ color: var(--kine-color-semantic-info, #64748b);
579
+ }
580
+
581
+ .k-button-info:hover {
582
+ background: color-mix(in srgb, var(--kine-color-semantic-info, #64748b) 12%, var(--kine-color-bg-primary));
583
+ border-color: var(--kine-color-semantic-info-hover, #94a3b8);
584
+ color: var(--kine-color-semantic-info-hover, #94a3b8);
585
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-info, #64748b) 50%, transparent);
586
+ }
587
+
588
+ .k-button-info:active {
589
+ background: color-mix(in srgb, var(--kine-color-semantic-info, #64748b) 20%, var(--kine-color-bg-primary));
590
+ }
591
+
592
+ /* === disabled === */
593
+ .k-button-disabled {
594
+ opacity: var(--kine-opacity-muted);
595
+ cursor: not-allowed;
596
+ pointer-events: none;
597
+ }
598
+
599
+ /* === loading === */
600
+ .k-button-loading {
601
+ cursor: not-allowed;
602
+ pointer-events: none;
603
+ opacity: var(--kine-opacity-medium);
604
+ }
605
+
606
+ .k-button-loading .k-button-spinner {
607
+ display: inline-block;
608
+ width: 12px;
609
+ height: 12px;
610
+ border: 1.5px solid currentColor;
611
+ border-top-color: transparent;
612
+ border-radius: 50%;
613
+ animation: k-button-spin 0.6s linear infinite;
614
+ flex-shrink: 0;
615
+ }
616
+
617
+ @keyframes k-button-spin {
618
+ to { transform: rotate(360deg); }
619
+ }
620
+
621
+ /* === plain === */
622
+ .k-button-plain {
623
+ background: transparent;
624
+ border-color: transparent;
625
+ color: var(--kine-color-text-primary);
626
+ }
627
+
628
+ .k-button-plain:hover {
629
+ background: var(--kine-color-bg-hover);
630
+ border-color: transparent;
631
+ color: #ffffff;
632
+ }
633
+
634
+ .k-button-plain:active {
635
+ background: var(--kine-color-border-subtle);
636
+ }
637
+
638
+ /* === link === */
639
+ .k-button-link {
640
+ background: transparent;
641
+ border-color: transparent;
642
+ color: var(--kine-color-accent-default);
643
+ padding: 0;
644
+ text-decoration: none;
645
+ }
646
+
647
+ .k-button-link:hover {
648
+ color: var(--kine-color-accent-hover);
649
+ border-color: transparent;
650
+ background: transparent;
651
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-accent-default) 50%, transparent);
652
+ }
653
+
654
+ /* === size variants === */
655
+ .k-button-large {
656
+ height: var(--kine-control-height-lg);
657
+ font-size: var(--kine-control-font-size-lg);
658
+ padding: 0 var(--kine-control-padding-x-lg);
659
+ }
660
+
661
+ .k-button-medium {
662
+ height: var(--kine-control-height-md);
663
+ font-size: var(--kine-control-font-size-md);
664
+ padding: 0 var(--kine-control-padding-x-md);
665
+ }
666
+
667
+ .k-button-small {
668
+ height: var(--kine-control-height-sm);
669
+ font-size: var(--kine-control-font-size-sm);
670
+ padding: 0 var(--kine-control-padding-x-sm);
671
+ }
346
672
  /**
347
673
  * @description KSearchTable 搜索表格组合组件样式 — Phosphor 主题
348
674
  * @author 阿怪
@@ -358,7 +684,7 @@
358
684
  width: 100%;
359
685
  box-sizing: border-box;
360
686
  background-color: transparent;
361
- gap: 12px;
687
+ gap: var(--kine-spacing-6);
362
688
  }
363
689
 
364
690
  /* 加载态透明度 */
@@ -373,9 +699,9 @@
373
699
  flex-direction: row;
374
700
  align-items: flex-end;
375
701
  flex-wrap: wrap;
376
- gap: 12px;
702
+ gap: var(--kine-spacing-6);
377
703
  flex-shrink: 0;
378
- padding: 16px;
704
+ padding: var(--kine-spacing-8);
379
705
  background-color: var(--kine-color-bg-primary);
380
706
  border-radius: var(--kine-radius-md);
381
707
  border: 1px solid var(--kine-color-border-default);
@@ -387,7 +713,7 @@
387
713
  display: flex;
388
714
  flex-direction: row;
389
715
  flex-wrap: wrap;
390
- gap: 12px;
716
+ gap: var(--kine-spacing-6);
391
717
  flex: 1;
392
718
  min-width: 0;
393
719
  }
@@ -397,57 +723,16 @@
397
723
  display: flex;
398
724
  flex-direction: row;
399
725
  align-items: center;
400
- gap: 8px;
726
+ gap: var(--kine-spacing-4);
401
727
  flex-shrink: 0;
402
728
  }
403
729
 
404
- /* ===== 搜索按钮基础样式(原生 button,业务可覆盖)===== */
405
- .k-search-table-btn {
406
- display: inline-flex;
407
- align-items: center;
408
- justify-content: center;
409
- height: 32px;
410
- padding: 0 16px;
411
- font-size: var(--kine-font-size-lg);
412
- border-radius: var(--kine-radius-sm);
413
- border: 1px solid var(--kine-color-border-default);
414
- background-color: var(--kine-color-bg-primary);
415
- color: var(--kine-color-text-primary);
416
- cursor: pointer;
417
- white-space: nowrap;
418
- transition:
419
- background-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
420
- border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
421
- color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
422
- box-sizing: border-box;
423
- font-family: var(--kine-font-family-system);
424
- }
425
-
426
- .k-search-table-btn:hover {
427
- background-color: var(--kine-color-bg-hover);
428
- border-color: var(--kine-color-accent-default);
429
- color: var(--kine-color-accent-default);
430
- }
431
-
432
- /* 主色按钮(搜索) */
433
- .k-search-table-btn--primary {
434
- background-color: var(--kine-color-accent-default);
435
- border-color: var(--kine-color-accent-default);
436
- color: #ffffff;
437
- }
438
-
439
- .k-search-table-btn--primary:hover {
440
- background-color: var(--kine-color-accent-hover);
441
- border-color: var(--kine-color-accent-hover);
442
- color: #ffffff;
443
- }
444
-
445
730
  /* ===== 工具栏:搜索区与表格之间 ===== */
446
731
  .k-search-table-toolbar {
447
732
  display: flex;
448
733
  flex-direction: row;
449
734
  align-items: center;
450
- gap: 8px;
735
+ gap: var(--kine-spacing-4);
451
736
  flex-shrink: 0;
452
737
  min-height: 36px;
453
738
  }
@@ -475,834 +760,2385 @@
475
760
  justify-content: flex-end;
476
761
  align-items: center;
477
762
  flex-shrink: 0;
478
- padding: 8px 0;
763
+ padding: var(--kine-spacing-4) 0;
764
+ }
765
+
766
+ /* ================================================================
767
+ 移动端(<768px)
768
+ ================================================================ */
769
+
770
+ @media (max-width: 767px) {
771
+ /* 搜索区从横排改为纵排 */
772
+ .k-search-table-search {
773
+ flex-direction: column;
774
+ align-items: stretch;
775
+ padding: var(--kine-spacing-6);
776
+ gap: var(--kine-spacing-4);
777
+ }
778
+
779
+ .k-search-table-search-form {
780
+ flex-direction: column;
781
+ }
782
+
783
+ /* 搜索按钮区靠右 */
784
+ .k-search-table-search-actions {
785
+ justify-content: flex-end;
786
+ }
787
+
788
+ /* 表格区允许横向滚动 */
789
+ .k-search-table-body {
790
+ overflow-x: auto;
791
+ }
479
792
  }
480
793
  /**
481
- * @description KLoginPage 登录页样式 — Phosphor 主题
794
+ * @description kine-ui tag 样式 — Phosphor 主题
482
795
  * @author 阿怪
483
- * @date 2026/2/26
484
- * @version v0.0.2
796
+ * @date 2026/2/27
797
+ * @version v1.1.0
485
798
  */
486
799
 
487
- /* ===== 全屏容器 ===== */
488
- .k-login-page {
489
- display: flex;
490
- flex-direction: column;
800
+ /* === 基础样式 === */
801
+ .k-tag {
802
+ display: inline-flex;
491
803
  align-items: center;
492
- justify-content: center;
493
- min-height: 100vh;
494
- width: 100%;
495
- box-sizing: border-box;
496
- padding: 24px;
497
- background-color: var(--kine-color-bg-secondary);
804
+ gap: var(--kine-spacing-2);
805
+ font-family: var(--kine-font-family-mono);
806
+ font-size: var(--kine-font-size-xs);
807
+ padding: var(--kine-spacing-1) var(--kine-spacing-4);
808
+ border: 1px solid var(--kine-color-border-default);
809
+ border-radius: var(--kine-radius-xs);
810
+ background: var(--kine-color-bg-tertiary);
811
+ color: var(--kine-color-text-secondary);
812
+ line-height: 1.4;
813
+ white-space: nowrap;
814
+ cursor: default;
815
+ user-select: none;
498
816
  }
499
817
 
500
- /* ===== 登录卡片 ===== */
501
- .k-login-card {
502
- width: 100%;
503
- max-width: 400px;
504
- background-color: var(--kine-color-bg-primary);
505
- border-radius: var(--kine-radius-md);
506
- border: 1px solid var(--kine-color-border-default);
507
- box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
508
- padding: 40px 36px 32px;
509
- box-sizing: border-box;
818
+ /* === 类型变体 === */
819
+ .k-tag-primary {
820
+ border-color: var(--kine-color-accent-default);
821
+ color: var(--kine-color-accent-default);
822
+ background: color-mix(in srgb, var(--kine-color-accent-default) 10%, var(--kine-color-bg-tertiary));
510
823
  }
511
824
 
512
- @media (max-width: 480px) {
513
- .k-login-card {
514
- padding: 32px 20px 24px;
515
- box-shadow: none;
516
- border-radius: 0;
517
- max-width: 100%;
518
- }
825
+ .k-tag-success {
826
+ border-color: var(--kine-color-semantic-success);
827
+ color: var(--kine-color-semantic-success);
828
+ background: color-mix(in srgb, var(--kine-color-semantic-success) 10%, var(--kine-color-bg-tertiary));
519
829
  }
520
830
 
521
- /* ===== Logo 区域 ===== */
522
- .k-login-logo {
523
- display: flex;
524
- justify-content: center;
525
- margin-bottom: 16px;
831
+ .k-tag-warning {
832
+ border-color: var(--kine-color-semantic-warning);
833
+ color: var(--kine-color-semantic-warning);
834
+ background: color-mix(in srgb, var(--kine-color-semantic-warning) 10%, var(--kine-color-bg-tertiary));
526
835
  }
527
836
 
528
- /* ===== 标题 ===== */
529
- .k-login-title {
530
- text-align: center;
531
- font-size: 22px;
532
- font-weight: 600;
533
- color: var(--kine-color-text-primary);
534
- margin: 0 0 28px;
535
- line-height: 1.4;
536
- font-family: var(--kine-font-family-system);
837
+ .k-tag-danger {
838
+ border-color: var(--kine-color-semantic-error);
839
+ color: var(--kine-color-semantic-error);
840
+ background: color-mix(in srgb, var(--kine-color-semantic-error) 10%, var(--kine-color-bg-tertiary));
537
841
  }
538
842
 
539
- /* ===== 表单 ===== */
540
- .k-login-form {
541
- display: flex;
542
- flex-direction: column;
543
- gap: 16px;
843
+ .k-tag-info {
844
+ border-color: var(--kine-color-semantic-info);
845
+ color: var(--kine-color-semantic-info);
846
+ background: color-mix(in srgb, var(--kine-color-semantic-info) 10%, var(--kine-color-bg-tertiary));
544
847
  }
545
848
 
546
- /* 表单项 */
547
- .k-login-form-item {
548
- display: flex;
549
- flex-direction: column;
550
- gap: 6px;
849
+ /* === 尺寸变体 === */
850
+ .k-tag-large {
851
+ font-size: var(--kine-font-size-md);
852
+ padding: var(--kine-spacing-2) var(--kine-spacing-6);
551
853
  }
552
854
 
553
- .k-login-form-item label {
554
- font-size: 13px;
555
- color: var(--kine-color-text-secondary);
556
- font-weight: 500;
557
- font-family: var(--kine-font-family-system);
855
+ .k-tag-medium {
856
+ font-size: var(--kine-font-size-xs);
857
+ padding: var(--kine-spacing-1) var(--kine-spacing-4);
558
858
  }
559
859
 
560
- .k-login-form-item input[type='text'],
561
- .k-login-form-item input[type='password'] {
562
- width: 100%;
563
- height: 40px;
564
- padding: 0 12px;
565
- box-sizing: border-box;
566
- border: 1px solid var(--kine-color-border-default);
567
- border-radius: var(--kine-radius-sm);
568
- font-size: 14px;
569
- color: var(--kine-color-text-primary);
570
- background-color: var(--kine-color-bg-primary);
571
- outline: none;
572
- font-family: var(--kine-font-family-system);
573
- transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
574
- }
575
-
576
- .k-login-form-item input[type='text']:focus,
577
- .k-login-form-item input[type='password']:focus {
578
- border-color: var(--kine-color-accent-default);
579
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--kine-color-accent-default) 20%, transparent);
860
+ .k-tag-small {
861
+ font-size: 8px;
862
+ padding: 1px var(--kine-spacing-3);
580
863
  }
581
864
 
582
- /* 记住我行 */
583
- .k-login-remember {
584
- display: flex;
865
+ /* === 可关闭 === */
866
+ .k-tag-close {
867
+ display: inline-flex;
585
868
  align-items: center;
586
- gap: 8px;
587
- font-size: 13px;
588
- color: var(--kine-color-text-secondary);
869
+ justify-content: center;
870
+ width: 12px;
871
+ height: 12px;
872
+ font-size: var(--kine-font-size-md);
873
+ line-height: 1;
589
874
  cursor: pointer;
590
- user-select: none;
591
- font-family: var(--kine-font-family-system);
875
+ opacity: 0.6;
876
+ border-radius: 50%;
877
+ transition: opacity var(--kine-motion-duration-fast), background var(--kine-motion-duration-fast);
592
878
  }
593
879
 
594
- .k-login-remember input[type='checkbox'] {
595
- width: 15px;
596
- height: 15px;
597
- cursor: pointer;
598
- accent-color: var(--kine-color-accent-default);
880
+ .k-tag-close:hover {
881
+ opacity: 1;
882
+ background: color-mix(in srgb, currentColor 20%, transparent);
883
+ }
884
+
885
+ /* === 禁用状态 === */
886
+ .k-tag-disabled {
887
+ opacity: var(--kine-opacity-muted);
888
+ pointer-events: none;
889
+ cursor: not-allowed;
599
890
  }
891
+ /**
892
+ * @description kine-ui image 样式 — Phosphor 主题
893
+ * @author 阿怪
894
+ * @date 2026/2/26
895
+ * @version v1.0.0
896
+ *
897
+ * 江湖的业务千篇一律,复杂的代码好几百行。
898
+ */
600
899
 
601
- /* 提交按钮 */
602
- .k-login-submit {
900
+ /* === 图片容器 === */
901
+ .k-image {
902
+ position: relative;
903
+ display: inline-block;
904
+ overflow: hidden;
603
905
  width: 100%;
604
- height: 42px;
605
- margin-top: 4px;
606
- border: none;
607
- border-radius: var(--kine-radius-sm);
608
- background-color: var(--kine-color-accent-default);
609
- color: #ffffff;
610
- font-size: 15px;
611
- font-weight: 500;
612
- cursor: pointer;
613
- font-family: var(--kine-font-family-system);
614
- transition:
615
- background-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
616
- opacity var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
906
+ height: 100%;
907
+ background: var(--kine-color-bg-secondary);
908
+ border-radius: var(--kine-radius-xs);
617
909
  }
618
910
 
619
- .k-login-submit:hover:not(:disabled) {
620
- background-color: var(--kine-color-accent-hover);
911
+ /* 有预览时鼠标变指针 */
912
+ .k-image-previewable {
913
+ cursor: zoom-in;
621
914
  }
622
915
 
623
- .k-login-submit:active:not(:disabled) {
624
- background-color: var(--kine-color-accent-alt);
916
+ /* === 实际图片元素 === */
917
+ .k-image-inner {
918
+ display: block;
919
+ width: 100%;
920
+ height: 100%;
921
+ transition: opacity var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
625
922
  }
626
923
 
627
- .k-login-submit:disabled,
628
- .k-login-submit--loading {
629
- opacity: 0.65;
630
- cursor: not-allowed;
924
+ .k-image-inner-hidden {
925
+ opacity: 0;
926
+ position: absolute;
927
+ top: 0;
928
+ left: 0;
929
+ pointer-events: none;
631
930
  }
632
931
 
633
- /* ===== 额外登录方式区域 ===== */
634
- .k-login-extra {
635
- margin-top: 20px;
636
- text-align: center;
932
+ /* === 占位容器(loading / error 共用) === */
933
+ .k-image-placeholder {
934
+ display: flex;
935
+ flex-direction: column;
936
+ align-items: center;
937
+ justify-content: center;
938
+ gap: var(--kine-spacing-4);
939
+ min-width: 100px;
940
+ min-height: 100px;
941
+ width: 100%;
942
+ height: 100%;
943
+ font-family: var(--kine-font-family-mono);
944
+ font-size: var(--kine-font-size-sm);
637
945
  }
638
946
 
639
- /* ===== 底部版权区域 ===== */
640
- .k-login-footer {
641
- margin-top: 32px;
642
- text-align: center;
643
- font-size: 12px;
947
+ .k-image-placeholder-icon {
948
+ width: 40px;
949
+ height: 40px;
950
+ }
951
+
952
+ /* loading 状态:accent 微光 + 动画 */
953
+ .k-image-loading {
644
954
  color: var(--kine-color-text-muted);
645
- font-family: var(--kine-font-family-system);
646
955
  }
647
- /**
648
- * @description KPageHeader 页面头部样式 — Phosphor 主题
649
- * @author 阿怪
650
- * @date 2026/2/26
651
- * @version v0.0.2
652
- */
653
956
 
654
- /* ===== 容器 ===== */
655
- .k-page-header {
656
- display: flex;
657
- flex-direction: column;
658
- width: 100%;
659
- box-sizing: border-box;
660
- padding: 16px 0 12px;
661
- border-bottom: 1px solid var(--kine-color-border-default);
662
- background-color: transparent;
663
- margin-bottom: 16px;
957
+ .k-image-loading .k-image-placeholder-icon {
958
+ animation: k-image-pulse 1.6s ease-in-out infinite;
959
+ color: var(--kine-color-accent-default);
664
960
  }
665
961
 
666
- /* ===== 面包屑区域 ===== */
667
- .k-page-header-breadcrumb {
668
- margin-bottom: 8px;
669
- font-size: var(--kine-font-size-lg);
962
+ @keyframes k-image-pulse {
963
+ 0%, 100% { opacity: 0.3; }
964
+ 50% { opacity: 1; }
965
+ }
966
+
967
+ /* error 状态 */
968
+ .k-image-error {
969
+ color: var(--kine-color-semantic-error);
970
+ }
971
+
972
+ .k-image-error-text {
670
973
  color: var(--kine-color-text-muted);
671
- font-family: var(--kine-font-family-system);
672
- min-height: 20px;
673
974
  }
674
975
 
675
- /* ===== 主行:标题 + 操作 ===== */
676
- .k-page-header-main {
976
+ /* === 全屏预览遮罩层 === */
977
+ .k-image-preview-mask {
978
+ position: fixed;
979
+ inset: 0;
980
+ background: color-mix(in srgb, var(--kine-color-bg-primary) 90%, transparent);
677
981
  display: flex;
678
- flex-direction: row;
679
982
  align-items: center;
680
- justify-content: space-between;
681
- gap: 16px;
682
- min-height: 32px;
983
+ justify-content: center;
683
984
  }
684
985
 
685
- /* ===== 左侧:返回 + 标题区 ===== */
686
- .k-page-header-left {
986
+ /* === 预览图片本体 === */
987
+ .k-image-preview-img {
988
+ max-width: 90vw;
989
+ max-height: 85vh;
990
+ object-fit: contain;
991
+ border-radius: var(--kine-radius-xs);
992
+ box-shadow: 0 0 40px color-mix(in srgb, var(--kine-color-accent-default) 20%, transparent);
993
+ transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
994
+ user-select: none;
995
+ }
996
+
997
+ /* === 工具栏 === */
998
+ .k-image-preview-toolbar {
999
+ position: absolute;
1000
+ top: var(--kine-spacing-8);
1001
+ left: 50%;
1002
+ transform: translateX(-50%);
687
1003
  display: flex;
688
- flex-direction: row;
689
1004
  align-items: center;
690
- gap: 8px;
691
- min-width: 0;
692
- flex: 1;
1005
+ gap: var(--kine-spacing-2);
1006
+ background: var(--kine-color-bg-secondary);
1007
+ border: 1px solid var(--kine-color-border-default);
1008
+ border-radius: var(--kine-radius-xs);
1009
+ padding: var(--kine-spacing-2) var(--kine-spacing-4);
1010
+ font-family: var(--kine-font-family-mono);
693
1011
  }
694
1012
 
695
- /* 返回按钮 */
696
- .k-page-header-back {
1013
+ /* === 工具按钮 === */
1014
+ .k-image-preview-btn {
697
1015
  display: inline-flex;
698
1016
  align-items: center;
699
1017
  justify-content: center;
700
1018
  width: 28px;
701
1019
  height: 28px;
702
- flex-shrink: 0;
703
- border: 1px solid var(--kine-color-border-default);
704
- border-radius: var(--kine-radius-sm);
705
- background-color: transparent;
706
- cursor: pointer;
1020
+ border: none;
1021
+ border-radius: var(--kine-radius-xs);
1022
+ background: transparent;
707
1023
  color: var(--kine-color-text-secondary);
708
- font-size: 14px;
709
- line-height: 1;
1024
+ font-size: 16px;
1025
+ cursor: pointer;
710
1026
  transition:
711
- background-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
712
- border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
713
- padding: 0;
714
- }
715
-
716
- .k-page-header-back:hover {
717
- background-color: var(--kine-color-bg-hover);
718
- border-color: var(--kine-color-accent-default);
719
- color: var(--kine-color-accent-default);
1027
+ color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1028
+ background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
720
1029
  }
721
1030
 
722
- /* 标题文字区 */
723
- .k-page-header-heading {
724
- display: flex;
725
- flex-direction: column;
726
- min-width: 0;
1031
+ .k-image-preview-btn:hover {
1032
+ color: var(--kine-color-text-primary);
1033
+ background: color-mix(in srgb, var(--kine-color-accent-default) 15%, transparent);
727
1034
  }
728
1035
 
729
- /* 主标题 */
730
- .k-page-header-title {
731
- font-size: 18px;
732
- font-weight: 600;
733
- color: var(--kine-color-text-primary);
734
- margin: 0;
735
- line-height: 1.4;
736
- white-space: nowrap;
737
- overflow: hidden;
738
- text-overflow: ellipsis;
739
- font-family: var(--kine-font-family-system);
1036
+ .k-image-preview-close:hover {
1037
+ color: var(--kine-color-semantic-error);
1038
+ background: color-mix(in srgb, var(--kine-color-semantic-error) 15%, transparent);
740
1039
  }
741
1040
 
742
- /* 副标题 */
743
- .k-page-header-subtitle {
744
- font-size: var(--kine-font-size-lg);
1041
+ /* 当前缩放比例显示 */
1042
+ .k-image-preview-scale {
1043
+ font-size: var(--kine-font-size-sm);
745
1044
  color: var(--kine-color-text-muted);
746
- margin: 2px 0 0;
747
- line-height: 1.4;
748
- white-space: nowrap;
749
- overflow: hidden;
750
- text-overflow: ellipsis;
751
- font-family: var(--kine-font-family-system);
1045
+ min-width: 40px;
1046
+ text-align: center;
752
1047
  }
753
1048
 
754
- /* ===== 右侧操作区 ===== */
755
- .k-page-header-extra {
1049
+ /* === 预览切换箭头 === */
1050
+ .k-image-preview-arrow {
1051
+ position: absolute;
1052
+ top: 50%;
1053
+ transform: translateY(-50%);
756
1054
  display: flex;
757
- flex-direction: row;
758
1055
  align-items: center;
759
- flex-shrink: 0;
760
- gap: 8px;
1056
+ justify-content: center;
1057
+ width: 44px;
1058
+ height: 44px;
1059
+ border: 1px solid var(--kine-color-border-default);
1060
+ border-radius: 50%;
1061
+ background: color-mix(in srgb, var(--kine-color-bg-secondary) 80%, transparent);
1062
+ color: var(--kine-color-text-primary);
1063
+ font-size: 26px;
1064
+ cursor: pointer;
1065
+ transition:
1066
+ background var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1067
+ border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
761
1068
  }
762
1069
 
763
- /* ===== 标题下方内容插槽 ===== */
764
- .k-page-header-content {
765
- margin-top: 12px;
1070
+ .k-image-preview-arrow:hover {
1071
+ background: var(--kine-color-bg-secondary);
1072
+ border-color: var(--kine-color-accent-default);
1073
+ color: var(--kine-color-accent-default);
1074
+ }
1075
+
1076
+ .k-image-preview-arrow-prev {
1077
+ left: 20px;
1078
+ }
1079
+
1080
+ .k-image-preview-arrow-next {
1081
+ right: 20px;
1082
+ }
1083
+
1084
+ /* === 图片计数 === */
1085
+ .k-image-preview-counter {
1086
+ position: absolute;
1087
+ bottom: var(--kine-spacing-8);
1088
+ left: 50%;
1089
+ transform: translateX(-50%);
1090
+ font-family: var(--kine-font-family-mono);
1091
+ font-size: var(--kine-font-size-sm);
1092
+ color: var(--kine-color-text-muted);
1093
+ background: var(--kine-color-bg-secondary);
1094
+ border: 1px solid var(--kine-color-border-default);
1095
+ border-radius: var(--kine-radius-xs);
1096
+ padding: var(--kine-spacing-1) var(--kine-spacing-5);
766
1097
  }
767
1098
  /**
768
- * @description KNavMenu 导航菜单样式 — Phosphor 主题
1099
+ * @description kine-ui input 样式
769
1100
  * @author 阿怪
770
1101
  * @date 2026/2/26
771
1102
  * @version v1.0.0
1103
+ *
1104
+ * 江湖的业务千篇一律,复杂的代码好几百行。
772
1105
  */
773
1106
 
774
- /* ===== 容器:撑满侧边栏,去掉 KMenu 默认边框 ===== */
775
- .k-nav-menu {
776
- display: flex;
777
- flex-direction: column;
1107
+ .k-input {
1108
+ display: block;
778
1109
  width: 100%;
779
- padding: 4px 0;
780
- }
781
-
782
- /* 根级 li:无缩进 */
783
- .k-nav-menu > .k-menu-item-root {
784
- list-style: none;
1110
+ box-sizing: border-box;
1111
+ font-family: var(--kine-font-family-mono);
1112
+ font-size: var(--kine-control-font-size-md);
1113
+ height: var(--kine-control-height-md);
1114
+ color: var(--kine-color-text-primary);
1115
+ background-color: var(--kine-control-bg);
1116
+ border: 1px solid var(--kine-control-border-color);
1117
+ border-radius: var(--kine-control-radius);
1118
+ padding: 0 var(--kine-control-padding-x-md);
1119
+ outline: none;
1120
+ transition: all var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
785
1121
  }
786
1122
 
787
- /* ===== 内容行通用 ===== */
788
- .k-nav-menu .k-menu-item-content {
789
- display: flex;
790
- align-items: center;
791
- gap: 10px;
792
- padding: 11px 18px;
793
- color: var(--kine-color-text-secondary);
794
- font-size: 15px;
795
- cursor: pointer;
796
- transition:
797
- background var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
798
- color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
799
- border-left: 2px solid transparent;
1123
+ .k-input::placeholder {
1124
+ color: var(--kine-color-text-muted);
800
1125
  }
801
1126
 
802
- .k-nav-menu .k-menu-item-content:hover {
803
- background: var(--kine-color-bg-hover);
804
- color: var(--kine-color-text-primary);
1127
+ .k-input:focus {
1128
+ border-color: var(--kine-color-accent-default);
1129
+ box-shadow: 0 0 var(--kine-shadow-glow-radius) color-mix(in srgb, var(--kine-color-accent-default) 30%, transparent);
805
1130
  }
806
1131
 
807
- /* ===== 分类父节点:小号标题风格 ===== */
808
- .k-nav-menu > .k-menu-item-root > .k-menu-item-content {
809
- font-size: 11px;
810
- font-weight: 600;
811
- color: var(--kine-color-text-muted);
812
- text-transform: uppercase;
813
- letter-spacing: 0.8px;
814
- padding: 14px 16px 6px;
815
- border-left: none;
1132
+ .k-input-disabled {
1133
+ opacity: var(--kine-opacity-muted);
1134
+ cursor: not-allowed;
1135
+ pointer-events: none;
816
1136
  }
817
1137
 
818
- .k-nav-menu > .k-menu-item-root > .k-menu-item-content:hover {
819
- background: transparent;
820
- color: var(--kine-color-text-secondary);
1138
+ .k-input-readonly {
1139
+ cursor: default;
821
1140
  }
822
1141
 
823
- /* 分类节点不显示 active 样式 */
824
- .k-nav-menu > .k-menu-item-root.k-menu-item-active > .k-menu-item-content {
825
- color: var(--kine-color-text-muted);
826
- background: transparent;
827
- border-left: none;
828
- padding-left: 16px;
1142
+ /* === size variants === */
1143
+ .k-input-large {
1144
+ height: var(--kine-control-height-lg);
1145
+ font-size: var(--kine-control-font-size-lg);
1146
+ padding: 0 var(--kine-control-padding-x-lg);
829
1147
  }
830
1148
 
831
- /* ===== 子节点(组件条目)===== */
832
- .k-nav-menu .k-menu-item-children {
833
- padding-left: 0;
834
- border-left: none;
835
- margin-left: 0;
1149
+ .k-input-medium {
1150
+ height: var(--kine-control-height-md);
1151
+ font-size: var(--kine-control-font-size-md);
1152
+ padding: 0 var(--kine-control-padding-x-md);
836
1153
  }
837
1154
 
838
- .k-nav-menu .k-menu-item-children .k-menu-item-content {
839
- padding: 11px 18px 11px 26px;
840
- font-size: 15px;
1155
+ .k-input-small {
1156
+ height: var(--kine-control-height-sm);
1157
+ font-size: var(--kine-control-font-size-sm);
1158
+ padding: 0 var(--kine-control-padding-x-sm);
841
1159
  }
842
1160
 
843
- /* ===== active 叶子节点 ===== */
844
- .k-nav-menu .k-menu-item-children .k-menu-item-active > .k-menu-item-content {
845
- background: color-mix(in srgb, var(--kine-color-accent-default) 12%, transparent);
846
- color: var(--kine-color-accent-default);
847
- font-weight: 500;
848
- border-left: 2px solid var(--kine-color-accent-default);
849
- padding-left: 22px; /* 24 - 2(border) */
1161
+ /* === word limit === */
1162
+ .k-input-word-limit {
1163
+ position: absolute;
1164
+ right: var(--kine-spacing-4);
1165
+ top: 50%;
1166
+ transform: translateY(-50%);
1167
+ font-family: var(--kine-font-family-mono);
1168
+ font-size: var(--kine-font-size-xs);
1169
+ color: var(--kine-color-text-muted);
1170
+ pointer-events: none;
850
1171
  }
851
1172
 
852
- .k-nav-menu .k-menu-item-children .k-menu-item-active > .k-menu-item-content:hover {
853
- background: color-mix(in srgb, var(--kine-color-accent-default) 18%, transparent);
1173
+ .k-input-wrapper {
1174
+ position: relative;
1175
+ display: inline-block;
1176
+ width: 100%;
854
1177
  }
855
1178
 
856
- /* ===== 展开箭头 ===== */
857
- .k-nav-menu .k-menu-item-arrow {
858
- flex-shrink: 0;
859
- width: 0;
860
- height: 0;
861
- border-top: 3px solid transparent;
862
- border-bottom: 3px solid transparent;
863
- border-left: 4px solid currentColor;
864
- opacity: 0.5;
865
- transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1179
+ textarea.k-input {
1180
+ height: auto;
1181
+ padding: var(--kine-spacing-4) var(--kine-control-padding-x-md);
1182
+ resize: vertical;
1183
+ min-height: 80px;
866
1184
  }
1185
+ /**
1186
+ * @description kine-ui select 样式 — Phosphor 主题
1187
+ * @author 阿怪
1188
+ * @date 2026/2/26
1189
+ * @version v1.0.0
1190
+ *
1191
+ * 江湖的业务千篇一律,复杂的代码好几百行。
1192
+ */
867
1193
 
868
- .k-nav-menu .k-menu-item-arrow-expand {
869
- transform: rotate(90deg);
1194
+ /* ===== 容器 ===== */
1195
+ .k-select {
1196
+ position: relative;
1197
+ display: inline-block;
1198
+ width: 100%;
1199
+ box-sizing: border-box;
870
1200
  }
871
1201
 
872
- /* ===== 禁用状态 ===== */
873
- .k-nav-menu .k-menu-item-disabled {
874
- opacity: 0.4;
1202
+ .k-select-disabled {
1203
+ opacity: var(--kine-opacity-muted);
875
1204
  cursor: not-allowed;
876
1205
  pointer-events: none;
877
1206
  }
878
1207
 
879
- /* ===== 折叠状态:只显示图标 ===== */
880
- .k-crud-sider--collapsed .k-nav-menu-label {
881
- display: none;
1208
+ /* ===== Trigger ===== */
1209
+ .k-select-trigger {
1210
+ display: flex;
1211
+ align-items: center;
1212
+ height: var(--kine-control-height-md);
1213
+ padding: 0 var(--kine-control-padding-x-md);
1214
+ box-sizing: border-box;
1215
+ background-color: var(--kine-control-bg);
1216
+ border: 1px solid var(--kine-control-border-color);
1217
+ border-radius: var(--kine-control-radius);
1218
+ cursor: pointer;
1219
+ transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1220
+ box-shadow var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
882
1221
  }
883
1222
 
884
- .k-crud-sider--collapsed .k-nav-menu .k-menu-item-content {
885
- justify-content: center;
886
- padding: 12px 0;
887
- border-left: none;
888
- gap: 0;
1223
+ .k-select-trigger:focus-within {
1224
+ border-color: var(--kine-color-accent-default);
1225
+ box-shadow: 0 0 var(--kine-shadow-glow-radius) color-mix(in srgb, var(--kine-color-accent-default) 30%, transparent);
889
1226
  }
890
1227
 
891
- .k-crud-sider--collapsed .k-nav-menu-icon {
892
- font-size: 20px;
893
- width: 64px;
1228
+ .k-select-trigger-multiple {
1229
+ flex-wrap: wrap;
1230
+ height: auto;
1231
+ min-height: var(--kine-control-height-md);
1232
+ gap: var(--kine-spacing-2);
1233
+ padding: var(--kine-spacing-2) var(--kine-control-padding-x-md);
1234
+ }
1235
+
1236
+ /* ===== Input ===== */
1237
+ .k-select-input {
1238
+ flex: 1;
1239
+ min-width: 60px;
1240
+ border: none;
1241
+ outline: none;
1242
+ background: transparent;
1243
+ font-family: var(--kine-font-family-mono);
1244
+ font-size: var(--kine-control-font-size-md);
1245
+ color: var(--kine-color-text-primary);
1246
+ cursor: pointer;
1247
+ padding: 0;
1248
+ }
1249
+
1250
+ .k-select-input::placeholder {
1251
+ color: var(--kine-color-text-muted);
1252
+ }
1253
+
1254
+ .k-select-input[readonly] {
1255
+ cursor: pointer;
1256
+ }
1257
+
1258
+ /* ===== Tags (多选) ===== */
1259
+ .k-select-tags {
894
1260
  display: flex;
1261
+ flex-wrap: wrap;
1262
+ gap: var(--kine-spacing-2);
895
1263
  align-items: center;
896
- justify-content: center;
897
1264
  }
898
1265
 
899
- /* 折叠时根节点也用统一的居中样式(覆盖分类标题的特殊样式) */
900
- .k-crud-sider--collapsed .k-nav-menu > .k-menu-item-root > .k-menu-item-content {
901
- font-size: inherit;
902
- font-weight: normal;
903
- text-transform: none;
904
- letter-spacing: normal;
905
- padding: 12px 0;
906
- justify-content: center;
907
- color: var(--kine-color-text-secondary);
908
- border-left: none;
1266
+ .k-select-tag {
1267
+ display: inline-flex;
1268
+ align-items: center;
1269
+ gap: var(--kine-spacing-2);
1270
+ padding: var(--kine-spacing-1) 7px;
1271
+ background-color: var(--kine-color-bg-tertiary);
1272
+ border: 1px solid var(--kine-color-border-default);
1273
+ border-radius: var(--kine-radius-xs);
1274
+ font-family: var(--kine-font-family-mono);
1275
+ font-size: var(--kine-font-size-xs);
1276
+ color: var(--kine-color-text-primary);
1277
+ user-select: none;
1278
+ transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
909
1279
  }
910
1280
 
911
- /* 折叠时隐藏展开箭头 */
912
- .k-crud-sider--collapsed .k-menu-item-arrow {
913
- display: none;
1281
+ .k-select-tag:hover {
1282
+ border-color: var(--kine-color-text-secondary);
914
1283
  }
915
1284
 
916
- /* 折叠时子菜单也对齐 */
917
- .k-crud-sider--collapsed .k-nav-menu .k-menu-item-children .k-menu-item-content {
918
- padding: 12px 0;
1285
+ .k-select-tag-text {
1286
+ line-height: 1;
1287
+ }
1288
+
1289
+ .k-select-tag-close {
1290
+ display: inline-flex;
1291
+ align-items: center;
919
1292
  justify-content: center;
1293
+ color: var(--kine-color-text-muted);
1294
+ font-size: var(--kine-font-size-sm);
1295
+ line-height: 1;
1296
+ cursor: pointer;
1297
+ transition: color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
920
1298
  }
921
1299
 
922
- /* 折叠时子菜单列表无缩进 */
923
- .k-crud-sider--collapsed .k-nav-menu .k-menu-item-children {
924
- padding-left: 0;
1300
+ .k-select-tag-close:hover {
1301
+ color: var(--kine-color-text-primary);
925
1302
  }
926
1303
 
927
- /* 折叠时 active 样式调整 */
928
- .k-crud-sider--collapsed .k-nav-menu .k-menu-item-children .k-menu-item-active > .k-menu-item-content {
929
- border-left: none;
930
- padding-left: 0;
931
- border-radius: 6px;
932
- margin: 0 8px;
1304
+ /* ===== Dropdown ===== */
1305
+ .k-select-dropdown {
1306
+ background-color: var(--kine-color-bg-secondary);
1307
+ border: 1px solid var(--kine-color-border-default);
1308
+ border-radius: var(--kine-radius-sm);
1309
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
1310
+ overflow: hidden;
1311
+ animation: k-select-dropdown-in var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
933
1312
  }
934
1313
 
935
- /* 折叠时 label 区域也隐藏 */
936
- .k-crud-sider--collapsed .k-menu-item-label {
937
- display: none;
1314
+ @keyframes k-select-dropdown-in {
1315
+ from {
1316
+ opacity: 0;
1317
+ transform: translateY(-4px);
1318
+ }
1319
+ to {
1320
+ opacity: 1;
1321
+ transform: translateY(0);
1322
+ }
938
1323
  }
939
1324
 
940
- /* ===== label 溢出省略 ===== */
941
- .k-nav-menu .k-menu-item-label {
942
- flex: 1;
943
- white-space: nowrap;
944
- overflow: hidden;
945
- text-overflow: ellipsis;
946
- display: flex;
947
- align-items: center;
948
- gap: 8px;
1325
+ /* ===== Options ===== */
1326
+ .k-select-options {
1327
+ max-height: 240px;
1328
+ overflow-y: auto;
1329
+ padding: var(--kine-spacing-2) 0;
949
1330
  }
950
1331
 
951
- /* ===== icon ===== */
952
- .k-nav-menu-icon {
953
- flex-shrink: 0;
954
- font-size: 18px;
955
- width: 22px;
1332
+ /* 复写 headless .m-option 基础样式 */
1333
+ .k-select-dropdown .m-option {
1334
+ padding: var(--kine-spacing-3) var(--kine-spacing-6);
1335
+ font-family: var(--kine-font-family-mono);
1336
+ font-size: var(--kine-font-size-sm);
1337
+ color: var(--kine-color-text-primary);
1338
+ cursor: pointer;
1339
+ transition: background-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1340
+ }
1341
+
1342
+ .k-select-dropdown .m-option:hover {
1343
+ background-color: var(--kine-color-bg-hover);
1344
+ }
1345
+
1346
+ .k-select-dropdown .m-option-selected {
1347
+ color: var(--kine-color-accent-default);
1348
+ background-color: color-mix(in srgb, var(--kine-color-accent-default) 10%, transparent);
1349
+ }
1350
+
1351
+ .k-select-dropdown .m-option-selected:hover {
1352
+ background-color: color-mix(in srgb, var(--kine-color-accent-default) 16%, transparent);
1353
+ }
1354
+
1355
+ .k-select-dropdown .m-option-disabled {
1356
+ opacity: var(--kine-opacity-muted);
1357
+ cursor: not-allowed;
1358
+ pointer-events: none;
1359
+ }
1360
+
1361
+ /* ===== Empty & Loading ===== */
1362
+ .k-select-empty,
1363
+ .k-select-loading {
1364
+ padding: var(--kine-spacing-6);
956
1365
  text-align: center;
1366
+ font-family: var(--kine-font-family-mono);
1367
+ font-size: var(--kine-font-size-sm);
1368
+ color: var(--kine-color-text-muted);
957
1369
  }
958
1370
 
959
- .k-nav-menu-label {
960
- white-space: nowrap;
961
- overflow: hidden;
962
- text-overflow: ellipsis;
1371
+ /* === size variants === */
1372
+ .k-select-large .k-select-trigger {
1373
+ height: var(--kine-control-height-lg);
1374
+ font-size: var(--kine-control-font-size-lg);
1375
+ padding: 0 var(--kine-control-padding-x-lg);
1376
+ }
1377
+
1378
+ .k-select-medium .k-select-trigger {
1379
+ height: var(--kine-control-height-md);
1380
+ font-size: var(--kine-control-font-size-md);
1381
+ padding: 0 var(--kine-control-padding-x-md);
1382
+ }
1383
+
1384
+ .k-select-small .k-select-trigger {
1385
+ height: var(--kine-control-height-sm);
1386
+ font-size: var(--kine-control-font-size-sm);
1387
+ padding: 0 var(--kine-control-padding-x-sm);
1388
+ }
1389
+
1390
+ .k-select-small .k-select-input {
1391
+ font-size: var(--kine-control-font-size-sm);
1392
+ }
1393
+
1394
+ .k-select-large .k-select-input {
1395
+ font-size: var(--kine-control-font-size-lg);
1396
+ }
1397
+
1398
+ /* === Clear button === */
1399
+ .k-select-clear {
1400
+ flex-shrink: 0;
1401
+ cursor: pointer;
1402
+ color: var(--kine-color-text-muted);
1403
+ font-size: var(--kine-font-size-sm);
1404
+ transition: color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1405
+ }
1406
+
1407
+ .k-select-clear:hover {
1408
+ color: var(--kine-color-text-primary);
1409
+ }
1410
+
1411
+ /* === Loading icon in trigger === */
1412
+ .k-select-loading-icon {
1413
+ flex-shrink: 0;
1414
+ width: 14px;
1415
+ height: 14px;
1416
+ border: 2px solid var(--kine-color-text-muted);
1417
+ border-top-color: transparent;
1418
+ border-radius: 50%;
1419
+ animation: k-select-spin 0.6s linear infinite;
1420
+ }
1421
+
1422
+ @keyframes k-select-spin {
1423
+ to { transform: rotate(360deg); }
1424
+ }
1425
+
1426
+ .k-select-loading-state .k-select-trigger {
1427
+ pointer-events: none;
1428
+ opacity: var(--kine-opacity-muted);
963
1429
  }
964
1430
  /**
965
- * @description 上传组件样式 — Phosphor sci-fi 暗色主题
1431
+ * @description KPageHeader 页面头部样式 — Phosphor 主题
966
1432
  * @author 阿怪
967
1433
  * @date 2026/2/26
968
- * @version v0.0.1
1434
+ * @version v0.0.2
969
1435
  */
970
1436
 
971
- /* ── 隐藏原生 input ── */
972
- .k-upload-input {
973
- display: none;
1437
+ /* ===== 容器 ===== */
1438
+ .k-page-header {
1439
+ display: flex;
1440
+ flex-direction: column;
1441
+ width: 100%;
1442
+ box-sizing: border-box;
1443
+ padding: var(--kine-spacing-8) 0 var(--kine-spacing-6);
1444
+ border-bottom: 1px solid var(--kine-color-border-default);
1445
+ background-color: transparent;
1446
+ margin-bottom: var(--kine-spacing-8);
974
1447
  }
975
1448
 
976
- /* ══════════════════════════════════════════
977
- KUpload — 基础上传区域
978
- ══════════════════════════════════════════ */
1449
+ /* ===== 面包屑区域 ===== */
1450
+ .k-page-header-breadcrumb {
1451
+ margin-bottom: var(--kine-spacing-4);
1452
+ font-size: var(--kine-font-size-lg);
1453
+ color: var(--kine-color-text-muted);
1454
+ font-family: var(--kine-font-family-system);
1455
+ min-height: 20px;
1456
+ }
979
1457
 
980
- .k-upload {
981
- position: relative;
982
- display: inline-flex;
1458
+ /* ===== 主行:标题 + 操作 ===== */
1459
+ .k-page-header-main {
1460
+ display: flex;
1461
+ flex-direction: row;
983
1462
  align-items: center;
984
- justify-content: center;
985
- width: 100%;
986
- min-height: 80px;
987
- border-radius: var(--kine-radius-sm);
988
- background: var(--kine-color-bg-secondary);
989
- cursor: pointer;
990
- transition:
991
- border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
992
- background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
993
- box-sizing: border-box;
1463
+ justify-content: space-between;
1464
+ gap: var(--kine-spacing-8);
1465
+ min-height: 32px;
994
1466
  }
995
1467
 
996
- /* 拖拽模式:虚线边框 */
997
- .k-upload-drag {
998
- border: 1px dashed var(--kine-color-border-default);
1468
+ /* ===== 左侧:返回 + 标题区 ===== */
1469
+ .k-page-header-left {
1470
+ display: flex;
1471
+ flex-direction: row;
1472
+ align-items: center;
1473
+ gap: var(--kine-spacing-4);
1474
+ min-width: 0;
1475
+ flex: 1;
999
1476
  }
1000
1477
 
1001
- .k-upload-drag:hover {
1002
- border-color: var(--kine-color-accent-default);
1003
- background: color-mix(in srgb, var(--kine-color-accent-default) 6%, var(--kine-color-bg-secondary));
1478
+ /* 标题文字区 */
1479
+ .k-page-header-heading {
1480
+ display: flex;
1481
+ flex-direction: column;
1482
+ min-width: 0;
1004
1483
  }
1005
1484
 
1006
- /* 拖拽悬停态 */
1007
- .k-upload-drag-over {
1008
- border-color: var(--kine-color-accent-default) !important;
1009
- background: color-mix(in srgb, var(--kine-color-accent-default) 10%, var(--kine-color-bg-secondary)) !important;
1010
- box-shadow: inset 0 0 0 1px var(--kine-color-accent-default);
1485
+ /* 主标题 */
1486
+ .k-page-header-title {
1487
+ font-size: 18px; /* 18px 无对应 token,保留 */
1488
+ font-weight: var(--kine-font-weight-semibold);
1489
+ color: var(--kine-color-text-primary);
1490
+ margin: 0;
1491
+ line-height: 1.4;
1492
+ white-space: nowrap;
1493
+ overflow: hidden;
1494
+ text-overflow: ellipsis;
1495
+ font-family: var(--kine-font-family-system);
1496
+ }
1497
+
1498
+ /* 副标题 */
1499
+ .k-page-header-subtitle {
1500
+ font-size: var(--kine-font-size-lg);
1501
+ color: var(--kine-color-text-muted);
1502
+ margin: var(--kine-spacing-1) 0 0;
1503
+ line-height: 1.4;
1504
+ white-space: nowrap;
1505
+ overflow: hidden;
1506
+ text-overflow: ellipsis;
1507
+ font-family: var(--kine-font-family-system);
1508
+ }
1509
+
1510
+ /* ===== 右侧操作区 ===== */
1511
+ .k-page-header-extra {
1512
+ display: flex;
1513
+ flex-direction: row;
1514
+ align-items: center;
1515
+ flex-shrink: 0;
1516
+ gap: var(--kine-spacing-4);
1517
+ }
1518
+
1519
+ /* ===== 标题下方内容插槽 ===== */
1520
+ .k-page-header-content {
1521
+ margin-top: var(--kine-spacing-6);
1522
+ }
1523
+ /**
1524
+ * @description KCrudPage 样式
1525
+ * @author 阿怪
1526
+ * @date 2026/3/22
1527
+ * @version v0.0.1
1528
+ */
1529
+
1530
+ /* ===== 根容器 ===== */
1531
+ .k-crud-page {
1532
+ display: flex;
1533
+ flex-direction: column;
1534
+ height: 100%;
1535
+ gap: var(--kine-spacing-6);
1536
+ padding: var(--kine-spacing-8);
1537
+ box-sizing: border-box;
1538
+ }
1539
+
1540
+ /* ===== 筛选项 ===== */
1541
+ .k-crud-page-filter-item {
1542
+ display: flex;
1543
+ flex-direction: column;
1544
+ gap: var(--kine-spacing-2);
1545
+ min-width: 140px;
1546
+ }
1547
+
1548
+ .k-crud-page-filter-label {
1549
+ font-size: var(--kine-font-size-sm);
1550
+ color: var(--kine-color-text-secondary);
1551
+ line-height: 1;
1552
+ }
1553
+
1554
+ /* KInput / KSelect 筛选控件宽度适配 */
1555
+ .k-crud-page-filter-control {
1556
+ width: 100%;
1557
+ }
1558
+
1559
+ /* ===== 列表图片 ===== */
1560
+ .k-crud-page .k-image-placeholder {
1561
+ min-width: unset;
1562
+ min-height: unset;
1563
+ }
1564
+
1565
+ .k-image-empty {
1566
+ color: var(--kine-color-text-muted);
1567
+ opacity: 0.4;
1568
+ }
1569
+
1570
+ /* ================================================================
1571
+ 移动端(<768px)
1572
+ ================================================================ */
1573
+
1574
+ @media (max-width: 767px) {
1575
+ .k-crud-page {
1576
+ padding: var(--kine-spacing-4);
1577
+ gap: var(--kine-spacing-4);
1578
+ }
1579
+
1580
+ /* 筛选项自动换行,撑满宽度 */
1581
+ .k-crud-page-filter-item {
1582
+ min-width: 0;
1583
+ flex: 1 1 100%;
1584
+ }
1585
+ }
1586
+
1587
+ /**
1588
+ * @description KLoginPage 登录页样式 — Phosphor 主题
1589
+ * @author 阿怪
1590
+ * @date 2026/2/26
1591
+ * @version v0.0.2
1592
+ */
1593
+
1594
+ /* ===== 全屏容器 ===== */
1595
+ .k-login-page {
1596
+ display: flex;
1597
+ flex-direction: column;
1598
+ align-items: center;
1599
+ justify-content: center;
1600
+ min-height: 100vh;
1601
+ width: 100%;
1602
+ box-sizing: border-box;
1603
+ padding: var(--kine-spacing-12);
1604
+ background-color: var(--kine-color-bg-secondary);
1605
+ }
1606
+
1607
+ /* ===== 登录卡片 ===== */
1608
+ .k-login-card {
1609
+ width: 100%;
1610
+ max-width: 400px;
1611
+ background-color: var(--kine-color-bg-primary);
1612
+ border-radius: var(--kine-radius-md);
1613
+ border: 1px solid var(--kine-color-border-default);
1614
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
1615
+ padding: var(--kine-spacing-20) 36px var(--kine-spacing-16);
1616
+ box-sizing: border-box;
1617
+ }
1618
+
1619
+ @media (max-width: 480px) {
1620
+ .k-login-card {
1621
+ padding: var(--kine-spacing-16) var(--kine-spacing-10) var(--kine-spacing-12);
1622
+ box-shadow: none;
1623
+ border-radius: 0;
1624
+ max-width: 100%;
1625
+ }
1626
+ }
1627
+
1628
+ /* ===== Logo 区域 ===== */
1629
+ .k-login-logo {
1630
+ display: flex;
1631
+ justify-content: center;
1632
+ margin-bottom: var(--kine-spacing-8);
1633
+ }
1634
+
1635
+ /* ===== 标题 ===== */
1636
+ .k-login-title {
1637
+ text-align: center;
1638
+ font-size: 22px; /* 22px 无精确 token,保留 */
1639
+ font-weight: var(--kine-font-weight-semibold);
1640
+ color: var(--kine-color-text-primary);
1641
+ margin: 0 0 var(--kine-spacing-14);
1642
+ line-height: 1.4;
1643
+ font-family: var(--kine-font-family-system);
1644
+ }
1645
+
1646
+ /* ===== 表单 ===== */
1647
+ .k-login-form {
1648
+ display: flex;
1649
+ flex-direction: column;
1650
+ gap: var(--kine-spacing-8);
1651
+ }
1652
+
1653
+ /* 表单项 */
1654
+ .k-login-form-item {
1655
+ display: flex;
1656
+ flex-direction: column;
1657
+ gap: var(--kine-spacing-3);
1658
+ }
1659
+
1660
+ .k-login-form-item label {
1661
+ font-size: var(--kine-font-size-lg);
1662
+ color: var(--kine-color-text-secondary);
1663
+ font-weight: var(--kine-font-weight-medium);
1664
+ font-family: var(--kine-font-family-system);
1665
+ }
1666
+
1667
+ /* KInput 宽度撑满表单项 */
1668
+ .k-login-form-item .k-input {
1669
+ width: 100%;
1670
+ }
1671
+
1672
+ /* 记住我行 */
1673
+ .k-login-remember {
1674
+ display: flex;
1675
+ align-items: center;
1676
+ gap: var(--kine-spacing-4);
1677
+ font-size: var(--kine-font-size-lg);
1678
+ color: var(--kine-color-text-secondary);
1679
+ cursor: pointer;
1680
+ user-select: none;
1681
+ font-family: var(--kine-font-family-system);
1682
+ }
1683
+
1684
+ .k-login-remember input[type='checkbox'] {
1685
+ width: 15px;
1686
+ height: 15px;
1687
+ cursor: pointer;
1688
+ accent-color: var(--kine-color-accent-default);
1689
+ }
1690
+
1691
+ /* ===== 额外登录方式区域 ===== */
1692
+ .k-login-extra {
1693
+ margin-top: var(--kine-spacing-10);
1694
+ text-align: center;
1695
+ }
1696
+
1697
+ /* ===== 底部版权区域 ===== */
1698
+ .k-login-footer {
1699
+ margin-top: var(--kine-spacing-16);
1700
+ text-align: center;
1701
+ font-size: var(--kine-font-size-md);
1702
+ color: var(--kine-color-text-muted);
1703
+ font-family: var(--kine-font-family-system);
1704
+ }
1705
+ /**
1706
+ * @description KNavMenu 导航菜单样式 — Phosphor 主题
1707
+ * @author 阿怪
1708
+ * @date 2026/2/26
1709
+ * @version v1.0.0
1710
+ */
1711
+
1712
+ /* ===== 容器:撑满侧边栏,去掉 KMenu 默认边框 ===== */
1713
+ .k-nav-menu {
1714
+ display: flex;
1715
+ flex-direction: column;
1716
+ width: 100%;
1717
+ padding: var(--kine-spacing-2) 0;
1718
+ }
1719
+
1720
+ /* 根级 li:无缩进 */
1721
+ .k-nav-menu > .k-menu-item-root {
1722
+ list-style: none;
1723
+ }
1724
+
1725
+ /* ===== 内容行通用 ===== */
1726
+ .k-nav-menu .k-menu-item-content {
1727
+ display: flex;
1728
+ align-items: center;
1729
+ gap: var(--kine-spacing-5);
1730
+ padding: 11px 18px; /* 11px/18px 无精确 token,保留 */
1731
+ color: var(--kine-color-text-secondary);
1732
+ font-size: 15px; /* 15px 无精确 token,保留 */
1733
+ cursor: pointer;
1734
+ transition:
1735
+ background var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1736
+ color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1737
+ border-left: 2px solid transparent;
1738
+ }
1739
+
1740
+ .k-nav-menu .k-menu-item-content:hover {
1741
+ background: var(--kine-color-bg-hover);
1742
+ color: var(--kine-color-text-primary);
1743
+ }
1744
+
1745
+ /* ===== 分类父节点:小号标题风格 ===== */
1746
+ .k-nav-menu > .k-menu-item-root > .k-menu-item-content {
1747
+ font-size: var(--kine-font-size-sm);
1748
+ font-weight: var(--kine-font-weight-semibold);
1749
+ color: var(--kine-color-text-muted);
1750
+ text-transform: uppercase;
1751
+ letter-spacing: 0.8px;
1752
+ padding: var(--kine-spacing-7) var(--kine-spacing-8) var(--kine-spacing-3);
1753
+ border-left: none;
1754
+ }
1755
+
1756
+ .k-nav-menu > .k-menu-item-root > .k-menu-item-content:hover {
1757
+ background: transparent;
1758
+ color: var(--kine-color-text-secondary);
1759
+ }
1760
+
1761
+ /* 分类节点不显示 active 样式 */
1762
+ .k-nav-menu > .k-menu-item-root.k-menu-item-active > .k-menu-item-content {
1763
+ color: var(--kine-color-text-muted);
1764
+ background: transparent;
1765
+ border-left: none;
1766
+ padding-left: var(--kine-spacing-8);
1767
+ }
1768
+
1769
+ /* ===== 子节点(组件条目)===== */
1770
+ .k-nav-menu .k-menu-item-children {
1771
+ padding-left: 0;
1772
+ border-left: none;
1773
+ margin-left: 0;
1774
+ }
1775
+
1776
+ .k-nav-menu .k-menu-item-children .k-menu-item-content {
1777
+ padding: 11px 18px 11px 26px; /* 11px/18px/26px 无精确 token,保留 */
1778
+ font-size: 15px; /* 15px 无精确 token,保留 */
1779
+ }
1780
+
1781
+ /* ===== active 叶子节点 ===== */
1782
+ .k-nav-menu .k-menu-item-children .k-menu-item-active > .k-menu-item-content {
1783
+ background: color-mix(in srgb, var(--kine-color-accent-default) 12%, transparent);
1784
+ color: var(--kine-color-accent-default);
1785
+ font-weight: var(--kine-font-weight-medium);
1786
+ border-left: 2px solid var(--kine-color-accent-default);
1787
+ padding-left: 22px; /* 24 - 2(border) */
1788
+ }
1789
+
1790
+ .k-nav-menu .k-menu-item-children .k-menu-item-active > .k-menu-item-content:hover {
1791
+ background: color-mix(in srgb, var(--kine-color-accent-default) 18%, transparent);
1792
+ }
1793
+
1794
+ /* ===== 展开箭头 ===== */
1795
+ .k-nav-menu .k-menu-item-arrow {
1796
+ flex-shrink: 0;
1797
+ width: 0;
1798
+ height: 0;
1799
+ border-top: 3px solid transparent;
1800
+ border-bottom: 3px solid transparent;
1801
+ border-left: 4px solid currentColor;
1802
+ opacity: 0.5;
1803
+ transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1804
+ }
1805
+
1806
+ .k-nav-menu .k-menu-item-arrow-expand {
1807
+ transform: rotate(90deg);
1808
+ }
1809
+
1810
+ /* ===== 禁用状态 ===== */
1811
+ .k-nav-menu .k-menu-item-disabled {
1812
+ opacity: 0.4;
1813
+ cursor: not-allowed;
1814
+ pointer-events: none;
1815
+ }
1816
+
1817
+ /* ===== 折叠状态:只显示图标 ===== */
1818
+ .k-crud-sider--collapsed .k-nav-menu-label {
1819
+ display: none;
1820
+ }
1821
+
1822
+ .k-crud-sider--collapsed .k-nav-menu .k-menu-item-content {
1823
+ justify-content: center;
1824
+ padding: var(--kine-spacing-6) 0;
1825
+ border-left: none;
1826
+ gap: 0;
1827
+ }
1828
+
1829
+ .k-crud-sider--collapsed .k-nav-menu-icon {
1830
+ font-size: var(--kine-font-size-3xl);
1831
+ width: 64px;
1832
+ display: flex;
1833
+ align-items: center;
1834
+ justify-content: center;
1835
+ }
1836
+
1837
+ /* 折叠时根节点也用统一的居中样式(覆盖分类标题的特殊样式) */
1838
+ .k-crud-sider--collapsed .k-nav-menu > .k-menu-item-root > .k-menu-item-content {
1839
+ font-size: inherit;
1840
+ font-weight: normal;
1841
+ text-transform: none;
1842
+ letter-spacing: normal;
1843
+ padding: var(--kine-spacing-6) 0;
1844
+ justify-content: center;
1845
+ color: var(--kine-color-text-secondary);
1846
+ border-left: none;
1847
+ }
1848
+
1849
+ /* 折叠时隐藏展开箭头 */
1850
+ .k-crud-sider--collapsed .k-menu-item-arrow {
1851
+ display: none;
1852
+ }
1853
+
1854
+ /* 折叠时子菜单也对齐 */
1855
+ .k-crud-sider--collapsed .k-nav-menu .k-menu-item-children .k-menu-item-content {
1856
+ padding: var(--kine-spacing-6) 0;
1857
+ justify-content: center;
1858
+ }
1859
+
1860
+ /* 折叠时子菜单列表无缩进 */
1861
+ .k-crud-sider--collapsed .k-nav-menu .k-menu-item-children {
1862
+ padding-left: 0;
1863
+ }
1864
+
1865
+ /* 折叠时 active 样式调整 */
1866
+ .k-crud-sider--collapsed .k-nav-menu .k-menu-item-children .k-menu-item-active > .k-menu-item-content {
1867
+ border-left: none;
1868
+ padding-left: 0;
1869
+ border-radius: var(--kine-radius-sm);
1870
+ margin: 0 var(--kine-spacing-4);
1871
+ }
1872
+
1873
+ /* 折叠时 label 区域也隐藏 */
1874
+ .k-crud-sider--collapsed .k-menu-item-label {
1875
+ display: none;
1876
+ }
1877
+
1878
+ /* ===== label 溢出省略 ===== */
1879
+ .k-nav-menu .k-menu-item-label {
1880
+ flex: 1;
1881
+ white-space: nowrap;
1882
+ overflow: hidden;
1883
+ text-overflow: ellipsis;
1884
+ display: flex;
1885
+ align-items: center;
1886
+ gap: var(--kine-spacing-4);
1887
+ }
1888
+
1889
+ /* ===== icon ===== */
1890
+ .k-nav-menu-icon {
1891
+ flex-shrink: 0;
1892
+ font-size: 18px; /* 18px 无对应 token,保留 */
1893
+ width: 22px;
1894
+ text-align: center;
1895
+ }
1896
+
1897
+ .k-nav-menu-label {
1898
+ white-space: nowrap;
1899
+ overflow: hidden;
1900
+ text-overflow: ellipsis;
1901
+ }
1902
+ /**
1903
+ * @description 上传组件样式 — Phosphor sci-fi 暗色主题
1904
+ * @author 阿怪
1905
+ * @date 2026/2/26
1906
+ * @version v0.0.1
1907
+ */
1908
+
1909
+ /* ── 隐藏原生 input ── */
1910
+ .k-upload-input {
1911
+ display: none;
1912
+ }
1913
+
1914
+ /* ══════════════════════════════════════════
1915
+ KUpload — 基础上传区域
1916
+ ══════════════════════════════════════════ */
1917
+
1918
+ .k-upload {
1919
+ position: relative;
1920
+ display: inline-flex;
1921
+ align-items: center;
1922
+ justify-content: center;
1923
+ width: 100%;
1924
+ min-height: 80px;
1925
+ border-radius: var(--kine-radius-sm);
1926
+ background: var(--kine-color-bg-secondary);
1927
+ cursor: pointer;
1928
+ transition:
1929
+ border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1930
+ background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1931
+ box-sizing: border-box;
1932
+ }
1933
+
1934
+ /* 拖拽模式:虚线边框 */
1935
+ .k-upload-drag {
1936
+ border: 1px dashed var(--kine-color-border-default);
1937
+ }
1938
+
1939
+ .k-upload-drag:hover {
1940
+ border-color: var(--kine-color-accent-default);
1941
+ background: color-mix(in srgb, var(--kine-color-accent-default) 6%, var(--kine-color-bg-secondary));
1942
+ }
1943
+
1944
+ /* 拖拽悬停态 */
1945
+ .k-upload-drag-over {
1946
+ border-color: var(--kine-color-accent-default) !important;
1947
+ background: color-mix(in srgb, var(--kine-color-accent-default) 10%, var(--kine-color-bg-secondary)) !important;
1948
+ box-shadow: inset 0 0 0 1px var(--kine-color-accent-default);
1949
+ }
1950
+
1951
+ /* 禁用态 */
1952
+ .k-upload-disabled {
1953
+ opacity: var(--kine-opacity-muted);
1954
+ cursor: not-allowed;
1955
+ pointer-events: none;
1956
+ }
1957
+
1958
+ /* 默认占位内容 */
1959
+ .k-upload-placeholder {
1960
+ display: flex;
1961
+ flex-direction: column;
1962
+ align-items: center;
1963
+ gap: var(--kine-spacing-3);
1964
+ pointer-events: none;
1965
+ }
1966
+
1967
+ .k-upload-icon {
1968
+ font-size: var(--kine-font-size-4xl);
1969
+ color: var(--kine-color-text-secondary);
1970
+ line-height: 1;
1971
+ }
1972
+
1973
+ .k-upload-text {
1974
+ font-family: var(--kine-font-family-mono);
1975
+ font-size: var(--kine-font-size-sm);
1976
+ color: var(--kine-color-text-secondary);
1977
+ }
1978
+
1979
+ /* ══════════════════════════════════════════
1980
+ KImageUpload — 图片网格
1981
+ ══════════════════════════════════════════ */
1982
+
1983
+ .k-image-upload {
1984
+ display: block;
1985
+ }
1986
+
1987
+ .k-image-upload-grid {
1988
+ display: flex;
1989
+ flex-wrap: wrap;
1990
+ gap: var(--kine-spacing-4);
1991
+ }
1992
+
1993
+ /* 图片卡片(预览 + 添加占位共用) */
1994
+ .k-image-upload-card {
1995
+ position: relative;
1996
+ border-radius: var(--kine-radius-sm);
1997
+ overflow: hidden;
1998
+ border: 1px solid var(--kine-color-border-default);
1999
+ background: var(--kine-color-bg-secondary);
2000
+ flex-shrink: 0;
2001
+ box-sizing: border-box;
2002
+ }
2003
+
2004
+ /* 添加卡片 */
2005
+ .k-image-upload-card--add {
2006
+ display: flex;
2007
+ align-items: center;
2008
+ justify-content: center;
2009
+ border-style: dashed;
2010
+ cursor: pointer;
2011
+ transition:
2012
+ border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
2013
+ background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2014
+ }
2015
+
2016
+ .k-image-upload-card--add:hover {
2017
+ border-color: var(--kine-color-accent-default);
2018
+ background: color-mix(in srgb, var(--kine-color-accent-default) 6%, var(--kine-color-bg-secondary));
2019
+ }
2020
+
2021
+ .k-image-upload-add-icon {
2022
+ font-size: 28px; /* 28px 无精确 token,保留 */
2023
+ color: var(--kine-color-text-secondary);
2024
+ line-height: 1;
2025
+ pointer-events: none;
2026
+ }
2027
+
2028
+ /* 错误态卡片边框 */
2029
+ .k-image-upload-card--error {
2030
+ border-color: var(--kine-color-semantic-error);
2031
+ }
2032
+
2033
+ /* 预览图 */
2034
+ .k-image-upload-preview {
2035
+ width: 100%;
2036
+ height: 100%;
2037
+ object-fit: cover;
2038
+ display: block;
2039
+ }
2040
+
2041
+ /* 上传进度覆盖层 */
2042
+ .k-image-upload-overlay {
2043
+ position: absolute;
2044
+ inset: 0;
2045
+ display: flex;
2046
+ flex-direction: column;
2047
+ align-items: center;
2048
+ justify-content: flex-end;
2049
+ background: rgba(0, 0, 0, 0.45);
2050
+ }
2051
+
2052
+ .k-image-upload-overlay--error {
2053
+ justify-content: center;
2054
+ font-family: var(--kine-font-family-mono);
2055
+ font-size: var(--kine-font-size-sm);
2056
+ color: var(--kine-color-semantic-error);
2057
+ }
2058
+
2059
+ .k-image-upload-progress {
2060
+ position: absolute;
2061
+ bottom: 0;
2062
+ left: 0;
2063
+ right: 0;
2064
+ background: var(--kine-color-accent-default);
2065
+ box-shadow: 0 0 var(--kine-shadow-glow-radius) var(--kine-color-accent-default);
2066
+ transition: height var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2067
+ opacity: 0.6;
2068
+ }
2069
+
2070
+ .k-image-upload-percent {
2071
+ position: relative;
2072
+ z-index: 1;
2073
+ font-family: var(--kine-font-family-mono);
2074
+ font-size: var(--kine-font-size-sm);
2075
+ color: #ffffff;
2076
+ padding-bottom: var(--kine-spacing-2);
2077
+ }
2078
+
2079
+ /* 删除按钮(悬停卡片时显示) */
2080
+ .k-image-upload-remove {
2081
+ position: absolute;
2082
+ top: var(--kine-spacing-1);
2083
+ right: var(--kine-spacing-1);
2084
+ width: 20px;
2085
+ height: 20px;
2086
+ display: none;
2087
+ align-items: center;
2088
+ justify-content: center;
2089
+ background: rgba(0, 0, 0, 0.6);
2090
+ border: none;
2091
+ border-radius: var(--kine-radius-xs);
2092
+ color: #ffffff;
2093
+ font-size: var(--kine-font-size-xl);
2094
+ cursor: pointer;
2095
+ line-height: 1;
2096
+ z-index: 10;
2097
+ padding: 0;
2098
+ }
2099
+
2100
+ .k-image-upload-card:hover .k-image-upload-remove {
2101
+ display: flex;
2102
+ }
2103
+
2104
+ .k-image-upload-remove:hover {
2105
+ background: var(--kine-color-semantic-error);
2106
+ }
2107
+
2108
+ /* ══════════════════════════════════════════
2109
+ KFileList — 文件列表
2110
+ ══════════════════════════════════════════ */
2111
+
2112
+ .k-file-list {
2113
+ list-style: none;
2114
+ margin: 0;
2115
+ padding: 0;
2116
+ display: flex;
2117
+ flex-direction: column;
2118
+ gap: var(--kine-spacing-2);
2119
+ width: 100%;
2120
+ }
2121
+
2122
+ .k-file-list-item {
2123
+ display: grid;
2124
+ grid-template-columns: 20px 1fr auto;
2125
+ align-items: center;
2126
+ column-gap: var(--kine-spacing-4);
2127
+ padding: var(--kine-spacing-3) var(--kine-spacing-4);
2128
+ border-radius: var(--kine-radius-xs);
2129
+ background: var(--kine-color-bg-secondary);
2130
+ border: 1px solid var(--kine-color-border-default);
2131
+ font-family: var(--kine-font-family-mono);
2132
+ transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2133
+ position: relative;
2134
+ }
2135
+
2136
+ /* 上传中时需要显示进度条,需要多行 */
2137
+ .k-file-list-item--uploading {
2138
+ grid-template-columns: 20px 1fr auto;
2139
+ grid-template-rows: auto 4px;
2140
+ }
2141
+
2142
+ /* 上传中删除按钮固定在第一行 */
2143
+ .k-file-list-item--uploading .k-file-list-remove {
2144
+ grid-row: 1;
2145
+ grid-column: 3;
2146
+ }
2147
+
2148
+ .k-file-list-item--success {
2149
+ border-color: color-mix(in srgb, var(--kine-color-semantic-success) 30%, var(--kine-color-border-default));
2150
+ }
2151
+
2152
+ .k-file-list-item--error {
2153
+ border-color: color-mix(in srgb, var(--kine-color-semantic-error) 40%, var(--kine-color-border-default));
2154
+ }
2155
+
2156
+ /* 文件图标 */
2157
+ .k-file-list-icon {
2158
+ font-size: var(--kine-font-size-md);
2159
+ text-align: center;
2160
+ flex-shrink: 0;
2161
+ }
2162
+
2163
+ .k-file-list-item--success .k-file-list-icon {
2164
+ color: var(--kine-color-semantic-success);
2165
+ }
2166
+
2167
+ .k-file-list-item--error .k-file-list-icon {
2168
+ color: var(--kine-color-semantic-error);
2169
+ }
2170
+
2171
+ .k-file-list-item--uploading .k-file-list-icon,
2172
+ .k-file-list-item--pending .k-file-list-icon {
2173
+ color: var(--kine-color-text-secondary);
2174
+ }
2175
+
2176
+ /* 文件信息 */
2177
+ .k-file-list-info {
2178
+ display: flex;
2179
+ flex-direction: column;
2180
+ gap: var(--kine-spacing-1);
2181
+ overflow: hidden;
2182
+ }
2183
+
2184
+ .k-file-list-name {
2185
+ font-size: var(--kine-font-size-sm);
2186
+ color: var(--kine-color-text-primary);
2187
+ white-space: nowrap;
2188
+ overflow: hidden;
2189
+ text-overflow: ellipsis;
2190
+ }
2191
+
2192
+ .k-file-list-link {
2193
+ color: var(--kine-color-accent-default);
2194
+ text-decoration: none;
2195
+ }
2196
+
2197
+ .k-file-list-link:hover {
2198
+ color: var(--kine-color-accent-hover);
2199
+ text-decoration: underline;
2200
+ }
2201
+
2202
+ .k-file-list-meta {
2203
+ font-size: calc(var(--kine-font-size-sm) - 1px);
2204
+ color: var(--kine-color-text-secondary);
2205
+ }
2206
+
2207
+ /* 进度条(位于第二行,跨满三列) */
2208
+ .k-file-list-progress-track {
2209
+ grid-column: 1 / -1;
2210
+ height: 3px;
2211
+ border-radius: var(--kine-radius-xs);
2212
+ background: var(--kine-color-bg-tertiary);
2213
+ overflow: hidden;
2214
+ margin-top: var(--kine-spacing-1);
2215
+ }
2216
+
2217
+ .k-file-list-progress-fill {
2218
+ height: 100%;
2219
+ border-radius: var(--kine-radius-xs);
2220
+ background: var(--kine-color-accent-default);
2221
+ box-shadow: 0 0 var(--kine-shadow-glow-radius) var(--kine-color-accent-default);
2222
+ transition: width var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2223
+ }
2224
+
2225
+ /* 删除按钮 */
2226
+ .k-file-list-remove {
2227
+ display: flex;
2228
+ align-items: center;
2229
+ justify-content: center;
2230
+ width: 20px;
2231
+ height: 20px;
2232
+ padding: 0;
2233
+ background: transparent;
2234
+ border: none;
2235
+ border-radius: var(--kine-radius-xs);
2236
+ color: var(--kine-color-text-secondary);
2237
+ font-size: var(--kine-font-size-2xl);
2238
+ cursor: pointer;
2239
+ line-height: 1;
2240
+ flex-shrink: 0;
2241
+ transition: color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2242
+ }
2243
+
2244
+ .k-file-list-remove:hover {
2245
+ color: var(--kine-color-semantic-error);
2246
+ }
2247
+ /**
2248
+ * @description KFormCard + KStickyActionBar 样式
2249
+ * @author 阿怪
2250
+ * @date 2026/3/22
2251
+ * @version v0.0.1
2252
+ */
2253
+
2254
+ /* ================================================================
2255
+ KFormCard
2256
+ ================================================================ */
2257
+
2258
+ .k-form-card {
2259
+ background: var(--kine-color-bg-tertiary, #fff);
2260
+ border: 1px solid var(--kine-color-border-default, #e5e7eb);
2261
+ border-radius: var(--kine-radius-md, 8px);
2262
+ margin-bottom: var(--kine-spacing-8);
2263
+ }
2264
+
2265
+ .k-form-card-header {
2266
+ display: flex;
2267
+ align-items: center;
2268
+ justify-content: space-between;
2269
+ padding: var(--kine-spacing-8) var(--kine-spacing-10);
2270
+ gap: var(--kine-spacing-6);
2271
+ user-select: none;
2272
+ }
2273
+
2274
+ .k-form-card-header--clickable {
2275
+ cursor: pointer;
2276
+ }
2277
+
2278
+ .k-form-card-header--clickable:hover {
2279
+ background: var(--kine-color-bg-hover, rgba(0, 0, 0, 0.02));
2280
+ border-radius: var(--kine-radius-md, 8px) var(--kine-radius-md, 8px) 0 0;
2281
+ }
2282
+
2283
+ .k-form-card--collapsed .k-form-card-header--clickable:hover {
2284
+ border-radius: var(--kine-radius-md, 8px);
2285
+ }
2286
+
2287
+ .k-form-card-header-left {
2288
+ display: flex;
2289
+ align-items: baseline;
2290
+ gap: var(--kine-spacing-4);
2291
+ min-width: 0;
2292
+ }
2293
+
2294
+ .k-form-card-title {
2295
+ font-size: var(--kine-font-size-xl);
2296
+ font-weight: var(--kine-font-weight-semibold);
2297
+ color: var(--kine-color-text-primary, #111827);
2298
+ margin: 0;
2299
+ white-space: nowrap;
2300
+ }
2301
+
2302
+ .k-form-card-subtitle {
2303
+ font-size: var(--kine-font-size-md);
2304
+ color: var(--kine-color-text-muted, #9ca3af);
2305
+ }
2306
+
2307
+ .k-form-card-header-right {
2308
+ display: flex;
2309
+ align-items: center;
2310
+ gap: var(--kine-spacing-4);
2311
+ flex-shrink: 0;
2312
+ }
2313
+
2314
+ .k-form-card-collapse-icon {
2315
+ display: inline-flex;
2316
+ align-items: center;
2317
+ font-size: var(--kine-font-size-2xl);
2318
+ color: var(--kine-color-text-muted, #9ca3af);
2319
+ transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2320
+ transform: rotate(-90deg);
2321
+ }
2322
+
2323
+ .k-form-card-collapse-icon--collapsed {
2324
+ transform: rotate(-180deg);
2325
+ }
2326
+
2327
+ .k-form-card-body {
2328
+ padding: var(--kine-spacing-10);
2329
+ }
2330
+
2331
+ /* 有 header 时,body 顶部不需要额外间距(header 自带 padding-bottom) */
2332
+ .k-form-card-header + .k-form-card-body {
2333
+ padding-top: 0;
2334
+ }
2335
+
2336
+ /* ================================================================
2337
+ KStickyActionBar
2338
+ ================================================================ */
2339
+
2340
+ .k-sticky-action-bar {
2341
+ position: sticky;
2342
+ bottom: 0;
2343
+ z-index: 10;
2344
+ display: flex;
2345
+ align-items: center;
2346
+ justify-content: flex-end;
2347
+ padding: var(--kine-spacing-6) var(--kine-spacing-12);
2348
+ background: var(--kine-color-bg-tertiary, #fff);
2349
+ border-top: 1px solid var(--kine-color-border-default, #e5e7eb);
2350
+ backdrop-filter: blur(8px);
2351
+ margin: 0 calc(-1 * var(--kine-spacing-12)) calc(-1 * var(--kine-spacing-10));
2352
+ }
2353
+
2354
+ .k-sticky-action-bar-hint {
2355
+ font-size: var(--kine-font-size-md);
2356
+ color: var(--kine-color-text-muted, #9ca3af);
2357
+ }
2358
+
2359
+ .k-sticky-action-bar-actions {
2360
+ display: flex;
2361
+ align-items: center;
2362
+ gap: var(--kine-spacing-4);
2363
+ }
2364
+
2365
+ /* ================================================================
2366
+ KApprovalDialog
2367
+ ================================================================ */
2368
+
2369
+ .k-approval-overlay {
2370
+ position: fixed;
2371
+ inset: 0;
2372
+ z-index: 1000;
2373
+ display: flex;
2374
+ align-items: center;
2375
+ justify-content: center;
2376
+ background: rgba(0, 0, 0, 0.4);
2377
+ backdrop-filter: blur(2px);
2378
+ }
2379
+
2380
+ .k-approval-dialog {
2381
+ width: 420px;
2382
+ max-width: calc(100vw - 48px);
2383
+ background: var(--kine-color-bg-tertiary, #fff);
2384
+ border-radius: var(--kine-radius-lg, 12px);
2385
+ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06);
2386
+ overflow: hidden;
2387
+ }
2388
+
2389
+ .k-approval-dialog-header {
2390
+ display: flex;
2391
+ align-items: center;
2392
+ justify-content: space-between;
2393
+ padding: var(--kine-spacing-10) var(--kine-spacing-12) 0;
2394
+ }
2395
+
2396
+ .k-approval-dialog-title {
2397
+ font-size: var(--kine-font-size-2xl);
2398
+ font-weight: var(--kine-font-weight-semibold);
2399
+ color: var(--kine-color-text-primary, #111827);
2400
+ }
2401
+
2402
+ .k-approval-dialog-close {
2403
+ display: flex;
2404
+ align-items: center;
2405
+ justify-content: center;
2406
+ width: 28px;
2407
+ height: 28px;
2408
+ border: none;
2409
+ border-radius: var(--kine-radius-sm, 6px);
2410
+ background: transparent;
2411
+ color: var(--kine-color-text-muted, #9ca3af);
2412
+ font-size: 18px; /* 18px 无对应 token,保留 */
2413
+ cursor: pointer;
2414
+ transition: background var(--kine-motion-duration-fast) var(--kine-motion-easing-default), color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2415
+ }
2416
+
2417
+ .k-approval-dialog-close:hover {
2418
+ background: var(--kine-color-bg-hover, rgba(0, 0, 0, 0.04));
2419
+ color: var(--kine-color-text-primary, #111827);
2420
+ }
2421
+
2422
+ .k-approval-dialog-body {
2423
+ padding: var(--kine-spacing-8) var(--kine-spacing-12);
2424
+ }
2425
+
2426
+ .k-approval-dialog-summary {
2427
+ padding: var(--kine-spacing-5) var(--kine-spacing-7);
2428
+ background: var(--kine-color-bg-primary, #f8f9fb);
2429
+ border-radius: var(--kine-radius-sm, 6px);
2430
+ font-size: var(--kine-font-size-lg);
2431
+ color: var(--kine-color-text-secondary, #6b7280);
2432
+ margin-bottom: var(--kine-spacing-6);
2433
+ font-variant-numeric: tabular-nums;
2434
+ }
2435
+
2436
+ .k-approval-dialog-desc {
2437
+ font-size: var(--kine-font-size-lg);
2438
+ color: var(--kine-color-text-secondary, #6b7280);
2439
+ line-height: 1.6;
2440
+ margin: 0 0 var(--kine-spacing-6);
2441
+ }
2442
+
2443
+ .k-approval-dialog-remark {
2444
+ display: block;
2445
+ width: 100%;
2446
+ padding: var(--kine-spacing-5) var(--kine-spacing-6);
2447
+ border: 1px solid var(--kine-color-border-default, #e5e7eb);
2448
+ border-radius: var(--kine-radius-sm, 6px);
2449
+ font-family: inherit;
2450
+ font-size: var(--kine-font-size-lg);
2451
+ color: var(--kine-color-text-primary, #111827);
2452
+ resize: vertical;
2453
+ min-height: 72px;
2454
+ transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default), box-shadow var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2455
+ box-sizing: border-box;
2456
+ }
2457
+
2458
+ .k-approval-dialog-remark::placeholder {
2459
+ color: var(--kine-color-text-muted, #9ca3af);
2460
+ }
2461
+
2462
+ .k-approval-dialog-remark:focus {
2463
+ outline: none;
2464
+ border-color: var(--kine-color-accent-default, #4f46e5);
2465
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.06);
2466
+ }
2467
+
2468
+ .k-approval-dialog-remark--required {
2469
+ border-color: var(--kine-color-semantic-error, #dc2626);
2470
+ }
2471
+
2472
+ .k-approval-dialog-remark--required:focus {
2473
+ border-color: var(--kine-color-semantic-error, #dc2626);
2474
+ box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.06);
2475
+ }
2476
+
2477
+ .k-approval-dialog-required-hint {
2478
+ display: block;
2479
+ font-size: var(--kine-font-size-sm);
2480
+ color: var(--kine-color-semantic-error, #dc2626);
2481
+ margin-top: var(--kine-spacing-2);
2482
+ }
2483
+
2484
+ .k-approval-dialog-footer {
2485
+ display: flex;
2486
+ align-items: center;
2487
+ justify-content: flex-end;
2488
+ gap: var(--kine-spacing-4);
2489
+ padding: 0 var(--kine-spacing-12) var(--kine-spacing-10);
2490
+ }
2491
+
2492
+ /* ================================================================
2493
+ KFormPage / KMasterDetailPage — 表单页布局
2494
+ ================================================================ */
2495
+
2496
+ /* wrapper: 全宽容器,承载 sticky bar 出血 */
2497
+ .k-form-page-wrapper {
2498
+ display: flex;
2499
+ flex-direction: column;
2500
+ min-height: 100%;
2501
+ }
2502
+
2503
+ .k-form-page {
2504
+ max-width: 960px;
2505
+ width: 100%;
2506
+ margin: 0 auto;
2507
+ padding: 0 0 var(--kine-spacing-10);
2508
+ flex: 1;
2509
+ }
2510
+
2511
+ .k-master-detail-page {
2512
+ max-width: 1120px;
2513
+ }
2514
+
2515
+ /* 页头 */
2516
+ .k-fp-header {
2517
+ display: flex;
2518
+ align-items: center;
2519
+ justify-content: space-between;
2520
+ margin-bottom: var(--kine-spacing-10);
2521
+ gap: var(--kine-spacing-6);
2522
+ }
2523
+
2524
+ .k-fp-header-left {
2525
+ display: flex;
2526
+ align-items: center;
2527
+ gap: var(--kine-spacing-5);
2528
+ min-width: 0;
2529
+ }
2530
+
2531
+ .k-fp-header-right {
2532
+ display: flex;
2533
+ align-items: center;
2534
+ gap: var(--kine-spacing-4);
2535
+ flex-shrink: 0;
2536
+ }
2537
+
2538
+ .k-fp-title {
2539
+ font-size: var(--kine-font-size-3xl);
2540
+ font-weight: 650;
2541
+ color: var(--kine-color-text-primary, #111827);
2542
+ margin: 0;
2543
+ letter-spacing: -0.3px;
2544
+ }
2545
+
2546
+ /* 面包屑 */
2547
+ .k-fp-breadcrumb {
2548
+ display: flex;
2549
+ align-items: center;
2550
+ gap: var(--kine-spacing-2);
2551
+ font-size: var(--kine-font-size-lg);
2552
+ }
2553
+
2554
+ .k-fp-breadcrumb-sep {
2555
+ color: var(--kine-color-text-muted, #9ca3af);
2556
+ margin: 0 var(--kine-spacing-1);
2557
+ }
2558
+
2559
+ .k-fp-breadcrumb-link {
2560
+ color: var(--kine-color-text-secondary, #6b7280);
2561
+ cursor: pointer;
2562
+ text-decoration: none;
2563
+ transition: color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2564
+ }
2565
+
2566
+ .k-fp-breadcrumb-link:hover {
2567
+ color: var(--kine-color-accent-default, #4f46e5);
2568
+ }
2569
+
2570
+ .k-fp-breadcrumb-text {
2571
+ color: var(--kine-color-text-primary, #111827);
2572
+ font-weight: var(--kine-font-weight-medium);
2573
+ }
2574
+
2575
+ /* 字段网格 */
2576
+ .k-fp-grid {
2577
+ display: grid;
2578
+ gap: var(--kine-spacing-8) var(--kine-spacing-10);
2579
+ }
2580
+
2581
+ .k-fp-grid--1 { grid-template-columns: 1fr; }
2582
+ .k-fp-grid--2 { grid-template-columns: repeat(2, 1fr); }
2583
+ .k-fp-grid--3 { grid-template-columns: repeat(3, 1fr); }
2584
+
2585
+ .k-fp-field {
2586
+ display: flex;
2587
+ flex-direction: column;
2588
+ gap: var(--kine-spacing-2);
2589
+ }
2590
+
2591
+ .k-fp-label {
2592
+ font-size: var(--kine-font-size-md);
2593
+ font-weight: var(--kine-font-weight-medium);
2594
+ color: var(--kine-color-text-secondary, #6b7280);
2595
+ text-transform: uppercase;
2596
+ letter-spacing: 0.03em;
2597
+ }
2598
+
2599
+ .k-fp-required {
2600
+ color: var(--kine-color-semantic-error, #dc2626);
2601
+ margin-left: var(--kine-spacing-1);
2602
+ }
2603
+
2604
+ /* 输入框 */
2605
+ .k-fp-input {
2606
+ height: 34px;
2607
+ padding: 0 var(--kine-spacing-5);
2608
+ border: 1px solid var(--kine-color-border-default, #e5e7eb);
2609
+ border-radius: var(--kine-radius-sm, 6px);
2610
+ font-size: var(--kine-font-size-lg);
2611
+ font-family: inherit;
2612
+ color: var(--kine-color-text-primary, #111827);
2613
+ background: var(--kine-color-bg-tertiary, #fff);
2614
+ transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default), box-shadow var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2615
+ box-sizing: border-box;
2616
+ width: 100%;
2617
+ }
2618
+
2619
+ .k-fp-input:focus {
2620
+ outline: none;
2621
+ border-color: var(--kine-color-accent-default, #4f46e5);
2622
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.06);
2623
+ }
2624
+
2625
+ .k-fp-input::placeholder {
2626
+ color: var(--kine-color-text-muted, #9ca3af);
2627
+ }
2628
+
2629
+ .k-fp-input--error {
2630
+ border-color: var(--kine-color-semantic-error, #dc2626);
2631
+ }
2632
+
2633
+ .k-fp-input--error:focus {
2634
+ box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.06);
2635
+ }
2636
+
2637
+ .k-fp-input--disabled {
2638
+ background: var(--kine-color-bg-inset, #f3f4f6);
2639
+ color: var(--kine-color-text-muted, #9ca3af);
2640
+ cursor: not-allowed;
2641
+ }
2642
+
2643
+ .k-fp-input--readonly {
2644
+ background: transparent;
2645
+ border-color: transparent;
2646
+ padding-left: 0;
2647
+ }
2648
+
2649
+ /* textarea */
2650
+ .k-fp-textarea {
2651
+ height: auto;
2652
+ min-height: 72px;
2653
+ padding: var(--kine-spacing-4) var(--kine-spacing-5);
2654
+ resize: vertical;
2655
+ }
2656
+
2657
+ /* number input wrapper with prefix/suffix */
2658
+ .k-fp-input-wrapper {
2659
+ display: flex;
2660
+ align-items: center;
2661
+ border: 1px solid var(--kine-color-border-default, #e5e7eb);
2662
+ border-radius: var(--kine-radius-sm, 6px);
2663
+ overflow: hidden;
2664
+ background: var(--kine-color-bg-tertiary, #fff);
2665
+ transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default), box-shadow var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2666
+ }
2667
+
2668
+ .k-fp-input-wrapper:focus-within {
2669
+ border-color: var(--kine-color-accent-default, #4f46e5);
2670
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.06);
2671
+ }
2672
+
2673
+ .k-fp-input-wrapper .k-fp-input {
2674
+ border: none;
2675
+ box-shadow: none;
2676
+ background: transparent;
2677
+ }
2678
+
2679
+ .k-fp-input-wrapper .k-fp-input:focus {
2680
+ box-shadow: none;
2681
+ }
2682
+
2683
+ .k-fp-input-prefix,
2684
+ .k-fp-input-suffix {
2685
+ display: flex;
2686
+ align-items: center;
2687
+ padding: 0 var(--kine-spacing-4);
2688
+ font-size: var(--kine-font-size-md);
2689
+ font-weight: var(--kine-font-weight-medium);
2690
+ color: var(--kine-color-text-muted, #9ca3af);
2691
+ background: var(--kine-color-bg-inset, #f3f4f6);
2692
+ white-space: nowrap;
2693
+ height: 32px;
2694
+ }
2695
+
2696
+ /* switch */
2697
+ .k-fp-switch {
2698
+ position: relative;
2699
+ display: inline-flex;
2700
+ cursor: pointer;
2701
+ }
2702
+
2703
+ .k-fp-switch input {
2704
+ position: absolute;
2705
+ opacity: 0;
2706
+ width: 0;
2707
+ height: 0;
2708
+ }
2709
+
2710
+ .k-fp-switch-track {
2711
+ display: inline-block;
2712
+ width: 36px;
2713
+ height: 20px;
2714
+ border-radius: 10px;
2715
+ background: var(--kine-color-border-default, #d1d5db);
2716
+ transition: background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2717
+ position: relative;
2718
+ }
2719
+
2720
+ .k-fp-switch-track::after {
2721
+ content: '';
2722
+ position: absolute;
2723
+ top: var(--kine-spacing-1);
2724
+ left: var(--kine-spacing-1);
2725
+ width: 16px;
2726
+ height: 16px;
2727
+ border-radius: 50%;
2728
+ background: #fff;
2729
+ transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2730
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
2731
+ }
2732
+
2733
+ .k-fp-switch input:checked + .k-fp-switch-track {
2734
+ background: var(--kine-color-accent-default, #4f46e5);
2735
+ }
2736
+
2737
+ .k-fp-switch input:checked + .k-fp-switch-track::after {
2738
+ transform: translateX(16px);
2739
+ }
2740
+
2741
+ /* 错误提示 */
2742
+ .k-fp-error {
2743
+ font-size: var(--kine-font-size-sm);
2744
+ color: var(--kine-color-semantic-error, #dc2626);
2745
+ margin-top: var(--kine-spacing-1);
2746
+ }
2747
+
2748
+ /* 加载中 */
2749
+ .k-fp-loading {
2750
+ padding: 64px var(--kine-spacing-12);
2751
+ text-align: center;
2752
+ font-size: var(--kine-font-size-lg);
2753
+ color: var(--kine-color-text-muted, #9ca3af);
2754
+ }
2755
+
2756
+ /* ================================================================
2757
+ Dark Mode
2758
+ ================================================================ */
2759
+
2760
+ @media (prefers-color-scheme: dark) {
2761
+ .k-form-card {
2762
+ background: var(--kine-color-bg-tertiary, #1e1e2e);
2763
+ border-color: var(--kine-color-border-default, #2e2e3e);
2764
+ }
2765
+
2766
+ .k-form-card-title {
2767
+ color: var(--kine-color-text-primary, #e5e5e5);
2768
+ }
2769
+
2770
+ .k-form-card-header--clickable:hover {
2771
+ background: var(--kine-color-bg-hover, rgba(255, 255, 255, 0.04));
2772
+ }
2773
+
2774
+ .k-sticky-action-bar {
2775
+ background: var(--kine-color-bg-tertiary, #1e1e2e);
2776
+ border-top-color: var(--kine-color-border-default, #2e2e3e);
2777
+ }
2778
+
2779
+ .k-approval-overlay {
2780
+ background: rgba(0, 0, 0, 0.6);
2781
+ }
2782
+
2783
+ .k-approval-dialog {
2784
+ background: var(--kine-color-bg-tertiary, #1e1e2e);
2785
+ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
2786
+ }
2787
+
2788
+ .k-approval-dialog-title {
2789
+ color: var(--kine-color-text-primary, #e5e5e5);
2790
+ }
2791
+
2792
+ .k-approval-dialog-summary {
2793
+ background: var(--kine-color-bg-primary, #161625);
2794
+ }
2795
+
2796
+ .k-approval-dialog-remark {
2797
+ background: var(--kine-color-bg-primary, #161625);
2798
+ border-color: var(--kine-color-border-default, #2e2e3e);
2799
+ color: var(--kine-color-text-primary, #e5e5e5);
2800
+ }
2801
+
2802
+ }
2803
+
2804
+ /* 同时支持 class 切换暗色模式 */
2805
+ .dark .k-form-card,
2806
+ [data-theme="dark"] .k-form-card {
2807
+ background: var(--kine-color-bg-tertiary, #1e1e2e);
2808
+ border-color: var(--kine-color-border-default, #2e2e3e);
2809
+ }
2810
+
2811
+ .dark .k-form-card-title,
2812
+ [data-theme="dark"] .k-form-card-title {
2813
+ color: var(--kine-color-text-primary, #e5e5e5);
2814
+ }
2815
+
2816
+ .dark .k-sticky-action-bar,
2817
+ [data-theme="dark"] .k-sticky-action-bar {
2818
+ background: var(--kine-color-bg-tertiary, #1e1e2e);
2819
+ border-top-color: var(--kine-color-border-default, #2e2e3e);
2820
+ }
2821
+
2822
+ .dark .k-approval-dialog,
2823
+ [data-theme="dark"] .k-approval-dialog {
2824
+ background: var(--kine-color-bg-tertiary, #1e1e2e);
2825
+ }
2826
+
2827
+ .dark .k-approval-dialog-remark,
2828
+ [data-theme="dark"] .k-approval-dialog-remark {
2829
+ background: var(--kine-color-bg-primary, #161625);
2830
+ border-color: var(--kine-color-border-default, #2e2e3e);
2831
+ color: var(--kine-color-text-primary, #e5e5e5);
2832
+ }
2833
+
2834
+ /* ================================================================
2835
+ 移动端(<768px)
2836
+ ================================================================ */
2837
+
2838
+ @media (max-width: 767px) {
2839
+ .k-form-page {
2840
+ padding: 0 0 var(--kine-spacing-6);
2841
+ }
2842
+
2843
+ /* 多列网格在移动端强制单列 */
2844
+ .k-fp-grid--2,
2845
+ .k-fp-grid--3 {
2846
+ grid-template-columns: 1fr;
2847
+ }
2848
+
2849
+ /* 跨列字段在单列模式下不需要 span */
2850
+ .k-fp-field[style*="grid-column"] {
2851
+ grid-column: span 1 !important;
2852
+ }
2853
+
2854
+ .k-form-card-body {
2855
+ padding: var(--kine-spacing-6);
2856
+ }
2857
+
2858
+ .k-form-card-header {
2859
+ padding: var(--kine-spacing-6) var(--kine-spacing-6);
2860
+ }
2861
+
2862
+ .k-fp-header {
2863
+ margin-bottom: var(--kine-spacing-6);
2864
+ }
2865
+
2866
+ .k-sticky-action-bar {
2867
+ padding: var(--kine-spacing-4) var(--kine-spacing-6);
2868
+ margin: 0 calc(-1 * var(--kine-spacing-6)) calc(-1 * var(--kine-spacing-6));
2869
+ }
2870
+
2871
+ .k-approval-dialog {
2872
+ width: calc(100vw - 32px);
2873
+ }
2874
+ }
2875
+
2876
+ /**
2877
+ * @description KEditableTable 样式 — 对标 AIDesigner 设计规范
2878
+ * @author 阿怪
2879
+ * @date 2026/3/22
2880
+ * @version v0.0.1
2881
+ *
2882
+ * 设计要点:
2883
+ * - 编辑行:左侧 3px 靛蓝竖线
2884
+ * - 删除行:红色文字 + 删线 + 内联确认
2885
+ * - 新增行:底部空行带 placeholder
2886
+ * - 汇总行:加粗金额
2887
+ */
2888
+
2889
+ .k-editable-table {
2890
+ width: 100%;
1011
2891
  }
1012
2892
 
1013
- /* 禁用态 */
1014
- .k-upload-disabled {
1015
- opacity: var(--kine-opacity-muted);
1016
- cursor: not-allowed;
1017
- pointer-events: none;
2893
+ /* ── 标题栏 ──────────────────────────── */
2894
+
2895
+ .k-et-header {
2896
+ display: flex;
2897
+ align-items: center;
2898
+ justify-content: space-between;
2899
+ padding: 0 0 var(--kine-spacing-6);
1018
2900
  }
1019
2901
 
1020
- /* 默认占位内容 */
1021
- .k-upload-placeholder {
2902
+ .k-et-header-left {
1022
2903
  display: flex;
1023
- flex-direction: column;
1024
2904
  align-items: center;
1025
- gap: 6px;
1026
- pointer-events: none;
2905
+ gap: var(--kine-spacing-4);
1027
2906
  }
1028
2907
 
1029
- .k-upload-icon {
1030
- font-size: 24px;
1031
- color: var(--kine-color-text-secondary);
1032
- line-height: 1;
2908
+ .k-et-title {
2909
+ font-size: var(--kine-font-size-xl);
2910
+ font-weight: var(--kine-font-weight-semibold);
2911
+ color: var(--kine-color-text-primary, #111827);
1033
2912
  }
1034
2913
 
1035
- .k-upload-text {
1036
- font-family: var(--kine-font-family-mono);
2914
+ .k-et-count {
1037
2915
  font-size: var(--kine-font-size-sm);
1038
- color: var(--kine-color-text-secondary);
2916
+ padding: 1px 7px;
2917
+ border-radius: 100px;
2918
+ background: var(--kine-color-bg-inset, #f3f4f6);
2919
+ color: var(--kine-color-text-secondary, #6b7280);
2920
+ font-weight: var(--kine-font-weight-medium);
1039
2921
  }
1040
2922
 
1041
- /* ══════════════════════════════════════════
1042
- KImageUpload — 图片网格
1043
- ══════════════════════════════════════════ */
1044
-
1045
- .k-image-upload {
1046
- display: block;
2923
+ .k-et-header-right {
2924
+ display: flex;
2925
+ align-items: center;
2926
+ gap: var(--kine-spacing-4);
1047
2927
  }
1048
2928
 
1049
- .k-image-upload-grid {
1050
- display: flex;
1051
- flex-wrap: wrap;
1052
- gap: 8px;
2929
+ /* ── 表格 ──────────────────────────── */
2930
+
2931
+ .k-et-table {
2932
+ width: 100%;
2933
+ border-collapse: collapse;
1053
2934
  }
1054
2935
 
1055
- /* 图片卡片(预览 + 添加占位共用) */
1056
- .k-image-upload-card {
1057
- position: relative;
1058
- border-radius: var(--kine-radius-sm);
1059
- overflow: hidden;
1060
- border: 1px solid var(--kine-color-border-default);
1061
- background: var(--kine-color-bg-secondary);
1062
- flex-shrink: 0;
1063
- box-sizing: border-box;
2936
+ .k-et-thead {
2937
+ border-bottom: 1px solid var(--kine-color-border-default, #e5e7eb);
1064
2938
  }
1065
2939
 
1066
- /* 添加卡片 */
1067
- .k-image-upload-card--add {
1068
- display: flex;
1069
- align-items: center;
1070
- justify-content: center;
1071
- border-style: dashed;
1072
- cursor: pointer;
1073
- transition:
1074
- border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1075
- background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
2940
+ .k-et-th {
2941
+ padding: var(--kine-spacing-4) var(--kine-spacing-6);
2942
+ font-size: var(--kine-font-size-sm);
2943
+ font-weight: var(--kine-font-weight-medium);
2944
+ color: var(--kine-color-text-muted, #9ca3af);
2945
+ text-transform: uppercase;
2946
+ letter-spacing: 0.05em;
2947
+ text-align: left;
2948
+ white-space: nowrap;
1076
2949
  }
1077
2950
 
1078
- .k-image-upload-card--add:hover {
1079
- border-color: var(--kine-color-accent-default);
1080
- background: color-mix(in srgb, var(--kine-color-accent-default) 6%, var(--kine-color-bg-secondary));
2951
+ .k-et-th-index {
2952
+ width: 40px;
1081
2953
  }
1082
2954
 
1083
- .k-image-upload-add-icon {
1084
- font-size: 28px;
1085
- color: var(--kine-color-text-secondary);
1086
- line-height: 1;
1087
- pointer-events: none;
2955
+ .k-et-th-actions {
2956
+ width: 70px;
1088
2957
  }
1089
2958
 
1090
- /* 错误态卡片边框 */
1091
- .k-image-upload-card--error {
1092
- border-color: var(--kine-color-semantic-error);
2959
+ .k-et-td {
2960
+ padding: var(--kine-spacing-5) var(--kine-spacing-6);
2961
+ font-size: var(--kine-font-size-lg);
2962
+ color: var(--kine-color-text-primary, #111827);
2963
+ border-bottom: 1px solid var(--kine-color-border-subtle, #f3f4f6);
2964
+ vertical-align: middle;
1093
2965
  }
1094
2966
 
1095
- /* 预览图 */
1096
- .k-image-upload-preview {
1097
- width: 100%;
1098
- height: 100%;
1099
- object-fit: cover;
1100
- display: block;
2967
+ .k-et-td-index {
2968
+ color: var(--kine-color-text-muted, #9ca3af);
2969
+ font-size: var(--kine-font-size-md);
2970
+ font-variant-numeric: tabular-nums;
1101
2971
  }
1102
2972
 
1103
- /* 上传进度覆盖层 */
1104
- .k-image-upload-overlay {
1105
- position: absolute;
1106
- inset: 0;
1107
- display: flex;
1108
- flex-direction: column;
1109
- align-items: center;
1110
- justify-content: flex-end;
1111
- background: rgba(0, 0, 0, 0.45);
2973
+ /* 对齐 */
2974
+ .k-et-align-center { text-align: center; }
2975
+ .k-et-align-right { text-align: right; }
2976
+
2977
+ /* 行 hover */
2978
+ .k-et-tr {
2979
+ transition: background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1112
2980
  }
1113
2981
 
1114
- .k-image-upload-overlay--error {
1115
- justify-content: center;
1116
- font-family: var(--kine-font-family-mono);
1117
- font-size: var(--kine-font-size-sm);
1118
- color: var(--kine-color-semantic-error);
2982
+ .k-et-tr:hover {
2983
+ background: var(--kine-color-bg-hover, rgba(0, 0, 0, 0.02));
1119
2984
  }
1120
2985
 
1121
- .k-image-upload-progress {
1122
- position: absolute;
1123
- bottom: 0;
1124
- left: 0;
1125
- right: 0;
1126
- background: var(--kine-color-accent-default);
1127
- box-shadow: 0 0 var(--kine-shadow-glow-radius) var(--kine-color-accent-default);
1128
- transition: height var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1129
- opacity: 0.6;
2986
+ /* ── 编辑行 ──────────────────────────── */
2987
+
2988
+ .k-et-tr--editing {
2989
+ background: rgba(79, 70, 229, 0.02);
2990
+ border-left: 3px solid var(--kine-color-accent-default, #4f46e5);
1130
2991
  }
1131
2992
 
1132
- .k-image-upload-percent {
1133
- position: relative;
1134
- z-index: 1;
1135
- font-family: var(--kine-font-family-mono);
1136
- font-size: var(--kine-font-size-sm);
1137
- color: #ffffff;
1138
- padding-bottom: 4px;
2993
+ .k-et-tr--editing:hover {
2994
+ background: rgba(79, 70, 229, 0.03);
1139
2995
  }
1140
2996
 
1141
- /* 删除按钮(悬停卡片时显示) */
1142
- .k-image-upload-remove {
1143
- position: absolute;
1144
- top: 2px;
1145
- right: 2px;
1146
- width: 20px;
1147
- height: 20px;
1148
- display: none;
1149
- align-items: center;
1150
- justify-content: center;
1151
- background: rgba(0, 0, 0, 0.6);
1152
- border: none;
1153
- border-radius: var(--kine-radius-xs);
1154
- color: #ffffff;
1155
- font-size: 14px;
1156
- cursor: pointer;
1157
- line-height: 1;
1158
- z-index: 10;
1159
- padding: 0;
2997
+ .k-et-tr--editing .k-et-td:first-child {
2998
+ padding-left: var(--kine-spacing-4); /* ~8px,视觉上约等于 12 - 3px border */
1160
2999
  }
1161
3000
 
1162
- .k-image-upload-card:hover .k-image-upload-remove {
1163
- display: flex;
3001
+ /* 行内编辑态 KInput / KSelect 包裹容器,宽度撑满单元格 */
3002
+ .k-et-input-wrap,
3003
+ .k-et-select-wrap {
3004
+ width: 100%;
1164
3005
  }
1165
3006
 
1166
- .k-image-upload-remove:hover {
1167
- background: var(--kine-color-semantic-error);
3007
+ .k-et-cell-readonly {
3008
+ color: var(--kine-color-text-muted, #9ca3af);
1168
3009
  }
1169
3010
 
1170
- /* ══════════════════════════════════════════
1171
- KFileList — 文件列表
1172
- ══════════════════════════════════════════ */
3011
+ /* ── 删除确认行 ──────────────────────────── */
1173
3012
 
1174
- .k-file-list {
1175
- list-style: none;
1176
- margin: 0;
1177
- padding: 0;
1178
- display: flex;
1179
- flex-direction: column;
1180
- gap: 4px;
1181
- width: 100%;
3013
+ .k-et-tr--deleting {
3014
+ background: rgba(220, 38, 38, 0.02);
1182
3015
  }
1183
3016
 
1184
- .k-file-list-item {
1185
- display: grid;
1186
- grid-template-columns: 20px 1fr auto;
3017
+ .k-et-tr--deleting:hover {
3018
+ background: rgba(220, 38, 38, 0.03);
3019
+ }
3020
+
3021
+ .k-et-delete-confirm {
3022
+ display: flex;
1187
3023
  align-items: center;
1188
- column-gap: 8px;
1189
- padding: 6px 8px;
1190
- border-radius: var(--kine-radius-xs);
1191
- background: var(--kine-color-bg-secondary);
1192
- border: 1px solid var(--kine-color-border-default);
1193
- font-family: var(--kine-font-family-mono);
1194
- transition: border-color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1195
- position: relative;
3024
+ gap: var(--kine-spacing-6);
3025
+ font-size: var(--kine-font-size-lg);
1196
3026
  }
1197
3027
 
1198
- /* 上传中时需要显示进度条,需要多行 */
1199
- .k-file-list-item--uploading {
1200
- grid-template-columns: 20px 1fr auto;
1201
- grid-template-rows: auto 4px;
3028
+ .k-et-deleted-text {
3029
+ color: var(--kine-color-semantic-error, #dc2626);
3030
+ text-decoration: line-through;
1202
3031
  }
1203
3032
 
1204
- /* 上传中删除按钮固定在第一行 */
1205
- .k-file-list-item--uploading .k-file-list-remove {
1206
- grid-row: 1;
1207
- grid-column: 3;
3033
+ .k-et-delete-ask {
3034
+ color: var(--kine-color-semantic-error, #dc2626);
3035
+ font-size: var(--kine-font-size-md);
1208
3036
  }
1209
3037
 
1210
- .k-file-list-item--success {
1211
- border-color: color-mix(in srgb, var(--kine-color-semantic-success) 30%, var(--kine-color-border-default));
3038
+ /* ── 操作图标列 ──────────────────────────── */
3039
+
3040
+ .k-et-td-actions {
3041
+ text-align: right;
3042
+ white-space: nowrap;
1212
3043
  }
1213
3044
 
1214
- .k-file-list-item--error {
1215
- border-color: color-mix(in srgb, var(--kine-color-semantic-error) 40%, var(--kine-color-border-default));
3045
+ /* ── 汇总行 ──────────────────────────── */
3046
+
3047
+ .k-et-tfoot {
3048
+ border-top: 1px solid var(--kine-color-border-default, #e5e7eb);
1216
3049
  }
1217
3050
 
1218
- /* 文件图标 */
1219
- .k-file-list-icon {
1220
- font-size: 12px;
1221
- text-align: center;
1222
- flex-shrink: 0;
3051
+ .k-et-tr--summary {
3052
+ background: transparent;
1223
3053
  }
1224
3054
 
1225
- .k-file-list-item--success .k-file-list-icon {
1226
- color: var(--kine-color-semantic-success);
3055
+ .k-et-tr--summary:hover {
3056
+ background: transparent;
1227
3057
  }
1228
3058
 
1229
- .k-file-list-item--error .k-file-list-icon {
1230
- color: var(--kine-color-semantic-error);
3059
+ .k-et-td-summary {
3060
+ font-weight: var(--kine-font-weight-semibold);
3061
+ color: var(--kine-color-text-primary, #111827);
3062
+ font-size: var(--kine-font-size-lg);
1231
3063
  }
1232
3064
 
1233
- .k-file-list-item--uploading .k-file-list-icon,
1234
- .k-file-list-item--pending .k-file-list-icon {
1235
- color: var(--kine-color-text-secondary);
3065
+ .k-et-summary-value {
3066
+ font-variant-numeric: tabular-nums;
3067
+ letter-spacing: -0.01em;
1236
3068
  }
1237
3069
 
1238
- /* 文件信息 */
1239
- .k-file-list-info {
3070
+ /* ── 空态 ──────────────────────────── */
3071
+
3072
+ .k-et-empty {
1240
3073
  display: flex;
1241
3074
  flex-direction: column;
1242
- gap: 2px;
1243
- overflow: hidden;
3075
+ align-items: center;
3076
+ gap: var(--kine-spacing-6);
3077
+ padding: var(--kine-spacing-24) var(--kine-spacing-12);
1244
3078
  }
1245
3079
 
1246
- .k-file-list-name {
1247
- font-size: var(--kine-font-size-sm);
1248
- color: var(--kine-color-text-primary);
1249
- white-space: nowrap;
1250
- overflow: hidden;
1251
- text-overflow: ellipsis;
3080
+ .k-et-empty-text {
3081
+ font-size: var(--kine-font-size-lg);
3082
+ color: var(--kine-color-text-muted, #9ca3af);
1252
3083
  }
1253
3084
 
1254
- .k-file-list-link {
1255
- color: var(--kine-color-accent-default);
1256
- text-decoration: none;
1257
- }
3085
+ /* ================================================================
3086
+ Dark Mode
3087
+ ================================================================ */
1258
3088
 
1259
- .k-file-list-link:hover {
1260
- color: var(--kine-color-accent-hover);
1261
- text-decoration: underline;
1262
- }
3089
+ @media (prefers-color-scheme: dark) {
3090
+ .k-et-thead {
3091
+ border-bottom-color: var(--kine-color-border-default, #2e2e3e);
3092
+ }
1263
3093
 
1264
- .k-file-list-meta {
1265
- font-size: calc(var(--kine-font-size-sm) - 1px);
1266
- color: var(--kine-color-text-secondary);
3094
+ .k-et-td {
3095
+ color: var(--kine-color-text-primary, #e5e5e5);
3096
+ border-bottom-color: var(--kine-color-border-subtle, #252535);
3097
+ }
3098
+
3099
+ .k-et-tr:hover {
3100
+ background: rgba(255, 255, 255, 0.03);
3101
+ }
3102
+
3103
+ .k-et-tr--editing {
3104
+ background: rgba(79, 70, 229, 0.06);
3105
+ }
3106
+
3107
+ .k-et-tfoot {
3108
+ border-top-color: var(--kine-color-border-default, #2e2e3e);
3109
+ }
3110
+
3111
+ .k-et-td-summary {
3112
+ color: var(--kine-color-text-primary, #e5e5e5);
3113
+ }
3114
+
3115
+ .k-et-icon-btn:hover {
3116
+ background: rgba(255, 255, 255, 0.06);
3117
+ }
3118
+
3119
+ .k-et-count {
3120
+ background: var(--kine-color-bg-inset, #252535);
3121
+ }
1267
3122
  }
1268
3123
 
1269
- /* 进度条(位于第二行,跨满三列) */
1270
- .k-file-list-progress-track {
1271
- grid-column: 1 / -1;
1272
- height: 3px;
1273
- border-radius: var(--kine-radius-xs);
1274
- background: var(--kine-color-bg-tertiary);
1275
- overflow: hidden;
1276
- margin-top: 2px;
3124
+ .dark .k-et-thead,
3125
+ [data-theme="dark"] .k-et-thead {
3126
+ border-bottom-color: var(--kine-color-border-default, #2e2e3e);
1277
3127
  }
1278
3128
 
1279
- .k-file-list-progress-fill {
1280
- height: 100%;
1281
- border-radius: var(--kine-radius-xs);
1282
- background: var(--kine-color-accent-default);
1283
- box-shadow: 0 0 var(--kine-shadow-glow-radius) var(--kine-color-accent-default);
1284
- transition: width var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
3129
+ .dark .k-et-td,
3130
+ [data-theme="dark"] .k-et-td {
3131
+ color: var(--kine-color-text-primary, #e5e5e5);
3132
+ border-bottom-color: var(--kine-color-border-subtle, #252535);
1285
3133
  }
1286
3134
 
1287
- /* 删除按钮 */
1288
- .k-file-list-remove {
1289
- display: flex;
1290
- align-items: center;
1291
- justify-content: center;
1292
- width: 20px;
1293
- height: 20px;
1294
- padding: 0;
1295
- background: transparent;
1296
- border: none;
1297
- border-radius: var(--kine-radius-xs);
1298
- color: var(--kine-color-text-secondary);
1299
- font-size: 16px;
1300
- cursor: pointer;
1301
- line-height: 1;
1302
- flex-shrink: 0;
1303
- transition: color var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
3135
+ .dark .k-et-tfoot,
3136
+ [data-theme="dark"] .k-et-tfoot {
3137
+ border-top-color: var(--kine-color-border-default, #2e2e3e);
1304
3138
  }
1305
3139
 
1306
- .k-file-list-remove:hover {
1307
- color: var(--kine-color-semantic-error);
3140
+ .dark .k-et-td-summary,
3141
+ [data-theme="dark"] .k-et-td-summary {
3142
+ color: var(--kine-color-text-primary, #e5e5e5);
1308
3143
  }
3144
+ /*$vite$:1*/