@liujitcn/kratos-admin-system 0.0.62 → 0.0.65
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 +16 -1
- package/dist/package/declarations/src/api/base/v1/ai_provider.d.ts +7 -0
- package/dist/package/declarations/src/api/system/admin/v1/ai_provider.d.ts +20 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_api_rate_limit_policy.d.ts +19 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_message_provider.d.ts +21 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_message_template.d.ts +16 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_oauth_provider.d.ts +18 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_rate_limit_rule.d.ts +21 -0
- package/dist/package/declarations/src/components/api/ApiTransfer.vue.d.ts +35 -0
- package/dist/package/declarations/src/components/api/apiTransfer.d.ts +13 -0
- package/dist/package/declarations/src/components/i18n/DynamicI18nCell.vue.d.ts +2 -2
- package/dist/package/declarations/src/components/i18n/dynamicI18n.d.ts +3 -4
- package/dist/package/declarations/src/locales/generated.d.ts +968 -0
- package/dist/package/declarations/src/rpc/base/v1/ai_message.d.ts +4 -0
- package/dist/package/declarations/src/rpc/base/v1/ai_provider.d.ts +29 -0
- package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +20 -0
- package/dist/package/declarations/src/rpc/google/protobuf/struct.d.ts +81 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/ai_provider.d.ts +133 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_api_rate_limit_policy.d.ts +137 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n.d.ts +4 -23
- package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +4 -4
- package/dist/package/declarations/src/rpc/system/admin/v1/base_message_category.d.ts +19 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_message_provider.d.ts +126 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_message_template.d.ts +99 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_oauth_provider.d.ts +133 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_rate_limit_rule.d.ts +144 -0
- package/dist/package/declarations/src/utils/persisted-message.d.ts +4 -0
- package/dist/package/declarations/src/utils/rateLimit.d.ts +24 -0
- package/dist/package/declarations/src/views/ai/chat/components/ChatPanel.vue.d.ts +11 -2
- package/dist/package/declarations/src/views/ai/chat/components/XSender.vue.d.ts +9 -0
- package/dist/package/declarations/src/views/ai/chat/modelDisplay.d.ts +5 -0
- package/dist/package/declarations/src/views/ai/chat/modelSelection.d.ts +9 -0
- package/dist/package/declarations/src/views/base/ai-provider/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/api-rate-limit-policy/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/message-provider/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/message-template/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/oauth-provider/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/views/base/rate-limit-rule/index.vue.d.ts +3 -0
- package/dist/package/src/api/base/v1/ai_provider.ts +22 -0
- package/dist/package/src/api/system/admin/v1/ai_provider.ts +57 -0
- package/dist/package/src/api/system/admin/v1/base_api_rate_limit_policy.ts +51 -0
- package/dist/package/src/api/system/admin/v1/base_message_provider.ts +57 -0
- package/dist/package/src/api/system/admin/v1/base_message_template.ts +44 -0
- package/dist/package/src/api/system/admin/v1/base_oauth_provider.ts +50 -0
- package/dist/package/src/api/system/admin/v1/base_rate_limit_rule.ts +58 -0
- package/dist/package/src/components/ai/Ai.vue +1 -1
- package/dist/package/src/components/api/ApiTransfer.vue +117 -0
- package/dist/package/src/components/api/apiTransfer.ts +27 -0
- package/dist/package/src/components/i18n/DynamicI18nCell.vue +8 -8
- package/dist/package/src/components/i18n/DynamicI18nEditor.vue +6 -3
- package/dist/package/src/components/i18n/dynamicI18n.ts +4 -5
- package/dist/package/src/components/tenant-project/TenantProjectManager.vue +2 -1
- package/dist/package/src/locales/en-US.json +246 -4
- package/dist/package/src/locales/ja-JP.json +246 -4
- package/dist/package/src/locales/zh-CN.json +246 -4
- package/dist/package/src/locales/zh-TW.json +246 -4
- package/dist/package/src/rpc/base/v1/ai_message.ts +7 -1
- package/dist/package/src/rpc/base/v1/ai_provider.ts +41 -0
- package/dist/package/src/rpc/base/v1/oauth.ts +16 -0
- package/dist/package/src/rpc/google/protobuf/struct.ts +80 -0
- package/dist/package/src/rpc/system/admin/v1/ai_provider.ts +155 -0
- package/dist/package/src/rpc/system/admin/v1/base_api_rate_limit_policy.ts +160 -0
- package/dist/package/src/rpc/system/admin/v1/base_i18n.ts +4 -24
- package/dist/package/src/rpc/system/admin/v1/base_message.ts +4 -4
- package/dist/package/src/rpc/system/admin/v1/base_message_category.ts +20 -0
- package/dist/package/src/rpc/system/admin/v1/base_message_provider.ts +150 -0
- package/dist/package/src/rpc/system/admin/v1/base_message_template.ts +117 -0
- package/dist/package/src/rpc/system/admin/v1/base_oauth_provider.ts +156 -0
- package/dist/package/src/rpc/system/admin/v1/base_rate_limit_rule.ts +167 -0
- package/dist/package/src/utils/persisted-message.ts +21 -0
- package/dist/package/src/utils/rateLimit.ts +140 -0
- package/dist/package/src/views/ai/chat/components/ChatPanel.vue +40 -5
- package/dist/package/src/views/ai/chat/components/XSender.vue +309 -3
- package/dist/package/src/views/ai/chat/index.vue +48 -1
- package/dist/package/src/views/ai/chat/modelDisplay.ts +67 -0
- package/dist/package/src/views/ai/chat/modelSelection.ts +31 -0
- package/dist/package/src/views/base/ai-provider/index.vue +613 -0
- package/dist/package/src/views/base/api-rate-limit-policy/index.vue +429 -0
- package/dist/package/src/views/base/backup-management/archive-record/index.vue +2 -0
- package/dist/package/src/views/base/backup-management/archive-restore/index.vue +2 -1
- package/dist/package/src/views/base/backup-management/backup-record/index.vue +2 -0
- package/dist/package/src/views/base/backup-management/backup-restore/index.vue +2 -1
- package/dist/package/src/views/base/config/index.vue +12 -13
- package/dist/package/src/views/base/dict/index.vue +2 -3
- package/dist/package/src/views/base/dict/item.vue +2 -3
- package/dist/package/src/views/base/job/index.vue +2 -3
- package/dist/package/src/views/base/job/log.vue +3 -2
- package/dist/package/src/views/base/menu/index.vue +27 -83
- package/dist/package/src/views/base/message/index.vue +9 -3
- package/dist/package/src/views/base/message-category/index.vue +34 -3
- package/dist/package/src/views/base/message-provider/index.vue +168 -0
- package/dist/package/src/views/base/message-template/index.vue +105 -0
- package/dist/package/src/views/base/migration/index.vue +1 -1
- package/dist/package/src/views/base/oauth-client/index.vue +6 -6
- package/dist/package/src/views/base/oauth-provider/index.vue +274 -0
- package/dist/package/src/views/base/rate-limit-rule/index.vue +327 -0
- package/dist/package/src/views/base/redact-output-policy/index.vue +1 -1
- package/dist/package/src/views/base/redact-rule/index.vue +12 -2
- package/dist/package/src/views/base/redact-storage-policy/index.vue +4 -0
- package/dist/package/src/views/base/tenant/index.vue +3 -3
- package/package.json +2 -2
|
@@ -47,7 +47,6 @@ import type {
|
|
|
47
47
|
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_job";
|
|
48
48
|
import router, { navigateTo } from "@liujitcn/kratos-admin-core/navigation";
|
|
49
49
|
import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
|
|
50
|
-
import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
|
|
51
50
|
import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
|
|
52
51
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
53
52
|
import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/i18n/DynamicI18nCell.vue";
|
|
@@ -168,7 +167,7 @@ function renderJobNameCell(scope: RenderScope<BaseJob>) {
|
|
|
168
167
|
const row = scope.row;
|
|
169
168
|
return h(DynamicI18nCell, {
|
|
170
169
|
source: row.name,
|
|
171
|
-
|
|
170
|
+
targetKey: "base_job.name",
|
|
172
171
|
targetId: row.id,
|
|
173
172
|
i18ns: row.i18ns
|
|
174
173
|
});
|
|
@@ -419,7 +418,7 @@ function handleSubmit() {
|
|
|
419
418
|
const submitData = JSON.parse(JSON.stringify(formData)) as BaseJobForm;
|
|
420
419
|
submitData.i18ns = serializeDynamicI18ns(
|
|
421
420
|
i18nValues.value,
|
|
422
|
-
|
|
421
|
+
"base_job.name",
|
|
423
422
|
submitData.id,
|
|
424
423
|
submitData.name
|
|
425
424
|
);
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<pre class="code-block">{{ formatJson(detail.input) }}</pre>
|
|
18
18
|
</el-descriptions-item>
|
|
19
19
|
<el-descriptions-item :label="t('system.base.job.log.field.output')">
|
|
20
|
-
<pre class="code-block">{{ formatJson(detail.output) }}</pre>
|
|
20
|
+
<pre class="code-block">{{ formatJson(resolvePersistedTaskOutput(detail.output)) }}</pre>
|
|
21
21
|
</el-descriptions-item>
|
|
22
22
|
</el-descriptions>
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
v-if="detail.status === BaseJobLogStatus.BASE_JOB_LOG_STATUS_FAIL"
|
|
26
26
|
:title="t('system.base.job.log.field.error')"
|
|
27
27
|
type="error"
|
|
28
|
-
:description="detail.error"
|
|
28
|
+
:description="resolvePersistedMessage(detail.error)"
|
|
29
29
|
class="mt-4"
|
|
30
30
|
show-icon
|
|
31
31
|
/>
|
|
@@ -52,6 +52,7 @@ import { formatDateTime, formatJson } from "@liujitcn/kratos-admin-core/format";
|
|
|
52
52
|
import type { BaseJobLog, PageBaseJobLogRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_job_log";
|
|
53
53
|
import { BaseJobLogStatus } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_job_log";
|
|
54
54
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
55
|
+
import { resolvePersistedMessage, resolvePersistedTaskOutput } from "../../../utils/persisted-message";
|
|
55
56
|
|
|
56
57
|
defineOptions({
|
|
57
58
|
name: "BaseJobLog",
|
|
@@ -38,15 +38,23 @@
|
|
|
38
38
|
<DynamicI18nEditor v-model="i18nValues" :source="formData.meta.title" :maxlength="100" />
|
|
39
39
|
</template>
|
|
40
40
|
|
|
41
|
-
<template #
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
<template #apiTransfer>
|
|
42
|
+
<ApiTransfer
|
|
43
|
+
v-model="formData.api"
|
|
44
|
+
:options="apiOptions"
|
|
45
|
+
:titles="[t('system.base.menu.value.available_api'), t('system.base.menu.value.selected_api')]"
|
|
46
|
+
>
|
|
47
|
+
<template #default="{ option }">
|
|
48
|
+
<el-popover effect="light" trigger="hover" placement="top" width="auto">
|
|
49
|
+
<template #default>
|
|
50
|
+
<div>{{ t("system.base.api.field.operation") }}:{{ option.operation }}</div>
|
|
51
|
+
<div>{{ t("system.base.api.field.method") }}:{{ option.method }}</div>
|
|
52
|
+
<div>{{ t("system.base.api.field.path") }}:{{ option.path }}</div>
|
|
53
|
+
</template>
|
|
54
|
+
<template #reference>{{ option.label }}</template>
|
|
55
|
+
</el-popover>
|
|
47
56
|
</template>
|
|
48
|
-
|
|
49
|
-
</el-popover>
|
|
57
|
+
</ApiTransfer>
|
|
50
58
|
</template>
|
|
51
59
|
</FormDialog>
|
|
52
60
|
</div>
|
|
@@ -65,9 +73,10 @@ import type {
|
|
|
65
73
|
} from "@liujitcn/kratos-admin-core/components/ProTable/interface";
|
|
66
74
|
import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
|
|
67
75
|
import SelectIcon from "@liujitcn/kratos-admin-core/components/SelectIcon/index.vue";
|
|
76
|
+
import ApiTransfer from "@liujitcn/kratos-admin-system/components/api/ApiTransfer.vue";
|
|
77
|
+
import { loadApiTransferCatalog, type ApiTransferOption } from "@liujitcn/kratos-admin-system/components/api/apiTransfer";
|
|
68
78
|
import { defBaseMenuService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_menu";
|
|
69
79
|
import { loadEnabledBaseLanguages } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_language";
|
|
70
|
-
import { defBaseApiService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_api";
|
|
71
80
|
import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
|
|
72
81
|
import type { BaseApi } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_api";
|
|
73
82
|
import type {
|
|
@@ -79,7 +88,6 @@ import type {
|
|
|
79
88
|
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_menu";
|
|
80
89
|
import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
|
|
81
90
|
import { BaseMenuType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/common";
|
|
82
|
-
import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
|
|
83
91
|
import { normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
|
|
84
92
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
85
93
|
import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/i18n/DynamicI18nEditor.vue";
|
|
@@ -113,6 +121,7 @@ const menuOptions = ref<ProFormOption[]>([]);
|
|
|
113
121
|
const parentMenuTypeMap = ref(new Map<number, BaseMenuType>());
|
|
114
122
|
const appMenuIds = ref(new Set<number>([APP_MENU_ROOT_ID]));
|
|
115
123
|
const apiList = ref<BaseApi[]>([]);
|
|
124
|
+
const apiOptions = ref<ApiTransferOption[]>([]);
|
|
116
125
|
const i18nValues = ref<DynamicI18nValue[]>(normalizeDynamicI18ns(undefined));
|
|
117
126
|
|
|
118
127
|
const dialog = reactive({
|
|
@@ -296,7 +305,7 @@ function renderMenuTitleCell(scope: RenderScope<BaseMenu>) {
|
|
|
296
305
|
const row = scope.row;
|
|
297
306
|
return h(DynamicI18nCell, {
|
|
298
307
|
source: row.meta?.title ?? "",
|
|
299
|
-
|
|
308
|
+
targetKey: "base_menu.meta.title",
|
|
300
309
|
targetId: row.id,
|
|
301
310
|
i18ns: row.i18ns
|
|
302
311
|
});
|
|
@@ -411,15 +420,6 @@ const headerActions = computed<HeaderActionProps[]>(() => [
|
|
|
411
420
|
}
|
|
412
421
|
]);
|
|
413
422
|
|
|
414
|
-
/** API 穿梭框可选数据。 */
|
|
415
|
-
const transferData = computed<ProFormOption[]>(() => {
|
|
416
|
-
return apiList.value.map(item => ({
|
|
417
|
-
...item,
|
|
418
|
-
value: item.operation,
|
|
419
|
-
label: `${item.service_desc}/${item.desc}`
|
|
420
|
-
}));
|
|
421
|
-
});
|
|
422
|
-
|
|
423
423
|
/** 菜单表单字段配置。 */
|
|
424
424
|
const formFields = computed<ProFormField[]>(() => [
|
|
425
425
|
{
|
|
@@ -653,14 +653,8 @@ const formFields = computed<ProFormField[]>(() => [
|
|
|
653
653
|
{
|
|
654
654
|
prop: "api",
|
|
655
655
|
label: t("system.base.menu.field.api_list"),
|
|
656
|
-
component: "
|
|
657
|
-
slotName: "
|
|
658
|
-
options: transferData.value,
|
|
659
|
-
props: {
|
|
660
|
-
class: "menu-api-transfer",
|
|
661
|
-
filterable: true,
|
|
662
|
-
titles: [t("system.base.menu.value.available_api"), t("system.base.menu.value.selected_api")]
|
|
663
|
-
},
|
|
656
|
+
component: "slot",
|
|
657
|
+
slotName: "apiTransfer",
|
|
664
658
|
visible: model =>
|
|
665
659
|
model.id === APP_MENU_ROOT_ID ||
|
|
666
660
|
model.type === BaseMenuType.BASE_MENU_TYPE_MENU ||
|
|
@@ -993,7 +987,7 @@ function buildSubmitPayload(): BaseMenuForm {
|
|
|
993
987
|
const payload = normalizeMenuForm(formData);
|
|
994
988
|
payload.i18ns = serializeDynamicI18ns(
|
|
995
989
|
i18nValues.value,
|
|
996
|
-
|
|
990
|
+
"base_menu.meta.title",
|
|
997
991
|
payload.id,
|
|
998
992
|
payload.meta?.title ?? ""
|
|
999
993
|
);
|
|
@@ -1054,10 +1048,11 @@ function buildSubmitPayload(): BaseMenuForm {
|
|
|
1054
1048
|
|
|
1055
1049
|
/** 加载菜单树选项和 API 列表,确保弹窗打开时相关数据已可用。 */
|
|
1056
1050
|
async function loadDialogResources() {
|
|
1057
|
-
const [menuData,
|
|
1051
|
+
const [menuData, apiCatalog] = await Promise.all([defBaseMenuService.TreeBaseMenu({}), loadApiTransferCatalog()]);
|
|
1058
1052
|
return {
|
|
1059
1053
|
menuOptions: buildMenuOptions(menuData.base_menus ?? []),
|
|
1060
|
-
apiList:
|
|
1054
|
+
apiList: apiCatalog.apis,
|
|
1055
|
+
apiOptions: apiCatalog.options
|
|
1061
1056
|
};
|
|
1062
1057
|
}
|
|
1063
1058
|
|
|
@@ -1137,6 +1132,7 @@ async function handleOpenDialog(parentMenu?: BaseMenu, menuId?: number) {
|
|
|
1137
1132
|
commit: ({ resources, data }) => {
|
|
1138
1133
|
menuOptions.value = resources.menuOptions;
|
|
1139
1134
|
apiList.value = resources.apiList;
|
|
1135
|
+
apiOptions.value = resources.apiOptions;
|
|
1140
1136
|
dialog.parentLocked = Boolean(parentMenu || menuId);
|
|
1141
1137
|
dialog.editing = Boolean(menuId);
|
|
1142
1138
|
dialog.parentType = parentMenu?.type ?? BaseMenuType.BASE_MENU_TYPE_UNSPECIFIED;
|
|
@@ -1264,51 +1260,6 @@ function handleDeleteMenu(selected?: number | string | Array<number | string> |
|
|
|
1264
1260
|
</style>
|
|
1265
1261
|
|
|
1266
1262
|
<style lang="scss">
|
|
1267
|
-
.menu-form-dialog {
|
|
1268
|
-
.menu-api-transfer {
|
|
1269
|
-
display: grid;
|
|
1270
|
-
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
|
1271
|
-
align-items: center;
|
|
1272
|
-
gap: 16px;
|
|
1273
|
-
width: 100%;
|
|
1274
|
-
.el-transfer-panel {
|
|
1275
|
-
width: 100%;
|
|
1276
|
-
min-width: 0;
|
|
1277
|
-
}
|
|
1278
|
-
.el-transfer__buttons {
|
|
1279
|
-
display: flex;
|
|
1280
|
-
flex-direction: column;
|
|
1281
|
-
gap: 12px;
|
|
1282
|
-
padding: 0;
|
|
1283
|
-
.el-button {
|
|
1284
|
-
margin: 0;
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
.el-transfer-panel__body {
|
|
1288
|
-
height: 360px;
|
|
1289
|
-
}
|
|
1290
|
-
.el-transfer-panel__list.is-filterable {
|
|
1291
|
-
height: 300px;
|
|
1292
|
-
}
|
|
1293
|
-
.el-transfer-panel__item.el-checkbox {
|
|
1294
|
-
align-items: flex-start;
|
|
1295
|
-
height: auto;
|
|
1296
|
-
min-height: 36px;
|
|
1297
|
-
padding-top: 8px;
|
|
1298
|
-
padding-bottom: 8px;
|
|
1299
|
-
.el-checkbox__input {
|
|
1300
|
-
top: 3px;
|
|
1301
|
-
}
|
|
1302
|
-
.el-checkbox__label {
|
|
1303
|
-
display: block;
|
|
1304
|
-
white-space: normal;
|
|
1305
|
-
overflow-wrap: anywhere;
|
|
1306
|
-
line-height: 20px;
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
1263
|
@media (max-width: 767px) {
|
|
1313
1264
|
.menu-form-dialog {
|
|
1314
1265
|
.el-col {
|
|
@@ -1322,13 +1273,6 @@ function handleDeleteMenu(selected?: number | string | Array<number | string> |
|
|
|
1322
1273
|
justify-content: flex-start;
|
|
1323
1274
|
width: auto !important;
|
|
1324
1275
|
}
|
|
1325
|
-
.menu-api-transfer {
|
|
1326
|
-
grid-template-columns: minmax(0, 1fr);
|
|
1327
|
-
.el-transfer__buttons {
|
|
1328
|
-
flex-direction: row;
|
|
1329
|
-
justify-content: center;
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
1276
|
}
|
|
1333
1277
|
}
|
|
1334
1278
|
</style>
|
|
@@ -87,7 +87,9 @@
|
|
|
87
87
|
optionLabel(statusOptions, detail.data.base_message?.status)
|
|
88
88
|
}}</el-descriptions-item>
|
|
89
89
|
<el-descriptions-item :label="t('system.base.message.field.sender')">{{
|
|
90
|
-
detail.data.base_message?.sender_name
|
|
90
|
+
detail.data.base_message?.sender_name === "系统"
|
|
91
|
+
? t("system.notification.sender.system")
|
|
92
|
+
: resolvePersistedMessage(detail.data.base_message?.sender_name)
|
|
91
93
|
}}</el-descriptions-item>
|
|
92
94
|
<el-descriptions-item :label="t('system.base.message.field.delivered_total')">{{
|
|
93
95
|
detail.data.base_message?.delivered_total
|
|
@@ -125,7 +127,9 @@
|
|
|
125
127
|
:label="t('system.base.message.field.last_error')"
|
|
126
128
|
min-width="220"
|
|
127
129
|
show-overflow-tooltip
|
|
128
|
-
|
|
130
|
+
>
|
|
131
|
+
<template #default="scope">{{ resolvePersistedMessage(scope.row.last_error) }}</template>
|
|
132
|
+
</el-table-column>
|
|
129
133
|
<el-table-column :label="t('common.field.operation')">
|
|
130
134
|
<template #default="scope">
|
|
131
135
|
<el-button
|
|
@@ -156,8 +160,10 @@ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
|
|
|
156
160
|
import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
|
|
157
161
|
import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
|
|
158
162
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
163
|
+
import { resolvePersistedMessage } from "../../../utils/persisted-message";
|
|
159
164
|
import { defBaseMessageService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_message";
|
|
160
165
|
import { defBaseMessageCategoryService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_message_category";
|
|
166
|
+
import { BaseMessageCategoryInboxEnabled } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_message_category";
|
|
161
167
|
import type {
|
|
162
168
|
BaseMessage,
|
|
163
169
|
BaseMessageDetail,
|
|
@@ -570,7 +576,7 @@ async function loadCategoryOptions() {
|
|
|
570
576
|
|
|
571
577
|
/** 请求消息分类选项。 */
|
|
572
578
|
async function requestCategoryOptions() {
|
|
573
|
-
const result = await defBaseMessageCategoryService.OptionBaseMessageCategory({});
|
|
579
|
+
const result = await defBaseMessageCategoryService.OptionBaseMessageCategory({ inbox_enabled: BaseMessageCategoryInboxEnabled.BASE_MESSAGE_CATEGORY_INBOX_ENABLED_ENABLE });
|
|
574
580
|
return result.list.map(item => ({ label: item.label, value: item.value, disabled: item.disabled }));
|
|
575
581
|
}
|
|
576
582
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
18
|
<script setup lang="ts">
|
|
19
|
-
import { computed, h, reactive, ref, type Component } from "vue";
|
|
19
|
+
import { computed, h, onMounted, reactive, ref, type Component } from "vue";
|
|
20
20
|
import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
|
|
21
21
|
import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
|
|
22
22
|
import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
|
|
@@ -26,11 +26,13 @@ import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-c
|
|
|
26
26
|
import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
|
|
27
27
|
import { t } from "@liujitcn/kratos-admin-core";
|
|
28
28
|
import { defBaseMessageCategoryService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_message_category";
|
|
29
|
+
import { defBaseMessageProviderService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_message_provider";
|
|
29
30
|
import type {
|
|
30
31
|
BaseMessageCategory,
|
|
31
32
|
BaseMessageCategoryForm,
|
|
32
33
|
PageBaseMessageCategoryRequest
|
|
33
34
|
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_message_category";
|
|
35
|
+
import { BaseMessageCategoryInboxEnabled } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_message_category";
|
|
34
36
|
import { MessagePriority } from "@liujitcn/kratos-admin-system/rpc/base/v1/notification";
|
|
35
37
|
import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
|
|
36
38
|
|
|
@@ -43,11 +45,16 @@ const proTable = ref<ProTableInstance>();
|
|
|
43
45
|
const formDialogRef = ref<InstanceType<typeof FormDialog>>();
|
|
44
46
|
const dialog = reactive({ visible: false, titleKey: "common.action.create" });
|
|
45
47
|
const formData = reactive<BaseMessageCategoryForm>(defaultForm());
|
|
48
|
+
const providerOptions = ref<ProFormOption[]>([]);
|
|
46
49
|
|
|
47
50
|
const statusOptions = computed<ProFormOption[]>(() => [
|
|
48
51
|
{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
|
|
49
52
|
{ label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
|
|
50
53
|
]);
|
|
54
|
+
const inboxEnabledOptions = computed<ProFormOption[]>(() => [
|
|
55
|
+
{ label: t("common.status.enabled"), value: BaseMessageCategoryInboxEnabled.BASE_MESSAGE_CATEGORY_INBOX_ENABLED_ENABLE },
|
|
56
|
+
{ label: t("common.status.disabled"), value: BaseMessageCategoryInboxEnabled.BASE_MESSAGE_CATEGORY_INBOX_ENABLED_DISABLE }
|
|
57
|
+
]);
|
|
51
58
|
const priorityOptions = computed<ProFormOption[]>(() => [
|
|
52
59
|
{ label: t("system.base.message.priority.normal"), value: MessagePriority.MESSAGE_PRIORITY_NORMAL },
|
|
53
60
|
{ label: t("system.base.message.priority.important"), value: MessagePriority.MESSAGE_PRIORITY_IMPORTANT },
|
|
@@ -175,6 +182,20 @@ const formFields = computed<ProFormField[]>(() => [
|
|
|
175
182
|
labelTooltip: t("system.base.message_category.tooltip.allow_delete"),
|
|
176
183
|
component: "switch"
|
|
177
184
|
},
|
|
185
|
+
{
|
|
186
|
+
prop: "inbox_enabled",
|
|
187
|
+
label: t("system.base.message_category.field.inbox"),
|
|
188
|
+
labelTooltip: t("system.base.message_category.tooltip.inbox"),
|
|
189
|
+
component: "radio-group",
|
|
190
|
+
options: inboxEnabledOptions.value
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
prop: "provider_id",
|
|
194
|
+
label: t("system.base.message_category.field.provider"),
|
|
195
|
+
labelTooltip: t("system.base.message_category.tooltip.provider"),
|
|
196
|
+
component: "checkbox-group",
|
|
197
|
+
options: providerOptions.value
|
|
198
|
+
},
|
|
178
199
|
{ prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value }
|
|
179
200
|
]);
|
|
180
201
|
|
|
@@ -288,10 +309,20 @@ function defaultForm(): BaseMessageCategoryForm {
|
|
|
288
309
|
retention_days: 180,
|
|
289
310
|
allow_archive: true,
|
|
290
311
|
allow_delete: true,
|
|
291
|
-
status: Status.STATUS_ENABLE
|
|
312
|
+
status: Status.STATUS_ENABLE,
|
|
313
|
+
provider_id: [],
|
|
314
|
+
inbox_enabled: BaseMessageCategoryInboxEnabled.BASE_MESSAGE_CATEGORY_INBOX_ENABLED_ENABLE
|
|
292
315
|
};
|
|
293
316
|
}
|
|
294
317
|
|
|
318
|
+
onMounted(loadProviderOptions);
|
|
319
|
+
|
|
320
|
+
/** 加载消息 Provider 复选项。 */
|
|
321
|
+
async function loadProviderOptions() {
|
|
322
|
+
const data = await defBaseMessageProviderService.OptionBaseMessageProvider({});
|
|
323
|
+
providerOptions.value = (data.list ?? []).map(item => ({ label: item.label, value: Number(item.value), disabled: item.disabled }));
|
|
324
|
+
}
|
|
325
|
+
|
|
295
326
|
/** 请求消息分类表格数据。 */
|
|
296
327
|
async function requestTable(params: Record<string, unknown>) {
|
|
297
328
|
const data = await defBaseMessageCategoryService.PageBaseMessageCategory(
|
|
@@ -316,7 +347,7 @@ async function openDialog(id?: number) {
|
|
|
316
347
|
async function handleSubmit() {
|
|
317
348
|
const valid = await formDialogRef.value?.validate();
|
|
318
349
|
if (!valid) return;
|
|
319
|
-
const payload = formData as BaseMessageCategoryForm;
|
|
350
|
+
const payload = JSON.parse(JSON.stringify(formData)) as BaseMessageCategoryForm;
|
|
320
351
|
if (payload.id) await defBaseMessageCategoryService.UpdateBaseMessageCategory({ base_message_category: payload });
|
|
321
352
|
else await defBaseMessageCategoryService.CreateBaseMessageCategory({ base_message_category: payload });
|
|
322
353
|
ElMessage.success(t("common.message.operation_success"));
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="table-box">
|
|
3
|
+
<ProTable ref="proTable" row-key="id" :columns="columns" :header-actions="headerActions" :request-api="requestTable" />
|
|
4
|
+
<FormDialog
|
|
5
|
+
v-model="dialog.visible"
|
|
6
|
+
ref="formDialogRef"
|
|
7
|
+
:title="t(dialog.editing ? 'common.action.edit' : 'common.action.create')"
|
|
8
|
+
width="min(1000px, calc(100vw - 32px))"
|
|
9
|
+
:model="formData"
|
|
10
|
+
:fields="formFields"
|
|
11
|
+
:rules="rules"
|
|
12
|
+
@confirm="handleSubmit"
|
|
13
|
+
@close="handleClose"
|
|
14
|
+
/>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { computed, reactive, ref } from "vue";
|
|
20
|
+
import { ElMessage, ElMessageBox } from "element-plus";
|
|
21
|
+
import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
|
|
22
|
+
import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
|
|
23
|
+
import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
|
|
24
|
+
import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
|
|
25
|
+
import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
|
|
26
|
+
import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
|
|
27
|
+
import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
|
|
28
|
+
import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
|
|
29
|
+
import { t } from "@liujitcn/kratos-admin-core";
|
|
30
|
+
import { defBaseMessageProviderService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_message_provider";
|
|
31
|
+
import type {
|
|
32
|
+
BaseMessageProvider,
|
|
33
|
+
BaseMessageProviderForm,
|
|
34
|
+
PageBaseMessageProviderRequest
|
|
35
|
+
} from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_message_provider";
|
|
36
|
+
import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
|
|
37
|
+
|
|
38
|
+
defineOptions({ name: "BaseMessageProvider", inheritAttrs: false });
|
|
39
|
+
|
|
40
|
+
interface ConfigItem {
|
|
41
|
+
key: string;
|
|
42
|
+
value: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface FormState extends BaseMessageProviderForm {
|
|
46
|
+
config_items: ConfigItem[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { BUTTONS } = useAuthButtons();
|
|
50
|
+
const { isDefaultTenant } = useTenantScope();
|
|
51
|
+
const proTable = ref<ProTableInstance>();
|
|
52
|
+
const formDialogRef = ref<InstanceType<typeof FormDialog>>();
|
|
53
|
+
const dialog = reactive({ visible: false, editing: false });
|
|
54
|
+
const formData = reactive<FormState>(defaultForm());
|
|
55
|
+
|
|
56
|
+
const statusOptions = computed<ProFormOption[]>(() => [
|
|
57
|
+
{ label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
|
|
58
|
+
{ label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const rules = computed(() => ({
|
|
62
|
+
provider: [{ required: true, message: t("system.base.message_provider.validation.provider"), trigger: "blur" }],
|
|
63
|
+
name: [{ required: true, message: t("system.base.message_provider.validation.name"), trigger: "blur" }]
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
const formFields = computed<ProFormField[]>(() => [
|
|
67
|
+
{ prop: "provider", label: t("system.base.message_provider.field.provider"), component: "input", props: { disabled: dialog.editing, maxlength: 32 } },
|
|
68
|
+
{ prop: "name", label: t("system.base.message_provider.field.name"), component: "input", props: { maxlength: 50 } },
|
|
69
|
+
{ prop: "description", label: t("system.base.message_provider.field.description"), component: "input", colSpan: 24, props: { maxlength: 255 } },
|
|
70
|
+
{ prop: "icon", label: t("system.base.message_provider.field.icon"), component: "input", props: { maxlength: 100 } },
|
|
71
|
+
{ prop: "client_id", label: t("system.base.message_provider.field.client_id"), component: "input", props: { maxlength: 255 } },
|
|
72
|
+
{ prop: "client_secret", label: t("system.base.message_provider.field.client_secret"), component: "input", props: { type: "password", showPassword: true, maxlength: 1024, placeholder: dialog.editing ? t("system.base.message_provider.placeholder.keep_secret") : "" } },
|
|
73
|
+
{ prop: "config_items", label: t("system.base.message_provider.field.config"), component: "kv-list", props: { keyInputProps: { maxlength: 128 } } },
|
|
74
|
+
{ prop: "sort", label: t("common.field.sort"), component: "input-number", props: { min: 0, precision: 0 } },
|
|
75
|
+
{ prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value }
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
const columns = computed<ColumnProps[]>(() => [
|
|
79
|
+
{ type: "selection", width: 55 },
|
|
80
|
+
{ prop: "name", label: t("system.base.message_provider.field.name"), minWidth: 150, search: { el: "input" } },
|
|
81
|
+
{ prop: "provider", label: t("system.base.message_provider.field.provider"), minWidth: 130, search: { el: "input" } },
|
|
82
|
+
{ prop: "client_id", label: t("system.base.message_provider.field.client_id"), minWidth: 180 },
|
|
83
|
+
{ prop: "secret_configured", label: t("system.base.message_provider.field.secret_configured"), width: 120, render: scope => (scope.row as BaseMessageProvider).secret_configured ? t("common.status.configured") : t("common.status.not_configured") },
|
|
84
|
+
{ prop: "sort", label: t("common.field.sort"), width: 80, align: "right" },
|
|
85
|
+
{ prop: "status", label: t("common.field.status"), width: 110, search: { el: "select", enum: statusOptions.value }, cellType: "status", statusProps: {
|
|
86
|
+
activeValue: Status.STATUS_ENABLE, inactiveValue: Status.STATUS_DISABLE, activeText: t("common.status.enabled"), inactiveText: t("common.status.disabled"),
|
|
87
|
+
disabled: () => !isDefaultTenant.value || !BUTTONS.value["base:message-provider:status"], beforeChange: scope => handleSetStatus(scope.row as BaseMessageProvider)
|
|
88
|
+
} },
|
|
89
|
+
{ prop: "updated_at", label: t("common.field.updated_at"), minWidth: 180, align: "center" },
|
|
90
|
+
{ prop: "operation", label: t("common.field.operation"), cellType: "actions", actions: [
|
|
91
|
+
{ label: t("common.action.edit"), link: true, icon: EditPen, hidden: () => !isDefaultTenant.value || !BUTTONS.value["base:message-provider:update"], onClick: scope => openDialog((scope.row as BaseMessageProvider).id) },
|
|
92
|
+
{ label: t("common.action.delete"), type: "danger", link: true, icon: Delete, hidden: () => !isDefaultTenant.value || !BUTTONS.value["base:message-provider:delete"], onClick: scope => handleDelete(scope.row as BaseMessageProvider) }
|
|
93
|
+
] }
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
const headerActions = computed<HeaderActionProps[]>(() => [
|
|
97
|
+
{ label: t("common.action.create"), type: "primary", icon: CirclePlus, hidden: !isDefaultTenant.value || !BUTTONS.value["base:message-provider:create"], onClick: () => openDialog() },
|
|
98
|
+
{ label: t("common.action.delete"), type: "danger", icon: Delete, hidden: !isDefaultTenant.value || !BUTTONS.value["base:message-provider:delete"], disabled: scope => !scope.isSelected, onClick: scope => handleDelete(scope.selectedListIds as number[]) }
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
function defaultForm(): FormState {
|
|
102
|
+
return { id: 0, provider: "", name: "", description: "", icon: "", client_id: "", client_secret: "", secret_configured: false, config: {}, config_items: [], sort: 0, status: Status.STATUS_DISABLE };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function requestTable(params: Record<string, unknown>) {
|
|
106
|
+
const data = await defBaseMessageProviderService.PageBaseMessageProvider(buildPageRequest<PageBaseMessageProviderRequest>(params as unknown as PageBaseMessageProviderRequest));
|
|
107
|
+
return { data: { list: data.base_message_providers ?? [], total: data.total } };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function openDialog(id?: number) {
|
|
111
|
+
await formDialogRef.value?.open({
|
|
112
|
+
load: () => (id ? defBaseMessageProviderService.GetBaseMessageProvider({ id }) : undefined),
|
|
113
|
+
commit: data => { Object.assign(formData, defaultForm(), data ?? {}); dialog.editing = Boolean(id); formData.config_items = configToItems(formData.config); }
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function handleSubmit() {
|
|
118
|
+
if (!(await formDialogRef.value?.validate())) return;
|
|
119
|
+
const config = configItemsToMap(formData.config_items);
|
|
120
|
+
if (!config) return;
|
|
121
|
+
const payload = JSON.parse(JSON.stringify(formData)) as BaseMessageProviderForm & { config_items?: ConfigItem[] };
|
|
122
|
+
delete payload.config_items;
|
|
123
|
+
payload.config = config;
|
|
124
|
+
if (payload.id) await defBaseMessageProviderService.UpdateBaseMessageProvider({ base_message_provider: payload });
|
|
125
|
+
else await defBaseMessageProviderService.CreateBaseMessageProvider({ base_message_provider: payload });
|
|
126
|
+
ElMessage.success(t("common.message.operation_success"));
|
|
127
|
+
dialog.visible = false;
|
|
128
|
+
await proTable.value?.getTableList();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function handleDelete(value: BaseMessageProvider | number | number[]) {
|
|
132
|
+
const ids = (Array.isArray(value) ? value : typeof value === "object" ? [value.id] : normalizeSelectedIds(value)).join(",");
|
|
133
|
+
if (!ids) return;
|
|
134
|
+
try {
|
|
135
|
+
await ElMessageBox.confirm(t("common.confirm.delete"), t("common.title.warning"), { type: "warning" });
|
|
136
|
+
} catch {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
await defBaseMessageProviderService.DeleteBaseMessageProvider({ id: ids });
|
|
140
|
+
await proTable.value?.getTableList();
|
|
141
|
+
ElMessage.success(t("common.message.operation_success"));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function handleSetStatus(row: BaseMessageProvider) {
|
|
145
|
+
const status = row.status === Status.STATUS_ENABLE ? Status.STATUS_DISABLE : Status.STATUS_ENABLE;
|
|
146
|
+
try {
|
|
147
|
+
await ElMessageBox.confirm(t("common.dialog.status_change", { action: t(status === Status.STATUS_ENABLE ? "common.status.enabled" : "common.status.disabled"), resource: t("system.base.message_provider.resource"), field: t("system.base.message_provider.field.name"), value: row.name }), t("common.title.notice"), { type: "warning" });
|
|
148
|
+
await defBaseMessageProviderService.SetBaseMessageProviderStatus({ id: row.id, status });
|
|
149
|
+
return true;
|
|
150
|
+
} catch { return false; }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function handleClose() { Object.assign(formData, defaultForm()); formDialogRef.value?.resetFields(); }
|
|
154
|
+
|
|
155
|
+
function configToItems(config: Record<string, any> | undefined): ConfigItem[] { return Object.entries(config ?? {}).map(([key, value]) => ({ key, value: typeof value === "string" ? value : JSON.stringify(value) })); }
|
|
156
|
+
|
|
157
|
+
function configItemsToMap(items: ConfigItem[]): Record<string, unknown> | undefined {
|
|
158
|
+
const result: Record<string, unknown> = {};
|
|
159
|
+
for (const item of items) {
|
|
160
|
+
const key = item.key.trim();
|
|
161
|
+
if (!key || Object.prototype.hasOwnProperty.call(result, key)) { ElMessage.error(t("system.base.message_provider.message.config_invalid")); return undefined; }
|
|
162
|
+
const value = item.value.trim();
|
|
163
|
+
if (!value) { result[key] = ""; continue; }
|
|
164
|
+
try { result[key] = JSON.parse(value); } catch { result[key] = value; }
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
</script>
|