@liujitcn/kratos-admin-system 0.0.49 → 0.0.50

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.
Files changed (94) hide show
  1. package/README.md +44 -8
  2. package/dist/package/declarations/src/api/system/admin/v1/base_i18n_custom.d.ts +18 -0
  3. package/dist/package/declarations/src/api/system/admin/v1/base_tenant.d.ts +2 -2
  4. package/dist/package/declarations/src/api/system/admin/v1/base_tenant_project.d.ts +23 -0
  5. package/dist/package/declarations/src/api/system/admin/v1/base_tenant_project_grant.d.ts +16 -0
  6. package/dist/package/declarations/src/components/tenant-project/ProjectGrantDialog.vue.d.ts +8 -0
  7. package/dist/package/declarations/src/components/tenant-project/TenantProjectManager.vue.d.ts +29 -0
  8. package/dist/package/declarations/src/components/tenant-project/TenantProjectSelect.vue.d.ts +31 -0
  9. package/dist/package/declarations/src/components/tenant-project/TenantProjectText.vue.d.ts +19 -0
  10. package/dist/package/declarations/src/components/tenant-project/tenant-project-manager-data.d.ts +14 -0
  11. package/dist/package/declarations/src/components/tenant-project/tenant-project-manager.d.ts +40 -0
  12. package/dist/package/declarations/src/index.d.ts +2 -0
  13. package/dist/package/declarations/src/locales/generated.d.ts +172 -0
  14. package/dist/package/declarations/src/rpc/base/v1/config.d.ts +11 -0
  15. package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n_custom.d.ts +105 -0
  16. package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant.d.ts +10 -1
  17. package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant_project.d.ts +141 -0
  18. package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant_project_grant.d.ts +105 -0
  19. package/dist/package/declarations/src/views/ai/chat/components/SessionPanel.vue.d.ts +2 -2
  20. package/dist/package/declarations/src/views/base/i18n-custom/index.vue.d.ts +3 -0
  21. package/dist/package/declarations/src/views/base/project-grant/index.vue.d.ts +3 -0
  22. package/dist/package/declarations/src/views/base/tenant-project/index.vue.d.ts +3 -0
  23. package/dist/package/src/api/system/admin/v1/base_i18n_custom.ts +72 -0
  24. package/dist/package/src/api/system/admin/v1/base_tenant.ts +3 -2
  25. package/dist/package/src/api/system/admin/v1/base_tenant_project.ts +94 -0
  26. package/dist/package/src/api/system/admin/v1/base_tenant_project_grant.ts +63 -0
  27. package/dist/package/src/components/tenant-project/ProjectGrantDialog.vue +108 -0
  28. package/dist/package/src/components/tenant-project/TenantProjectManager.vue +452 -0
  29. package/dist/package/src/components/tenant-project/TenantProjectSelect.vue +83 -0
  30. package/dist/package/src/components/tenant-project/TenantProjectText.vue +37 -0
  31. package/dist/package/src/components/tenant-project/tenant-project-manager-data.ts +26 -0
  32. package/dist/package/src/components/tenant-project/tenant-project-manager.ts +48 -0
  33. package/dist/package/src/index.ts +12 -0
  34. package/dist/package/src/locales/README.md +1 -1
  35. package/dist/package/src/locales/en-US.json +45 -2
  36. package/dist/package/src/locales/ja-JP.json +45 -2
  37. package/dist/package/src/locales/zh-CN.json +45 -2
  38. package/dist/package/src/locales/zh-TW.json +45 -2
  39. package/dist/package/src/module.ts +3 -3
  40. package/dist/package/src/rpc/base/v1/config.ts +12 -0
  41. package/dist/package/src/rpc/system/admin/v1/base_i18n_custom.ts +126 -0
  42. package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +11 -1
  43. package/dist/package/src/rpc/system/admin/v1/base_tenant_project.ts +166 -0
  44. package/dist/package/src/rpc/system/admin/v1/base_tenant_project_grant.ts +128 -0
  45. package/dist/package/src/views/ai/chat/components/XSender.vue +4 -3
  46. package/dist/package/src/views/base/api-log/index.vue +3 -3
  47. package/dist/package/src/views/base/config/index.vue +3 -3
  48. package/dist/package/src/views/base/data-access-log/index.vue +3 -3
  49. package/dist/package/src/views/base/dept/index.vue +10 -45
  50. package/dist/package/src/views/base/dict/index.vue +3 -3
  51. package/dist/package/src/views/base/dict/item.vue +3 -3
  52. package/dist/package/src/views/base/file/index.vue +12 -3
  53. package/dist/package/src/views/base/i18n-custom/index.vue +321 -0
  54. package/dist/package/src/views/base/job/index.vue +3 -3
  55. package/dist/package/src/views/base/login-log/index.vue +13 -4
  56. package/dist/package/src/views/base/login-policy/index.vue +97 -34
  57. package/dist/package/src/views/base/menu/index.vue +3 -3
  58. package/dist/package/src/views/base/message/index.vue +9 -32
  59. package/dist/package/src/views/base/message-category/index.vue +2 -4
  60. package/dist/package/src/views/base/oauth-client/index.vue +8 -42
  61. package/dist/package/src/views/base/online-session/index.vue +8 -27
  62. package/dist/package/src/views/base/operation-log/index.vue +3 -3
  63. package/dist/package/src/views/base/permission-log/index.vue +3 -3
  64. package/dist/package/src/views/base/policy-evaluation-log/index.vue +3 -3
  65. package/dist/package/src/views/base/post/index.vue +9 -42
  66. package/dist/package/src/views/base/project-grant/index.vue +336 -0
  67. package/dist/package/src/views/base/role/index.vue +13 -47
  68. package/dist/package/src/views/base/tenant/index.vue +163 -19
  69. package/dist/package/src/views/base/tenant-project/index.vue +12 -0
  70. package/dist/package/src/views/base/user/index.vue +30 -51
  71. package/dist/package/src/views/profile/components/login-log.vue +15 -2
  72. package/dist/package/src/views/profile/components/password.vue +1 -1
  73. package/dist/package/src/views/profile/components/security.vue +2 -2
  74. package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +2 -2
  75. package/dist/package/src/views/tool/code-gen/config.ts +2 -1
  76. package/package.json +2 -2
  77. /package/dist/package/declarations/src/components/{ChangePasswordForm.vue.d.ts → account/ChangePasswordForm.vue.d.ts} +0 -0
  78. /package/dist/package/declarations/src/components/{ForcedPasswordDialog.vue.d.ts → account/ForcedPasswordDialog.vue.d.ts} +0 -0
  79. /package/dist/package/declarations/src/components/{Ai.vue.d.ts → ai/Ai.vue.d.ts} +0 -0
  80. /package/dist/package/declarations/src/components/{DynamicI18nCell.vue.d.ts → i18n/DynamicI18nCell.vue.d.ts} +0 -0
  81. /package/dist/package/declarations/src/components/{DynamicI18nEditor.vue.d.ts → i18n/DynamicI18nEditor.vue.d.ts} +0 -0
  82. /package/dist/package/declarations/src/components/{dynamicI18n.d.ts → i18n/dynamicI18n.d.ts} +0 -0
  83. /package/dist/package/declarations/src/components/{LogTable.vue.d.ts → log/LogTable.vue.d.ts} +0 -0
  84. /package/dist/package/declarations/src/components/{log.d.ts → log/log.d.ts} +0 -0
  85. /package/dist/package/declarations/src/components/{Notification.vue.d.ts → notification/Notification.vue.d.ts} +0 -0
  86. /package/dist/package/src/components/{ChangePasswordForm.vue → account/ChangePasswordForm.vue} +0 -0
  87. /package/dist/package/src/components/{ForcedPasswordDialog.vue → account/ForcedPasswordDialog.vue} +0 -0
  88. /package/dist/package/src/components/{Ai.vue → ai/Ai.vue} +0 -0
  89. /package/dist/package/src/components/{DynamicI18nCell.vue → i18n/DynamicI18nCell.vue} +0 -0
  90. /package/dist/package/src/components/{DynamicI18nEditor.vue → i18n/DynamicI18nEditor.vue} +0 -0
  91. /package/dist/package/src/components/{dynamicI18n.ts → i18n/dynamicI18n.ts} +0 -0
  92. /package/dist/package/src/components/{LogTable.vue → log/LogTable.vue} +0 -0
  93. /package/dist/package/src/components/{log.ts → log/log.ts} +0 -0
  94. /package/dist/package/src/components/{Notification.vue → notification/Notification.vue} +0 -0
@@ -0,0 +1,321 @@
1
+ <!-- 国际化自定义翻译 -->
2
+ <template>
3
+ <div class="table-box">
4
+ <ProTable
5
+ ref="proTable"
6
+ row-key="id"
7
+ :columns="columns"
8
+ :header-actions="headerActions"
9
+ :request-api="requestBaseI18nCustomTable"
10
+ />
11
+
12
+ <FormDialog
13
+ v-model="dialog.visible"
14
+ ref="formDialogRef"
15
+ :title="t(dialog.editing ? 'system.base.i18n_custom.action.edit' : 'system.base.i18n_custom.action.create')"
16
+ width="680px"
17
+ :model="formData"
18
+ :fields="formFields"
19
+ :rules="rules"
20
+ @confirm="handleSubmit"
21
+ @close="handleCloseDialog"
22
+ />
23
+ </div>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed, reactive, ref } from "vue";
28
+ import { ElMessage, ElMessageBox } from "element-plus";
29
+ import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
30
+ import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
31
+ import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
32
+ import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
33
+ import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
34
+ import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
35
+ import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
36
+ import {
37
+ getCurrentLocale,
38
+ getDefaultLocaleText,
39
+ normalizeLocale,
40
+ refreshAdminRuntimeConfig,
41
+ t
42
+ } from "@liujitcn/kratos-admin-core";
43
+ import { defBaseI18nCustomService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_i18n_custom";
44
+ import { loadEnabledBaseLanguages } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_language";
45
+ import type {
46
+ BaseI18nCustom,
47
+ BaseI18nCustomForm,
48
+ PageBaseI18nCustomRequest
49
+ } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n_custom";
50
+ import { BaseConfigSite } from "@liujitcn/kratos-admin-system/rpc/base/v1/config";
51
+ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
52
+
53
+ defineOptions({ name: "BaseI18nCustom", inheritAttrs: false });
54
+
55
+ const { BUTTONS } = useAuthButtons();
56
+ const proTable = ref<ProTableInstance>();
57
+ const formDialogRef = ref<InstanceType<typeof FormDialog>>();
58
+ const enabledLanguages = ref<Array<{ language_code: string; native_name?: string; language_name?: string }>>([]);
59
+ const dialog = reactive({ editing: false, visible: false });
60
+ const formData = reactive<BaseI18nCustomForm>({
61
+ id: 0,
62
+ site: BaseConfigSite.BASE_CONFIG_SITE_ADMIN,
63
+ key: "",
64
+ locale: getCurrentLocale(),
65
+ value: "",
66
+ status: Status.STATUS_ENABLE,
67
+ remark: ""
68
+ });
69
+
70
+ const siteOptions = computed<ProFormOption[]>(() => [
71
+ { label: t("system.base.i18n_custom.site.system"), value: BaseConfigSite.BASE_CONFIG_SITE_SYSTEM },
72
+ { label: t("system.base.i18n_custom.site.admin"), value: BaseConfigSite.BASE_CONFIG_SITE_ADMIN },
73
+ { label: t("system.base.i18n_custom.site.app"), value: BaseConfigSite.BASE_CONFIG_SITE_APP }
74
+ ]);
75
+
76
+ const localeOptions = computed<ProFormOption[]>(() =>
77
+ enabledLanguages.value.map(item => ({
78
+ label: item.native_name || item.language_name || item.language_code,
79
+ value: item.language_code
80
+ }))
81
+ );
82
+
83
+ const statusOptions = computed<ProFormOption[]>(() => [
84
+ { label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
85
+ { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
86
+ ]);
87
+
88
+ const rules = computed(() => ({
89
+ site: [{ required: true, message: t("system.base.i18n_custom.placeholder.site"), trigger: "change" }],
90
+ key: [{ required: true, message: t("system.base.i18n_custom.placeholder.key"), trigger: "blur" }],
91
+ locale: [{ required: true, message: t("system.base.i18n_custom.placeholder.locale"), trigger: "change" }],
92
+ value: [{ required: true, message: t("system.base.i18n_custom.placeholder.value"), trigger: "blur" }]
93
+ }));
94
+
95
+ const formFields = computed<ProFormField[]>(() => [
96
+ {
97
+ prop: "site",
98
+ label: t("system.base.i18n_custom.field.site"),
99
+ component: "select",
100
+ options: siteOptions.value,
101
+ props: { disabled: dialog.editing }
102
+ },
103
+ {
104
+ prop: "key",
105
+ label: t("system.base.i18n_custom.field.key"),
106
+ component: "input",
107
+ props: { maxlength: 255, placeholder: t("system.base.i18n_custom.placeholder.key"), disabled: dialog.editing }
108
+ },
109
+ {
110
+ prop: "locale",
111
+ label: t("system.base.i18n_custom.field.locale"),
112
+ component: "select",
113
+ options: localeOptions.value,
114
+ props: { filterable: true, placeholder: t("system.base.i18n_custom.placeholder.locale"), disabled: dialog.editing }
115
+ },
116
+ {
117
+ prop: "value",
118
+ label: t("system.base.i18n_custom.field.value"),
119
+ component: "input",
120
+ props: { type: "textarea", rows: 4, maxlength: 10000, showWordLimit: true, placeholder: t("system.base.i18n_custom.placeholder.value") }
121
+ },
122
+ { prop: "status", label: t("system.base.i18n_custom.field.status"), component: "radio-group", options: statusOptions.value },
123
+ {
124
+ prop: "remark",
125
+ label: t("system.base.i18n_custom.field.remark"),
126
+ component: "input",
127
+ props: { maxlength: 255, placeholder: t("system.base.i18n_custom.placeholder.remark") }
128
+ }
129
+ ]);
130
+
131
+ const columns = computed<ColumnProps[]>(() => [
132
+ { type: "selection", width: 55 },
133
+ { prop: "key", label: t("system.base.i18n_custom.field.key"), minWidth: 250, search: { el: "input" } },
134
+ {
135
+ prop: "site",
136
+ label: t("system.base.i18n_custom.field.site"),
137
+ width: 110,
138
+ search: { el: "select", enum: siteOptions.value },
139
+ render: scope => siteOptions.value.find(item => item.value === (scope.row as BaseI18nCustom).site)?.label || "-"
140
+ },
141
+ {
142
+ prop: "locale",
143
+ label: t("system.base.i18n_custom.field.locale"),
144
+ width: 120,
145
+ search: { el: "select", enum: localeOptions },
146
+ render: scope => getLanguageLabel((scope.row as BaseI18nCustom).locale)
147
+ },
148
+ {
149
+ prop: "default_value",
150
+ label: t("system.base.i18n_custom.field.default_value"),
151
+ minWidth: 200,
152
+ render: scope => getDefaultLocaleText(normalizeLocale((scope.row as BaseI18nCustom).locale), (scope.row as BaseI18nCustom).key) || "-"
153
+ },
154
+ { prop: "value", label: t("system.base.i18n_custom.field.value"), minWidth: 200 },
155
+ {
156
+ prop: "status",
157
+ label: t("system.base.i18n_custom.field.status"),
158
+ width: 100,
159
+ search: { el: "select", enum: statusOptions.value },
160
+ cellType: "status",
161
+ statusProps: {
162
+ activeValue: Status.STATUS_ENABLE,
163
+ inactiveValue: Status.STATUS_DISABLE,
164
+ activeText: t("common.status.enabled"),
165
+ inactiveText: t("common.status.disabled"),
166
+ disabled: () => !BUTTONS.value["base:i18n-custom:status"],
167
+ beforeChange: scope => handleBeforeSetStatus(scope.row as BaseI18nCustom)
168
+ }
169
+ },
170
+ { prop: "created_at", label: t("common.field.created_at"), minWidth: 180, align: "center" },
171
+ {
172
+ prop: "operation",
173
+ label: t("common.field.operation"),
174
+ cellType: "actions",
175
+ actions: [
176
+ {
177
+ label: t("common.action.edit"),
178
+ type: "primary",
179
+ link: true,
180
+ icon: EditPen,
181
+ hidden: () => !BUTTONS.value["base:i18n-custom:update"],
182
+ onClick: scope => handleOpenDialog((scope.row as BaseI18nCustom).id)
183
+ },
184
+ {
185
+ label: t("common.action.delete"),
186
+ type: "danger",
187
+ link: true,
188
+ icon: Delete,
189
+ hidden: () => !BUTTONS.value["base:i18n-custom:delete"],
190
+ onClick: scope => handleDelete(scope.row as BaseI18nCustom)
191
+ }
192
+ ]
193
+ }
194
+ ]);
195
+
196
+ const headerActions = computed<HeaderActionProps[]>(() => [
197
+ {
198
+ label: t("common.action.create"),
199
+ type: "success",
200
+ icon: CirclePlus,
201
+ hidden: () => !BUTTONS.value["base:i18n-custom:create"],
202
+ onClick: () => handleOpenDialog()
203
+ },
204
+ {
205
+ label: t("common.action.delete"),
206
+ type: "danger",
207
+ icon: Delete,
208
+ hidden: () => !BUTTONS.value["base:i18n-custom:delete"],
209
+ disabled: scope => !scope.selectedList.length,
210
+ onClick: scope => handleDelete(scope.selectedList as BaseI18nCustom[])
211
+ }
212
+ ]);
213
+
214
+ /** 请求国际化自定义翻译分页列表。 */
215
+ async function requestBaseI18nCustomTable(params: PageBaseI18nCustomRequest) {
216
+ await loadLanguages();
217
+ const data = await defBaseI18nCustomService.PageBaseI18nCustom(buildPageRequest(params));
218
+ return { data: { list: data.items ?? [], total: data.total } };
219
+ }
220
+
221
+ /** 加载启用语言选项。 */
222
+ async function loadLanguages() {
223
+ enabledLanguages.value = await loadEnabledBaseLanguages();
224
+ }
225
+
226
+ /** 返回语言显示名称。 */
227
+ function getLanguageLabel(locale: string) {
228
+ const language = enabledLanguages.value.find(item => item.language_code === locale);
229
+ return language?.native_name || language?.language_name || locale;
230
+ }
231
+
232
+ /** 打开国际化自定义翻译编辑弹窗。 */
233
+ async function handleOpenDialog(id?: number) {
234
+ await loadLanguages();
235
+ resetForm();
236
+ dialog.editing = Boolean(id);
237
+ dialog.visible = true;
238
+ if (!id) return;
239
+ Object.assign(formData, await defBaseI18nCustomService.GetBaseI18nCustom({ id }));
240
+ }
241
+
242
+ /** 关闭编辑弹窗并重置表单。 */
243
+ function handleCloseDialog() {
244
+ dialog.visible = false;
245
+ resetForm();
246
+ }
247
+
248
+ /** 重置国际化自定义翻译表单。 */
249
+ function resetForm() {
250
+ formDialogRef.value?.resetFields();
251
+ formDialogRef.value?.clearValidate();
252
+ Object.assign(formData, {
253
+ id: 0,
254
+ site: BaseConfigSite.BASE_CONFIG_SITE_ADMIN,
255
+ key: "",
256
+ locale: getCurrentLocale(),
257
+ value: "",
258
+ status: Status.STATUS_ENABLE,
259
+ remark: ""
260
+ });
261
+ }
262
+
263
+ /** 提交国际化自定义翻译。 */
264
+ async function handleSubmit() {
265
+ const valid = await formDialogRef.value?.validate();
266
+ if (!valid) return;
267
+ const payload = JSON.parse(JSON.stringify(formData)) as BaseI18nCustomForm;
268
+ if (payload.id) {
269
+ await defBaseI18nCustomService.UpdateBaseI18nCustom({ i18n_custom: payload });
270
+ } else {
271
+ await defBaseI18nCustomService.CreateBaseI18nCustom({ i18n_custom: payload });
272
+ }
273
+ await refreshAdminRuntimeConfig();
274
+ ElMessage.success(t(payload.id ? "common.message.update_success" : "common.message.create_success", { resource: t("system.base.i18n_custom.resource") }));
275
+ handleCloseDialog();
276
+ proTable.value?.getTableList();
277
+ }
278
+
279
+ /** 设置国际化自定义翻译状态前确认。 */
280
+ function handleBeforeSetStatus(row: BaseI18nCustom) {
281
+ return ElMessageBox.confirm(
282
+ t("system.base.i18n_custom.message.confirm_status", {
283
+ action: row.status === Status.STATUS_ENABLE ? t("common.status.disabled") : t("common.status.enabled"),
284
+ name: row.key
285
+ }),
286
+ t("common.title.warning"),
287
+ { type: "warning", confirmButtonText: t("common.action.confirm"), cancelButtonText: t("common.action.cancel") }
288
+ ).then(
289
+ async () => {
290
+ await defBaseI18nCustomService.SetBaseI18nCustomStatus({
291
+ id: row.id,
292
+ status: row.status === Status.STATUS_ENABLE ? Status.STATUS_DISABLE : Status.STATUS_ENABLE
293
+ });
294
+ await refreshAdminRuntimeConfig();
295
+ return true;
296
+ },
297
+ () => false
298
+ );
299
+ }
300
+
301
+ /** 删除国际化自定义翻译,兼容单项和批量操作。 */
302
+ function handleDelete(selected?: BaseI18nCustom | BaseI18nCustom[] | number | string | Array<number | string>) {
303
+ const rows = Array.isArray(selected) ? (selected.filter(item => typeof item === "object") as BaseI18nCustom[]) : selected && typeof selected === "object" ? [selected] : [];
304
+ const ids = (rows.length ? rows.map(item => item.id) : normalizeSelectedIds(selected as number | string | Array<number | string>)).join(",");
305
+ if (!ids) {
306
+ ElMessage.warning(t("common.message.select_delete_item"));
307
+ return;
308
+ }
309
+ ElMessageBox.confirm(
310
+ t("system.base.i18n_custom.message.confirm_delete", { name: rows.length === 1 ? rows[0].key : ids }),
311
+ t("common.title.warning"),
312
+ { type: "warning", confirmButtonText: t("common.action.confirm"), cancelButtonText: t("common.action.cancel") }
313
+ ).then(async () => {
314
+ await defBaseI18nCustomService.DeleteBaseI18nCustom({ id: ids });
315
+ await refreshAdminRuntimeConfig();
316
+ ElMessage.success(t("common.message.delete_success"));
317
+ proTable.value?.getTableList();
318
+ });
319
+ }
320
+
321
+ </script>
@@ -48,14 +48,14 @@ import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
48
48
  import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
49
49
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
50
50
  import { t } from "@liujitcn/kratos-admin-core";
51
- import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/DynamicI18nCell.vue";
52
- import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/DynamicI18nEditor.vue";
51
+ import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/i18n/DynamicI18nCell.vue";
52
+ import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/i18n/DynamicI18nEditor.vue";
53
53
  import {
54
54
  normalizeDynamicI18ns,
55
55
  serializeDynamicI18ns,
56
56
  type DynamicI18nRecord,
57
57
  type DynamicI18nValue
58
- } from "@liujitcn/kratos-admin-system/components/dynamicI18n";
58
+ } from "@liujitcn/kratos-admin-system/components/i18n/dynamicI18n";
59
59
 
60
60
  defineOptions({
61
61
  name: "BaseJob",
@@ -5,11 +5,12 @@
5
5
  <script setup lang="ts">
6
6
  import { computed, ref } from "vue";
7
7
  import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
8
+ import { requestTenantCodeOptions, useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
8
9
  import { t } from "@liujitcn/kratos-admin-core";
9
- import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log";
10
+ import { formatLogDateTime } from "@liujitcn/kratos-admin-system/components/log/log";
10
11
  import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
11
- import LogTable, { type LogTableConfig } from "@liujitcn/kratos-admin-system/components/LogTable.vue";
12
- import { logDateSearch, logDetailColumn, logEnumLabel, createLogEnumOptions, requestLogTrace } from "@liujitcn/kratos-admin-system/components/log";
12
+ import LogTable, { type LogTableConfig } from "@liujitcn/kratos-admin-system/components/log/LogTable.vue";
13
+ import { logDateSearch, logDetailColumn, logEnumLabel, createLogEnumOptions, requestLogTrace } from "@liujitcn/kratos-admin-system/components/log/log";
13
14
  import { defBaseLoginLogService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_login_log";
14
15
  import { BaseLogResult } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_log";
15
16
  import { BaseLoginLogType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_login_log";
@@ -18,6 +19,7 @@ import type { BaseLoginLog, PageBaseLoginLogRequest } from "@liujitcn/kratos-adm
18
19
  defineOptions({ name: "BaseLoginLog", inheritAttrs: false });
19
20
 
20
21
  const page = ref<InstanceType<typeof LogTable>>();
22
+ const { tenantColumns } = useTenantScope();
21
23
  const resultOptions = computed(() =>
22
24
  createLogEnumOptions([
23
25
  [BaseLogResult.BASE_LOG_RESULT_UNSPECIFIED, t("system.base.log.result.unspecified")],
@@ -39,7 +41,14 @@ const loginTypeOptions = computed(() =>
39
41
 
40
42
  const columns = computed<ColumnProps[]>(() => [
41
43
  { prop: "user_name", label: t("system.base.log.field.user_name"), minWidth: 130 },
42
- { prop: "tenant_code", label: t("system.base.log.field.tenant_code"), minWidth: 120, align: "left" },
44
+ ...tenantColumns({
45
+ prop: "tenant_code",
46
+ label: t("system.base.log.field.tenant_code"),
47
+ minWidth: 120,
48
+ searchEl: "select",
49
+ enum: requestTenantCodeOptions,
50
+ render: scope => String((scope.row as BaseLoginLog).tenant_code ?? "")
51
+ }),
43
52
  {
44
53
  prop: "login_type",
45
54
  label: t("system.base.log.field.login_type"),
@@ -9,6 +9,7 @@
9
9
  v-model="dialog.visible"
10
10
  :title="t(dialog.titleKey)"
11
11
  width="980px"
12
+ label-width="auto"
12
13
  :model="formData"
13
14
  :fields="formFields"
14
15
  :rules="formRules"
@@ -19,15 +20,34 @@
19
20
  <div class="rules-editor">
20
21
  <div v-for="(rule, index) in formData.rules" :key="rule.id || index" class="rule-row">
21
22
  <el-select v-model="rule.restriction_type" class="rule-type">
22
- <el-option v-for="option in restrictionTypeOptions" :key="String(option.value)" :label="option.label" :value="option.value" />
23
+ <el-option
24
+ v-for="option in restrictionTypeOptions"
25
+ :key="String(option.value)"
26
+ :label="option.label"
27
+ :value="option.value"
28
+ />
23
29
  </el-select>
24
30
  <el-select v-model="rule.restriction_method" class="rule-method">
25
- <el-option v-for="option in restrictionMethodOptions" :key="String(option.value)" :label="option.label" :value="option.value" />
31
+ <el-option
32
+ v-for="option in restrictionMethodOptions"
33
+ :key="String(option.value)"
34
+ :label="option.label"
35
+ :value="option.value"
36
+ />
26
37
  </el-select>
27
- <el-input v-model="rule.restriction_value" class="rule-value" :placeholder="rulePlaceholder(rule.restriction_method)" />
38
+ <el-input
39
+ v-model="rule.restriction_value"
40
+ class="rule-value"
41
+ :placeholder="rulePlaceholder(rule.restriction_method)"
42
+ />
28
43
  <el-input v-model="rule.reason" class="rule-reason" :placeholder="t('system.base.login_policy.placeholder.reason')" />
29
44
  <el-select v-model="rule.status" class="rule-status">
30
- <el-option v-for="option in statusOptions" :key="String(option.value)" :label="option.label" :value="option.value" />
45
+ <el-option
46
+ v-for="option in statusOptions"
47
+ :key="String(option.value)"
48
+ :label="option.label"
49
+ :value="option.value"
50
+ />
31
51
  </el-select>
32
52
  <el-button link type="danger" :icon="Delete" @click="removeRule(index)" />
33
53
  </div>
@@ -36,6 +56,9 @@
36
56
  </el-button>
37
57
  </div>
38
58
  </template>
59
+ <template #initialPasswordStrength>
60
+ <PasswordStrength :password="formData.initial_password" />
61
+ </template>
39
62
  </FormDialog>
40
63
  </div>
41
64
  </template>
@@ -46,14 +69,15 @@ import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
46
69
  import { ElButton, ElMessage, ElMessageBox, ElTag } from "element-plus";
47
70
  import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
48
71
  import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
72
+ import PasswordStrength from "@liujitcn/kratos-admin-core/components/PasswordStrength/index.vue";
49
73
  import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
50
74
  import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
51
75
  import { useAuthButtons } from "@liujitcn/kratos-admin-core/auth";
52
76
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
53
77
  import { PASSWORD_CRYPTO_SCENE, encryptPassword } from "@liujitcn/kratos-admin-core/security";
78
+ import { useTenantScope } from "@liujitcn/kratos-admin-core/tenant";
54
79
  import { t } from "@liujitcn/kratos-admin-core";
55
80
  import { defBaseLoginPolicyService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_login_policy";
56
- import { defBaseTenantService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_tenant";
57
81
  import { defBaseUserService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_user";
58
82
  import type { SelectOptionResponse_Option } from "@liujitcn/kratos-admin-system/rpc/common/v1/common";
59
83
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
@@ -81,9 +105,9 @@ const { BUTTONS } = useAuthButtons();
81
105
  const proTable = ref<ProTableInstance>();
82
106
  const formDialogRef = ref<InstanceType<typeof FormDialog>>();
83
107
  const dialog = reactive({ visible: false, titleKey: "common.action.create" });
84
- const tenantOptions = ref<SelectOptionResponse_Option[]>([]);
85
108
  const userOptions = ref<SelectOptionResponse_Option[]>([]);
86
109
  const formData = reactive<BaseLoginPolicyFormState>(defaultForm());
110
+ const { isDefaultTenant, tenantFormField, loadTenantOptions } = useTenantScope();
87
111
 
88
112
  const scopeTypeOptions = computed<ProFormOption[]>(() => [
89
113
  { label: t("system.base.login_policy.scope.global"), value: BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_GLOBAL },
@@ -91,15 +115,36 @@ const scopeTypeOptions = computed<ProFormOption[]>(() => [
91
115
  { label: t("common.field.user"), value: BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_USER }
92
116
  ]);
93
117
  const restrictionTypeOptions = computed<ProFormOption[]>(() => [
94
- { label: t("system.base.login_policy.restriction.blacklist"), value: BaseLoginPolicyRestrictionType.BASE_LOGIN_POLICY_RESTRICTION_TYPE_BLACKLIST },
95
- { label: t("system.base.login_policy.restriction.whitelist"), value: BaseLoginPolicyRestrictionType.BASE_LOGIN_POLICY_RESTRICTION_TYPE_WHITELIST }
118
+ {
119
+ label: t("system.base.login_policy.restriction.blacklist"),
120
+ value: BaseLoginPolicyRestrictionType.BASE_LOGIN_POLICY_RESTRICTION_TYPE_BLACKLIST
121
+ },
122
+ {
123
+ label: t("system.base.login_policy.restriction.whitelist"),
124
+ value: BaseLoginPolicyRestrictionType.BASE_LOGIN_POLICY_RESTRICTION_TYPE_WHITELIST
125
+ }
96
126
  ]);
97
127
  const restrictionMethodOptions = computed<ProFormOption[]>(() => [
98
- { label: t("system.base.login_policy.method.ip"), value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_IP },
99
- { label: t("system.base.login_policy.method.mac"), value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_MAC },
100
- { label: t("system.base.login_policy.method.region"), value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_REGION },
101
- { label: t("system.base.login_policy.method.time"), value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_TIME },
102
- { label: t("system.base.login_policy.method.device"), value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_DEVICE }
128
+ {
129
+ label: t("system.base.login_policy.method.ip"),
130
+ value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_IP
131
+ },
132
+ {
133
+ label: t("system.base.login_policy.method.mac"),
134
+ value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_MAC
135
+ },
136
+ {
137
+ label: t("system.base.login_policy.method.region"),
138
+ value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_REGION
139
+ },
140
+ {
141
+ label: t("system.base.login_policy.method.time"),
142
+ value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_TIME
143
+ },
144
+ {
145
+ label: t("system.base.login_policy.method.device"),
146
+ value: BaseLoginPolicyRestrictionMethod.BASE_LOGIN_POLICY_RESTRICTION_METHOD_DEVICE
147
+ }
103
148
  ]);
104
149
  const statusOptions = computed<ProFormOption[]>(() => [
105
150
  { label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
@@ -107,14 +152,15 @@ const statusOptions = computed<ProFormOption[]>(() => [
107
152
  ]);
108
153
 
109
154
  const formFields = computed<ProFormField[]>(() => [
110
- { prop: "scope_type", label: t("system.base.login_policy.field.scope_type"), component: "select", options: scopeTypeOptions.value },
111
155
  {
112
- prop: "tenant_id",
113
- label: t("common.field.tenant"),
156
+ prop: "scope_type",
157
+ label: t("system.base.login_policy.field.scope_type"),
114
158
  component: "select",
115
- options: tenantOptions.value,
116
- visible: model => model.scope_type !== BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_GLOBAL,
117
- props: { filterable: true, clearable: true }
159
+ options: scopeTypeOptions.value
160
+ },
161
+ {
162
+ ...tenantFormField({ label: t("common.field.tenant"), props: { clearable: true } }),
163
+ visible: model => isDefaultTenant.value && model.scope_type !== BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_GLOBAL
118
164
  },
119
165
  {
120
166
  prop: "user_id",
@@ -178,6 +224,12 @@ const formFields = computed<ProFormField[]>(() => [
178
224
  component: "password",
179
225
  props: { placeholder: t("system.base.login_policy.placeholder.initial_password"), showPassword: true }
180
226
  },
227
+ {
228
+ prop: "initialPasswordStrength",
229
+ label: t("system.base.login_policy.field.password_strength"),
230
+ component: "slot",
231
+ slotName: "initialPasswordStrength"
232
+ },
181
233
  { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value },
182
234
  { prop: "rules", label: t("system.base.login_policy.field.rules"), component: "slot", slotName: "rules", colSpan: 24 }
183
235
  ]);
@@ -186,15 +238,25 @@ const formRules = computed(() => ({
186
238
  scope_type: [{ required: true, message: t("system.base.login_policy.validation.scope_type"), trigger: "change" }],
187
239
  tenant_id: [{ validator: validateTenant, trigger: "change" }],
188
240
  user_id: [{ validator: validateUser, trigger: "change" }],
189
- max_failed_attempts: [{ required: true, message: t("system.base.login_policy.validation.max_failed_attempts"), trigger: "change" }],
190
- lock_duration_minutes: [{ required: true, message: t("system.base.login_policy.validation.lock_duration_minutes"), trigger: "change" }],
191
- password_min_length: [{ required: true, message: t("system.base.login_policy.validation.password_min_length"), trigger: "change" }],
192
- password_history_count: [{ required: true, message: t("system.base.login_policy.validation.password_history_count"), trigger: "change" }],
241
+ max_failed_attempts: [
242
+ { required: true, message: t("system.base.login_policy.validation.max_failed_attempts"), trigger: "change" }
243
+ ],
244
+ lock_duration_minutes: [
245
+ { required: true, message: t("system.base.login_policy.validation.lock_duration_minutes"), trigger: "change" }
246
+ ],
247
+ password_min_length: [
248
+ { required: true, message: t("system.base.login_policy.validation.password_min_length"), trigger: "change" }
249
+ ],
250
+ password_history_count: [
251
+ { required: true, message: t("system.base.login_policy.validation.password_history_count"), trigger: "change" }
252
+ ],
193
253
  password_min_complexity_classes: [
194
254
  { required: true, message: t("system.base.login_policy.validation.password_min_complexity_classes"), trigger: "change" }
195
255
  ],
196
- password_max_age_days: [{ required: true, message: t("system.base.login_policy.validation.password_max_age_days"), trigger: "change" }]
197
- ,mfa_remember_days: [{ required: true, message: t("system.base.login_policy.validation.mfa_remember_days"), trigger: "change" }]
256
+ password_max_age_days: [
257
+ { required: true, message: t("system.base.login_policy.validation.password_max_age_days"), trigger: "change" }
258
+ ],
259
+ mfa_remember_days: [{ required: true, message: t("system.base.login_policy.validation.mfa_remember_days"), trigger: "change" }]
198
260
  }));
199
261
 
200
262
  const columns = computed<ColumnProps[]>(() => [
@@ -233,7 +295,12 @@ const columns = computed<ColumnProps[]>(() => [
233
295
  }
234
296
  },
235
297
  { prop: "password_min_length", label: t("system.base.login_policy.field.password_min_length"), width: 110, align: "right" },
236
- { prop: "password_history_count", label: t("system.base.login_policy.field.password_history_count"), width: 110, align: "right" },
298
+ {
299
+ prop: "password_history_count",
300
+ label: t("system.base.login_policy.field.password_history_count"),
301
+ width: 110,
302
+ align: "right"
303
+ },
237
304
  {
238
305
  prop: "password_min_complexity_classes",
239
306
  label: t("system.base.login_policy.field.password_min_complexity_classes"),
@@ -384,12 +451,6 @@ async function openDialog(id?: number) {
384
451
  dialog.visible = true;
385
452
  }
386
453
 
387
- /** 加载租户选项。 */
388
- async function loadTenantOptions() {
389
- const response = await defBaseTenantService.OptionBaseTenant({ keyword: "" });
390
- tenantOptions.value = response.list ?? [];
391
- }
392
-
393
454
  /** 加载指定租户的用户选项。 */
394
455
  async function loadUserOptions(tenantId: number) {
395
456
  const response = await defBaseUserService.OptionBaseUser({ keyword: "", tenant_id: tenantId });
@@ -472,7 +533,8 @@ function scopeTypeLabel(value: BaseLoginPolicyScopeType) {
472
533
 
473
534
  /** 输出策略目标名称。 */
474
535
  function targetLabel(row: BaseLoginPolicy) {
475
- if (row.scope_type === BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_GLOBAL) return t("system.base.login_policy.scope.global");
536
+ if (row.scope_type === BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_GLOBAL)
537
+ return t("system.base.login_policy.scope.global");
476
538
  if (row.scope_type === BaseLoginPolicyScopeType.BASE_LOGIN_POLICY_SCOPE_TYPE_USER) return row.user_name || String(row.user_id);
477
539
  return row.tenant_name || String(row.tenant_id);
478
540
  }
@@ -488,7 +550,8 @@ function renderRules(row: BaseLoginPolicy) {
488
550
  h(
489
551
  ElTag,
490
552
  { key: `${rule.id || index}`, size: "small", class: "rule-tag" },
491
- () => `${restrictionTypeLabel(rule.restriction_type)}/${restrictionMethodLabel(rule.restriction_method)}: ${rule.restriction_value}`
553
+ () =>
554
+ `${restrictionTypeLabel(rule.restriction_type)}/${restrictionMethodLabel(rule.restriction_method)}: ${rule.restriction_value}`
492
555
  )
493
556
  )
494
557
  );
@@ -79,14 +79,14 @@ import { BaseMenuType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/
79
79
  import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
80
80
  import { normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
81
81
  import { t } from "@liujitcn/kratos-admin-core";
82
- import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/DynamicI18nEditor.vue";
83
- import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/DynamicI18nCell.vue";
82
+ import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/i18n/DynamicI18nEditor.vue";
83
+ import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/i18n/DynamicI18nCell.vue";
84
84
  import {
85
85
  normalizeDynamicI18ns,
86
86
  serializeDynamicI18ns,
87
87
  type DynamicI18nRecord,
88
88
  type DynamicI18nValue
89
- } from "@liujitcn/kratos-admin-system/components/dynamicI18n";
89
+ } from "@liujitcn/kratos-admin-system/components/i18n/dynamicI18n";
90
90
 
91
91
  defineOptions({
92
92
  name: "BaseMenu",