@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.
- package/.vlaude/last-session-id +1 -0
- package/components/crudPage/KCrudPage.tsx +178 -0
- package/components/crudPage/crudPage.css +64 -0
- package/components/crudPage/index.ts +10 -0
- package/components/editableTable/KEditableTable.tsx +281 -0
- package/components/editableTable/editableTable.css +268 -0
- package/components/editableTable/index.ts +10 -0
- package/components/formPage/KApprovalDialog.tsx +142 -0
- package/components/formPage/KFormCard.tsx +65 -0
- package/components/formPage/KFormPage.tsx +128 -0
- package/components/formPage/KMasterDetailPage.tsx +205 -0
- package/components/formPage/KStickyActionBar.tsx +33 -0
- package/components/formPage/formPage.css +629 -0
- package/components/formPage/index.ts +14 -0
- package/components/layout/KContent.tsx +20 -0
- package/components/layout/KHeader.tsx +37 -0
- package/components/layout/KLayout.tsx +82 -0
- package/components/layout/KSider.tsx +80 -0
- package/components/layout/index.ts +18 -0
- package/components/layout/layout.css +262 -0
- package/components/login/KLoginPage.tsx +129 -0
- package/components/login/index.ts +10 -0
- package/components/login/login.css +118 -0
- package/components/navMenu/KNavMenu.tsx +175 -0
- package/components/navMenu/index.ts +2 -0
- package/components/navMenu/navMenu.css +197 -0
- package/components/pageHeader/KPageHeader.tsx +85 -0
- package/components/pageHeader/index.ts +9 -0
- package/components/pageHeader/pageHeader.css +93 -0
- package/components/searchTable/KSearchTable.tsx +138 -0
- package/components/searchTable/index.ts +10 -0
- package/components/searchTable/searchTable.css +121 -0
- package/components/upload/KFileList.tsx +95 -0
- package/components/upload/KImageUpload.tsx +286 -0
- package/components/upload/KUpload.tsx +206 -0
- package/components/upload/index.ts +13 -0
- package/components/upload/types.ts +26 -0
- package/components/upload/upload.css +345 -0
- package/composables/auth/authGuard.ts +128 -0
- package/composables/auth/index.ts +23 -0
- package/composables/auth/types.ts +109 -0
- package/composables/auth/useAuth.ts +278 -0
- package/composables/auth/vCan.ts +95 -0
- package/composables/defineRepository.ts +224 -0
- package/composables/error/createErrorHandler.ts +46 -0
- package/composables/error/defaultFeedbackHandler.ts +76 -0
- package/composables/error/dispatchError.ts +70 -0
- package/composables/error/index.ts +32 -0
- package/composables/error/types.ts +57 -0
- package/composables/error/useErrorHandler.ts +41 -0
- package/composables/form/index.ts +18 -0
- package/composables/form/renderFormField.tsx +119 -0
- package/composables/form/types.ts +129 -0
- package/composables/form/useFormPage.ts +183 -0
- package/composables/index.ts +62 -0
- package/composables/page/index.ts +11 -0
- package/composables/page/types.ts +62 -0
- package/composables/page/useCrudPage.ts +88 -0
- package/composables/request/composables.ts +206 -0
- package/composables/request/controlGate.ts +143 -0
- package/composables/request/createRequest.ts +173 -0
- package/composables/request/index.ts +71 -0
- package/composables/request/orchestrator.ts +145 -0
- package/composables/request/requestBuilder.ts +418 -0
- package/composables/request/transport/fetchTransport.ts +79 -0
- package/composables/request/transport/xhrTransport.ts +100 -0
- package/composables/request/types.ts +226 -0
- package/composables/request/upload.ts +146 -0
- package/composables/router/createRouterGuard.ts +134 -0
- package/composables/router/defineCrudRoutes.ts +116 -0
- package/composables/router/index.ts +22 -0
- package/composables/router/types.ts +128 -0
- package/composables/router/useMenuFromRoutes.ts +109 -0
- package/composables/router/useTabStore.ts +183 -0
- package/composables/search/index.ts +11 -0
- package/composables/search/useAutoCompleteSearch.ts +161 -0
- package/composables/setupCrud.ts +43 -0
- package/composables/storage/createStorageAdapter.ts +72 -0
- package/composables/storage/index.ts +13 -0
- package/composables/storage/types.ts +30 -0
- package/composables/storage/useStorage.ts +108 -0
- package/composables/store/defineUserStore.ts +122 -0
- package/composables/store/index.ts +11 -0
- package/composables/types.ts +118 -0
- package/dist/components/crudPage/KCrudPage.d.ts +14 -0
- package/dist/components/crudPage/index.d.ts +9 -0
- package/dist/components/editableTable/KEditableTable.d.ts +146 -0
- package/dist/components/editableTable/index.d.ts +10 -0
- package/dist/components/formPage/KApprovalDialog.d.ts +99 -0
- package/dist/components/formPage/KFormCard.d.ts +49 -0
- package/dist/components/formPage/KFormPage.d.ts +14 -0
- package/dist/components/formPage/KMasterDetailPage.d.ts +14 -0
- package/dist/components/formPage/KStickyActionBar.d.ts +16 -0
- package/dist/components/formPage/index.d.ts +14 -0
- package/dist/components/layout/KLayout.d.ts +7 -4
- package/dist/composables/auth/useAuth.d.ts +5 -5
- package/dist/composables/error/types.d.ts +2 -1
- package/dist/composables/form/index.d.ts +12 -0
- package/dist/composables/form/renderFormField.d.ts +11 -0
- package/dist/composables/form/types.d.ts +104 -0
- package/dist/composables/form/useFormPage.d.ts +38 -0
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/page/index.d.ts +10 -0
- package/dist/composables/page/types.d.ts +61 -0
- package/dist/composables/page/useCrudPage.d.ts +14 -0
- package/dist/composables/request/createRequest.d.ts +2 -0
- package/dist/composables/request/requestBuilder.d.ts +2 -0
- package/dist/composables/search/index.d.ts +10 -0
- package/dist/composables/search/useAutoCompleteSearch.d.ts +50 -0
- package/dist/crud.css +2499 -663
- package/dist/crud.js +11512 -2910
- package/dist/index.d.ts +11 -0
- package/dist/setup.d.ts +2 -2
- package/index.ts +144 -0
- package/package.json +20 -19
- package/setup.ts +288 -0
- package/tsconfig.json +12 -0
- package/vite.config.build.ts +52 -0
package/dist/index.d.ts
CHANGED
|
@@ -8,10 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export * from './components/layout';
|
|
10
10
|
export { KSearchTable } from './components/searchTable';
|
|
11
|
+
export { KCrudPage } from './components/crudPage';
|
|
11
12
|
export { KLoginPage } from './components/login';
|
|
12
13
|
export type { LoginForm } from './components/login';
|
|
13
14
|
export { KPageHeader } from './components/pageHeader';
|
|
14
15
|
export { defineRepository } from './composables/defineRepository';
|
|
16
|
+
export { useCrudPage } from './composables/page';
|
|
17
|
+
export type { CrudPageConfig, CrudColumnConfig, CrudFilterConfig, StatusMapItem } from './composables/page';
|
|
15
18
|
export { setupCrud, createCrudApp, createQueryClient, useRequestClient, REQUEST_CLIENT_KEY } from './setup';
|
|
16
19
|
export type { CrudOptions, CrudAppOptions, EnhancedApp } from './setup';
|
|
17
20
|
export type { EntityId, ListParams, MutationOptions, Repository, RepositoryEndpoints, UseListReturn, UseDetailReturn, UseMutationReturn, } from './composables/types';
|
|
@@ -27,3 +30,11 @@ export { createRequest, createDefaultRequest, createStrictRequest, createPermiss
|
|
|
27
30
|
export type { RequestMethod, ControlPolicy, CachePolicy, RetryPolicy, Lifecycle, RequestConfig, WrappedResponse, NetworkError, UserFeedbackHandler, Transport, TransportRequest, TransportResponse, RequestOptions, RequestClient, RequestBuilderContext, OrchestratorNode, FailureStrategy, OrchestratorResult, UploadOptions, UploaderOptions, UploadHandle, Uploader, UsePollingReturn, BatchLoaderOptions, UseBatchLoaderReturn, } from './composables/request';
|
|
28
31
|
export { defineUserStore } from './composables/store';
|
|
29
32
|
export type { UserStoreOptions, UserStore, LoginResult } from './composables/store';
|
|
33
|
+
export { KFormCard, KStickyActionBar, KApprovalDialog, KFormPage, KMasterDetailPage } from './components/formPage';
|
|
34
|
+
export type { ApprovalType } from './components/formPage';
|
|
35
|
+
export { useFormPage } from './composables/form';
|
|
36
|
+
export type { FormFieldType, FormFieldConfig, FormPageConfig, DetailTableConfig, MasterDetailPageConfig, UseFormPageOptions, UseFormPageReturn, } from './composables/form';
|
|
37
|
+
export { KEditableTable } from './components/editableTable';
|
|
38
|
+
export type { EditableColumn, EditableTableRow } from './components/editableTable';
|
|
39
|
+
export { useAutoCompleteSearch } from './composables/search';
|
|
40
|
+
export type { AutoCompleteSearchOptions, AutoCompleteSearchReturn } from './composables/search';
|
package/dist/setup.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { App, Component } from 'vue';
|
|
1
|
+
import { App, Component, InjectionKey } from 'vue';
|
|
2
2
|
import { QueryClient, VueQueryPluginOptions } from '@tanstack/vue-query';
|
|
3
3
|
import { RequestOptions } from './composables/request/types';
|
|
4
4
|
import { RequestClient } from './composables/request/createRequest';
|
|
@@ -42,7 +42,7 @@ export interface CrudAppOptions {
|
|
|
42
42
|
query?: CrudOptions;
|
|
43
43
|
}
|
|
44
44
|
/** provide/inject 使用的唯一 symbol key */
|
|
45
|
-
export declare const REQUEST_CLIENT_KEY:
|
|
45
|
+
export declare const REQUEST_CLIENT_KEY: InjectionKey<RequestClient>;
|
|
46
46
|
/**
|
|
47
47
|
* 在组件中获取通过 createCrudApp 注入的 RequestClient。
|
|
48
48
|
*
|
package/index.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description @kine-design/crud 入口
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v0.0.1
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './components/layout';
|
|
11
|
+
export { KSearchTable } from './components/searchTable';
|
|
12
|
+
export { KCrudPage } from './components/crudPage';
|
|
13
|
+
export { KLoginPage } from './components/login';
|
|
14
|
+
export type { LoginForm } from './components/login';
|
|
15
|
+
export { KPageHeader } from './components/pageHeader';
|
|
16
|
+
export { defineRepository } from './composables/defineRepository';
|
|
17
|
+
export { useCrudPage } from './composables/page';
|
|
18
|
+
export type { CrudPageConfig, CrudColumnConfig, CrudFilterConfig, StatusMapItem } from './composables/page';
|
|
19
|
+
export { setupCrud, createCrudApp, createQueryClient, useRequestClient, REQUEST_CLIENT_KEY } from './setup';
|
|
20
|
+
export type { CrudOptions, CrudAppOptions, EnhancedApp } from './setup';
|
|
21
|
+
export type {
|
|
22
|
+
EntityId,
|
|
23
|
+
ListParams,
|
|
24
|
+
MutationOptions,
|
|
25
|
+
Repository,
|
|
26
|
+
RepositoryEndpoints,
|
|
27
|
+
UseListReturn,
|
|
28
|
+
UseDetailReturn,
|
|
29
|
+
UseMutationReturn,
|
|
30
|
+
} from './composables/types';
|
|
31
|
+
|
|
32
|
+
export { KNavMenu } from './components/navMenu';
|
|
33
|
+
export type { NavMenuData } from './components/navMenu';
|
|
34
|
+
|
|
35
|
+
export { KUpload, KImageUpload, KFileList } from './components/upload';
|
|
36
|
+
export type { UploadFile, UploadRequest } from './components/upload';
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
defineCrudRoutes,
|
|
40
|
+
createTabStore,
|
|
41
|
+
useTabStore,
|
|
42
|
+
useMenuFromRoutes,
|
|
43
|
+
createRouterGuard,
|
|
44
|
+
addTabFromRoute,
|
|
45
|
+
} from './composables/router';
|
|
46
|
+
export type {
|
|
47
|
+
CrudRouteMeta,
|
|
48
|
+
CrudRouteConfig,
|
|
49
|
+
CrudRouteRecord,
|
|
50
|
+
TabItem,
|
|
51
|
+
TabStore,
|
|
52
|
+
RouteLocationLike,
|
|
53
|
+
RouterGuard,
|
|
54
|
+
RouterGuardOptions,
|
|
55
|
+
} from './composables/router';
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
createAuth,
|
|
59
|
+
useAuth,
|
|
60
|
+
createAuthGuard,
|
|
61
|
+
createVCan,
|
|
62
|
+
} from './composables/auth';
|
|
63
|
+
export type {
|
|
64
|
+
Permission,
|
|
65
|
+
PermissionScope,
|
|
66
|
+
UserInfo,
|
|
67
|
+
AuthState,
|
|
68
|
+
AuthOptions,
|
|
69
|
+
AuthReturn,
|
|
70
|
+
AuthGuardOptions,
|
|
71
|
+
BeforeEachGuard,
|
|
72
|
+
CanBinding,
|
|
73
|
+
CanBindingObject,
|
|
74
|
+
} from './composables/auth';
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
createRequest,
|
|
78
|
+
createDefaultRequest,
|
|
79
|
+
createStrictRequest,
|
|
80
|
+
createPermissiveRequest,
|
|
81
|
+
createUploader,
|
|
82
|
+
useRequest,
|
|
83
|
+
usePolling,
|
|
84
|
+
useBatchLoader,
|
|
85
|
+
orchestrate,
|
|
86
|
+
createNode,
|
|
87
|
+
after,
|
|
88
|
+
BusinessError,
|
|
89
|
+
NetworkRequestError,
|
|
90
|
+
ControlGate,
|
|
91
|
+
FetchTransport,
|
|
92
|
+
XhrTransport,
|
|
93
|
+
RequestBuilder,
|
|
94
|
+
} from './composables/request';
|
|
95
|
+
export type {
|
|
96
|
+
RequestMethod,
|
|
97
|
+
ControlPolicy,
|
|
98
|
+
CachePolicy,
|
|
99
|
+
RetryPolicy,
|
|
100
|
+
Lifecycle,
|
|
101
|
+
RequestConfig,
|
|
102
|
+
WrappedResponse,
|
|
103
|
+
NetworkError,
|
|
104
|
+
UserFeedbackHandler,
|
|
105
|
+
Transport,
|
|
106
|
+
TransportRequest,
|
|
107
|
+
TransportResponse,
|
|
108
|
+
RequestOptions,
|
|
109
|
+
RequestClient,
|
|
110
|
+
RequestBuilderContext,
|
|
111
|
+
OrchestratorNode,
|
|
112
|
+
FailureStrategy,
|
|
113
|
+
OrchestratorResult,
|
|
114
|
+
UploadOptions,
|
|
115
|
+
UploaderOptions,
|
|
116
|
+
UploadHandle,
|
|
117
|
+
Uploader,
|
|
118
|
+
UsePollingReturn,
|
|
119
|
+
BatchLoaderOptions,
|
|
120
|
+
UseBatchLoaderReturn,
|
|
121
|
+
} from './composables/request';
|
|
122
|
+
|
|
123
|
+
export { defineUserStore } from './composables/store';
|
|
124
|
+
export type { UserStoreOptions, UserStore, LoginResult } from './composables/store';
|
|
125
|
+
|
|
126
|
+
export { KFormCard, KStickyActionBar, KApprovalDialog, KFormPage, KMasterDetailPage } from './components/formPage';
|
|
127
|
+
export type { ApprovalType } from './components/formPage';
|
|
128
|
+
|
|
129
|
+
export { useFormPage } from './composables/form';
|
|
130
|
+
export type {
|
|
131
|
+
FormFieldType,
|
|
132
|
+
FormFieldConfig,
|
|
133
|
+
FormPageConfig,
|
|
134
|
+
DetailTableConfig,
|
|
135
|
+
MasterDetailPageConfig,
|
|
136
|
+
UseFormPageOptions,
|
|
137
|
+
UseFormPageReturn,
|
|
138
|
+
} from './composables/form';
|
|
139
|
+
|
|
140
|
+
export { KEditableTable } from './components/editableTable';
|
|
141
|
+
export type { EditableColumn, EditableTableRow } from './components/editableTable';
|
|
142
|
+
|
|
143
|
+
export { useAutoCompleteSearch } from './composables/search';
|
|
144
|
+
export type { AutoCompleteSearchOptions, AutoCompleteSearchReturn } from './composables/search';
|
package/package.json
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kine-design/crud",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/crud.js",
|
|
6
|
-
"module": "./dist/crud.js",
|
|
7
6
|
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"import": {
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"default": "./dist/crud.js"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist"
|
|
18
|
-
],
|
|
19
7
|
"dependencies": {
|
|
20
|
-
"@
|
|
21
|
-
"@tanstack/vue-query": "^5.92.9",
|
|
22
|
-
"kine-ui": "0.0.1-beta.1",
|
|
8
|
+
"@tanstack/vue-query": "^5.92.10",
|
|
23
9
|
"pinia": "^3.0.3",
|
|
24
|
-
"vue": "^3.
|
|
25
|
-
"vue-router": "^
|
|
10
|
+
"vue": "^3.5.30",
|
|
11
|
+
"vue-router": "^5.0.3",
|
|
12
|
+
"@kine-design/core": "0.0.1-beta.6",
|
|
13
|
+
"kine-ui": "0.0.1-beta.12"
|
|
26
14
|
},
|
|
27
15
|
"publishConfig": {
|
|
28
|
-
"access": "public"
|
|
16
|
+
"access": "public",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
]
|
|
29
20
|
},
|
|
30
21
|
"scripts": {
|
|
31
22
|
"build": "vite build --config vite.config.build.ts"
|
|
23
|
+
},
|
|
24
|
+
"module": "./dist/crud.js",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/crud.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"./dist/crud.css": "./dist/crud.css"
|
|
32
33
|
}
|
|
33
34
|
}
|
package/setup.ts
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description CRUD 基础设施安装函数,在 main.ts 调用一次即可
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/2/26
|
|
5
|
+
* @version v0.0.1
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createApp as vueCreateApp, inject, type App, type Component, type InjectionKey } from 'vue';
|
|
11
|
+
import {
|
|
12
|
+
VueQueryPlugin,
|
|
13
|
+
QueryClient,
|
|
14
|
+
type VueQueryPluginOptions,
|
|
15
|
+
} from '@tanstack/vue-query';
|
|
16
|
+
import { createPinia } from 'pinia';
|
|
17
|
+
import type { AuthReturn } from './composables/auth/types';
|
|
18
|
+
import type { RequestOptions } from './composables/request/types';
|
|
19
|
+
import type { RequestClient } from './composables/request/createRequest';
|
|
20
|
+
import type { ErrorHandlerOptions } from './composables/error/types';
|
|
21
|
+
import { createAuth } from './composables/auth/useAuth';
|
|
22
|
+
import { createAuthGuard, type BeforeEachGuard } from './composables/auth/authGuard';
|
|
23
|
+
import { createVCan } from './composables/auth/vCan';
|
|
24
|
+
import { createRequest } from './composables/request/createRequest';
|
|
25
|
+
import { createErrorHandler } from './composables/error/createErrorHandler';
|
|
26
|
+
|
|
27
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
// 局部 vue-router 类型声明(不引入 vue-router 依赖)
|
|
29
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/** 最小化 Router 接口,只声明本文件用到的方法 */
|
|
32
|
+
interface RouterLike {
|
|
33
|
+
beforeEach(guard: BeforeEachGuard): void;
|
|
34
|
+
install(app: App): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
38
|
+
// CrudOptions — TanStack Query 配置
|
|
39
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
/** setupCrud / createCrudApp 的配置选项 */
|
|
42
|
+
export interface CrudOptions {
|
|
43
|
+
/**
|
|
44
|
+
* 自定义 QueryClient 实例。
|
|
45
|
+
* 不传时内部自动创建,使用合理的默认配置。
|
|
46
|
+
*/
|
|
47
|
+
queryClient?: QueryClient;
|
|
48
|
+
/** 透传给 VueQueryPlugin 的其余选项(queryClient 字段会被覆盖)。 */
|
|
49
|
+
vueQueryOptions?: Omit<VueQueryPluginOptions, 'queryClient'>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
53
|
+
// CrudAppOptions — 一站式初始化配置
|
|
54
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
/** createCrudApp 高级版本的完整配置 */
|
|
57
|
+
export interface CrudAppOptions {
|
|
58
|
+
/** Vue Router 实例 */
|
|
59
|
+
router?: RouterLike;
|
|
60
|
+
/** Auth 配置(传入后自动 createAuth + createAuthGuard + v-can 指令) */
|
|
61
|
+
auth?: {
|
|
62
|
+
fetchUser: () => Promise<{ user: import('./composables/auth/types').UserInfo; permissions: import('./composables/auth/types').Permission[]; token: string }>;
|
|
63
|
+
onUnauthorized?: () => void;
|
|
64
|
+
storage?: 'local' | 'session' | false;
|
|
65
|
+
loginPath?: string;
|
|
66
|
+
};
|
|
67
|
+
/** Request 配置(传入后自动 createRequest 并挂载到 app.provide) */
|
|
68
|
+
request?: RequestOptions;
|
|
69
|
+
/** 错误处理配置 */
|
|
70
|
+
error?: ErrorHandlerOptions;
|
|
71
|
+
/** TanStack Query 配置 */
|
|
72
|
+
query?: CrudOptions;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
76
|
+
// REQUEST_CLIENT_KEY + useRequestClient
|
|
77
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
/** provide/inject 使用的唯一 symbol key */
|
|
80
|
+
export const REQUEST_CLIENT_KEY: InjectionKey<RequestClient> = Symbol('kine-design:request');
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 在组件中获取通过 createCrudApp 注入的 RequestClient。
|
|
84
|
+
*
|
|
85
|
+
* @throws 若未在 createCrudApp 中配置 request 选项,抛出错误。
|
|
86
|
+
*/
|
|
87
|
+
export function useRequestClient(): RequestClient {
|
|
88
|
+
const client = inject(REQUEST_CLIENT_KEY);
|
|
89
|
+
if (!client) {
|
|
90
|
+
throw new Error('[useRequestClient] 未找到 RequestClient,请在 createCrudApp 中配置 request 选项。');
|
|
91
|
+
}
|
|
92
|
+
return client;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 创建一个预配置好的 QueryClient 实例(供高级场景直接使用)。
|
|
97
|
+
*/
|
|
98
|
+
export function createQueryClient(): QueryClient {
|
|
99
|
+
return new QueryClient({
|
|
100
|
+
defaultOptions: {
|
|
101
|
+
queries: {
|
|
102
|
+
// 窗口重新聚焦时不自动重新请求,业务层按需覆盖
|
|
103
|
+
refetchOnWindowFocus: false,
|
|
104
|
+
// 失败后重试 1 次
|
|
105
|
+
retry: 1,
|
|
106
|
+
// 数据保鲜时间 1 分钟
|
|
107
|
+
staleTime: 1000 * 60,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 在 Vue App 实例上安装 CRUD 基础设施(TanStack Query)。
|
|
115
|
+
* 推荐在 main.ts 调用一次,业务代码无需再关心 TanStack Query 安装细节。
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* // main.ts
|
|
120
|
+
* import { createApp } from 'vue';
|
|
121
|
+
* import { setupCrud } from '@kine-design/crud/setup';
|
|
122
|
+
*
|
|
123
|
+
* const app = createApp(App);
|
|
124
|
+
* setupCrud(app);
|
|
125
|
+
* app.mount('#app');
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export function setupCrud(app: App, options?: CrudOptions): void {
|
|
129
|
+
const queryClient = options?.queryClient ?? createQueryClient();
|
|
130
|
+
|
|
131
|
+
app.use(VueQueryPlugin, {
|
|
132
|
+
queryClient,
|
|
133
|
+
...options?.vueQueryOptions,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 自动安装 Pinia(若尚未安装)
|
|
137
|
+
installPinia(app);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 安装 Pinia 到 Vue App。
|
|
142
|
+
* 通过检查 app._context.provides 中是否已存在 Pinia 的 symbol 来避免重复安装。
|
|
143
|
+
*/
|
|
144
|
+
function installPinia(app: App): void {
|
|
145
|
+
// Pinia 安装后会在 provides 中注入一个 symbol key,
|
|
146
|
+
// 检查 provides 中是否已有 Pinia 实例(其 _a 属性指向 app)
|
|
147
|
+
const provides = (app as { _context: { provides: Record<symbol, unknown> } })._context.provides;
|
|
148
|
+
const hasPinia = Object.getOwnPropertySymbols(provides).some(sym => {
|
|
149
|
+
const val = provides[sym];
|
|
150
|
+
return val !== null && typeof val === 'object' && '_a' in (val as Record<string, unknown>);
|
|
151
|
+
});
|
|
152
|
+
if (!hasPinia) {
|
|
153
|
+
app.use(createPinia());
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
// EnhancedApp — mount 前自动恢复 auth 状态
|
|
159
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
/** 增强的 App 接口,mount 时自动恢复 auth 状态 */
|
|
162
|
+
export interface EnhancedApp extends Omit<App, 'mount'> {
|
|
163
|
+
mount(rootContainer: string | Element): App;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
167
|
+
// createCrudApp — 两种签名
|
|
168
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* createCrudApp — 链式风格的工厂函数,等同于 createApp + setupCrud。
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* // 基础用法
|
|
176
|
+
* createCrudApp(App).mount('#app');
|
|
177
|
+
*
|
|
178
|
+
* // 高级用法:一站式初始化
|
|
179
|
+
* createCrudApp(App, {
|
|
180
|
+
* router,
|
|
181
|
+
* auth: { fetchUser, onUnauthorized: () => router.push('/login'), storage: 'local' },
|
|
182
|
+
* request: { baseURL: '/api' },
|
|
183
|
+
* error: { unauthorizedStrategy: 'redirect' },
|
|
184
|
+
* }).mount('#app');
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export function createCrudApp(
|
|
188
|
+
rootComponent: Component,
|
|
189
|
+
rootProps?: Record<string, unknown>,
|
|
190
|
+
options?: CrudOptions,
|
|
191
|
+
): App;
|
|
192
|
+
export function createCrudApp(
|
|
193
|
+
rootComponent: Component,
|
|
194
|
+
options: CrudAppOptions,
|
|
195
|
+
): EnhancedApp;
|
|
196
|
+
export function createCrudApp(
|
|
197
|
+
rootComponent: Component,
|
|
198
|
+
rootPropsOrOptions?: Record<string, unknown> | CrudAppOptions,
|
|
199
|
+
crudOptions?: CrudOptions,
|
|
200
|
+
): App | EnhancedApp {
|
|
201
|
+
// 判断第二个参数是 CrudAppOptions 还是 rootProps
|
|
202
|
+
if (rootPropsOrOptions && isCrudAppOptions(rootPropsOrOptions)) {
|
|
203
|
+
return createCrudAppWithOptions(rootComponent, rootPropsOrOptions as CrudAppOptions);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 原有逻辑:createCrudApp(rootComponent, rootProps?, crudOptions?)
|
|
207
|
+
const app = vueCreateApp(rootComponent, rootPropsOrOptions as Record<string, unknown> | undefined);
|
|
208
|
+
setupCrud(app, crudOptions);
|
|
209
|
+
return app;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
213
|
+
// 内部:判断是否为 CrudAppOptions
|
|
214
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
function isCrudAppOptions(obj: Record<string, unknown> | CrudAppOptions): boolean {
|
|
217
|
+
return 'router' in obj || 'auth' in obj || 'request' in obj || 'error' in obj || 'query' in obj;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
221
|
+
// 内部:高级版本实现
|
|
222
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
function createCrudAppWithOptions(
|
|
225
|
+
rootComponent: Component,
|
|
226
|
+
options: CrudAppOptions,
|
|
227
|
+
): EnhancedApp {
|
|
228
|
+
const app = vueCreateApp(rootComponent);
|
|
229
|
+
|
|
230
|
+
// 1. Auth(必须在 Router 安装前创建,否则初始导航绕过守卫)
|
|
231
|
+
let auth: AuthReturn | undefined;
|
|
232
|
+
if (options.auth) {
|
|
233
|
+
auth = createAuth(app, {
|
|
234
|
+
fetchUser: options.auth.fetchUser,
|
|
235
|
+
onUnauthorized: options.auth.onUnauthorized,
|
|
236
|
+
storage: options.auth.storage,
|
|
237
|
+
});
|
|
238
|
+
// v-can 指令
|
|
239
|
+
app.directive('can', createVCan(auth));
|
|
240
|
+
// 路由守卫:注册在 router 实例上(不依赖 app.use),确保 install 触发初始导航时守卫已就位
|
|
241
|
+
if (options.router) {
|
|
242
|
+
const guard = createAuthGuard(auth, { loginPath: options.auth.loginPath ?? '/login' });
|
|
243
|
+
options.router.beforeEach(guard);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
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
|
|
253
|
+
setupCrud(app, options.query);
|
|
254
|
+
|
|
255
|
+
// 4. Request
|
|
256
|
+
if (options.request) {
|
|
257
|
+
const requestOptions: RequestOptions = { ...options.request };
|
|
258
|
+
// 如果有 auth,自动注入 getToken
|
|
259
|
+
if (auth && !requestOptions.getToken) {
|
|
260
|
+
requestOptions.getToken = () => auth!.token.value;
|
|
261
|
+
}
|
|
262
|
+
// 如果有 auth,自动注入 onUnauthorized
|
|
263
|
+
if (auth && !requestOptions.onUnauthorized) {
|
|
264
|
+
requestOptions.onUnauthorized = options.auth?.onUnauthorized;
|
|
265
|
+
}
|
|
266
|
+
const client = createRequest(requestOptions);
|
|
267
|
+
app.provide(REQUEST_CLIENT_KEY, client);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 5. Error Handler
|
|
271
|
+
if (options.error) {
|
|
272
|
+
createErrorHandler(app, options.error);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 返回增强的 app,mount 前先恢复 auth
|
|
276
|
+
const enhancedApp: EnhancedApp = Object.create(app);
|
|
277
|
+
enhancedApp.mount = (rootContainer: string | Element): App => {
|
|
278
|
+
const doMount = () => app.mount(rootContainer);
|
|
279
|
+
if (auth) {
|
|
280
|
+
auth.restore().finally(doMount);
|
|
281
|
+
} else {
|
|
282
|
+
doMount();
|
|
283
|
+
}
|
|
284
|
+
return app;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
return enhancedApp;
|
|
288
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description @kine-design/crud 构建配置
|
|
3
|
+
* @author 阿怪
|
|
4
|
+
* @date 2026/3/16
|
|
5
|
+
* @version v1.0.0
|
|
6
|
+
*
|
|
7
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
|
+
*/
|
|
9
|
+
import { defineConfig } from 'vite';
|
|
10
|
+
import Jsx from '@vitejs/plugin-vue-jsx';
|
|
11
|
+
import dts from 'vite-plugin-dts';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
resolve: {
|
|
16
|
+
alias: {
|
|
17
|
+
'@kine-design/core': path.resolve(__dirname, '../core'),
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
build: {
|
|
21
|
+
outDir: 'dist',
|
|
22
|
+
emptyOutDir: true,
|
|
23
|
+
minify: false,
|
|
24
|
+
lib: {
|
|
25
|
+
entry: path.resolve(__dirname, 'index.ts'),
|
|
26
|
+
name: 'KineCrud',
|
|
27
|
+
fileName: 'crud',
|
|
28
|
+
formats: ['es'],
|
|
29
|
+
},
|
|
30
|
+
rolldownOptions: {
|
|
31
|
+
external: [
|
|
32
|
+
'vue',
|
|
33
|
+
'vue-router',
|
|
34
|
+
'pinia',
|
|
35
|
+
'@tanstack/vue-query',
|
|
36
|
+
'kine-ui',
|
|
37
|
+
],
|
|
38
|
+
output: {
|
|
39
|
+
assetFileNames: 'crud.[ext]',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
plugins: [
|
|
44
|
+
Jsx(),
|
|
45
|
+
dts({
|
|
46
|
+
include: ['./**/*.ts', './**/*.tsx'],
|
|
47
|
+
exclude: ['node_modules'],
|
|
48
|
+
outDir: 'dist',
|
|
49
|
+
tsconfigPath: './tsconfig.json',
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
});
|