@kine-design/crud 0.0.1-beta.24 → 0.0.1-beta.25
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 -1
- package/components/crudPage/KCrudPage.tsx +4 -2
- package/components/editableTable/KEditableTable.tsx +11 -9
- package/components/formPage/KApprovalDialog.tsx +24 -23
- package/components/formPage/KFormPage.tsx +10 -5
- package/components/formPage/KMasterDetailPage.tsx +8 -6
- package/components/layout/KSider.tsx +4 -1
- package/components/login/KLoginPage.tsx +8 -6
- package/components/searchTable/KSearchTable.tsx +5 -2
- package/components/upload/KFileList.tsx +16 -8
- package/components/upload/KImageUpload.tsx +4 -2
- package/components/upload/KUpload.tsx +4 -2
- package/composables/error/dispatchError.ts +9 -7
- package/composables/form/renderFormField.tsx +6 -4
- package/composables/form/useFormPage.ts +3 -1
- package/composables/request/requestBuilder.ts +8 -5
- package/composables/request/transport/xhrTransport.ts +3 -1
- package/composables/request/types.ts +8 -5
- package/composables/request/upload.ts +4 -2
- package/composables/router/defineCrudRoutes.ts +5 -3
- package/dist/components/editableTable/KEditableTable.d.ts +5 -5
- package/dist/crud.js +1189 -698
- package/package.json +3 -3
- package/setup.ts +11 -12
- package/tsconfig.json +12 -12
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
} from './types';
|
|
22
22
|
import { BusinessError, NetworkRequestError } from './types';
|
|
23
23
|
import { buildCacheKey, ControlGate } from './controlGate';
|
|
24
|
+
import { getActiveLocaleMessages } from '@kine-design/core';
|
|
24
25
|
|
|
25
26
|
// ────────────────────────────────────────────────────────────────────────────
|
|
26
27
|
// 内部:缓存存储
|
|
@@ -89,6 +90,7 @@ function toQueryString(params: Record<string, unknown>): string {
|
|
|
89
90
|
async function unwrapResponse<T>(
|
|
90
91
|
response: { status: number; statusText: string; headers: Record<string, string>; text(): Promise<string>; json<R>(): Promise<R> },
|
|
91
92
|
): Promise<T> {
|
|
93
|
+
const t = getActiveLocaleMessages();
|
|
92
94
|
// HTTP 错误
|
|
93
95
|
if (response.status < 200 || response.status >= 300) {
|
|
94
96
|
// 4xx/5xx:尝试解析 body,提取业务错误信息
|
|
@@ -98,7 +100,7 @@ async function unwrapResponse<T>(
|
|
|
98
100
|
try {
|
|
99
101
|
const json = await response.json<WrappedResponse<unknown>>();
|
|
100
102
|
if (isWrappedResponse(json) && !json.success) {
|
|
101
|
-
throw new BusinessError(json.message ||
|
|
103
|
+
throw new BusinessError(json.message || t.request.failedWithStatus(response.status));
|
|
102
104
|
}
|
|
103
105
|
} catch (e) {
|
|
104
106
|
if (e instanceof BusinessError) throw e;
|
|
@@ -121,7 +123,7 @@ async function unwrapResponse<T>(
|
|
|
121
123
|
// 检查是否为 WrappedResponse 结构
|
|
122
124
|
if (isWrappedResponse<T>(json)) {
|
|
123
125
|
if (!json.success) {
|
|
124
|
-
throw new BusinessError(json.message ||
|
|
126
|
+
throw new BusinessError(json.message || t.request.failed);
|
|
125
127
|
}
|
|
126
128
|
return json.data;
|
|
127
129
|
}
|
|
@@ -277,6 +279,7 @@ export class RequestBuilder {
|
|
|
277
279
|
// ── 执行 ────────────────────────────────────────────────────────────────
|
|
278
280
|
|
|
279
281
|
async execute<T>(): Promise<T> {
|
|
282
|
+
const t = getActiveLocaleMessages();
|
|
280
283
|
const { transport, controlGate, baseURL, defaultHeaders, getToken, onUnauthorized, responseInterceptor, registerAbort } = this.context;
|
|
281
284
|
|
|
282
285
|
// 构建完整 URL
|
|
@@ -364,7 +367,7 @@ export class RequestBuilder {
|
|
|
364
367
|
|
|
365
368
|
// 写操作成功后自动反馈
|
|
366
369
|
if (this.context.feedback && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(this.method)) {
|
|
367
|
-
this.context.feedback.showSuccess(
|
|
370
|
+
this.context.feedback.showSuccess(t.request.success);
|
|
368
371
|
}
|
|
369
372
|
|
|
370
373
|
return finalResult as T;
|
|
@@ -376,8 +379,8 @@ export class RequestBuilder {
|
|
|
376
379
|
// 写操作失败自动反馈错误信息
|
|
377
380
|
if (this.context.feedback) {
|
|
378
381
|
const msg = error instanceof BusinessError ? error.message
|
|
379
|
-
: error instanceof NetworkRequestError ?
|
|
380
|
-
:
|
|
382
|
+
: error instanceof NetworkRequestError ? t.request.failedWithMsg(error.message)
|
|
383
|
+
: t.request.opFailed;
|
|
381
384
|
this.context.feedback.showError(msg);
|
|
382
385
|
}
|
|
383
386
|
throw error;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { getActiveLocaleMessages } from '@kine-design/core';
|
|
10
11
|
import type { Transport, TransportRequest, TransportResponse } from '../types';
|
|
11
12
|
|
|
12
13
|
/** 解析 XHR 响应头字符串为 Record */
|
|
@@ -27,6 +28,7 @@ function parseResponseHeaders(rawHeaders: string): Record<string, string> {
|
|
|
27
28
|
|
|
28
29
|
export class XhrTransport implements Transport {
|
|
29
30
|
send(request: TransportRequest): Promise<TransportResponse> {
|
|
31
|
+
const t = getActiveLocaleMessages();
|
|
30
32
|
return new Promise((resolve, reject) => {
|
|
31
33
|
const xhr = new XMLHttpRequest();
|
|
32
34
|
|
|
@@ -83,7 +85,7 @@ export class XhrTransport implements Transport {
|
|
|
83
85
|
};
|
|
84
86
|
|
|
85
87
|
xhr.onerror = () => {
|
|
86
|
-
reject({ type: 'unknown' as const, error: new Error(
|
|
88
|
+
reject({ type: 'unknown' as const, error: new Error(t.request.networkError) });
|
|
87
89
|
};
|
|
88
90
|
|
|
89
91
|
xhr.ontimeout = () => {
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { getActiveLocaleMessages } from '@kine-design/core';
|
|
11
|
+
|
|
10
12
|
// ────────────────────────────────────────────────────────────────────────────
|
|
11
13
|
// 请求方法
|
|
12
14
|
// ────────────────────────────────────────────────────────────────────────────
|
|
@@ -111,13 +113,14 @@ export class NetworkRequestError extends Error {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
function networkErrorMessage(e: NetworkError): string {
|
|
116
|
+
const t = getActiveLocaleMessages();
|
|
114
117
|
switch (e.type) {
|
|
115
|
-
case 'invalidURL': return
|
|
116
|
-
case 'timeout': return
|
|
118
|
+
case 'invalidURL': return t.request.invalidUrl(e.url);
|
|
119
|
+
case 'timeout': return t.request.timeout;
|
|
117
120
|
case 'httpError': return `HTTP ${e.status} ${e.statusText}`;
|
|
118
|
-
case 'decodingFailed': return
|
|
119
|
-
case 'aborted': return
|
|
120
|
-
case 'unknown': return
|
|
121
|
+
case 'decodingFailed': return t.request.decodeFailed(e.reason);
|
|
122
|
+
case 'aborted': return t.request.canceled;
|
|
123
|
+
case 'unknown': return t.request.unknownError(String(e.error));
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
126
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { ref, type Ref } from 'vue';
|
|
11
|
+
import { getActiveLocaleMessages } from '@kine-design/core';
|
|
11
12
|
import type { UploaderOptions, UploadOptions, WrappedResponse } from './types';
|
|
12
13
|
import { BusinessError, NetworkRequestError } from './types';
|
|
13
14
|
import { XhrTransport } from './transport/xhrTransport';
|
|
@@ -55,6 +56,7 @@ export function createUploader(uploaderOptions: UploaderOptions = {}): Uploader
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
function doUpload<T>(formData: FormData, options: UploadOptions): UploadHandle<T> {
|
|
59
|
+
const t = getActiveLocaleMessages();
|
|
58
60
|
const progress = ref(0);
|
|
59
61
|
const abortController = new AbortController();
|
|
60
62
|
|
|
@@ -83,7 +85,7 @@ export function createUploader(uploaderOptions: UploaderOptions = {}): Uploader
|
|
|
83
85
|
if (contentType.includes('application/json')) {
|
|
84
86
|
const json = await response.json<WrappedResponse<T> | T>();
|
|
85
87
|
if (isWrappedResponse<T>(json)) {
|
|
86
|
-
if (!json.success) throw new BusinessError(json.message ||
|
|
88
|
+
if (!json.success) throw new BusinessError(json.message || t.request.uploadFailed);
|
|
87
89
|
return json.data;
|
|
88
90
|
}
|
|
89
91
|
return json as T;
|
|
@@ -94,7 +96,7 @@ export function createUploader(uploaderOptions: UploaderOptions = {}): Uploader
|
|
|
94
96
|
|
|
95
97
|
return {
|
|
96
98
|
progress,
|
|
97
|
-
abort: () => abortController.abort(
|
|
99
|
+
abort: () => abortController.abort(t.request.uploadCanceled),
|
|
98
100
|
promise,
|
|
99
101
|
};
|
|
100
102
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { getActiveLocaleMessages } from '@kine-design/core';
|
|
10
11
|
import type { CrudRouteConfig, CrudRouteRecord } from './types';
|
|
11
12
|
|
|
12
13
|
// ────────────────────────────────────────────────────────────────────────────
|
|
@@ -62,15 +63,16 @@ interface OpSpec {
|
|
|
62
63
|
export function defineCrudRoutes(config: CrudRouteConfig): CrudRouteRecord[] {
|
|
63
64
|
const { name, path, permission, title, icon } = config;
|
|
64
65
|
const resource = permission ?? name.toLowerCase();
|
|
66
|
+
const t = getActiveLocaleMessages();
|
|
65
67
|
|
|
66
68
|
// 规范化 basePath,确保以 / 开头、不以 / 结尾
|
|
67
69
|
const basePath = path.replace(/\/+$/, '');
|
|
68
70
|
|
|
69
71
|
const opSpecs: OpSpec[] = [
|
|
70
72
|
{ op: 'list', suffix: '', action: 'read', component: config.list, titleSuffix: '', keepAlive: true, hidden: false },
|
|
71
|
-
{ op: 'new', suffix: '/new', action: 'create', component: config.new, titleSuffix:
|
|
72
|
-
{ op: 'modify', suffix: '/:id/edit', action: 'update', component: config.modify, titleSuffix:
|
|
73
|
-
{ op: 'detail', suffix: '/:id', action: 'read', component: config.detail, titleSuffix:
|
|
73
|
+
{ op: 'new', suffix: '/new', action: 'create', component: config.new, titleSuffix: t.routes.createSuffix, keepAlive: false, hidden: true },
|
|
74
|
+
{ op: 'modify', suffix: '/:id/edit', action: 'update', component: config.modify, titleSuffix: t.routes.editSuffix, keepAlive: false, hidden: true },
|
|
75
|
+
{ op: 'detail', suffix: '/:id', action: 'read', component: config.detail, titleSuffix: t.routes.detailSuffix, keepAlive: false, hidden: true },
|
|
74
76
|
];
|
|
75
77
|
|
|
76
78
|
const routes: CrudRouteRecord[] = [];
|
|
@@ -60,12 +60,12 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
60
60
|
/** 汇总行标签 */
|
|
61
61
|
summaryLabel: {
|
|
62
62
|
type: StringConstructor;
|
|
63
|
-
default:
|
|
63
|
+
default: undefined;
|
|
64
64
|
};
|
|
65
65
|
/** 新增行按钮文本 */
|
|
66
66
|
addText: {
|
|
67
67
|
type: StringConstructor;
|
|
68
|
-
default:
|
|
68
|
+
default: undefined;
|
|
69
69
|
};
|
|
70
70
|
/** 是否可新增 */
|
|
71
71
|
addable: {
|
|
@@ -77,7 +77,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
77
77
|
type: StringConstructor;
|
|
78
78
|
default: string;
|
|
79
79
|
};
|
|
80
|
-
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("
|
|
80
|
+
}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("update:modelValue" | "add" | "remove")[], "update:modelValue" | "add" | "remove", import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
|
|
81
81
|
/** 列定义 */
|
|
82
82
|
columns: {
|
|
83
83
|
type: PropType<EditableColumn[]>;
|
|
@@ -111,12 +111,12 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
111
111
|
/** 汇总行标签 */
|
|
112
112
|
summaryLabel: {
|
|
113
113
|
type: StringConstructor;
|
|
114
|
-
default:
|
|
114
|
+
default: undefined;
|
|
115
115
|
};
|
|
116
116
|
/** 新增行按钮文本 */
|
|
117
117
|
addText: {
|
|
118
118
|
type: StringConstructor;
|
|
119
|
-
default:
|
|
119
|
+
default: undefined;
|
|
120
120
|
};
|
|
121
121
|
/** 是否可新增 */
|
|
122
122
|
addable: {
|