@liujitcn/kratos-admin-system 0.0.58 → 0.0.60
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/dist/package/declarations/src/locales/generated.d.ts +8 -0
- package/dist/package/src/components/notification/Notification.vue +3 -1
- package/dist/package/src/locales/en-US.json +3 -1
- package/dist/package/src/locales/ja-JP.json +3 -1
- package/dist/package/src/locales/zh-CN.json +3 -1
- package/dist/package/src/locales/zh-TW.json +3 -1
- package/dist/package/src/views/ai/chat/index.vue +14 -3
- package/dist/package/src/views/base/dashboard/index.vue +3 -3
- package/dist/package/src/views/base/login-policy/index.vue +6 -0
- package/dist/package/src/views/base/message/index.vue +15 -2
- package/dist/package/src/views/base/redact-storage-policy/index.vue +6 -1
- package/dist/package/src/views/message/inbox/index.vue +3 -1
- package/dist/package/src/views/tool/code-gen/code-preview/index.vue +9 -1
- package/dist/package/src/views/tool/code-gen/columns/index.vue +7 -1
- package/dist/package/src/views/tool/code-gen/preview/index.vue +9 -3
- package/dist/package/src/views/tool/code-gen/proto/index.vue +12 -3
- package/dist/package/src/views/tool/runtime-log/index.vue +5 -1
- package/package.json +2 -2
|
@@ -1577,6 +1577,8 @@ export declare const LOCALE_MESSAGES: {
|
|
|
1577
1577
|
"system.base.i18n_custom.placeholder.remark": string;
|
|
1578
1578
|
"system.base.i18n_custom.message.confirm_status": string;
|
|
1579
1579
|
"system.base.i18n_custom.message.confirm_delete": string;
|
|
1580
|
+
"system.dashboard.last_7_days": string;
|
|
1581
|
+
"system.dashboard.total": string;
|
|
1580
1582
|
};
|
|
1581
1583
|
readonly 'en-US': {
|
|
1582
1584
|
"system.base.config.tab.basic": string;
|
|
@@ -3156,6 +3158,8 @@ export declare const LOCALE_MESSAGES: {
|
|
|
3156
3158
|
"system.base.i18n_custom.placeholder.remark": string;
|
|
3157
3159
|
"system.base.i18n_custom.message.confirm_status": string;
|
|
3158
3160
|
"system.base.i18n_custom.message.confirm_delete": string;
|
|
3161
|
+
"system.dashboard.last_7_days": string;
|
|
3162
|
+
"system.dashboard.total": string;
|
|
3159
3163
|
};
|
|
3160
3164
|
readonly 'ja-JP': {
|
|
3161
3165
|
"system.base.config.tab.basic": string;
|
|
@@ -4735,6 +4739,8 @@ export declare const LOCALE_MESSAGES: {
|
|
|
4735
4739
|
"system.base.i18n_custom.placeholder.remark": string;
|
|
4736
4740
|
"system.base.i18n_custom.message.confirm_status": string;
|
|
4737
4741
|
"system.base.i18n_custom.message.confirm_delete": string;
|
|
4742
|
+
"system.dashboard.last_7_days": string;
|
|
4743
|
+
"system.dashboard.total": string;
|
|
4738
4744
|
};
|
|
4739
4745
|
readonly 'zh-TW': {
|
|
4740
4746
|
"system.base.config.tab.basic": string;
|
|
@@ -6314,6 +6320,8 @@ export declare const LOCALE_MESSAGES: {
|
|
|
6314
6320
|
"system.base.i18n_custom.placeholder.remark": string;
|
|
6315
6321
|
"system.base.i18n_custom.message.confirm_status": string;
|
|
6316
6322
|
"system.base.i18n_custom.message.confirm_delete": string;
|
|
6323
|
+
"system.dashboard.last_7_days": string;
|
|
6324
|
+
"system.dashboard.total": string;
|
|
6317
6325
|
};
|
|
6318
6326
|
};
|
|
6319
6327
|
export type GeneratedLocale = keyof typeof LOCALE_MESSAGES;
|
|
@@ -186,7 +186,9 @@ function openAction() {
|
|
|
186
186
|
|
|
187
187
|
/** 解析收件箱分类图标,未知图标使用默认图标。 */
|
|
188
188
|
function resolveNotificationIcon(icon: string) {
|
|
189
|
-
|
|
189
|
+
// 使用自有属性判定,避免原型链上的属性(如 constructor)被误判为合法图标键。
|
|
190
|
+
if (!Object.hasOwn(notificationIcons, icon)) return CollectionTag;
|
|
191
|
+
return notificationIcons[icon as keyof typeof notificationIcons];
|
|
190
192
|
}
|
|
191
193
|
</script>
|
|
192
194
|
|
|
@@ -1575,5 +1575,7 @@
|
|
|
1575
1575
|
"system.base.i18n_custom.placeholder.value": "Enter custom text",
|
|
1576
1576
|
"system.base.i18n_custom.placeholder.remark": "Enter a remark",
|
|
1577
1577
|
"system.base.i18n_custom.message.confirm_status": "Are you sure you want to {action} \"{name}\"?",
|
|
1578
|
-
"system.base.i18n_custom.message.confirm_delete": "Are you sure you want to delete custom translation \"{name}\"?"
|
|
1578
|
+
"system.base.i18n_custom.message.confirm_delete": "Are you sure you want to delete custom translation \"{name}\"?",
|
|
1579
|
+
"system.dashboard.last_7_days": "Last 7 days",
|
|
1580
|
+
"system.dashboard.total": "Total {count}"
|
|
1579
1581
|
}
|
|
@@ -1575,5 +1575,7 @@
|
|
|
1575
1575
|
"system.base.i18n_custom.placeholder.value": "カスタム文言を入力してください",
|
|
1576
1576
|
"system.base.i18n_custom.placeholder.remark": "備考を入力してください",
|
|
1577
1577
|
"system.base.i18n_custom.message.confirm_status": "「{name}」を{action}しますか?",
|
|
1578
|
-
"system.base.i18n_custom.message.confirm_delete": "カスタム翻訳「{name}」を削除しますか?"
|
|
1578
|
+
"system.base.i18n_custom.message.confirm_delete": "カスタム翻訳「{name}」を削除しますか?",
|
|
1579
|
+
"system.dashboard.last_7_days": "直近7日間",
|
|
1580
|
+
"system.dashboard.total": "合計 {count}"
|
|
1579
1581
|
}
|
|
@@ -1575,5 +1575,7 @@
|
|
|
1575
1575
|
"system.base.i18n_custom.placeholder.value": "请输入自定义文案",
|
|
1576
1576
|
"system.base.i18n_custom.placeholder.remark": "请输入备注",
|
|
1577
1577
|
"system.base.i18n_custom.message.confirm_status": "确定将“{name}”{action}吗?",
|
|
1578
|
-
"system.base.i18n_custom.message.confirm_delete": "确定删除自定义翻译“{name}”吗?"
|
|
1578
|
+
"system.base.i18n_custom.message.confirm_delete": "确定删除自定义翻译“{name}”吗?",
|
|
1579
|
+
"system.dashboard.last_7_days": "近 7 天",
|
|
1580
|
+
"system.dashboard.total": "总计 {count}"
|
|
1579
1581
|
}
|
|
@@ -1575,5 +1575,7 @@
|
|
|
1575
1575
|
"system.base.i18n_custom.placeholder.value": "請輸入自訂文案",
|
|
1576
1576
|
"system.base.i18n_custom.placeholder.remark": "請輸入備註",
|
|
1577
1577
|
"system.base.i18n_custom.message.confirm_status": "確定要將「{name}」{action}嗎?",
|
|
1578
|
-
"system.base.i18n_custom.message.confirm_delete": "確定要刪除自訂翻譯「{name}」嗎?"
|
|
1578
|
+
"system.base.i18n_custom.message.confirm_delete": "確定要刪除自訂翻譯「{name}」嗎?",
|
|
1579
|
+
"system.dashboard.last_7_days": "近 7 天",
|
|
1580
|
+
"system.dashboard.total": "總計 {count}"
|
|
1579
1581
|
}
|
|
@@ -105,6 +105,8 @@ const starterShortcuts = ref<AiShortcut[]>([]);
|
|
|
105
105
|
const messages = ref<Record<string, ChatMessageItem[]>>({});
|
|
106
106
|
const pendingDeltaMap = new Map<string, AiStreamPayload>();
|
|
107
107
|
const runningStreamTaskMap = new Map<string, AiStreamTask>();
|
|
108
|
+
/** 每个会话最近一次消息列表请求的序号,用于丢弃晚到的旧列表响应。 */
|
|
109
|
+
const loadMessagesSeq = new Map<string, number>();
|
|
108
110
|
let pendingDeltaFrame = 0;
|
|
109
111
|
let speakingMessageID = "";
|
|
110
112
|
let createSessionPromise: Promise<string | undefined> | undefined;
|
|
@@ -192,6 +194,8 @@ async function sendAiPayload(payload: SubmitPayload) {
|
|
|
192
194
|
// 同一个会话内仍然串行发送,避免历史上下文和消息顺序被并发请求打乱。
|
|
193
195
|
if (isSessionSending(sessionID)) return false;
|
|
194
196
|
|
|
197
|
+
// 使该会话仍在途的消息列表请求失效,避免其晚到后整体覆盖刚发送的本地气泡。
|
|
198
|
+
invalidateLoadMessages(sessionID);
|
|
195
199
|
const localUserMessage = createLocalUserMessage(payload);
|
|
196
200
|
const thinkingMessage = createThinkingMessage({ sessionID });
|
|
197
201
|
messages.value[sessionID] = sortMessages([...(messages.value[sessionID] ?? []), localUserMessage, thinkingMessage]);
|
|
@@ -650,22 +654,29 @@ async function loadAiShortcuts() {
|
|
|
650
654
|
}
|
|
651
655
|
}
|
|
652
656
|
|
|
657
|
+
/** 使指定会话仍在途的消息列表请求失效。 */
|
|
658
|
+
function invalidateLoadMessages(sessionID: string) {
|
|
659
|
+
loadMessagesSeq.set(sessionID, (loadMessagesSeq.get(sessionID) ?? 0) + 1);
|
|
660
|
+
}
|
|
661
|
+
|
|
653
662
|
/** 加载指定会话的消息记录。 */
|
|
654
663
|
async function loadMessages(sessionID: string, options?: { force?: boolean }) {
|
|
655
664
|
if (!sessionID) return;
|
|
656
665
|
if (!options?.force && isSessionSending(sessionID) && messages.value[sessionID]?.length) return;
|
|
657
666
|
|
|
667
|
+
const requestId = (loadMessagesSeq.get(sessionID) ?? 0) + 1;
|
|
668
|
+
loadMessagesSeq.set(sessionID, requestId);
|
|
658
669
|
loadingSessionID.value = sessionID;
|
|
659
670
|
try {
|
|
660
671
|
const response = await defAiMessageService.ListAiMessage({ session_id: sessionID });
|
|
661
|
-
if (
|
|
672
|
+
if (loadMessagesSeq.get(sessionID) !== requestId) return;
|
|
662
673
|
messages.value[sessionID] = normalizeMessageList(response?.messages);
|
|
663
674
|
} catch {
|
|
664
|
-
if (
|
|
675
|
+
if (loadMessagesSeq.get(sessionID) === requestId) {
|
|
665
676
|
messages.value[sessionID] = [];
|
|
666
677
|
}
|
|
667
678
|
} finally {
|
|
668
|
-
if (loadingSessionID.value === sessionID) {
|
|
679
|
+
if (loadMessagesSeq.get(sessionID) === requestId && loadingSessionID.value === sessionID) {
|
|
669
680
|
loadingSessionID.value = "";
|
|
670
681
|
}
|
|
671
682
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<template #header
|
|
23
23
|
><div class="chart-heading">
|
|
24
24
|
<span>{{ t("system.dashboard.login_trend") }}</span
|
|
25
|
-
><small
|
|
25
|
+
><small>{{ t("system.dashboard.last_7_days") }}</small>
|
|
26
26
|
</div></template
|
|
27
27
|
>
|
|
28
28
|
<div class="chart-wrap"><ECharts :option="loginTrendOption" height="285" /></div>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<template #header
|
|
32
32
|
><div class="chart-heading">
|
|
33
33
|
<span>{{ t("system.dashboard.login_distribution") }}</span
|
|
34
|
-
><small
|
|
34
|
+
><small>{{ t("system.dashboard.total", { count: loginDistributionTotal }) }}</small>
|
|
35
35
|
</div></template
|
|
36
36
|
>
|
|
37
37
|
<div class="chart-wrap"><ECharts :option="loginDistributionOption" height="265" /></div>
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
<template #header
|
|
41
41
|
><div class="chart-heading">
|
|
42
42
|
<span>{{ t("system.dashboard.operation_distribution") }}</span
|
|
43
|
-
><small
|
|
43
|
+
><small>{{ t("system.dashboard.total", { count: operationDistributionTotal }) }}</small>
|
|
44
44
|
</div></template
|
|
45
45
|
>
|
|
46
46
|
<div class="chart-wrap"><ECharts :option="operationDistributionOption" height="265" /></div>
|
|
@@ -388,14 +388,20 @@ watch(
|
|
|
388
388
|
}
|
|
389
389
|
);
|
|
390
390
|
|
|
391
|
+
/** 用户选项请求序号,用于丢弃快速切换租户时晚到的旧列表。 */
|
|
392
|
+
let userOptionsRequestId = 0;
|
|
393
|
+
|
|
391
394
|
watch(
|
|
392
395
|
() => formData.tenant_id,
|
|
393
396
|
async tenantId => {
|
|
394
397
|
if (formData.scope_type !== BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_USER || !tenantId) {
|
|
398
|
+
userOptionsRequestId += 1;
|
|
395
399
|
userOptions.value = [];
|
|
396
400
|
return;
|
|
397
401
|
}
|
|
402
|
+
const requestId = ++userOptionsRequestId;
|
|
398
403
|
const response = await defBaseUserService.OptionBaseUser({ keyword: "", tenant_id: tenantId });
|
|
404
|
+
if (requestId !== userOptionsRequestId || formData.tenant_id !== tenantId) return;
|
|
399
405
|
userOptions.value = response.list ?? [];
|
|
400
406
|
}
|
|
401
407
|
);
|
|
@@ -243,6 +243,19 @@ watch(
|
|
|
243
243
|
}
|
|
244
244
|
);
|
|
245
245
|
|
|
246
|
+
/** 校验受众列表:至少包含一条有效受众(租户全员天然有效,其余类型需填写有效 ID)。 */
|
|
247
|
+
function validateAudiences(_rule: unknown, value: unknown, callback: (error?: Error) => void) {
|
|
248
|
+
const audiences = Array.isArray(value) ? (value as BaseMessageAudienceForm[]) : [];
|
|
249
|
+
const hasValidAudience = audiences.some(
|
|
250
|
+
audience => audience.type === MessageAudienceType.MESSAGE_AUDIENCE_TYPE_TENANT || Number(audience.id) > 0
|
|
251
|
+
);
|
|
252
|
+
if (hasValidAudience) {
|
|
253
|
+
callback();
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
callback(new Error(t("system.base.message.validation.audience_id")));
|
|
257
|
+
}
|
|
258
|
+
|
|
246
259
|
const rules = computed(() => ({
|
|
247
260
|
tenant_id: isDefaultTenant.value
|
|
248
261
|
? [
|
|
@@ -274,7 +287,7 @@ const rules = computed(() => ({
|
|
|
274
287
|
trigger: "blur"
|
|
275
288
|
}
|
|
276
289
|
],
|
|
277
|
-
audiences: [{
|
|
290
|
+
audiences: [{ validator: validateAudiences, trigger: "change" }]
|
|
278
291
|
}));
|
|
279
292
|
|
|
280
293
|
const formFields = computed<ProFormField[]>(() => [
|
|
@@ -328,7 +341,7 @@ const formFields = computed<ProFormField[]>(() => [
|
|
|
328
341
|
component: "slot",
|
|
329
342
|
slotName: "audiences",
|
|
330
343
|
colSpan: 24,
|
|
331
|
-
rules: [{
|
|
344
|
+
rules: [{ validator: validateAudiences, trigger: "change" }]
|
|
332
345
|
},
|
|
333
346
|
{
|
|
334
347
|
prop: "action_type",
|
|
@@ -208,7 +208,12 @@ const rules = computed<FormRules>(() => ({
|
|
|
208
208
|
tenant_id: [{ required: isDefaultTenant.value, message: t("common.validation.required_select", { field: t("common.field.tenant") }), trigger: "change" }],
|
|
209
209
|
source_name: [{ required: true, message: t("system.base.redact_storage_policy.validation.source_name"), trigger: "change" }],
|
|
210
210
|
table_name: [{ required: true, message: t("system.base.redact_storage_policy.validation.table_name"), trigger: "change" }],
|
|
211
|
-
column_rows: [{ validator: (_rule, value: StorageColumnRow[], callback) =>
|
|
211
|
+
column_rows: [{ validator: (_rule, value: StorageColumnRow[], callback) => {
|
|
212
|
+
const hasRule = value?.some(row => Boolean(row.rule_id));
|
|
213
|
+
// 编辑态下清空规则(存在 id 但 rule_id 为空)需放行,交由提交逻辑删除旧策略。
|
|
214
|
+
const hasRemoval = value?.some(row => row.id > 0 && !row.rule_id);
|
|
215
|
+
hasRule || hasRemoval ? callback() : callback(new Error(t("system.base.redact_storage_policy.validation.configured_fields")));
|
|
216
|
+
}, trigger: "change" }]
|
|
212
217
|
}));
|
|
213
218
|
const columns = computed<ColumnProps[]>(() => [
|
|
214
219
|
{ type: "selection", width: 55 },
|
|
@@ -232,7 +232,9 @@ async function remove(row: Notification) {
|
|
|
232
232
|
|
|
233
233
|
/** 解析收件箱分类图标,未知图标使用默认图标。 */
|
|
234
234
|
function resolveNotificationIcon(icon: string) {
|
|
235
|
-
|
|
235
|
+
// 使用自有属性判定,避免原型链上的属性(如 constructor)被误判为合法图标键。
|
|
236
|
+
if (!Object.hasOwn(notificationIcons, icon)) return CollectionTag;
|
|
237
|
+
return notificationIcons[icon as keyof typeof notificationIcons];
|
|
236
238
|
}
|
|
237
239
|
</script>
|
|
238
240
|
|
|
@@ -80,6 +80,9 @@ const tableId = computed(() => {
|
|
|
80
80
|
/** 当前代码预览页标题。 */
|
|
81
81
|
const pageTitle = computed(() => table.value?.comment || table.value?.name || t("system.code.gen.preview.title.code"));
|
|
82
82
|
|
|
83
|
+
/** 代码预览加载序号,用于丢弃旧表晚到的响应。 */
|
|
84
|
+
let codePreviewRequestId = 0;
|
|
85
|
+
|
|
83
86
|
// 路由生成对象变化时重新载入对应代码预览。
|
|
84
87
|
watch(
|
|
85
88
|
tableId,
|
|
@@ -91,6 +94,7 @@ watch(
|
|
|
91
94
|
|
|
92
95
|
/** 加载当前表配置与固定项目路径下的代码预览。 */
|
|
93
96
|
async function loadCodePreview() {
|
|
97
|
+
const requestId = ++codePreviewRequestId;
|
|
94
98
|
table.value = undefined;
|
|
95
99
|
files.value = [];
|
|
96
100
|
previewError.value = "";
|
|
@@ -99,9 +103,11 @@ async function loadCodePreview() {
|
|
|
99
103
|
loading.value = true;
|
|
100
104
|
try {
|
|
101
105
|
const currentTable = await defCodeGenTableService.GetCodeGenTable({ id: tableId.value });
|
|
106
|
+
if (requestId !== codePreviewRequestId) return;
|
|
102
107
|
table.value = currentTable;
|
|
103
108
|
try {
|
|
104
109
|
const preview = await defCodeGenService.PreviewCodeGen({ table_id: tableId.value, output_paths: undefined });
|
|
110
|
+
if (requestId !== codePreviewRequestId) return;
|
|
105
111
|
files.value = preview.files ?? [];
|
|
106
112
|
missingI18ns.value = preview.missing_i18ns ?? [];
|
|
107
113
|
if (missingI18ns.value.length) {
|
|
@@ -111,12 +117,14 @@ async function loadCodePreview() {
|
|
|
111
117
|
}
|
|
112
118
|
if (!files.value.length && !previewError.value) previewError.value = t("system.code.gen.preview.message.no_preview_files");
|
|
113
119
|
} catch {
|
|
120
|
+
if (requestId !== codePreviewRequestId) return;
|
|
114
121
|
// 预览错误在页面内转成可操作提示,避免全局错误弹窗只显示“系统出错”。
|
|
115
122
|
previewError.value = t("system.code.gen.preview.message.load_failed");
|
|
116
123
|
}
|
|
124
|
+
if (requestId !== codePreviewRequestId) return;
|
|
117
125
|
syncWorkspaceTitle();
|
|
118
126
|
} finally {
|
|
119
|
-
loading.value = false;
|
|
127
|
+
if (requestId === codePreviewRequestId) loading.value = false;
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
130
|
|
|
@@ -694,6 +694,9 @@ const dictionaryItemsForEditor = computed(
|
|
|
694
694
|
/** 当前选项编辑器中的静态数据。 */
|
|
695
695
|
const staticOptionsForEditor = computed(() => staticOptions.get(optionDialog.cacheKey) ?? []);
|
|
696
696
|
|
|
697
|
+
/** 字段配置加载序号,用于丢弃旧表晚到的响应,避免覆盖成旧表配置。 */
|
|
698
|
+
let columnQueryRequestId = 0;
|
|
699
|
+
|
|
697
700
|
// 路由生成对象变化时重新加载字段配置。
|
|
698
701
|
watch(tableId, () => {
|
|
699
702
|
void handleQuery();
|
|
@@ -706,6 +709,7 @@ watch(canEdit, () => {
|
|
|
706
709
|
|
|
707
710
|
/** 查询生成对象字段配置。 */
|
|
708
711
|
async function handleQuery() {
|
|
712
|
+
const requestId = ++columnQueryRequestId;
|
|
709
713
|
loading.value = true;
|
|
710
714
|
try {
|
|
711
715
|
destroyColumnSortable();
|
|
@@ -717,14 +721,16 @@ async function handleQuery() {
|
|
|
717
721
|
defCodeGenTableService.GetCodeGenTable({ id: tableId.value }),
|
|
718
722
|
defCodeGenColumnService.ListCodeGenColumn({ table_id: tableId.value })
|
|
719
723
|
]);
|
|
724
|
+
if (requestId !== columnQueryRequestId) return;
|
|
720
725
|
Object.assign(formData, table);
|
|
721
726
|
// 字段配置和预览都保留数据库完整字段快照,由用户决定是否调整默认配置。
|
|
722
727
|
columns.value = (response.code_gen_columns ?? []).map(normalizeColumn);
|
|
723
728
|
syncWorkspaceTitle();
|
|
724
729
|
await nextTick();
|
|
730
|
+
if (requestId !== columnQueryRequestId) return;
|
|
725
731
|
initColumnSortable();
|
|
726
732
|
} finally {
|
|
727
|
-
loading.value = false;
|
|
733
|
+
if (requestId === columnQueryRequestId) loading.value = false;
|
|
728
734
|
}
|
|
729
735
|
}
|
|
730
736
|
|
|
@@ -344,6 +344,9 @@ const treeParentOptions = computed<ProFormOption[]>(() => {
|
|
|
344
344
|
return [{ label: t("system.code.gen.preview.value.top_level"), value: 0 }, ...mapPreviewRowsToOptions(treeRows)];
|
|
345
345
|
});
|
|
346
346
|
|
|
347
|
+
/** 页面预览加载序号,用于丢弃旧表晚到的响应。 */
|
|
348
|
+
let previewRequestId = 0;
|
|
349
|
+
|
|
347
350
|
// 路由生成对象变化时重新载入对应预览。
|
|
348
351
|
watch(tableId, () => {
|
|
349
352
|
void loadPreview();
|
|
@@ -397,8 +400,8 @@ async function requestPreviewTable(params: Record<string, any>) {
|
|
|
397
400
|
if (pageType.value === "tree" && snapshot.value?.table.parent_column) {
|
|
398
401
|
return { data: buildCodeGenPreviewTree(rows, primaryColumn.value, snapshot.value.table.parent_column) };
|
|
399
402
|
}
|
|
400
|
-
const pageNum = Number(params.
|
|
401
|
-
const pageSize = Number(params.
|
|
403
|
+
const pageNum = Number(params.page_num ?? 1);
|
|
404
|
+
const pageSize = Number(params.page_size ?? 10);
|
|
402
405
|
const start = (pageNum - 1) * pageSize;
|
|
403
406
|
return { data: { list: rows.slice(start, start + pageSize), total: rows.length } };
|
|
404
407
|
}
|
|
@@ -421,6 +424,7 @@ function refreshTable() {
|
|
|
421
424
|
|
|
422
425
|
/** 加载当前表、字段和 Proto 配置并创建页面预览。 */
|
|
423
426
|
async function loadPreview() {
|
|
427
|
+
const requestId = ++previewRequestId;
|
|
424
428
|
loading.value = true;
|
|
425
429
|
try {
|
|
426
430
|
snapshot.value = null;
|
|
@@ -429,12 +433,14 @@ async function loadPreview() {
|
|
|
429
433
|
databaseTables.value = [];
|
|
430
434
|
if (!tableId.value) return;
|
|
431
435
|
const table = await defCodeGenTableService.GetCodeGenTable({ id: tableId.value });
|
|
436
|
+
if (requestId !== previewRequestId) return;
|
|
432
437
|
const [columnResponse, protoResponse, dictionaryResponse, databaseTableResponse] = await Promise.all([
|
|
433
438
|
defCodeGenColumnService.ListCodeGenColumn({ table_id: tableId.value }),
|
|
434
439
|
defCodeGenProtoService.ListCodeGenProto({ table_id: tableId.value }),
|
|
435
440
|
defBaseDictService.OptionBaseDict({}),
|
|
436
441
|
defCodeGenTableService.ListCodeGenDatabaseTable({ source_name: table.source_name })
|
|
437
442
|
]);
|
|
443
|
+
if (requestId !== previewRequestId) return;
|
|
438
444
|
snapshot.value = { table, columns: columnResponse.code_gen_columns ?? [] };
|
|
439
445
|
protoChecks.value = protoResponse.code_gen_protos ?? [];
|
|
440
446
|
dictionaries.value = dictionaryResponse.base_dicts ?? [];
|
|
@@ -442,7 +448,7 @@ async function loadPreview() {
|
|
|
442
448
|
createMockRows();
|
|
443
449
|
syncWorkspaceTitle();
|
|
444
450
|
} finally {
|
|
445
|
-
loading.value = false;
|
|
451
|
+
if (requestId === previewRequestId) loading.value = false;
|
|
446
452
|
}
|
|
447
453
|
}
|
|
448
454
|
|
|
@@ -312,6 +312,9 @@ const configDialogLoading = computed(() => {
|
|
|
312
312
|
return !!tableName && loadingTargetColumns.has(tableName);
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
+
/** Proto 配置加载序号,用于丢弃旧表晚到的响应。 */
|
|
316
|
+
let protoQueryRequestId = 0;
|
|
317
|
+
|
|
315
318
|
// 路由生成对象变化时重新加载 Proto 配置。
|
|
316
319
|
watch(tableId, () => {
|
|
317
320
|
void handleQuery();
|
|
@@ -321,6 +324,7 @@ watch(tableId, () => {
|
|
|
321
324
|
* 查询生成对象字段与 Proto 配置。
|
|
322
325
|
*/
|
|
323
326
|
async function handleQuery() {
|
|
327
|
+
const requestId = ++protoQueryRequestId;
|
|
324
328
|
loading.value = true;
|
|
325
329
|
try {
|
|
326
330
|
Object.assign(formData, createDefaultCodeGenTableForm());
|
|
@@ -329,15 +333,19 @@ async function handleQuery() {
|
|
|
329
333
|
Object.keys(targetColumnOptions).forEach(key => delete targetColumnOptions[key]);
|
|
330
334
|
if (!tableId.value) return;
|
|
331
335
|
const table = await defCodeGenTableService.GetCodeGenTable({ id: tableId.value });
|
|
336
|
+
if (requestId !== protoQueryRequestId) return;
|
|
332
337
|
const tableResponse = await defCodeGenTableService.ListCodeGenDatabaseTable({ source_name: table.source_name });
|
|
338
|
+
if (requestId !== protoQueryRequestId) return;
|
|
333
339
|
Object.assign(formData, table);
|
|
334
340
|
databaseTables.value = tableResponse.tables ?? [];
|
|
335
341
|
const columnResponse = await defCodeGenColumnService.ListCodeGenDatabaseColumn({ source_name: formData.source_name, table_name: formData.name });
|
|
342
|
+
if (requestId !== protoQueryRequestId) return;
|
|
336
343
|
targetColumnOptions[formData.name] = createColumnOptions(columnResponse.columns ?? []);
|
|
337
|
-
await loadProtoChecks();
|
|
344
|
+
await loadProtoChecks(requestId);
|
|
345
|
+
if (requestId !== protoQueryRequestId) return;
|
|
338
346
|
syncWorkspaceTitle();
|
|
339
347
|
} finally {
|
|
340
|
-
loading.value = false;
|
|
348
|
+
if (requestId === protoQueryRequestId) loading.value = false;
|
|
341
349
|
}
|
|
342
350
|
}
|
|
343
351
|
|
|
@@ -356,9 +364,10 @@ function syncWorkspaceTitle() {
|
|
|
356
364
|
/**
|
|
357
365
|
* 自动检查当前生成对象需要的 Proto 能力。
|
|
358
366
|
*/
|
|
359
|
-
async function loadProtoChecks() {
|
|
367
|
+
async function loadProtoChecks(requestId: number) {
|
|
360
368
|
if (!formData.id) return;
|
|
361
369
|
const data = await defCodeGenProtoService.ListCodeGenProto({ table_id: formData.id });
|
|
370
|
+
if (requestId !== protoQueryRequestId) return;
|
|
362
371
|
protoChecks.value = (data.code_gen_protos ?? []).map(item => ({
|
|
363
372
|
...item,
|
|
364
373
|
config: normalizeCodeGenProtoConfig(item.config)
|
|
@@ -470,7 +470,11 @@ onActivated(() => {
|
|
|
470
470
|
}
|
|
471
471
|
});
|
|
472
472
|
|
|
473
|
-
onDeactivated(
|
|
473
|
+
onDeactivated(() => {
|
|
474
|
+
// 使隐藏前仍在途的实时控制台请求失效,避免其在组件失活后重建无人清理的订阅。
|
|
475
|
+
activeRequestId += 1;
|
|
476
|
+
stopRuntimeSubscription();
|
|
477
|
+
});
|
|
474
478
|
|
|
475
479
|
onBeforeUnmount(() => {
|
|
476
480
|
if (filterTimer) clearTimeout(filterTimer);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liujitcn/kratos-admin-system",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.60",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "kratos-admin system management module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"sortablejs": "^1.15.2",
|
|
17
17
|
"swagger-ui-dist": "^5.32.15",
|
|
18
18
|
"vue-element-plus-x": "^2.0.3",
|
|
19
|
-
"@liujitcn/kratos-admin-core": "0.0.
|
|
19
|
+
"@liujitcn/kratos-admin-core": "0.0.60"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"@element-plus/icons-vue": "^2.3.1",
|