@kine-design/crud 0.0.1-beta.25 → 0.0.1-beta.26

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.
@@ -109,7 +109,7 @@ export default defineComponent({
109
109
  const renderFilters = () => {
110
110
  if (!props.config.filters?.length) return null;
111
111
  return props.config.filters.map(f => (
112
- <div class="k-crud-page-filter-item" key={f.param}>
112
+ <div class="k-crud-page-filter-item" data-k={`filter:${f.param}`} key={f.param}>
113
113
  <label class="k-crud-page-filter-label">{f.label}</label>
114
114
  {f.type === 'select' ? (
115
115
  <KSelect
@@ -138,7 +138,7 @@ export default defineComponent({
138
138
  };
139
139
 
140
140
  return () => (
141
- <div class="k-crud-page" ref={rootRef}>
141
+ <div class="k-crud-page" data-k="page:crudList" ref={rootRef}>
142
142
  <KPageHeader title={props.config.title}>
143
143
  {{ extra: slots.headerExtra }}
144
144
  </KPageHeader>
@@ -97,9 +97,9 @@ export default defineComponent({
97
97
  {ctx.slots.search?.()}
98
98
  </div>
99
99
  {/* 搜索 / 重置按钮区 */}
100
- <div class="k-search-table-search-actions">
101
- <KButton type="primary" text={t.value.searchTable.search} onClick={onSearch} />
102
- <KButton text={t.value.searchTable.reset} onClick={onReset} />
100
+ <div class="k-search-table-search-actions" data-k="action:searchActions">
101
+ <KButton type="primary" text={t.value.searchTable.search} data-k="action:search" onClick={onSearch} />
102
+ <KButton text={t.value.searchTable.reset} data-k="action:reset" onClick={onReset} />
103
103
  </div>
104
104
  </div>
105
105
  )}
@@ -66,4 +66,6 @@ export interface CrudPageConfig {
66
66
  detailPath?: string;
67
67
  /** 图片列 src 转换函数,将原始值转为可访问 URL */
68
68
  imageResolver?: (raw: string) => string;
69
+ /** 默认查询参数,始终附带在请求中(用户选择的 filter 值会覆盖同名参数) */
70
+ defaultParams?: Record<string, unknown>;
69
71
  }
@@ -43,6 +43,7 @@ export function useCrudPage(config: CrudPageConfig, tableBodyRef?: Ref<HTMLEleme
43
43
  loading.value = true;
44
44
  try {
45
45
  const params: Record<string, unknown> = {
46
+ ...config.defaultParams,
46
47
  page: page.value,
47
48
  pageSize: pageSize.value,
48
49
  };
@@ -68,4 +68,6 @@ export interface CrudPageConfig {
68
68
  detailPath?: string;
69
69
  /** 图片列 src 转换函数,将原始值转为可访问 URL */
70
70
  imageResolver?: (raw: string) => string;
71
+ /** 默认查询参数,始终附带在请求中(用户选择的 filter 值会覆盖同名参数) */
72
+ defaultParams?: Record<string, unknown>;
71
73
  }
package/dist/crud.css CHANGED
@@ -315,11 +315,11 @@
315
315
 
316
316
  /* 行 hover 效果 */
317
317
  .k-tbody .k-tr {
318
- transition: background var(--kine-motion-duration-fast);
318
+ transition: background var(--kine-interaction-transition-duration);
319
319
  }
320
320
 
321
321
  .k-tbody .k-tr:hover {
322
- background: var(--kine-color-bg-hover);
322
+ background: var(--kine-color-neutral-3);
323
323
  }
324
324
 
325
325
  /* 空数据占位 */
@@ -397,23 +397,23 @@
397
397
  border: 1px solid transparent;
398
398
  color: var(--kine-color-text-secondary);
399
399
  cursor: pointer;
400
- transition: background var(--kine-motion-duration-fast), color var(--kine-motion-duration-fast);
400
+ transition: background var(--kine-interaction-transition-duration), color var(--kine-interaction-transition-duration);
401
401
  }
402
402
 
403
403
  .k-pager:hover {
404
- background: var(--kine-color-bg-hover);
404
+ background: var(--kine-color-neutral-3);
405
405
  color: var(--kine-color-text-primary);
406
406
  }
407
407
 
408
408
  /* 当前页高亮 */
409
409
  .k-pager-current {
410
410
  color: var(--kine-color-accent-default);
411
- background: color-mix(in srgb, var(--kine-color-accent-default) 10%, transparent);
412
- border-color: color-mix(in srgb, var(--kine-color-accent-default) 30%, transparent);
411
+ background: var(--kine-color-accent-light);
412
+ border-color: color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-focus-glow), transparent);
413
413
  }
414
414
 
415
415
  .k-pager-current:hover {
416
- background: color-mix(in srgb, var(--kine-color-accent-default) 15%, transparent);
416
+ background: color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-hover-intensity), transparent);
417
417
  color: var(--kine-color-accent-hover);
418
418
  }
419
419
 
@@ -440,12 +440,12 @@
440
440
  color: var(--kine-color-text-secondary);
441
441
  font-size: var(--kine-font-size-2xl);
442
442
  cursor: pointer;
443
- transition: background var(--kine-motion-duration-fast), color var(--kine-motion-duration-fast);
443
+ transition: background var(--kine-interaction-transition-duration), color var(--kine-interaction-transition-duration);
444
444
  }
445
445
 
446
446
  .k-page-prev:hover,
447
447
  .k-page-next:hover {
448
- background: var(--kine-color-bg-hover);
448
+ background: var(--kine-color-neutral-3);
449
449
  color: var(--kine-color-text-primary);
450
450
  }
451
451
 
@@ -485,7 +485,7 @@
485
485
  color: var(--kine-color-text-primary);
486
486
  cursor: pointer;
487
487
  outline: none;
488
- transition: all var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
488
+ transition: all var(--kine-interaction-transition-duration) var(--kine-motion-easing-default);
489
489
  user-select: none;
490
490
  display: inline-flex;
491
491
  align-items: center;
@@ -494,31 +494,31 @@
494
494
 
495
495
  /* === default hover/active === */
496
496
  .k-button:hover {
497
- background: var(--kine-color-bg-hover);
498
- border-color: var(--kine-color-text-secondary);
499
- color: #ffffff;
497
+ background: var(--kine-color-neutral-3);
498
+ border-color: var(--kine-color-neutral-5);
499
+ color: var(--kine-color-text-inverse);
500
500
  }
501
501
 
502
502
  .k-button:active {
503
- background: var(--kine-color-border-subtle);
503
+ background: var(--kine-color-neutral-4);
504
504
  }
505
505
 
506
506
  /* === primary === */
507
507
  .k-button-primary {
508
- background: color-mix(in srgb, var(--kine-color-accent-default) 10%, var(--kine-color-bg-tertiary));
508
+ background: var(--kine-color-accent-light);
509
509
  border-color: var(--kine-color-accent-default);
510
510
  color: var(--kine-color-accent-default);
511
511
  }
512
512
 
513
513
  .k-button-primary:hover {
514
- background: color-mix(in srgb, var(--kine-color-accent-default) 18%, var(--kine-color-bg-primary));
514
+ background: color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-hover-intensity), var(--kine-color-bg-primary));
515
515
  border-color: var(--kine-color-accent-hover);
516
516
  color: var(--kine-color-accent-hover);
517
- text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-accent-default) 50%, transparent);
517
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-text-glow), transparent);
518
518
  }
519
519
 
520
520
  .k-button-primary:active {
521
- background: color-mix(in srgb, var(--kine-color-accent-default) 25%, var(--kine-color-bg-primary));
521
+ background: color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-active-intensity), var(--kine-color-bg-primary));
522
522
  }
523
523
 
524
524
  /* === success === */
@@ -528,14 +528,14 @@
528
528
  }
529
529
 
530
530
  .k-button-success:hover {
531
- background: color-mix(in srgb, var(--kine-color-semantic-success) 12%, var(--kine-color-bg-primary));
531
+ background: color-mix(in srgb, var(--kine-color-semantic-success) var(--kine-interaction-hover-intensity), var(--kine-color-bg-primary));
532
532
  border-color: var(--kine-color-semantic-success-hover);
533
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);
534
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-success) var(--kine-interaction-text-glow), transparent);
535
535
  }
536
536
 
537
537
  .k-button-success:active {
538
- background: color-mix(in srgb, var(--kine-color-semantic-success) 20%, var(--kine-color-bg-primary));
538
+ background: color-mix(in srgb, var(--kine-color-semantic-success) var(--kine-interaction-active-intensity), var(--kine-color-bg-primary));
539
539
  }
540
540
 
541
541
  /* === warning === */
@@ -545,14 +545,14 @@
545
545
  }
546
546
 
547
547
  .k-button-warning:hover {
548
- background: color-mix(in srgb, var(--kine-color-semantic-warning) 12%, var(--kine-color-bg-primary));
548
+ background: color-mix(in srgb, var(--kine-color-semantic-warning) var(--kine-interaction-hover-intensity), var(--kine-color-bg-primary));
549
549
  border-color: var(--kine-color-semantic-warning-hover);
550
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);
551
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-warning) var(--kine-interaction-text-glow), transparent);
552
552
  }
553
553
 
554
554
  .k-button-warning:active {
555
- background: color-mix(in srgb, var(--kine-color-semantic-warning) 20%, var(--kine-color-bg-primary));
555
+ background: color-mix(in srgb, var(--kine-color-semantic-warning) var(--kine-interaction-active-intensity), var(--kine-color-bg-primary));
556
556
  }
557
557
 
558
558
  /* === danger === */
@@ -562,31 +562,31 @@
562
562
  }
563
563
 
564
564
  .k-button-danger:hover {
565
- background: color-mix(in srgb, var(--kine-color-semantic-error) 12%, var(--kine-color-bg-primary));
565
+ background: color-mix(in srgb, var(--kine-color-semantic-error) var(--kine-interaction-hover-intensity), var(--kine-color-bg-primary));
566
566
  border-color: var(--kine-color-semantic-error-hover);
567
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);
568
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-error) var(--kine-interaction-text-glow), transparent);
569
569
  }
570
570
 
571
571
  .k-button-danger:active {
572
- background: color-mix(in srgb, var(--kine-color-semantic-error) 20%, var(--kine-color-bg-primary));
572
+ background: color-mix(in srgb, var(--kine-color-semantic-error) var(--kine-interaction-active-intensity), var(--kine-color-bg-primary));
573
573
  }
574
574
 
575
575
  /* === info === */
576
576
  .k-button-info {
577
- border-color: var(--kine-color-semantic-info, #64748b);
578
- color: var(--kine-color-semantic-info, #64748b);
577
+ border-color: var(--kine-color-semantic-info);
578
+ color: var(--kine-color-semantic-info);
579
579
  }
580
580
 
581
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);
582
+ background: color-mix(in srgb, var(--kine-color-semantic-info) var(--kine-interaction-hover-intensity), var(--kine-color-bg-primary));
583
+ border-color: var(--kine-color-semantic-info-hover);
584
+ color: var(--kine-color-semantic-info-hover);
585
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-semantic-info) var(--kine-interaction-text-glow), transparent);
586
586
  }
587
587
 
588
588
  .k-button-info:active {
589
- background: color-mix(in srgb, var(--kine-color-semantic-info, #64748b) 20%, var(--kine-color-bg-primary));
589
+ background: color-mix(in srgb, var(--kine-color-semantic-info) var(--kine-interaction-active-intensity), var(--kine-color-bg-primary));
590
590
  }
591
591
 
592
592
  /* === disabled === */
@@ -626,13 +626,13 @@
626
626
  }
627
627
 
628
628
  .k-button-plain:hover {
629
- background: var(--kine-color-bg-hover);
629
+ background: var(--kine-color-neutral-3);
630
630
  border-color: transparent;
631
- color: #ffffff;
631
+ color: var(--kine-color-text-inverse);
632
632
  }
633
633
 
634
634
  .k-button-plain:active {
635
- background: var(--kine-color-border-subtle);
635
+ background: var(--kine-color-neutral-4);
636
636
  }
637
637
 
638
638
  /* === link === */
@@ -648,7 +648,7 @@
648
648
  color: var(--kine-color-accent-hover);
649
649
  border-color: transparent;
650
650
  background: transparent;
651
- text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-accent-default) 50%, transparent);
651
+ text-shadow: 0 0 6px color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-text-glow), transparent);
652
652
  }
653
653
 
654
654
  /* === size variants === */
@@ -819,31 +819,31 @@
819
819
  .k-tag-primary {
820
820
  border-color: var(--kine-color-accent-default);
821
821
  color: var(--kine-color-accent-default);
822
- background: color-mix(in srgb, var(--kine-color-accent-default) 10%, var(--kine-color-bg-tertiary));
822
+ background: var(--kine-color-accent-light);
823
823
  }
824
824
 
825
825
  .k-tag-success {
826
826
  border-color: var(--kine-color-semantic-success);
827
827
  color: var(--kine-color-semantic-success);
828
- background: color-mix(in srgb, var(--kine-color-semantic-success) 10%, var(--kine-color-bg-tertiary));
828
+ background: var(--kine-color-semantic-success-light);
829
829
  }
830
830
 
831
831
  .k-tag-warning {
832
832
  border-color: var(--kine-color-semantic-warning);
833
833
  color: var(--kine-color-semantic-warning);
834
- background: color-mix(in srgb, var(--kine-color-semantic-warning) 10%, var(--kine-color-bg-tertiary));
834
+ background: var(--kine-color-semantic-warning-light);
835
835
  }
836
836
 
837
837
  .k-tag-danger {
838
838
  border-color: var(--kine-color-semantic-error);
839
839
  color: var(--kine-color-semantic-error);
840
- background: color-mix(in srgb, var(--kine-color-semantic-error) 10%, var(--kine-color-bg-tertiary));
840
+ background: var(--kine-color-semantic-error-light);
841
841
  }
842
842
 
843
843
  .k-tag-info {
844
844
  border-color: var(--kine-color-semantic-info);
845
845
  color: var(--kine-color-semantic-info);
846
- background: color-mix(in srgb, var(--kine-color-semantic-info) 10%, var(--kine-color-bg-tertiary));
846
+ background: var(--kine-color-semantic-info-light);
847
847
  }
848
848
 
849
849
  /* === 尺寸变体 === */
@@ -874,12 +874,12 @@
874
874
  cursor: pointer;
875
875
  opacity: 0.6;
876
876
  border-radius: 50%;
877
- transition: opacity var(--kine-motion-duration-fast), background var(--kine-motion-duration-fast);
877
+ transition: opacity var(--kine-interaction-transition-duration), background var(--kine-interaction-transition-duration);
878
878
  }
879
879
 
880
880
  .k-tag-close:hover {
881
881
  opacity: 1;
882
- background: color-mix(in srgb, currentColor 20%, transparent);
882
+ background: color-mix(in srgb, currentColor var(--kine-interaction-active-intensity), transparent);
883
883
  }
884
884
 
885
885
  /* === 禁用状态 === */
@@ -989,7 +989,7 @@
989
989
  max-height: 85vh;
990
990
  object-fit: contain;
991
991
  border-radius: var(--kine-radius-xs);
992
- box-shadow: 0 0 40px color-mix(in srgb, var(--kine-color-accent-default) 20%, transparent);
992
+ box-shadow: 0 0 40px color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-active-intensity), transparent);
993
993
  transition: transform var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
994
994
  user-select: none;
995
995
  }
@@ -1024,18 +1024,18 @@
1024
1024
  font-size: 16px;
1025
1025
  cursor: pointer;
1026
1026
  transition:
1027
- color var(--kine-motion-duration-fast) var(--kine-motion-easing-default),
1028
- background var(--kine-motion-duration-fast) var(--kine-motion-easing-default);
1027
+ color var(--kine-interaction-transition-duration) var(--kine-motion-easing-default),
1028
+ background var(--kine-interaction-transition-duration) var(--kine-motion-easing-default);
1029
1029
  }
1030
1030
 
1031
1031
  .k-image-preview-btn:hover {
1032
1032
  color: var(--kine-color-text-primary);
1033
- background: color-mix(in srgb, var(--kine-color-accent-default) 15%, transparent);
1033
+ background: color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-hover-intensity), transparent);
1034
1034
  }
1035
1035
 
1036
1036
  .k-image-preview-close:hover {
1037
1037
  color: var(--kine-color-semantic-error);
1038
- background: color-mix(in srgb, var(--kine-color-semantic-error) 15%, transparent);
1038
+ background: color-mix(in srgb, var(--kine-color-semantic-error) var(--kine-interaction-hover-intensity), transparent);
1039
1039
  }
1040
1040
 
1041
1041
  /* 当前缩放比例显示 */
@@ -1063,8 +1063,8 @@
1063
1063
  font-size: 26px;
1064
1064
  cursor: pointer;
1065
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);
1066
+ background var(--kine-interaction-transition-duration) var(--kine-motion-easing-default),
1067
+ border-color var(--kine-interaction-transition-duration) var(--kine-motion-easing-default);
1068
1068
  }
1069
1069
 
1070
1070
  .k-image-preview-arrow:hover {
@@ -1126,7 +1126,7 @@
1126
1126
 
1127
1127
  .k-input:focus {
1128
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);
1129
+ box-shadow: 0 0 var(--kine-shadow-glow-radius) color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-focus-glow), transparent);
1130
1130
  }
1131
1131
 
1132
1132
  .k-input-disabled {
@@ -1222,7 +1222,7 @@ textarea.k-input {
1222
1222
 
1223
1223
  .k-select-trigger:focus-within {
1224
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);
1225
+ box-shadow: 0 0 var(--kine-shadow-glow-radius) color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-focus-glow), transparent);
1226
1226
  }
1227
1227
 
1228
1228
  .k-select-trigger-multiple {
@@ -1340,16 +1340,16 @@ textarea.k-input {
1340
1340
  }
1341
1341
 
1342
1342
  .k-select-dropdown .m-option:hover {
1343
- background-color: var(--kine-color-bg-hover);
1343
+ background-color: var(--kine-color-neutral-3);
1344
1344
  }
1345
1345
 
1346
1346
  .k-select-dropdown .m-option-selected {
1347
1347
  color: var(--kine-color-accent-default);
1348
- background-color: color-mix(in srgb, var(--kine-color-accent-default) 10%, transparent);
1348
+ background-color: var(--kine-color-accent-light);
1349
1349
  }
1350
1350
 
1351
1351
  .k-select-dropdown .m-option-selected:hover {
1352
- background-color: color-mix(in srgb, var(--kine-color-accent-default) 16%, transparent);
1352
+ background-color: color-mix(in srgb, var(--kine-color-accent-default) var(--kine-interaction-hover-intensity), transparent);
1353
1353
  }
1354
1354
 
1355
1355
  .k-select-dropdown .m-option-disabled {
package/dist/crud.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Comment, Fragment, Teleport, cloneVNode, computed, createApp, createTextVNode, createVNode, defineComponent, h, inject, isRef, mergeProps, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, reactive, ref, resolveComponent, shallowRef, toRef, triggerRef, watch } from "vue";
2
- import { QueryClient, VueQueryPlugin, useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
3
2
  import { createPinia, defineStore } from "pinia";
3
+ import { QueryClient, VueQueryPlugin, useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
4
4
  import { useRoute, useRouter } from "vue-router";
5
5
  //#region \0rolldown/runtime.js
6
6
  var __create = Object.create;
@@ -6814,6 +6814,74 @@ var ImageCore = {
6814
6814
  useImage
6815
6815
  };
6816
6816
  //#endregion
6817
+ //#region ../core/compositions/overlay/useOverlayStack.ts
6818
+ /**
6819
+ * @description overlay stack manager — unified z-index and ESC handling for all popups
6820
+ * @author kine-design
6821
+ * @date 2026/5/22 00:00
6822
+ * @version v1.0.0
6823
+ *
6824
+ * 江湖的业务千篇一律,复杂的代码好几百行。
6825
+ */
6826
+ var Z_INDEX_BASE = 100;
6827
+ defineStore("overlayStack", () => {
6828
+ const overlayStack = ref([]);
6829
+ const isEmpty = computed(() => overlayStack.value.length === 0);
6830
+ const topItem = computed(() => overlayStack.value.length > 0 ? overlayStack.value[overlayStack.value.length - 1] : void 0);
6831
+ const push = (item) => {
6832
+ const zIndex = overlayStack.value.length + Z_INDEX_BASE;
6833
+ const entry = {
6834
+ ...item,
6835
+ zIndex
6836
+ };
6837
+ overlayStack.value.push(entry);
6838
+ return entry;
6839
+ };
6840
+ const pop = () => {
6841
+ const item = overlayStack.value.pop();
6842
+ if (item) item.close();
6843
+ return item;
6844
+ };
6845
+ const remove = (id) => {
6846
+ const index = overlayStack.value.findIndex((item) => item.id === id);
6847
+ if (index !== -1) {
6848
+ overlayStack.value.splice(index, 1);
6849
+ recalculateZIndices();
6850
+ }
6851
+ };
6852
+ const recalculateZIndices = () => {
6853
+ overlayStack.value.forEach((item, index) => {
6854
+ item.zIndex = index + Z_INDEX_BASE;
6855
+ });
6856
+ };
6857
+ const handleEsc = (e) => {
6858
+ if (e.key === "Escape" && !isEmpty.value) pop();
6859
+ };
6860
+ let listenerAttached = false;
6861
+ const attachEscListener = () => {
6862
+ if (!listenerAttached) {
6863
+ document.addEventListener("keydown", handleEsc);
6864
+ listenerAttached = true;
6865
+ }
6866
+ };
6867
+ const detachEscListener = () => {
6868
+ if (listenerAttached) {
6869
+ document.removeEventListener("keydown", handleEsc);
6870
+ listenerAttached = false;
6871
+ }
6872
+ };
6873
+ return {
6874
+ overlayStack,
6875
+ isEmpty,
6876
+ topItem,
6877
+ push,
6878
+ pop,
6879
+ remove,
6880
+ attachEscListener,
6881
+ detachEscListener
6882
+ };
6883
+ });
6884
+ //#endregion
6817
6885
  //#region ../core/locale/index.ts
6818
6886
  /**
6819
6887
  * @description kine-design locale entry — built-in language packs + types.
@@ -7467,7 +7535,10 @@ var KTable_default = kDefineComponent((_props, { slots }) => {
7467
7535
  });
7468
7536
  const style = p.height ? { height: p.height } : void 0;
7469
7537
  const { thead, tbody } = initTable({
7470
- empty: createVNode("tbody", { "class": "m-table-empty k-table-empty" }, [createVNode("tr", null, [createVNode("th", { "colspan": columns.length }, [slots.empty?.() ?? t.value.common.noData])])]),
7538
+ empty: createVNode("tbody", {
7539
+ "class": "m-table-empty k-table-empty",
7540
+ "data-k": "state:tableEmpty"
7541
+ }, [createVNode("tr", null, [createVNode("th", { "colspan": columns.length }, [slots.empty?.() ?? t.value.common.noData])])]),
7471
7542
  tbodyTr: ({ data, param, slot, style: cellStyle, slotInfo }) => createVNode("td", {
7472
7543
  "style": cellStyle,
7473
7544
  "data-k": testAnchor?.value && param ? `col:${param}` : void 0,
@@ -7491,8 +7562,14 @@ var KTable_default = kDefineComponent((_props, { slots }) => {
7491
7562
  ],
7492
7563
  "style": cellStyle
7493
7564
  }, [slot ? slot() : label]),
7494
- thead: (ths) => createVNode("thead", { "class": "m-thead k-thead" }, [createVNode("tr", { "class": "m-tr k-tr" }, [ths])]),
7495
- tbody: (trs) => createVNode("tbody", { "class": "m-tbody k-tbody" }, [trs]),
7565
+ thead: (ths) => createVNode("thead", {
7566
+ "class": "m-thead k-thead",
7567
+ "data-k": "region:tableHead"
7568
+ }, [createVNode("tr", { "class": "m-tr k-tr" }, [ths])]),
7569
+ tbody: (trs) => createVNode("tbody", {
7570
+ "class": "m-tbody k-tbody",
7571
+ "data-k": "region:tableBody"
7572
+ }, [trs]),
7496
7573
  tbodyTrs: (tds, i) => createVNode("tr", {
7497
7574
  "class": "m-tr k-tr",
7498
7575
  "key": i
@@ -7727,12 +7804,17 @@ var KSearchTable_default = /* @__PURE__ */ defineComponent({
7727
7804
  ctx.emit("update:page", page);
7728
7805
  };
7729
7806
  return () => createVNode("div", { "class": ["k-search-table", props.loading ? "k-search-table--loading" : ""] }, [
7730
- props.searchable && createVNode("div", { "class": "k-search-table-search" }, [createVNode("div", { "class": "k-search-table-search-form" }, [ctx.slots.search?.()]), createVNode("div", { "class": "k-search-table-search-actions" }, [createVNode(KButton_default, {
7807
+ props.searchable && createVNode("div", { "class": "k-search-table-search" }, [createVNode("div", { "class": "k-search-table-search-form" }, [ctx.slots.search?.()]), createVNode("div", {
7808
+ "class": "k-search-table-search-actions",
7809
+ "data-k": "action:searchActions"
7810
+ }, [createVNode(KButton_default, {
7731
7811
  "type": "primary",
7732
7812
  "text": t.value.searchTable.search,
7813
+ "data-k": "action:search",
7733
7814
  "onClick": onSearch
7734
7815
  }, null), createVNode(KButton_default, {
7735
7816
  "text": t.value.searchTable.reset,
7817
+ "data-k": "action:reset",
7736
7818
  "onClick": onReset
7737
7819
  }, null)])]),
7738
7820
  ctx.slots.toolbar && createVNode("div", { "class": "k-search-table-toolbar" }, [ctx.slots.toolbar()]),
@@ -9335,7 +9417,6 @@ function createCrudAppWithOptions(rootComponent, options) {
9335
9417
  options.router.beforeEach(guard);
9336
9418
  }
9337
9419
  }
9338
- if (options.router) app.use(options.router);
9339
9420
  setupCrud(app, options.query);
9340
9421
  if (options.request) {
9341
9422
  const requestOptions = { ...options.request };
@@ -9347,7 +9428,10 @@ function createCrudAppWithOptions(rootComponent, options) {
9347
9428
  if (options.error) createErrorHandler(app, options.error);
9348
9429
  const enhancedApp = Object.create(app);
9349
9430
  enhancedApp.mount = (rootContainer) => {
9350
- const doMount = () => app.mount(rootContainer);
9431
+ const doMount = () => {
9432
+ if (options.router) app.use(options.router);
9433
+ app.mount(rootContainer);
9434
+ };
9351
9435
  if (auth) auth.restore().finally(doMount);
9352
9436
  else doMount();
9353
9437
  return app;
@@ -9420,6 +9504,7 @@ function useCrudPage(config, tableBodyRef) {
9420
9504
  loading.value = true;
9421
9505
  try {
9422
9506
  const params = {
9507
+ ...config.defaultParams,
9423
9508
  page: page.value,
9424
9509
  pageSize: pageSize.value
9425
9510
  };
@@ -9571,6 +9656,7 @@ var KCrudPage_default = /* @__PURE__ */ defineComponent({
9571
9656
  if (!props.config.filters?.length) return null;
9572
9657
  return props.config.filters.map((f) => createVNode("div", {
9573
9658
  "class": "k-crud-page-filter-item",
9659
+ "data-k": `filter:${f.param}`,
9574
9660
  "key": f.param
9575
9661
  }, [createVNode("label", { "class": "k-crud-page-filter-label" }, [f.label]), f.type === "select" ? createVNode(KSelect_default, {
9576
9662
  "class": "k-crud-page-filter-control",
@@ -9593,6 +9679,7 @@ var KCrudPage_default = /* @__PURE__ */ defineComponent({
9593
9679
  };
9594
9680
  return () => createVNode("div", {
9595
9681
  "class": "k-crud-page",
9682
+ "data-k": "page:crudList",
9596
9683
  "ref": rootRef
9597
9684
  }, [createVNode(KPageHeader_default, { "title": props.config.title }, { extra: slots.headerExtra }), createVNode(KSearchTable_default, {
9598
9685
  "data": list.value,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kine-design/crud",
3
- "version": "0.0.1-beta.25",
3
+ "version": "0.0.1-beta.26",
4
4
  "type": "module",
5
5
  "main": "./dist/crud.js",
6
6
  "types": "./dist/index.d.ts",
@@ -12,8 +12,8 @@
12
12
  "pinia": "^3.0.3",
13
13
  "vue": "^3.5.30",
14
14
  "vue-router": "^5.0.3",
15
- "@kine-design/core": "0.0.1-beta.11",
16
- "kine-ui": "0.0.1-beta.21"
15
+ "@kine-design/core": "0.0.1-beta.12",
16
+ "kine-ui": "0.0.1-beta.22"
17
17
  },
18
18
  "publishConfig": {
19
19
  "access": "public",
package/setup.ts CHANGED
@@ -244,22 +244,15 @@ function createCrudAppWithOptions(
244
244
  }
245
245
  }
246
246
 
247
- // 2. Router(install 时触发初始导航,此时守卫已注册)
248
- if (options.router) {
249
- app.use(options.router as { install: (app: App) => void });
250
- }
251
-
252
- // 3. TanStack Query
247
+ // 2. TanStack Query
253
248
  setupCrud(app, options.query);
254
249
 
255
- // 4. Request
250
+ // 3. Request
256
251
  if (options.request) {
257
252
  const requestOptions: RequestOptions = { ...options.request };
258
- // 如果有 auth,自动注入 getToken
259
253
  if (auth && !requestOptions.getToken) {
260
254
  requestOptions.getToken = () => auth!.token.value;
261
255
  }
262
- // 如果有 auth,自动注入 onUnauthorized
263
256
  if (auth && !requestOptions.onUnauthorized) {
264
257
  requestOptions.onUnauthorized = options.auth?.onUnauthorized;
265
258
  }
@@ -267,15 +260,23 @@ function createCrudAppWithOptions(
267
260
  app.provide(REQUEST_CLIENT_KEY, client);
268
261
  }
269
262
 
270
- // 5. Error Handler
263
+ // 4. Error Handler
271
264
  if (options.error) {
272
265
  createErrorHandler(app, options.error);
273
266
  }
274
267
 
275
268
  // 返回增强的 app,mount 前先恢复 auth
269
+ // Router 安装延迟到 doMount:app.use(router) 会触发初始导航,
270
+ // 必须在 auth.restore() 完成(permissions 已加载)之后执行,否则
271
+ // authGuard 会在 permissions 为空时将受保护路由重定向到 /403。
276
272
  const enhancedApp: EnhancedApp = Object.create(app);
277
273
  enhancedApp.mount = (rootContainer: string | Element): App => {
278
- const doMount = () => app.mount(rootContainer);
274
+ const doMount = () => {
275
+ if (options.router) {
276
+ app.use(options.router as { install: (app: App) => void });
277
+ }
278
+ app.mount(rootContainer);
279
+ };
279
280
  if (auth) {
280
281
  auth.restore().finally(doMount);
281
282
  } else {