@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
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @description 命令式 Storage 适配器,供 Auth 等模块做持久化
3
+ * @author 阿怪
4
+ * @date 2026/3/15
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ import type { StorageType } from './types';
11
+
12
+ // ────────────────────────────────────────────────────────────────────────────
13
+ // StorageAdapter 接口
14
+ // ────────────────────────────────────────────────────────────────────────────
15
+
16
+ export interface StorageAdapter {
17
+ /** 读取并反序列化,key 不存在时返回 null */
18
+ get<T>(key: string): T | null;
19
+ /** 序列化并写入 */
20
+ set<T>(key: string, value: T): void;
21
+ /** 移除指定 key */
22
+ remove(key: string): void;
23
+ }
24
+
25
+ // ────────────────────────────────────────────────────────────────────────────
26
+ // createStorageAdapter
27
+ // ────────────────────────────────────────────────────────────────────────────
28
+
29
+ /**
30
+ * 创建非响应式的命令式 Storage 适配器。
31
+ * 内部直接操作 localStorage / sessionStorage,JSON 序列化。
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const adapter = createStorageAdapter('local');
36
+ * adapter.set('user', { name: '阿怪' });
37
+ * const user = adapter.get<{ name: string }>('user');
38
+ * adapter.remove('user');
39
+ * ```
40
+ */
41
+ export function createStorageAdapter(storageType: StorageType): StorageAdapter {
42
+ function resolveStorage(): Storage | null {
43
+ if (typeof window === 'undefined') return null;
44
+ return storageType === 'local' ? window.localStorage : window.sessionStorage;
45
+ }
46
+
47
+ return {
48
+ get<T>(key: string): T | null {
49
+ const storage = resolveStorage();
50
+ if (!storage) return null;
51
+ const raw = storage.getItem(key);
52
+ if (raw === null) return null;
53
+ try {
54
+ return JSON.parse(raw) as T;
55
+ } catch {
56
+ return raw as T;
57
+ }
58
+ },
59
+
60
+ set<T>(key: string, value: T): void {
61
+ const storage = resolveStorage();
62
+ if (!storage) return;
63
+ storage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
64
+ },
65
+
66
+ remove(key: string): void {
67
+ const storage = resolveStorage();
68
+ if (!storage) return;
69
+ storage.removeItem(key);
70
+ },
71
+ };
72
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @description 响应式 Storage 模块统一导出
3
+ * @author 阿怪
4
+ * @date 2026/3/15
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ export { useStorage } from './useStorage';
11
+ export { createStorageAdapter } from './createStorageAdapter';
12
+ export type { StorageAdapter } from './createStorageAdapter';
13
+ export type { StorageType, StorageOptions, UseStorageReturn } from './types';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @description 响应式 Storage 模块类型定义
3
+ * @author 阿怪
4
+ * @date 2026/3/15
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ import type { Ref } from 'vue';
11
+
12
+ // ────────────────────────────────────────────────────────────────────────────
13
+ // Storage 类型
14
+ // ────────────────────────────────────────────────────────────────────────────
15
+
16
+ /** 存储类型:localStorage 或 sessionStorage */
17
+ export type StorageType = 'local' | 'session';
18
+
19
+ /** useStorage 配置项 */
20
+ export interface StorageOptions<T> {
21
+ /** 自定义序列化函数,默认 JSON.stringify */
22
+ serializer?: (value: T) => string;
23
+ /** 自定义反序列化函数,默认 JSON.parse */
24
+ deserializer?: (raw: string) => T;
25
+ /** 是否监听跨 tab 同步(仅 localStorage 有效),默认 true */
26
+ listenCrossTab?: boolean;
27
+ }
28
+
29
+ /** useStorage 返回值 */
30
+ export type UseStorageReturn<T> = Ref<T | null>;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @description 响应式 Storage composable,自动序列化与跨 tab 同步
3
+ * @author 阿怪
4
+ * @date 2026/3/15
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ import { ref, watch, onUnmounted, type Ref } from 'vue';
11
+ import type { StorageOptions, StorageType, UseStorageReturn } from './types';
12
+
13
+ // ────────────────────────────────────────────────────────────────────────────
14
+ // 内部辅助
15
+ // ────────────────────────────────────────────────────────────────────────────
16
+
17
+ /** 根据 StorageType 获取对应的 Web Storage 实例,SSR 环境返回 null */
18
+ function resolveStorage(storageType: StorageType): Storage | null {
19
+ if (typeof window === 'undefined') return null;
20
+ return storageType === 'local' ? window.localStorage : window.sessionStorage;
21
+ }
22
+
23
+ /** 默认序列化:string 直接返回,其余 JSON.stringify */
24
+ function defaultSerializer<T>(value: T): string {
25
+ return typeof value === 'string' ? value : JSON.stringify(value);
26
+ }
27
+
28
+ /** 默认反序列化:尝试 JSON.parse,失败则返回原始字符串 */
29
+ function defaultDeserializer<T>(raw: string): T {
30
+ try {
31
+ return JSON.parse(raw) as T;
32
+ } catch {
33
+ return raw as T;
34
+ }
35
+ }
36
+
37
+ // ────────────────────────────────────────────────────────────────────────────
38
+ // useStorage
39
+ // ────────────────────────────────────────────────────────────────────────────
40
+
41
+ /**
42
+ * 返回一个与 Web Storage 双向绑定的响应式 Ref。
43
+ *
44
+ * - 读取时从 storage 反序列化并缓存到内存
45
+ * - 写入时自动序列化并存入 storage,设为 null 时 removeItem
46
+ * - localStorage 默认监听 storage 事件实现跨 tab 同步
47
+ * - SSR 安全:服务端降级为纯内存 ref
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const token = useStorage<string>('auth-token');
52
+ * token.value = 'xxx'; // 自动写入 localStorage
53
+ * token.value = null; // 自动 removeItem
54
+ * ```
55
+ */
56
+ export function useStorage<T>(
57
+ key: string,
58
+ defaultValue?: T,
59
+ storageType: StorageType = 'local',
60
+ options: StorageOptions<T> = {},
61
+ ): UseStorageReturn<T> {
62
+ const storage = resolveStorage(storageType);
63
+ const serialize = options.serializer ?? defaultSerializer;
64
+ const deserialize = options.deserializer ?? defaultDeserializer;
65
+ const listenCrossTab = options.listenCrossTab ?? true;
66
+
67
+ // ── 初始化:从 storage 读取或使用默认值 ──────────────────────────────────
68
+
69
+ function readFromStorage(): T | null {
70
+ if (!storage) return defaultValue ?? null;
71
+ const raw = storage.getItem(key);
72
+ if (raw === null) return defaultValue ?? null;
73
+ return deserialize(raw);
74
+ }
75
+
76
+ const data: Ref<T | null> = ref(readFromStorage()) as Ref<T | null>;
77
+
78
+ // ── watch:值变化时写入 storage ────────────────────────────────────────
79
+
80
+ watch(data, (newValue) => {
81
+ if (!storage) return;
82
+ if (newValue === null || newValue === undefined) {
83
+ storage.removeItem(key);
84
+ } else {
85
+ storage.setItem(key, serialize(newValue));
86
+ }
87
+ }, { deep: true });
88
+
89
+ // ── 跨 tab 同步(仅 localStorage) ────────────────────────────────────
90
+
91
+ let onStorageChange: ((e: StorageEvent) => void) | null = null;
92
+
93
+ if (storage && storageType === 'local' && listenCrossTab && typeof window !== 'undefined') {
94
+ onStorageChange = (e: StorageEvent) => {
95
+ if (e.key !== key || e.storageArea !== storage) return;
96
+ data.value = e.newValue === null ? (defaultValue ?? null) : deserialize(e.newValue);
97
+ };
98
+ window.addEventListener('storage', onStorageChange);
99
+
100
+ onUnmounted(() => {
101
+ if (onStorageChange) {
102
+ window.removeEventListener('storage', onStorageChange);
103
+ }
104
+ });
105
+ }
106
+
107
+ return data;
108
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @description 用户 Store 工厂,基于 Pinia + Auth 实现登录/登出/权限管理
3
+ * @author 阿怪
4
+ * @date 2026/3/15
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ import { computed } from 'vue';
11
+ import { defineStore } from 'pinia';
12
+ import { useAuth } from '../auth/useAuth';
13
+ import type { Permission, PermissionScope, UserInfo } from '../auth/types';
14
+
15
+ // ────────────────────────────────────────────────────────────────────────────
16
+ // 类型定义
17
+ // ────────────────────────────────────────────────────────────────────────────
18
+
19
+ /** loginApi 返回的登录结果 */
20
+ export interface LoginResult {
21
+ user: UserInfo;
22
+ permissions: Permission[];
23
+ token: string;
24
+ }
25
+
26
+ /** defineUserStore 的配置选项 */
27
+ export interface UserStoreOptions {
28
+ /** 登录 API 调用 */
29
+ loginApi: (credentials: { account: string; password: string }) => Promise<LoginResult>;
30
+ /** 登录成功后的回调(通常用于跳转首页) */
31
+ onLoginSuccess?: () => void;
32
+ /** 登出后的回调(通常用于跳转登录页) */
33
+ onLogoutSuccess?: () => void;
34
+ }
35
+
36
+ /** defineUserStore 返回的 store 实例类型(Pinia 会自动解包 ComputedRef) */
37
+ export interface UserStore {
38
+ /** 当前用户 */
39
+ readonly user: UserInfo | null;
40
+ /** 是否已登录 */
41
+ readonly isLoggedIn: boolean;
42
+ /** 当前 token */
43
+ readonly token: string | null;
44
+ /** 权限列表 */
45
+ readonly permissions: Permission[];
46
+ /** 权限检查 */
47
+ can: (resource: string, action: string, scope?: PermissionScope) => boolean;
48
+ /** 完整登录流程:调 loginApi → auth.loginWith() → 持久化 → onLoginSuccess */
49
+ login: (account: string, password: string) => Promise<void>;
50
+ /** 登出:auth.logout() → onLogoutSuccess */
51
+ logout: () => void;
52
+ /** 启动时恢复状态:从 storage 恢复 → fetchUser 验证 */
53
+ initUser: () => Promise<void>;
54
+ }
55
+
56
+ // ────────────────────────────────────────────────────────────────────────────
57
+ // defineUserStore — 工厂函数
58
+ // ────────────────────────────────────────────────────────────────────────────
59
+
60
+ /**
61
+ * 创建用户 Store 的工厂函数。
62
+ * 返回一个 Pinia useStore 函数,调用时返回 UserStore 实例。
63
+ *
64
+ * 内部消费 useAuth() 获取底层 auth 状态,所有数据源于 auth 的 reactive state,
65
+ * Pinia store 仅作为组合层,不重复持有状态。
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // stores/user.ts
70
+ * import { defineUserStore } from '@kine-design/crud';
71
+ *
72
+ * export const useUserStore = defineUserStore({
73
+ * loginApi: (creds) => http.post('/api/login', creds),
74
+ * onLoginSuccess: () => router.push('/'),
75
+ * onLogoutSuccess: () => router.push('/login'),
76
+ * });
77
+ *
78
+ * // 组件中
79
+ * const userStore = useUserStore();
80
+ * await userStore.login('admin', '123456');
81
+ * ```
82
+ */
83
+ export function defineUserStore(options: UserStoreOptions): () => UserStore {
84
+ const { loginApi, onLoginSuccess, onLogoutSuccess } = options;
85
+
86
+ const useStore = defineStore('kine-user', () => {
87
+ const auth = useAuth();
88
+
89
+ // ── 来自 auth 的计算属性 ─────────────────────────────────────────────
90
+ const user = computed(() => auth.user.value);
91
+ const isLoggedIn = computed(() => auth.isAuthenticated.value);
92
+ const token = computed(() => auth.token.value);
93
+ const permissions = computed(() => auth.permissions.value);
94
+
95
+ // ── 权限检查(直接委托 auth) ────────────────────────────────────────
96
+ function can(resource: string, action: string, scope?: PermissionScope): boolean {
97
+ return auth.can(resource, action, scope);
98
+ }
99
+
100
+ // ── 登录:调 loginApi → 注入 auth → 回调 ────────────────────────────
101
+ async function login(account: string, password: string): Promise<void> {
102
+ const result = await loginApi({ account, password });
103
+ auth.loginWith(result);
104
+ onLoginSuccess?.();
105
+ }
106
+
107
+ // ── 登出:清除 auth → 回调 ──────────────────────────────────────────
108
+ function logout(): void {
109
+ auth.logout();
110
+ onLogoutSuccess?.();
111
+ }
112
+
113
+ // ── 初始化:从 storage 恢复 auth 状态 ────────────────────────────────
114
+ async function initUser(): Promise<void> {
115
+ await auth.restore();
116
+ }
117
+
118
+ return { user, isLoggedIn, token, permissions, can, login, logout, initUser };
119
+ });
120
+
121
+ return useStore as () => UserStore;
122
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @description store 模块 barrel export
3
+ * @author 阿怪
4
+ * @date 2026/3/15
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ export { defineUserStore } from './defineUserStore';
11
+ export type { UserStoreOptions, UserStore, LoginResult } from './defineUserStore';
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @description defineRepository 类型定义
3
+ * @author 阿怪
4
+ * @date 2026/2/26
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ import type { MaybeRef } from 'vue';
11
+
12
+ // ────────────────────────────────────────────────────────────────────────────
13
+ // 基础类型
14
+ // ────────────────────────────────────────────────────────────────────────────
15
+
16
+ /** 通用列表请求参数 */
17
+ export type ListParams = Record<string, unknown>;
18
+
19
+ /** 通用 ID 类型 */
20
+ export type EntityId = string | number;
21
+
22
+ // ────────────────────────────────────────────────────────────────────────────
23
+ // Endpoint 定义 — 业务层传入的原始 API 函数
24
+ // ────────────────────────────────────────────────────────────────────────────
25
+
26
+ export interface RepositoryEndpoints<
27
+ TList,
28
+ TDetail,
29
+ TCreateInput,
30
+ TCreateOutput,
31
+ TUpdateInput,
32
+ TUpdateOutput,
33
+ > {
34
+ /** 列表查询 */
35
+ list?: (params: ListParams) => Promise<TList>;
36
+ /** 单条详情查询 */
37
+ detail?: (id: EntityId) => Promise<TDetail>;
38
+ /** 创建 */
39
+ create?: (data: TCreateInput) => Promise<TCreateOutput>;
40
+ /** 更新 */
41
+ update?: (id: EntityId, data: TUpdateInput) => Promise<TUpdateOutput>;
42
+ /** 删除 */
43
+ remove?: (id: EntityId) => Promise<void>;
44
+ }
45
+
46
+ // ────────────────────────────────────────────────────────────────────────────
47
+ // Mutation 选项
48
+ // ────────────────────────────────────────────────────────────────────────────
49
+
50
+ /** mutation 共用选项 */
51
+ export interface MutationOptions {
52
+ /**
53
+ * 跨领域缓存失效声明。
54
+ * mutation 成功后除自身领域外,还会额外失效这些领域的所有 query。
55
+ */
56
+ invalidates?: string[];
57
+ }
58
+
59
+ // ────────────────────────────────────────────────────────────────────────────
60
+ // useList / useDetail 返回类型(透传 TanStack 的核心字段)
61
+ // ────────────────────────────────────────────────────────────────────────────
62
+
63
+ /**
64
+ * useList 返回值(只暴露业务层常用字段,屏蔽 TanStack 底层细节)。
65
+ * 需要更多字段时可在此扩展。
66
+ */
67
+ export interface UseListReturn<TData> {
68
+ data: import('vue').ComputedRef<TData | undefined>;
69
+ isLoading: import('vue').ComputedRef<boolean>;
70
+ isFetching: import('vue').ComputedRef<boolean>;
71
+ isError: import('vue').ComputedRef<boolean>;
72
+ error: import('vue').ComputedRef<Error | null>;
73
+ refetch: () => void;
74
+ }
75
+
76
+ /** useDetail 返回值 */
77
+ export interface UseDetailReturn<TData> {
78
+ data: import('vue').ComputedRef<TData | undefined>;
79
+ isLoading: import('vue').ComputedRef<boolean>;
80
+ isFetching: import('vue').ComputedRef<boolean>;
81
+ isError: import('vue').ComputedRef<boolean>;
82
+ error: import('vue').ComputedRef<Error | null>;
83
+ refetch: () => void;
84
+ }
85
+
86
+ /** useMutation 返回值(create / update / remove 共用) */
87
+ export interface UseMutationReturn<TVariables, TData> {
88
+ mutate: TVariables extends void
89
+ ? () => Promise<TData>
90
+ : (variables: TVariables) => Promise<TData>;
91
+ isPending: import('vue').ComputedRef<boolean>;
92
+ isError: import('vue').ComputedRef<boolean>;
93
+ error: import('vue').ComputedRef<Error | null>;
94
+ }
95
+
96
+ // ────────────────────────────────────────────────────────────────────────────
97
+ // Repository 实例接口
98
+ // ────────────────────────────────────────────────────────────────────────────
99
+
100
+ export interface Repository<
101
+ TList,
102
+ TDetail,
103
+ TCreateInput,
104
+ TCreateOutput,
105
+ TUpdateInput,
106
+ TUpdateOutput,
107
+ > {
108
+ /** 列表 query hook */
109
+ useList: (params?: MaybeRef<ListParams>) => UseListReturn<TList>;
110
+ /** 详情 query hook */
111
+ useDetail: (id: MaybeRef<EntityId>) => UseDetailReturn<TDetail>;
112
+ /** 创建 mutation hook */
113
+ useCreate: (options?: MutationOptions) => UseMutationReturn<TCreateInput, TCreateOutput>;
114
+ /** 更新 mutation hook */
115
+ useUpdate: (options?: MutationOptions) => UseMutationReturn<{ id: EntityId; data: TUpdateInput }, TUpdateOutput>;
116
+ /** 删除 mutation hook */
117
+ useRemove: (options?: MutationOptions) => UseMutationReturn<EntityId, void>;
118
+ }
@@ -0,0 +1,14 @@
1
+ import { PropType } from 'vue';
2
+ import { CrudPageConfig } from '../../composables/page/types';
3
+ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
4
+ config: {
5
+ type: PropType<CrudPageConfig>;
6
+ required: true;
7
+ };
8
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
9
+ config: {
10
+ type: PropType<CrudPageConfig>;
11
+ required: true;
12
+ };
13
+ }>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
14
+ export default _default;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @description KCrudPage barrel export
3
+ * @author 阿怪
4
+ * @date 2026/3/22
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ export { default as KCrudPage } from './KCrudPage';
@@ -0,0 +1,146 @@
1
+ import { PropType } from 'vue';
2
+ export interface EditableColumn {
3
+ /** 字段名 */
4
+ param: string;
5
+ /** 列标题 */
6
+ label: string;
7
+ /** 列宽 */
8
+ width?: string;
9
+ /** 输入类型 */
10
+ editType?: 'text' | 'number' | 'select' | 'search' | 'readonly';
11
+ /** select 类型的选项 */
12
+ options?: Array<{
13
+ label: string;
14
+ value: string | number;
15
+ }>;
16
+ /** 对齐方式 */
17
+ align?: 'left' | 'center' | 'right';
18
+ /** 是否在汇总行中求和 */
19
+ summary?: boolean;
20
+ /** 汇总行格式化 */
21
+ summaryFormat?: (sum: number) => string;
22
+ }
23
+ export interface EditableTableRow {
24
+ /** 行唯一标识 */
25
+ _id: string | number;
26
+ /** 行数据 */
27
+ [key: string]: unknown;
28
+ }
29
+ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
30
+ /** 列定义 */
31
+ columns: {
32
+ type: PropType<EditableColumn[]>;
33
+ required: true;
34
+ };
35
+ /** 行数据(v-model) */
36
+ modelValue: {
37
+ type: PropType<EditableTableRow[]>;
38
+ default: () => never[];
39
+ };
40
+ /** 标题 */
41
+ title: {
42
+ type: StringConstructor;
43
+ default: string;
44
+ };
45
+ /** 是否显示序号列 */
46
+ showIndex: {
47
+ type: BooleanConstructor;
48
+ default: boolean;
49
+ };
50
+ /** 是否显示操作列 */
51
+ showActions: {
52
+ type: BooleanConstructor;
53
+ default: boolean;
54
+ };
55
+ /** 是否显示汇总行 */
56
+ showSummary: {
57
+ type: BooleanConstructor;
58
+ default: boolean;
59
+ };
60
+ /** 汇总行标签 */
61
+ summaryLabel: {
62
+ type: StringConstructor;
63
+ default: string;
64
+ };
65
+ /** 新增行按钮文本 */
66
+ addText: {
67
+ type: StringConstructor;
68
+ default: string;
69
+ };
70
+ /** 是否可新增 */
71
+ addable: {
72
+ type: BooleanConstructor;
73
+ default: boolean;
74
+ };
75
+ /** 币种前缀(用于金额汇总展示) */
76
+ currencyPrefix: {
77
+ type: StringConstructor;
78
+ default: string;
79
+ };
80
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("add" | "update:modelValue" | "remove")[], "add" | "update:modelValue" | "remove", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
81
+ /** 列定义 */
82
+ columns: {
83
+ type: PropType<EditableColumn[]>;
84
+ required: true;
85
+ };
86
+ /** 行数据(v-model) */
87
+ modelValue: {
88
+ type: PropType<EditableTableRow[]>;
89
+ default: () => never[];
90
+ };
91
+ /** 标题 */
92
+ title: {
93
+ type: StringConstructor;
94
+ default: string;
95
+ };
96
+ /** 是否显示序号列 */
97
+ showIndex: {
98
+ type: BooleanConstructor;
99
+ default: boolean;
100
+ };
101
+ /** 是否显示操作列 */
102
+ showActions: {
103
+ type: BooleanConstructor;
104
+ default: boolean;
105
+ };
106
+ /** 是否显示汇总行 */
107
+ showSummary: {
108
+ type: BooleanConstructor;
109
+ default: boolean;
110
+ };
111
+ /** 汇总行标签 */
112
+ summaryLabel: {
113
+ type: StringConstructor;
114
+ default: string;
115
+ };
116
+ /** 新增行按钮文本 */
117
+ addText: {
118
+ type: StringConstructor;
119
+ default: string;
120
+ };
121
+ /** 是否可新增 */
122
+ addable: {
123
+ type: BooleanConstructor;
124
+ default: boolean;
125
+ };
126
+ /** 币种前缀(用于金额汇总展示) */
127
+ currencyPrefix: {
128
+ type: StringConstructor;
129
+ default: string;
130
+ };
131
+ }>> & Readonly<{
132
+ "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
133
+ onRemove?: ((...args: any[]) => any) | undefined;
134
+ onAdd?: ((...args: any[]) => any) | undefined;
135
+ }>, {
136
+ title: string;
137
+ modelValue: EditableTableRow[];
138
+ showIndex: boolean;
139
+ showActions: boolean;
140
+ showSummary: boolean;
141
+ summaryLabel: string;
142
+ addText: string;
143
+ addable: boolean;
144
+ currencyPrefix: string;
145
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
146
+ export default _default;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @description editableTable barrel export
3
+ * @author 阿怪
4
+ * @date 2026/3/22
5
+ * @version v0.0.1
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ export { default as KEditableTable } from './KEditableTable';
10
+ export type { EditableColumn, EditableTableRow } from './KEditableTable';