@liujitcn/kratos-admin-system 0.0.51 → 0.0.53
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/README.md +1 -1
- package/dist/package/declarations/src/api/base/v1/sse.d.ts +1 -1
- package/dist/package/declarations/src/components/tenant-project/TenantProjectManager.vue.d.ts +1 -2
- package/dist/package/declarations/src/components/tenant-project/tenant-project-manager-data.d.ts +10 -0
- package/dist/package/declarations/src/components/tenant-project/tenant-project-manager.d.ts +8 -3
- package/dist/package/declarations/src/index.d.ts +1 -1
- package/dist/package/declarations/src/locales/generated.d.ts +32 -0
- package/dist/package/declarations/src/rpc/base/v1/ai_search.d.ts +26 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +0 -1
- package/dist/package/declarations/src/views/ai/chat/components/speech-recognition.d.ts +6 -2
- package/dist/package/src/api/base/v1/sse.ts +19 -12
- package/dist/package/src/components/log/LogTable.vue +25 -18
- package/dist/package/src/components/notification/Notification.vue +14 -7
- package/dist/package/src/components/tenant-project/TenantProjectManager.vue +106 -62
- package/dist/package/src/components/tenant-project/tenant-project-manager-data.ts +39 -1
- package/dist/package/src/components/tenant-project/tenant-project-manager.ts +19 -4
- package/dist/package/src/components/tenant-project-grant/ProjectGrantDialog.vue +22 -7
- package/dist/package/src/index.ts +2 -0
- package/dist/package/src/locales/en-US.json +8 -0
- package/dist/package/src/locales/ja-JP.json +8 -0
- package/dist/package/src/locales/zh-CN.json +8 -0
- package/dist/package/src/locales/zh-TW.json +8 -0
- package/dist/package/src/rpc/base/v1/ai_search.ts +37 -0
- package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +0 -1
- package/dist/package/src/views/ai/chat/components/XSender.vue +1 -36
- package/dist/package/src/views/ai/chat/components/speech-recognition.ts +28 -7
- package/dist/package/src/views/ai/chat/index.vue +16 -7
- package/dist/package/src/views/base/api-log/index.vue +1 -1
- package/dist/package/src/views/base/area/index.vue +15 -9
- package/dist/package/src/views/base/backup-management/archive-config/index.vue +22 -10
- package/dist/package/src/views/base/backup-management/backup-config/index.vue +13 -6
- package/dist/package/src/views/base/config/index.vue +38 -14
- package/dist/package/src/views/base/dept/index.vue +31 -25
- package/dist/package/src/views/base/dict/index.vue +12 -8
- package/dist/package/src/views/base/dict/item.vue +12 -8
- package/dist/package/src/views/base/i18n-custom/index.vue +13 -7
- package/dist/package/src/views/base/job/index.vue +12 -8
- package/dist/package/src/views/base/job/log.vue +14 -9
- package/dist/package/src/views/base/language/index.vue +7 -4
- package/dist/package/src/views/base/login-policy/index.vue +22 -11
- package/dist/package/src/views/base/menu/index.vue +23 -16
- package/dist/package/src/views/base/message/index.vue +65 -21
- package/dist/package/src/views/base/message-category/index.vue +10 -4
- package/dist/package/src/views/base/oauth-client/index.vue +15 -5
- package/dist/package/src/views/base/post/index.vue +10 -4
- package/dist/package/src/views/base/redact-output-policy/index.vue +12 -5
- package/dist/package/src/views/base/redact-rule/index.vue +8 -7
- package/dist/package/src/views/base/redact-storage-policy/index.vue +32 -8
- package/dist/package/src/views/base/role/index.vue +24 -17
- package/dist/package/src/views/base/tenant/index.vue +7 -6
- package/dist/package/src/views/base/tenant-project-grant/index.vue +44 -27
- package/dist/package/src/views/base/user/components/dept-tree.vue +4 -9
- package/dist/package/src/views/base/user/index.vue +39 -28
- package/dist/package/src/views/message/inbox/index.vue +8 -3
- package/dist/package/src/views/profile/components/base.vue +1 -1
- package/dist/package/src/views/profile/index.vue +1 -1
- package/dist/package/src/views/tool/cache/index.vue +1 -1
- package/dist/package/src/views/tool/code-gen/columns/index.vue +35 -16
- package/dist/package/src/views/tool/code-gen/table/index.vue +58 -31
- package/package.json +2 -2
|
@@ -28,20 +28,31 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
|
|
30
30
|
<script setup lang="ts">
|
|
31
|
-
import { computed, reactive, ref, useSlots } from "vue";
|
|
31
|
+
import { computed, onMounted, reactive, ref, useSlots } from "vue";
|
|
32
32
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
33
33
|
import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
|
|
34
|
-
import type {
|
|
34
|
+
import type {
|
|
35
|
+
ColumnProps,
|
|
36
|
+
HeaderActionProps,
|
|
37
|
+
ProTableInstance,
|
|
38
|
+
RenderScope,
|
|
39
|
+
TableActionProps
|
|
40
|
+
} from "@liujitcn/kratos-admin-core/components/ProTable/interface";
|
|
35
41
|
import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
|
|
36
42
|
import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
|
|
37
43
|
import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
|
|
38
44
|
import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
|
|
39
45
|
import { defBaseTenantProjectService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_tenant_project";
|
|
40
|
-
import type {
|
|
46
|
+
import type {
|
|
47
|
+
BaseTenantProject,
|
|
48
|
+
BaseTenantProjectForm,
|
|
49
|
+
PageBaseTenantProjectRequest
|
|
50
|
+
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_tenant_project";
|
|
41
51
|
import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
|
|
42
52
|
import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
|
|
43
53
|
import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
|
|
44
54
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
55
|
+
import { arrangeTenantProjectColumns } from "./tenant-project-manager-data";
|
|
45
56
|
import {
|
|
46
57
|
mergeTenantProjectExtraData,
|
|
47
58
|
tenantProjectKey,
|
|
@@ -66,8 +77,11 @@ const emit = defineEmits<{
|
|
|
66
77
|
"extra-data-error": [error: unknown];
|
|
67
78
|
}>();
|
|
68
79
|
|
|
69
|
-
/**
|
|
70
|
-
type BaseTenantProjectFormState = Omit<BaseTenantProjectForm, "tenant_id"
|
|
80
|
+
/** 项目表单状态,默认租户创建时必须选择目标租户。 */
|
|
81
|
+
type BaseTenantProjectFormState = Omit<BaseTenantProjectForm, "tenant_id"> & {
|
|
82
|
+
/** 项目所属租户。 */
|
|
83
|
+
tenant_id?: number;
|
|
84
|
+
};
|
|
71
85
|
|
|
72
86
|
const { BUTTONS } = useAuthButtons();
|
|
73
87
|
const slots = useSlots();
|
|
@@ -88,6 +102,8 @@ const statusOptions = computed<ProFormOption[]>(() => [
|
|
|
88
102
|
const formData = reactive<BaseTenantProjectFormState>({
|
|
89
103
|
/** 项目ID。 */
|
|
90
104
|
id: 0,
|
|
105
|
+
/** 项目所属租户。 */
|
|
106
|
+
tenant_id: undefined,
|
|
91
107
|
/** 项目名称。 */
|
|
92
108
|
name: "",
|
|
93
109
|
/** 项目编号。 */
|
|
@@ -100,6 +116,13 @@ const formData = reactive<BaseTenantProjectFormState>({
|
|
|
100
116
|
remark: ""
|
|
101
117
|
});
|
|
102
118
|
const rules = computed(() => ({
|
|
119
|
+
tenant_id: [
|
|
120
|
+
{
|
|
121
|
+
required: true,
|
|
122
|
+
message: t("common.validation.required_select", { field: t("common.field.tenant") }),
|
|
123
|
+
trigger: "change"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
103
126
|
name: [
|
|
104
127
|
{
|
|
105
128
|
required: true,
|
|
@@ -141,10 +164,14 @@ const rules = computed(() => ({
|
|
|
141
164
|
]
|
|
142
165
|
}));
|
|
143
166
|
|
|
144
|
-
const { isDefaultTenant } = useTenantScope();
|
|
167
|
+
const { isDefaultTenant, tenantColumns, tenantFormField, toRequestTenantId, loadTenantOptions } = useTenantScope();
|
|
168
|
+
onMounted(() => {
|
|
169
|
+
if (isDefaultTenant.value) void loadTenantOptions();
|
|
170
|
+
});
|
|
145
171
|
|
|
146
172
|
/** 项目表单字段配置。 */
|
|
147
173
|
const formFields = computed<ProFormField[]>(() => [
|
|
174
|
+
tenantFormField({ label: t("common.field.tenant"), disabledOnEdit: true }),
|
|
148
175
|
{
|
|
149
176
|
prop: "name",
|
|
150
177
|
label: t("system.base.tenant_project.field.name"),
|
|
@@ -202,56 +229,60 @@ function resolveProjectBoolean(value: boolean | ((context: TenantProjectContext)
|
|
|
202
229
|
}
|
|
203
230
|
|
|
204
231
|
/** 项目表格列配置。 */
|
|
205
|
-
const columns = computed<ColumnProps[]>(() =>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
prop: "
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
{ prop: "remark", label: t("common.field.remark"), minWidth: 160 },
|
|
226
|
-
...props.extraColumns,
|
|
227
|
-
{ prop: "created_at", align: "center", label: t("common.field.created_at"), minWidth: 180 },
|
|
228
|
-
{ prop: "updated_at", label: t("common.field.updated_at"), minWidth: 180, align: "center" },
|
|
229
|
-
{
|
|
230
|
-
prop: "operation",
|
|
231
|
-
label: t("common.field.operation"),
|
|
232
|
-
cellType: "actions",
|
|
233
|
-
actions: [
|
|
234
|
-
...props.extraActions.map(toTableAction),
|
|
235
|
-
{
|
|
236
|
-
label: t("common.action.edit"),
|
|
237
|
-
type: "primary",
|
|
238
|
-
link: true,
|
|
239
|
-
icon: EditPen,
|
|
240
|
-
hidden: () => !isDefaultTenant.value || !BUTTONS.value["base:tenant:project:update"],
|
|
241
|
-
params: scope => ({ projectId: scope.row.id }),
|
|
242
|
-
onClick: (scope, params) => handleOpenDialog((params?.projectId as number | undefined) ?? (scope.row as BaseTenantProject).id)
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
label: t("common.action.delete"),
|
|
246
|
-
type: "danger",
|
|
247
|
-
link: true,
|
|
248
|
-
icon: Delete,
|
|
249
|
-
hidden: () => !isDefaultTenant.value || !BUTTONS.value["base:tenant:project:delete"],
|
|
250
|
-
onClick: scope => handleDelete(scope.row as BaseTenantProject)
|
|
232
|
+
const columns = computed<ColumnProps[]>(() => {
|
|
233
|
+
const baseColumns: ColumnProps[] = [
|
|
234
|
+
{ type: "selection", width: 55 },
|
|
235
|
+
...tenantColumns({ label: t("common.field.tenant"), order: 1 }),
|
|
236
|
+
{ prop: "name", label: t("system.base.tenant_project.field.name"), minWidth: 180, search: { el: "input" } },
|
|
237
|
+
{ prop: "code", label: t("system.base.tenant_project.field.code"), minWidth: 140, search: { el: "input" } },
|
|
238
|
+
{ prop: "sort", label: t("common.field.sort"), minWidth: 90, align: "right" },
|
|
239
|
+
{
|
|
240
|
+
prop: "status",
|
|
241
|
+
label: t("common.field.status"),
|
|
242
|
+
minWidth: 100,
|
|
243
|
+
search: { el: "select" },
|
|
244
|
+
cellType: "status",
|
|
245
|
+
statusProps: {
|
|
246
|
+
activeValue: Status.STATUS_ENABLE,
|
|
247
|
+
inactiveValue: Status.STATUS_DISABLE,
|
|
248
|
+
activeText: t("common.status.enabled"),
|
|
249
|
+
inactiveText: t("common.status.disabled"),
|
|
250
|
+
disabled: () => !isDefaultTenant.value || !BUTTONS.value["base:tenant:project:status"],
|
|
251
|
+
beforeChange: scope => handleBeforeSetStatus(scope.row as BaseTenantProject)
|
|
251
252
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
},
|
|
254
|
+
{ prop: "remark", label: t("common.field.remark"), minWidth: 160 },
|
|
255
|
+
{ prop: "created_at", align: "center", label: t("common.field.created_at"), minWidth: 180 },
|
|
256
|
+
{ prop: "updated_at", label: t("common.field.updated_at"), minWidth: 180, align: "center" },
|
|
257
|
+
{
|
|
258
|
+
prop: "operation",
|
|
259
|
+
label: t("common.field.operation"),
|
|
260
|
+
cellType: "actions",
|
|
261
|
+
actions: [
|
|
262
|
+
...props.extraActions.map(toTableAction),
|
|
263
|
+
{
|
|
264
|
+
label: t("common.action.edit"),
|
|
265
|
+
type: "primary",
|
|
266
|
+
link: true,
|
|
267
|
+
icon: EditPen,
|
|
268
|
+
hidden: () => !isDefaultTenant.value || !BUTTONS.value["base:tenant:project:update"],
|
|
269
|
+
params: scope => ({ projectId: scope.row.id }),
|
|
270
|
+
onClick: (scope, params) =>
|
|
271
|
+
handleOpenDialog((params?.projectId as number | undefined) ?? (scope.row as BaseTenantProject).id)
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
label: t("common.action.delete"),
|
|
275
|
+
type: "danger",
|
|
276
|
+
link: true,
|
|
277
|
+
icon: Delete,
|
|
278
|
+
hidden: () => !isDefaultTenant.value || !BUTTONS.value["base:tenant:project:delete"],
|
|
279
|
+
onClick: scope => handleDelete(scope.row as BaseTenantProject)
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
return arrangeTenantProjectColumns(baseColumns, props.extraColumns);
|
|
285
|
+
});
|
|
255
286
|
|
|
256
287
|
/** 项目顶部按钮配置。 */
|
|
257
288
|
const headerActions = computed<HeaderActionProps[]>(() => [
|
|
@@ -275,7 +306,10 @@ const headerActions = computed<HeaderActionProps[]>(() => [
|
|
|
275
306
|
/** 请求项目分页列表并加载当前页外部业务字段。 */
|
|
276
307
|
async function requestBaseTenantProjectTable(params: PageBaseTenantProjectRequest) {
|
|
277
308
|
const revision = ++extraDataRequestRevision;
|
|
278
|
-
const request =
|
|
309
|
+
const request = {
|
|
310
|
+
...buildPageRequest(params),
|
|
311
|
+
tenant_id: toRequestTenantId(params.tenant_id)
|
|
312
|
+
} as PageBaseTenantProjectRequest;
|
|
279
313
|
const data = await defBaseTenantProjectService.PageBaseTenantProject(request);
|
|
280
314
|
const projects = data.base_tenant_projects ?? [];
|
|
281
315
|
if (!props.loadExtraData || !projects.length) {
|
|
@@ -315,15 +349,22 @@ function resolveTenantProjectSlotContext(scope: Record<string, any>) {
|
|
|
315
349
|
|
|
316
350
|
/** 打开项目编辑弹窗。 */
|
|
317
351
|
async function handleOpenDialog(id?: number) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
352
|
+
await formDialogRef.value?.open({
|
|
353
|
+
load: async () => {
|
|
354
|
+
await loadTenantOptions();
|
|
355
|
+
return id ? defBaseTenantProjectService.GetBaseTenantProject({ id }) : undefined;
|
|
356
|
+
},
|
|
357
|
+
commit: data => {
|
|
358
|
+
resetForm();
|
|
359
|
+
dialog.titleKey = id ? "common.action.edit_resource" : "common.action.create_resource";
|
|
360
|
+
if (data) Object.assign(formData, data);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
322
363
|
}
|
|
323
364
|
|
|
324
365
|
/** 关闭项目弹窗并清理表单。 */
|
|
325
366
|
function handleCloseDialog() {
|
|
326
|
-
|
|
367
|
+
formDialogRef.value?.close();
|
|
327
368
|
resetForm();
|
|
328
369
|
}
|
|
329
370
|
|
|
@@ -332,6 +373,7 @@ function resetForm() {
|
|
|
332
373
|
formDialogRef.value?.resetFields();
|
|
333
374
|
formDialogRef.value?.clearValidate();
|
|
334
375
|
formData.id = 0;
|
|
376
|
+
formData.tenant_id = undefined;
|
|
335
377
|
formData.name = "";
|
|
336
378
|
formData.code = "";
|
|
337
379
|
formData.sort = 1;
|
|
@@ -344,7 +386,9 @@ function handleSubmit() {
|
|
|
344
386
|
formDialogRef.value?.validate()?.then(valid => {
|
|
345
387
|
if (!valid) return;
|
|
346
388
|
const submitData = JSON.parse(JSON.stringify(formData)) as Partial<BaseTenantProjectForm>;
|
|
347
|
-
|
|
389
|
+
const tenantId = toRequestTenantId(formData.tenant_id);
|
|
390
|
+
if (tenantId === undefined) delete submitData.tenant_id;
|
|
391
|
+
else submitData.tenant_id = tenantId;
|
|
348
392
|
const request = submitData.id
|
|
349
393
|
? defBaseTenantProjectService.UpdateBaseTenantProject({ base_tenant_project: submitData as BaseTenantProjectForm })
|
|
350
394
|
: defBaseTenantProjectService.CreateBaseTenantProject({ base_tenant_project: submitData as BaseTenantProjectForm });
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { BaseTenantProject } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_tenant_project";
|
|
2
2
|
|
|
3
|
+
/** 租户项目表格列的最小结构,用于在不依赖表格组件的情况下排列扩展列。 */
|
|
4
|
+
type TenantProjectColumnLike = {
|
|
5
|
+
prop?: string;
|
|
6
|
+
type?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
3
9
|
/** 租户项目业务数据查询键。 */
|
|
4
10
|
export interface TenantProjectKey {
|
|
5
11
|
/** 租户 ID。 */
|
|
@@ -11,13 +17,45 @@ export interface TenantProjectKey {
|
|
|
11
17
|
/** 租户项目扩展数据,外层键由租户 ID 和项目 ID 组成。 */
|
|
12
18
|
export type TenantProjectExtraData = Record<string, Record<string, unknown>>;
|
|
13
19
|
|
|
20
|
+
/** 按基础字段位置排列租户项目管理的扩展列。 */
|
|
21
|
+
export function arrangeTenantProjectColumns<T extends TenantProjectColumnLike>(
|
|
22
|
+
baseColumns: T[],
|
|
23
|
+
extraColumns: Array<T & { after?: string }>
|
|
24
|
+
): T[] {
|
|
25
|
+
const baseKeys = new Set(baseColumns.map(column => column.prop ?? column.type));
|
|
26
|
+
const extrasByAnchor = new Map<string | undefined, T[]>();
|
|
27
|
+
for (const extraColumn of extraColumns) {
|
|
28
|
+
const { after, ...column } = extraColumn;
|
|
29
|
+
const anchor = after && baseKeys.has(after) ? after : "remark";
|
|
30
|
+
const columns = extrasByAnchor.get(anchor) ?? [];
|
|
31
|
+
columns.push(column as T);
|
|
32
|
+
extrasByAnchor.set(anchor, columns);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const result: T[] = [];
|
|
36
|
+
for (const baseColumn of baseColumns) {
|
|
37
|
+
result.push(baseColumn);
|
|
38
|
+
const anchor = baseColumn.prop ?? baseColumn.type;
|
|
39
|
+
const columns = extrasByAnchor.get(anchor);
|
|
40
|
+
if (!columns) continue;
|
|
41
|
+
result.push(...columns);
|
|
42
|
+
extrasByAnchor.delete(anchor);
|
|
43
|
+
}
|
|
44
|
+
const remaining: T[] = [];
|
|
45
|
+
for (const columns of extrasByAnchor.values()) remaining.push(...columns);
|
|
46
|
+
return [...result, ...remaining];
|
|
47
|
+
}
|
|
48
|
+
|
|
14
49
|
/** 创建租户项目扩展数据的稳定键。 */
|
|
15
50
|
export function tenantProjectKey(tenantId: number, projectId: number): string {
|
|
16
51
|
return `${tenantId}:${projectId}`;
|
|
17
52
|
}
|
|
18
53
|
|
|
19
54
|
/** 将外部业务字段合并到项目行,同时保护公共项目字段。 */
|
|
20
|
-
export function mergeTenantProjectExtraData(
|
|
55
|
+
export function mergeTenantProjectExtraData(
|
|
56
|
+
project: BaseTenantProject,
|
|
57
|
+
extra?: Record<string, unknown>
|
|
58
|
+
): BaseTenantProject & Record<string, unknown> {
|
|
21
59
|
if (!extra) return { ...project } as BaseTenantProject & Record<string, unknown>;
|
|
22
60
|
|
|
23
61
|
const protectedFields = new Set(["id", "tenant_id", "code", "name", "status", "sort", "remark", "created_at", "updated_at"]);
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
BaseTenantProject,
|
|
3
|
+
PageBaseTenantProjectRequest
|
|
4
|
+
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_tenant_project";
|
|
2
5
|
import type { ColumnProps, TableActionProps } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
|
|
3
6
|
import type { TenantProjectExtraData, TenantProjectKey } from "./tenant-project-manager-data";
|
|
4
7
|
|
|
5
|
-
export {
|
|
8
|
+
export {
|
|
9
|
+
arrangeTenantProjectColumns,
|
|
10
|
+
mergeTenantProjectExtraData,
|
|
11
|
+
tenantProjectKey,
|
|
12
|
+
type TenantProjectExtraData,
|
|
13
|
+
type TenantProjectKey
|
|
14
|
+
} from "./tenant-project-manager-data";
|
|
6
15
|
|
|
7
16
|
/** 租户项目单条业务上下文。 */
|
|
8
17
|
export interface TenantProjectContext<TData extends Record<string, unknown> = Record<string, unknown>> extends TenantProjectKey {
|
|
@@ -37,10 +46,16 @@ export type TenantProjectAction = Omit<TableActionProps, "disabled" | "hidden" |
|
|
|
37
46
|
onClick: (context: TenantProjectContext, params?: Record<string, any>) => void | Promise<void>;
|
|
38
47
|
};
|
|
39
48
|
|
|
49
|
+
/** 租户项目管理的扩展列配置。 */
|
|
50
|
+
export type TenantProjectExtraColumn = ColumnProps & {
|
|
51
|
+
/** 插入到指定基础字段后面,未配置时默认插入备注字段后面。 */
|
|
52
|
+
after?: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
40
55
|
/** 租户项目管理组件属性。 */
|
|
41
56
|
export interface TenantProjectManagerProps {
|
|
42
|
-
/**
|
|
43
|
-
extraColumns?:
|
|
57
|
+
/** 追加到基础列表的表格列,可通过 after 指定插入位置。 */
|
|
58
|
+
extraColumns?: TenantProjectExtraColumn[];
|
|
44
59
|
/** 追加到基础操作列的业务操作。 */
|
|
45
60
|
extraActions?: TenantProjectAction[];
|
|
46
61
|
/** 加载当前页外部业务字段。 */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<FormDialog
|
|
3
|
+
ref="formDialogRef"
|
|
3
4
|
v-model="visible"
|
|
4
5
|
:title="t('system.base.tenant_project.grant')"
|
|
5
6
|
:model="form"
|
|
@@ -26,6 +27,7 @@ import type {
|
|
|
26
27
|
import type { SelectOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
|
|
27
28
|
|
|
28
29
|
const visible = ref(false);
|
|
30
|
+
const formDialogRef = ref<InstanceType<typeof FormDialog>>();
|
|
29
31
|
const loading = ref(false);
|
|
30
32
|
const projectOptions = ref<SelectOptionResponse_Option[]>([]);
|
|
31
33
|
const form = reactive({ tenant_id: 0, all: false, project_id: [] as number[] });
|
|
@@ -42,13 +44,26 @@ const fields = computed<ProFormField[]>(() => [
|
|
|
42
44
|
|
|
43
45
|
/** 打开指定主体的授权表单,目标租户切换后重新加载直接授权。 */
|
|
44
46
|
async function open(type: BaseTenantProjectGrantSubjectType, id: number, tenantId: number) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
await formDialogRef.value?.open({
|
|
48
|
+
load: async () => {
|
|
49
|
+
await loadTenantOptions(true);
|
|
50
|
+
const request = { tenant_id: tenantId, subject_type: type, subject_id: id };
|
|
51
|
+
const [options, grant] = await Promise.all([
|
|
52
|
+
defBaseTenantProjectService.OptionBaseTenantProject({ tenant_id: request.tenant_id }),
|
|
53
|
+
defBaseTenantProjectGrantService.GetBaseTenantProjectGrant(request)
|
|
54
|
+
]);
|
|
55
|
+
return { request, projects: options.list ?? [], grant };
|
|
56
|
+
},
|
|
57
|
+
commit: ({ request, projects, grant }) => {
|
|
58
|
+
reset();
|
|
59
|
+
subjectType = request.subject_type;
|
|
60
|
+
subjectId = request.subject_id;
|
|
61
|
+
form.tenant_id = request.tenant_id;
|
|
62
|
+
projectOptions.value = projects;
|
|
63
|
+
form.all = grant.project_id.length === 1 && grant.project_id[0] === 0;
|
|
64
|
+
form.project_id = form.all ? [] : grant.project_id;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
52
67
|
}
|
|
53
68
|
|
|
54
69
|
/** 加载目标租户项目和当前主体的直接授权,避免快速切换时旧响应覆盖新结果。 */
|
|
@@ -3,9 +3,11 @@ export type { AdminAiExtension } from "./ai";
|
|
|
3
3
|
export { default as TenantProjectManager } from "./components/tenant-project/TenantProjectManager.vue";
|
|
4
4
|
export {
|
|
5
5
|
mergeTenantProjectExtraData,
|
|
6
|
+
arrangeTenantProjectColumns,
|
|
6
7
|
tenantProjectKey,
|
|
7
8
|
type TenantProjectAction,
|
|
8
9
|
type TenantProjectContext,
|
|
10
|
+
type TenantProjectExtraColumn,
|
|
9
11
|
type TenantProjectExtraData,
|
|
10
12
|
type TenantProjectExtraDataLoadContext,
|
|
11
13
|
type TenantProjectExtraDataLoader,
|
|
@@ -398,6 +398,8 @@
|
|
|
398
398
|
"system.base.log.field.os": "Operating system",
|
|
399
399
|
"system.base.log.field.path": "Path",
|
|
400
400
|
"system.base.log.field.project": "Project",
|
|
401
|
+
"system.base.log.field.role_code": "Role code",
|
|
402
|
+
"system.base.log.field.role_id": "Role ID",
|
|
401
403
|
"system.base.log.field.reason": "Reason",
|
|
402
404
|
"system.base.log.field.reason_code": "Reason code",
|
|
403
405
|
"system.base.log.field.referer": "Referrer",
|
|
@@ -648,6 +650,11 @@
|
|
|
648
650
|
"system.base.message.content_format.plain": "Plain text",
|
|
649
651
|
"system.base.message.detail.action": "Details",
|
|
650
652
|
"system.base.message.detail.title": "Message details",
|
|
653
|
+
"system.base.message.dispatch_status.pending": "Pending",
|
|
654
|
+
"system.base.message.dispatch_status.running": "Delivering",
|
|
655
|
+
"system.base.message.dispatch_status.succeeded": "Completed",
|
|
656
|
+
"system.base.message.dispatch_status.failed": "Failed",
|
|
657
|
+
"system.base.message.dispatch_status.cancelled": "Cancelled",
|
|
651
658
|
"system.base.message.field.action_target": "Action view key",
|
|
652
659
|
"system.base.message.field.action_type": "Click action",
|
|
653
660
|
"system.base.message.field.attempt_count": "Attempts",
|
|
@@ -760,6 +767,7 @@
|
|
|
760
767
|
"system.base.migration.title.list": "Migration records",
|
|
761
768
|
"system.base.migration.value.default_module": "Database migration",
|
|
762
769
|
"system.base.oauth_client.action.copy_credentials": "Copy credentials",
|
|
770
|
+
"system.base.oauth_client.confirm.rotate_credentials": "Rotating the client credentials immediately invalidates the old secret. Continue?",
|
|
763
771
|
"system.base.oauth_client.field.api": "Authorized APIs",
|
|
764
772
|
"system.base.oauth_client.field.client_id": "Client ID",
|
|
765
773
|
"system.base.oauth_client.field.client_name": "Client name",
|
|
@@ -398,6 +398,8 @@
|
|
|
398
398
|
"system.base.log.field.os": "オペレーティング システム",
|
|
399
399
|
"system.base.log.field.path": "パス",
|
|
400
400
|
"system.base.log.field.project": "プロジェクト",
|
|
401
|
+
"system.base.log.field.role_code": "ロールコード",
|
|
402
|
+
"system.base.log.field.role_id": "ロール ID",
|
|
401
403
|
"system.base.log.field.reason": "理由",
|
|
402
404
|
"system.base.log.field.reason_code": "理由コード",
|
|
403
405
|
"system.base.log.field.referer": "ソース ページ",
|
|
@@ -648,6 +650,11 @@
|
|
|
648
650
|
"system.base.message.content_format.plain": "プレーンテキスト",
|
|
649
651
|
"system.base.message.detail.action": "詳細",
|
|
650
652
|
"system.base.message.detail.title": "メッセージ詳細",
|
|
653
|
+
"system.base.message.dispatch_status.pending": "配信待ち",
|
|
654
|
+
"system.base.message.dispatch_status.running": "配信中",
|
|
655
|
+
"system.base.message.dispatch_status.succeeded": "完了",
|
|
656
|
+
"system.base.message.dispatch_status.failed": "失敗",
|
|
657
|
+
"system.base.message.dispatch_status.cancelled": "キャンセル済み",
|
|
651
658
|
"system.base.message.field.action_target": "遷移先ビューキー",
|
|
652
659
|
"system.base.message.field.action_type": "クリック操作",
|
|
653
660
|
"system.base.message.field.attempt_count": "試行回数",
|
|
@@ -760,6 +767,7 @@
|
|
|
760
767
|
"system.base.migration.title.list": "マイグレーション履歴一覧",
|
|
761
768
|
"system.base.migration.value.default_module": "データベースの移行",
|
|
762
769
|
"system.base.oauth_client.action.copy_credentials": "資格情報をコピー",
|
|
770
|
+
"system.base.oauth_client.confirm.rotate_credentials": "クライアント資格情報をローテーションすると旧シークレットは直ちに無効になります。続行しますか?",
|
|
763
771
|
"system.base.oauth_client.field.api": "許可された API",
|
|
764
772
|
"system.base.oauth_client.field.client_id": "クライアント ID",
|
|
765
773
|
"system.base.oauth_client.field.client_name": "クライアント名",
|
|
@@ -398,6 +398,8 @@
|
|
|
398
398
|
"system.base.log.field.os": "操作系统",
|
|
399
399
|
"system.base.log.field.path": "请求路径",
|
|
400
400
|
"system.base.log.field.project": "项目范围",
|
|
401
|
+
"system.base.log.field.role_code": "角色编码",
|
|
402
|
+
"system.base.log.field.role_id": "角色 ID",
|
|
401
403
|
"system.base.log.field.reason": "原因说明",
|
|
402
404
|
"system.base.log.field.reason_code": "原因编码",
|
|
403
405
|
"system.base.log.field.referer": "来源页",
|
|
@@ -648,6 +650,11 @@
|
|
|
648
650
|
"system.base.message.content_format.plain": "纯文本",
|
|
649
651
|
"system.base.message.detail.action": "详情",
|
|
650
652
|
"system.base.message.detail.title": "消息详情",
|
|
653
|
+
"system.base.message.dispatch_status.pending": "待投递",
|
|
654
|
+
"system.base.message.dispatch_status.running": "投递中",
|
|
655
|
+
"system.base.message.dispatch_status.succeeded": "已完成",
|
|
656
|
+
"system.base.message.dispatch_status.failed": "失败",
|
|
657
|
+
"system.base.message.dispatch_status.cancelled": "已取消",
|
|
651
658
|
"system.base.message.field.action_target": "动作视图键",
|
|
652
659
|
"system.base.message.field.action_type": "点击动作",
|
|
653
660
|
"system.base.message.field.attempt_count": "尝试次数",
|
|
@@ -760,6 +767,7 @@
|
|
|
760
767
|
"system.base.migration.title.list": "迁移记录列表",
|
|
761
768
|
"system.base.migration.value.default_module": "数据库迁移",
|
|
762
769
|
"system.base.oauth_client.action.copy_credentials": "复制客户端凭据",
|
|
770
|
+
"system.base.oauth_client.confirm.rotate_credentials": "轮换客户端凭据会立即使旧密钥失效,确认继续吗?",
|
|
763
771
|
"system.base.oauth_client.field.api": "授权接口",
|
|
764
772
|
"system.base.oauth_client.field.client_id": "客户端标识",
|
|
765
773
|
"system.base.oauth_client.field.client_name": "客户端名称",
|
|
@@ -398,6 +398,8 @@
|
|
|
398
398
|
"system.base.log.field.os": "作業系統",
|
|
399
399
|
"system.base.log.field.path": "請求路徑",
|
|
400
400
|
"system.base.log.field.project": "專案範圍",
|
|
401
|
+
"system.base.log.field.role_code": "角色編碼",
|
|
402
|
+
"system.base.log.field.role_id": "角色 ID",
|
|
401
403
|
"system.base.log.field.reason": "原因說明",
|
|
402
404
|
"system.base.log.field.reason_code": "原因編碼",
|
|
403
405
|
"system.base.log.field.referer": "來源頁",
|
|
@@ -648,6 +650,11 @@
|
|
|
648
650
|
"system.base.message.content_format.plain": "純文字",
|
|
649
651
|
"system.base.message.detail.action": "詳情",
|
|
650
652
|
"system.base.message.detail.title": "訊息詳情",
|
|
653
|
+
"system.base.message.dispatch_status.pending": "待投遞",
|
|
654
|
+
"system.base.message.dispatch_status.running": "投遞中",
|
|
655
|
+
"system.base.message.dispatch_status.succeeded": "已完成",
|
|
656
|
+
"system.base.message.dispatch_status.failed": "失敗",
|
|
657
|
+
"system.base.message.dispatch_status.cancelled": "已取消",
|
|
651
658
|
"system.base.message.field.action_target": "動作視圖鍵",
|
|
652
659
|
"system.base.message.field.action_type": "點擊動作",
|
|
653
660
|
"system.base.message.field.attempt_count": "嘗試次數",
|
|
@@ -760,6 +767,7 @@
|
|
|
760
767
|
"system.base.migration.title.list": "遷移記錄列表",
|
|
761
768
|
"system.base.migration.value.default_module": "資料庫遷移",
|
|
762
769
|
"system.base.oauth_client.action.copy_credentials": "複製客戶端憑據",
|
|
770
|
+
"system.base.oauth_client.confirm.rotate_credentials": "輪換客戶端憑據會立即使舊密鑰失效,確定要繼續嗎?",
|
|
763
771
|
"system.base.oauth_client.field.api": "授權介面",
|
|
764
772
|
"system.base.oauth_client.field.client_id": "客戶端識別碼",
|
|
765
773
|
"system.base.oauth_client.field.client_name": "客戶端名稱",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
|
2
|
+
// versions:
|
|
3
|
+
// protoc-gen-ts_proto v2.11.8
|
|
4
|
+
// protoc unknown
|
|
5
|
+
// source: base/v1/ai_search.proto
|
|
6
|
+
|
|
7
|
+
/* eslint-disable */
|
|
8
|
+
|
|
9
|
+
/** AI 助手联网搜索请求 */
|
|
10
|
+
export interface SearchAiWebRequest {
|
|
11
|
+
/** 搜索关键词 */
|
|
12
|
+
query: string;
|
|
13
|
+
/** 返回结果数量:0 表示默认5条,最大10条 */
|
|
14
|
+
limit: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** AI 助手联网搜索响应 */
|
|
18
|
+
export interface SearchAiWebResponse {
|
|
19
|
+
/** 搜索结果列表 */
|
|
20
|
+
items: SearchAiWebItem[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** AI 助手联网搜索结果 */
|
|
24
|
+
export interface SearchAiWebItem {
|
|
25
|
+
/** 结果标题 */
|
|
26
|
+
title: string;
|
|
27
|
+
/** 结果链接 */
|
|
28
|
+
url: string;
|
|
29
|
+
/** 结果摘要 */
|
|
30
|
+
snippet: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Base AI 助手联网搜索服务 */
|
|
34
|
+
export interface AiSearchService {
|
|
35
|
+
/** 联网搜索公开信息并返回结果摘要 */
|
|
36
|
+
SearchAiWeb(request: SearchAiWebRequest): Promise<SearchAiWebResponse>;
|
|
37
|
+
}
|
|
@@ -236,42 +236,7 @@ function setRecordText(recordText: string) {
|
|
|
236
236
|
|
|
237
237
|
/** 标准化语音识别文本,压掉多余空白。 */
|
|
238
238
|
function normalizeRecordText(recordText: string) {
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/** 压缩 useRecord 在中文连续识别时返回的前缀累计文本。 */
|
|
243
|
-
function collapseCumulativeRecordText(text: string) {
|
|
244
|
-
if (text.length < 4) return text;
|
|
245
|
-
for (let candidateLength = 2; candidateLength <= Math.floor(text.length / 2); candidateLength++) {
|
|
246
|
-
const candidate = text.slice(-candidateLength);
|
|
247
|
-
const matchResult = matchCumulativeRecordCandidate(text, candidate);
|
|
248
|
-
if (matchResult.matched && (matchResult.hasPartial || matchResult.segmentCount >= 3)) {
|
|
249
|
-
return candidate;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return text;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/** 判断文本是否由同一识别结果的前缀片段累计组成。 */
|
|
256
|
-
function matchCumulativeRecordCandidate(text: string, candidate: string) {
|
|
257
|
-
let index = 0;
|
|
258
|
-
let segmentCount = 0;
|
|
259
|
-
let hasPartial = false;
|
|
260
|
-
while (index < text.length) {
|
|
261
|
-
let matchedLength = 0;
|
|
262
|
-
const maxLength = Math.min(candidate.length, text.length - index);
|
|
263
|
-
for (let length = maxLength; length >= 1; length--) {
|
|
264
|
-
if (candidate.startsWith(text.slice(index, index + length))) {
|
|
265
|
-
matchedLength = length;
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
if (!matchedLength) return { matched: false, segmentCount, hasPartial };
|
|
270
|
-
if (matchedLength < candidate.length) hasPartial = true;
|
|
271
|
-
segmentCount++;
|
|
272
|
-
index += matchedLength;
|
|
273
|
-
}
|
|
274
|
-
return { matched: true, segmentCount, hasPartial };
|
|
239
|
+
return recordText.replace(/\s+/g, " ").trim();
|
|
275
240
|
}
|
|
276
241
|
|
|
277
242
|
/** 根据浏览器语音识别错误类型生成用户可理解的提示。 */
|