@liujitcn/kratos-admin-system 0.0.38 → 0.0.40

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 (147) hide show
  1. package/README.md +22 -0
  2. package/dist/package/declarations/src/api/system/admin/v1/base_config.d.ts +1 -5
  3. package/dist/package/declarations/src/api/system/admin/v1/base_login_log.d.ts +3 -1
  4. package/dist/package/declarations/src/api/system/admin/v1/base_session.d.ts +7 -1
  5. package/dist/package/declarations/src/components/DynamicI18nCell.vue.d.ts +2 -8
  6. package/dist/package/declarations/src/components/DynamicI18nEditor.vue.d.ts +20 -3
  7. package/dist/package/declarations/src/components/dynamicI18n.d.ts +2 -2
  8. package/dist/package/declarations/src/locales/generated.d.ts +5770 -5686
  9. package/dist/package/declarations/src/rpc/base/v1/login.d.ts +2 -0
  10. package/dist/package/declarations/src/rpc/base/v1/notification.d.ts +1 -1
  11. package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +4 -0
  12. package/dist/package/declarations/src/rpc/base/v1/oauth_client.d.ts +1 -1
  13. package/dist/package/declarations/src/rpc/system/admin/v1/base_api_log.d.ts +1 -1
  14. package/dist/package/declarations/src/rpc/system/admin/v1/base_config.d.ts +4 -40
  15. package/dist/package/declarations/src/rpc/system/admin/v1/base_data_access_log.d.ts +1 -1
  16. package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n.d.ts +1 -1
  17. package/dist/package/declarations/src/rpc/system/admin/v1/base_log.d.ts +1 -1
  18. package/dist/package/declarations/src/rpc/system/admin/v1/base_login_log.d.ts +10 -1
  19. package/dist/package/declarations/src/rpc/system/admin/v1/base_login_policy.d.ts +8 -0
  20. package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +1 -1
  21. package/dist/package/declarations/src/rpc/system/admin/v1/base_message_category.d.ts +1 -1
  22. package/dist/package/declarations/src/rpc/system/admin/v1/base_migration.d.ts +1 -1
  23. package/dist/package/declarations/src/rpc/system/admin/v1/base_operation_log.d.ts +1 -1
  24. package/dist/package/declarations/src/rpc/system/admin/v1/base_permission_log.d.ts +1 -1
  25. package/dist/package/declarations/src/rpc/system/admin/v1/base_policy_evaluation_log.d.ts +1 -1
  26. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_output_policy.d.ts +1 -1
  27. package/dist/package/declarations/src/rpc/system/admin/v1/base_redact_storage_policy.d.ts +1 -1
  28. package/dist/package/declarations/src/rpc/system/admin/v1/base_session.d.ts +41 -0
  29. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_archive.d.ts +1 -1
  30. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_archive_record.d.ts +1 -1
  31. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_archive_restore.d.ts +1 -1
  32. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_backup.d.ts +1 -1
  33. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_backup_record.d.ts +1 -1
  34. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_backup_restore.d.ts +1 -1
  35. package/dist/package/declarations/src/rpc/system/admin/v1/base_table_source.d.ts +1 -1
  36. package/dist/package/declarations/src/rpc/system/admin/v1/cache.d.ts +1 -1
  37. package/dist/package/declarations/src/rpc/system/admin/v1/oauth_client.d.ts +1 -1
  38. package/dist/package/declarations/src/rpc/system/admin/v1/ops_monitoring.d.ts +1 -1
  39. package/dist/package/declarations/src/utils/code-gen-progress.d.ts +3 -0
  40. package/dist/package/declarations/src/views/profile/components/login-log.vue.d.ts +3 -0
  41. package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenGenerateConfirm.vue.d.ts +11 -0
  42. package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue.d.ts +5 -9
  43. package/dist/package/declarations/src/views/tool/code-gen/config.d.ts +3 -0
  44. package/dist/package/src/api/base/v1/sse.ts +11 -2
  45. package/dist/package/src/api/system/admin/v1/base_config.ts +0 -20
  46. package/dist/package/src/api/system/admin/v1/base_login_log.ts +10 -0
  47. package/dist/package/src/api/system/admin/v1/base_session.ts +32 -1
  48. package/dist/package/src/components/DynamicI18nCell.vue +55 -220
  49. package/dist/package/src/components/DynamicI18nEditor.vue +150 -146
  50. package/dist/package/src/components/dynamicI18n.ts +10 -6
  51. package/dist/package/src/config/index.ts +1 -3
  52. package/dist/package/src/locales/en-US.json +1444 -1435
  53. package/dist/package/src/locales/ja-JP.json +1448 -1439
  54. package/dist/package/src/locales/zh-CN.json +1444 -1435
  55. package/dist/package/src/locales/zh-TW.json +1445 -1436
  56. package/dist/package/src/rpc/base/v1/ai_message.ts +1 -1
  57. package/dist/package/src/rpc/base/v1/ai_session.ts +1 -1
  58. package/dist/package/src/rpc/base/v1/ai_tool.ts +1 -1
  59. package/dist/package/src/rpc/base/v1/config.ts +1 -1
  60. package/dist/package/src/rpc/base/v1/login.ts +3 -1
  61. package/dist/package/src/rpc/base/v1/notification.ts +2 -2
  62. package/dist/package/src/rpc/base/v1/oauth.ts +5 -1
  63. package/dist/package/src/rpc/base/v1/oauth_client.ts +2 -2
  64. package/dist/package/src/rpc/base/v1/sse.ts +1 -1
  65. package/dist/package/src/rpc/common/v1/analytics.ts +1 -1
  66. package/dist/package/src/rpc/common/v1/common.ts +1 -1
  67. package/dist/package/src/rpc/common/v1/enum.ts +1 -1
  68. package/dist/package/src/rpc/common/v1/types.ts +1 -1
  69. package/dist/package/src/rpc/google/protobuf/empty.ts +1 -1
  70. package/dist/package/src/rpc/google/protobuf/timestamp.ts +1 -1
  71. package/dist/package/src/rpc/system/admin/v1/auth.ts +1 -1
  72. package/dist/package/src/rpc/system/admin/v1/base_api.ts +1 -1
  73. package/dist/package/src/rpc/system/admin/v1/base_api_log.ts +2 -2
  74. package/dist/package/src/rpc/system/admin/v1/base_area.ts +1 -1
  75. package/dist/package/src/rpc/system/admin/v1/base_config.ts +4 -44
  76. package/dist/package/src/rpc/system/admin/v1/base_dashboard.ts +1 -1
  77. package/dist/package/src/rpc/system/admin/v1/base_data_access_log.ts +2 -2
  78. package/dist/package/src/rpc/system/admin/v1/base_dept.ts +1 -1
  79. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +1 -1
  80. package/dist/package/src/rpc/system/admin/v1/base_dict_item.ts +1 -1
  81. package/dist/package/src/rpc/system/admin/v1/base_file.ts +1 -1
  82. package/dist/package/src/rpc/system/admin/v1/base_i18n.ts +2 -2
  83. package/dist/package/src/rpc/system/admin/v1/base_job.ts +1 -1
  84. package/dist/package/src/rpc/system/admin/v1/base_job_log.ts +1 -1
  85. package/dist/package/src/rpc/system/admin/v1/base_language.ts +1 -1
  86. package/dist/package/src/rpc/system/admin/v1/base_log.ts +2 -2
  87. package/dist/package/src/rpc/system/admin/v1/base_login_log.ts +12 -2
  88. package/dist/package/src/rpc/system/admin/v1/base_login_policy.ts +11 -1
  89. package/dist/package/src/rpc/system/admin/v1/base_menu.ts +1 -1
  90. package/dist/package/src/rpc/system/admin/v1/base_message.ts +2 -2
  91. package/dist/package/src/rpc/system/admin/v1/base_message_category.ts +2 -2
  92. package/dist/package/src/rpc/system/admin/v1/base_migration.ts +2 -2
  93. package/dist/package/src/rpc/system/admin/v1/base_operation_log.ts +2 -2
  94. package/dist/package/src/rpc/system/admin/v1/base_permission_log.ts +2 -2
  95. package/dist/package/src/rpc/system/admin/v1/base_policy_evaluation_log.ts +2 -2
  96. package/dist/package/src/rpc/system/admin/v1/base_post.ts +1 -1
  97. package/dist/package/src/rpc/system/admin/v1/base_redact_common.ts +1 -1
  98. package/dist/package/src/rpc/system/admin/v1/base_redact_output_policy.ts +2 -2
  99. package/dist/package/src/rpc/system/admin/v1/base_redact_rule.ts +1 -1
  100. package/dist/package/src/rpc/system/admin/v1/base_redact_storage_policy.ts +2 -2
  101. package/dist/package/src/rpc/system/admin/v1/base_role.ts +1 -1
  102. package/dist/package/src/rpc/system/admin/v1/base_session.ts +47 -1
  103. package/dist/package/src/rpc/system/admin/v1/base_table_archive.ts +2 -2
  104. package/dist/package/src/rpc/system/admin/v1/base_table_archive_record.ts +2 -2
  105. package/dist/package/src/rpc/system/admin/v1/base_table_archive_restore.ts +2 -2
  106. package/dist/package/src/rpc/system/admin/v1/base_table_backup.ts +2 -2
  107. package/dist/package/src/rpc/system/admin/v1/base_table_backup_record.ts +2 -2
  108. package/dist/package/src/rpc/system/admin/v1/base_table_backup_restore.ts +2 -2
  109. package/dist/package/src/rpc/system/admin/v1/base_table_source.ts +2 -2
  110. package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +1 -1
  111. package/dist/package/src/rpc/system/admin/v1/base_third_account.ts +1 -1
  112. package/dist/package/src/rpc/system/admin/v1/base_user.ts +1 -1
  113. package/dist/package/src/rpc/system/admin/v1/cache.ts +2 -2
  114. package/dist/package/src/rpc/system/admin/v1/code_gen.ts +1 -1
  115. package/dist/package/src/rpc/system/admin/v1/code_gen_column.ts +1 -1
  116. package/dist/package/src/rpc/system/admin/v1/code_gen_proto.ts +1 -1
  117. package/dist/package/src/rpc/system/admin/v1/code_gen_table.ts +1 -1
  118. package/dist/package/src/rpc/system/admin/v1/common.ts +1 -1
  119. package/dist/package/src/rpc/system/admin/v1/oauth_client.ts +2 -2
  120. package/dist/package/src/rpc/system/admin/v1/ops_monitoring.ts +2 -2
  121. package/dist/package/src/rpc/system/admin/v1/runtime_log.ts +1 -1
  122. package/dist/package/src/rpc/system/common/v1/common.ts +1 -1
  123. package/dist/package/src/rpc/system/config/v1/system_config.ts +1 -1
  124. package/dist/package/src/utils/code-gen-progress.ts +15 -0
  125. package/dist/package/src/views/base/config/index.vue +183 -48
  126. package/dist/package/src/views/base/dict/index.vue +6 -9
  127. package/dist/package/src/views/base/dict/item.vue +6 -15
  128. package/dist/package/src/views/base/job/index.vue +16 -17
  129. package/dist/package/src/views/base/login-policy/index.vue +28 -0
  130. package/dist/package/src/views/base/menu/index.vue +78 -15
  131. package/dist/package/src/views/base/online-session/index.vue +116 -0
  132. package/dist/package/src/views/base/user/index.vue +20 -8
  133. package/dist/package/src/views/profile/components/login-log.vue +123 -0
  134. package/dist/package/src/views/profile/components/session.vue +46 -61
  135. package/dist/package/src/views/profile/index.vue +13 -9
  136. package/dist/package/src/views/tool/code-gen/code-preview/index.vue +5 -15
  137. package/dist/package/src/views/tool/code-gen/columns/index.vue +17 -25
  138. package/dist/package/src/views/tool/code-gen/components/CodeGenGenerateConfirm.vue +115 -0
  139. package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +27 -186
  140. package/dist/package/src/views/tool/code-gen/components/CodeGenProgressDialog.vue +2 -0
  141. package/dist/package/src/views/tool/code-gen/config.ts +15 -1
  142. package/dist/package/src/views/tool/code-gen/table/index.vue +100 -45
  143. package/package.json +3 -2
  144. package/dist/package/declarations/src/config/database-backup.d.ts +0 -12
  145. package/dist/package/src/config/database-backup.ts +0 -57
  146. package/dist/package/src/views/base/runtime-config/index.vue +0 -479
  147. /package/dist/package/declarations/src/views/base/{runtime-config → online-session}/index.vue.d.ts +0 -0
@@ -12,8 +12,13 @@
12
12
  <FormDialog
13
13
  v-model="dialog.visible"
14
14
  ref="formDialogRef"
15
+ class="system-config-dialog"
15
16
  :title="t(dialog.titleKey, { resource: t('system.base.config.resource') })"
16
- width="1200px"
17
+ width="min(1440px, calc(100vw - 32px))"
18
+ top="4vh"
19
+ :col-span="12"
20
+ :gutter="24"
21
+ :confirm-loading="saving"
17
22
  :model="formData"
18
23
  :fields="formFields"
19
24
  :rules="rules"
@@ -56,6 +61,25 @@
56
61
  inline-prompt
57
62
  />
58
63
  </template>
64
+ <template #formValue>
65
+ <div class="config-form-value">
66
+ <template v-if="formDefinition">
67
+ <p>
68
+ <el-icon><component :is="formDefinition.icon" /></el-icon> {{ t(formDefinition.descriptionKey) }}
69
+ </p>
70
+ <ProForm
71
+ :key="formDefinition.key"
72
+ ref="valueFormRef"
73
+ :model="formValue"
74
+ :fields="localizedFormFields"
75
+ :col-span="12"
76
+ :gutter="24"
77
+ label-width="180px"
78
+ />
79
+ </template>
80
+ <el-alert v-else :title="t('system.base.config.message.form_unavailable')" type="warning" :closable="false" />
81
+ </div>
82
+ </template>
59
83
  <template #nameI18ns>
60
84
  <DynamicI18nEditor v-model="nameI18nValues" :source="formData.name" :maxlength="100" />
61
85
  </template>
@@ -67,12 +91,14 @@
67
91
  </template>
68
92
 
69
93
  <script setup lang="ts">
70
- import { computed, h, reactive, ref } from "vue";
94
+ import { computed, h, reactive, ref, watch } from "vue";
71
95
  import { useDebounceFn } from "@vueuse/core";
72
96
  import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
73
97
  import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
98
+ import ProForm from "@liujitcn/kratos-admin-core/components/ProForm/index.vue";
99
+ import { runtimeConfigDefinitions, type RuntimeConfigModel } from "@liujitcn/kratos-admin-system/config";
74
100
  import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
75
- import type { ProFormField, ProFormOption } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
101
+ import type { ProFormField, ProFormOption, ProFormInstance } from "@liujitcn/kratos-admin-core/components/ProForm/interface";
76
102
  import DictLabel from "@liujitcn/kratos-admin-core/components/Dict/DictLabel.vue";
77
103
  import RichTextPreview from "@liujitcn/kratos-admin-core/components/RichTextPreview/index.vue";
78
104
  import UploadImg from "@liujitcn/kratos-admin-core/components/Upload/Img.vue";
@@ -88,13 +114,17 @@ import type {
88
114
  import type { BaseI18n } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
89
115
  import { BaseConfigSite } from "@liujitcn/kratos-admin-system/rpc/base/v1/config";
90
116
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
91
- import { BaseConfigHiddenStatus, BaseConfigType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_config";
117
+ import { BaseConfigType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_config";
92
118
  import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
93
119
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
94
120
  import { t } from "@liujitcn/kratos-admin-core";
95
121
  import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/DynamicI18nEditor.vue";
96
122
  import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/DynamicI18nCell.vue";
97
- import { getEditableLanguageOptions, type DynamicI18nValue } from "@liujitcn/kratos-admin-system/components/dynamicI18n";
123
+ import {
124
+ getEditableLanguageOptions,
125
+ serializeDynamicI18ns,
126
+ type DynamicI18nValue
127
+ } from "@liujitcn/kratos-admin-system/components/dynamicI18n";
98
128
 
99
129
  /** 系统配置编辑表单状态,新增时枚举字段保持为空,避免把未知值 0 显示为下拉文本。 */
100
130
  type BaseConfigFormState = Omit<BaseConfigForm, "site" | "type"> & {
@@ -113,6 +143,37 @@ const { BUTTONS } = useAuthButtons();
113
143
  const proTable = ref<ProTableInstance>();
114
144
  const formDialogRef = ref<InstanceType<typeof FormDialog>>();
115
145
 
146
+ const saving = ref(false);
147
+ const valueFormRef = ref<ProFormInstance>();
148
+ const formValue = ref<RuntimeConfigModel>({});
149
+ const formDefinition = computed(() => runtimeConfigDefinitions.find(item => item.key === formData.key));
150
+ const localizedFormFields = computed<ProFormField[]>(() =>
151
+ (formDefinition.value?.fields ?? []).map(field => ({
152
+ prop: field.prop,
153
+ label: t(field.labelKey),
154
+ component: field.component,
155
+ props: field.props,
156
+ itemProps: field.itemProps,
157
+ options: field.options,
158
+ visible: field.visible,
159
+ labelTooltip: field.labelTooltipKey ? t(field.labelTooltipKey) : undefined,
160
+ rules: field.rules?.map(rule => ({
161
+ ...rule,
162
+ message: t(
163
+ rule.messageKey,
164
+ rule.messageArgs
165
+ ? Object.fromEntries(
166
+ Object.entries(rule.messageArgs).map(([key, value]) => [
167
+ key,
168
+ typeof value === "object" ? t(value.key) : typeof value === "boolean" ? String(value) : value
169
+ ])
170
+ )
171
+ : undefined
172
+ )
173
+ }))
174
+ }))
175
+ );
176
+
116
177
  const dialog = reactive({
117
178
  titleKey: "common.action.create_resource",
118
179
  visible: false
@@ -131,8 +192,6 @@ const formData = reactive<BaseConfigFormState>({
131
192
  key: "",
132
193
  /** 配置value */
133
194
  value: "",
134
- /** 隐藏状态。 */
135
- hidden_status: BaseConfigHiddenStatus.BASE_CONFIG_HIDDEN_STATUS_VISIBLE,
136
195
  /** 状态 */
137
196
  status: Status.STATUS_ENABLE,
138
197
  /** 配置名称非主语言翻译。 */
@@ -141,6 +200,16 @@ const formData = reactive<BaseConfigFormState>({
141
200
  value_i18ns: []
142
201
  });
143
202
 
203
+ /** 切换表单类型或编码时加载对应默认内容。 */
204
+ watch(
205
+ () => [formData.type, formData.key],
206
+ () => {
207
+ loadFormValue();
208
+ if (formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM) formData.site = BaseConfigSite.BASE_CONFIG_SITE_SYSTEM;
209
+ },
210
+ { flush: "sync" }
211
+ );
212
+
144
213
  /** 将配置值翻译记录转换为编辑器值,缺少记录时保留可编辑的空行。 */
145
214
  function normalizeConfigI18ns(targetType: I18nTargetType): DynamicI18nValue[] {
146
215
  const records = targetType === I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME ? formData.name_i18ns : formData.value_i18ns;
@@ -258,6 +327,7 @@ const dictValueCode = computed(() => BASE_CONFIG_DICT_CODE_MAP[formData.key] ??
258
327
  const formFields = computed<ProFormField[]>(() => [
259
328
  {
260
329
  prop: "name",
330
+ suffixSlotName: "nameI18ns",
261
331
  label: t("system.base.config.field.name"),
262
332
  component: "input",
263
333
  props: {
@@ -269,12 +339,13 @@ const formFields = computed<ProFormField[]>(() => [
269
339
  prop: "site",
270
340
  label: t("system.base.config.field.site"),
271
341
  component: "dict",
272
- props: { code: "base_config_site", disabled: formData.id > 0 }
342
+ props: { code: "base_config_site", disabled: formData.id > 0 || formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM }
273
343
  },
274
344
  {
275
345
  prop: "key",
276
346
  label: t("system.base.config.field.key"),
277
- component: "input",
347
+ component: formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM ? "select" : "input",
348
+ options: runtimeConfigDefinitions.map(item => ({ label: `${t(item.titleKey)}(${item.key})`, value: item.key })),
278
349
  props: {
279
350
  placeholder: t("common.validation.required_input", { field: t("system.base.config.field.key") }),
280
351
  disabled: formData.id > 0
@@ -286,11 +357,20 @@ const formFields = computed<ProFormField[]>(() => [
286
357
  component: "dict",
287
358
  props: { code: "base_config_type", disabled: formData.id > 0 }
288
359
  },
360
+ {
361
+ prop: "formValue",
362
+ label: t("system.base.config.field.value"),
363
+ component: "slot",
364
+ slotName: "formValue",
365
+ visible: model => model.type === BaseConfigType.BASE_CONFIG_TYPE_FORM,
366
+ colSpan: 24
367
+ },
289
368
  {
290
369
  prop: "value",
291
370
  label: t("system.base.config.field.value"),
292
371
  component: "slot",
293
372
  slotName: "textValue",
373
+ suffixSlotName: "valueI18ns",
294
374
  visible: model => model.type == BaseConfigType.BASE_CONFIG_TYPE_TEXT
295
375
  },
296
376
  {
@@ -305,6 +385,7 @@ const formFields = computed<ProFormField[]>(() => [
305
385
  label: t("system.base.config.field.value"),
306
386
  component: "slot",
307
387
  slotName: "richTextValue",
388
+ suffixSlotName: "valueI18ns",
308
389
  visible: model => model.type == BaseConfigType.BASE_CONFIG_TYPE_RICH_TEXT,
309
390
  colSpan: 24
310
391
  },
@@ -323,22 +404,12 @@ const formFields = computed<ProFormField[]>(() => [
323
404
  visible: model => model.type == BaseConfigType.BASE_CONFIG_TYPE_BOOLEAN
324
405
  },
325
406
  {
326
- prop: "i18ns",
327
- label: t("system.base.i18n.field.name_i18ns"),
328
- component: "slot",
329
- slotName: "nameI18ns",
330
- colSpan: 24
331
- },
332
- {
333
- prop: "i18ns",
334
- label: t("system.base.i18n.field.value_i18ns"),
335
- component: "slot",
336
- slotName: "valueI18ns",
337
- visible: model =>
338
- model.type == BaseConfigType.BASE_CONFIG_TYPE_TEXT || model.type == BaseConfigType.BASE_CONFIG_TYPE_RICH_TEXT,
339
- colSpan: 24
340
- },
341
- { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value }
407
+ prop: "status",
408
+ label: t("common.field.status"),
409
+ component: "radio-group",
410
+ options: statusOptions.value,
411
+ props: { disabled: formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM }
412
+ }
342
413
  ]);
343
414
 
344
415
  /** 系统配置表格列配置。 */
@@ -384,7 +455,8 @@ const columns = computed<ColumnProps[]>(() => [
384
455
  inactiveValue: Status.STATUS_DISABLE,
385
456
  activeText: t("common.status.enabled"),
386
457
  inactiveText: t("common.status.disabled"),
387
- disabled: () => !BUTTONS.value["base:config:status"],
458
+ disabled: scope =>
459
+ !BUTTONS.value["base:config:status"] || (scope.row as BaseConfig).type === BaseConfigType.BASE_CONFIG_TYPE_FORM,
388
460
  beforeChange: scope => handleBeforeSetStatus(scope.row as BaseConfig)
389
461
  }
390
462
  },
@@ -411,7 +483,8 @@ const columns = computed<ColumnProps[]>(() => [
411
483
  type: "danger",
412
484
  link: true,
413
485
  icon: Delete,
414
- hidden: () => !BUTTONS.value["base:config:delete"],
486
+ hidden: scope =>
487
+ !BUTTONS.value["base:config:delete"] || (scope.row as BaseConfig).type === BaseConfigType.BASE_CONFIG_TYPE_FORM,
415
488
  onClick: scope => handleDelete(scope.row as BaseConfig)
416
489
  }
417
490
  ]
@@ -433,6 +506,7 @@ function renderConfigNameCell(row: BaseConfig) {
433
506
  * 将配置键渲染为可悬停查看配置值的单元格。
434
507
  */
435
508
  function renderConfigKeyCell(row: BaseConfig) {
509
+ if (row.type === BaseConfigType.BASE_CONFIG_TYPE_FORM) return h("span", row.key);
436
510
  return h(
437
511
  ElTooltip,
438
512
  {
@@ -537,10 +611,23 @@ async function handleOpenDialog(configId?: number) {
537
611
  await loadEnabledBaseLanguages();
538
612
  resetForm();
539
613
  dialog.titleKey = configId ? "common.action.edit_resource" : "common.action.create_resource";
614
+ if (configId) {
615
+ Object.assign(formData, await defBaseConfigService.GetBaseConfig({ id: configId }));
616
+ if (formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM) {
617
+ loadFormValue(formData.value);
618
+ }
619
+ }
540
620
  dialog.visible = true;
541
- if (!configId) return;
621
+ }
542
622
 
543
- Object.assign(formData, await defBaseConfigService.GetBaseConfig({ id: configId }));
623
+ /** 按注册定义创建独立模型,并用已保存的配置值覆盖默认值。 */
624
+ function loadFormValue(value?: string) {
625
+ const definition = formDefinition.value;
626
+ formValue.value =
627
+ formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM && definition
628
+ ? Object.assign(definition.createModel(), value ? JSON.parse(value) : {})
629
+ : {};
630
+ valueFormRef.value?.clearValidate();
544
631
  }
545
632
 
546
633
  /**
@@ -563,36 +650,62 @@ function resetForm() {
563
650
  formData.type = undefined;
564
651
  formData.key = "";
565
652
  formData.value = "";
566
- formData.hidden_status = BaseConfigHiddenStatus.BASE_CONFIG_HIDDEN_STATUS_VISIBLE;
567
653
  formData.name_i18ns = [];
568
654
  formData.value_i18ns = [];
655
+ formValue.value = {};
656
+ valueFormRef.value?.clearValidate();
569
657
  formData.status = Status.STATUS_ENABLE;
570
658
  }
571
659
 
572
660
  /**
573
661
  * 提交系统配置表单。
574
662
  */
575
- function handleSubmit() {
576
- if (formData.type === BaseConfigType.BASE_CONFIG_TYPE_BOOLEAN) {
663
+ async function handleSubmit() {
664
+ if (formData.type === BaseConfigType.BASE_CONFIG_TYPE_FORM) {
665
+ if (!formDefinition.value) {
666
+ ElMessage.warning(t("system.base.config.message.form_unavailable"));
667
+ return;
668
+ }
669
+ if ((await valueFormRef.value?.validate()) !== true) return;
670
+ formData.value = JSON.stringify(formValue.value);
671
+ } else if (formData.type === BaseConfigType.BASE_CONFIG_TYPE_BOOLEAN) {
577
672
  formData.value = formData.value === "true" ? "true" : "false";
578
673
  }
579
- formDialogRef.value?.validate()?.then(valid => {
580
- if (!valid) return;
581
-
674
+ if ((await formDialogRef.value?.validate()) !== true) return;
675
+ saving.value = true;
676
+ try {
582
677
  const submitData = JSON.parse(JSON.stringify(formData)) as BaseConfigForm;
583
- const request = submitData.id
584
- ? defBaseConfigService.UpdateBaseConfig({ base_config: submitData })
585
- : defBaseConfigService.CreateBaseConfig({ base_config: submitData });
586
- request.then(() => {
587
- ElMessage.success(
588
- t(submitData.id ? "common.message.update_success" : "common.message.create_success", {
589
- resource: t("system.base.config.resource")
590
- })
591
- );
592
- handleCloseDialog();
593
- refreshTable();
594
- });
595
- });
678
+ submitData.name_i18ns = serializeDynamicI18ns(
679
+ nameI18nValues.value,
680
+ I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME,
681
+ submitData.id,
682
+ submitData.name
683
+ );
684
+ submitData.value_i18ns =
685
+ submitData.type === BaseConfigType.BASE_CONFIG_TYPE_TEXT || submitData.type === BaseConfigType.BASE_CONFIG_TYPE_RICH_TEXT
686
+ ? serializeDynamicI18ns(
687
+ valueI18nValues.value,
688
+ I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_VALUE,
689
+ submitData.id,
690
+ submitData.value
691
+ )
692
+ : [];
693
+
694
+ if (submitData.id) {
695
+ await defBaseConfigService.UpdateBaseConfig({ base_config: submitData });
696
+ } else {
697
+ await defBaseConfigService.CreateBaseConfig({ base_config: submitData });
698
+ }
699
+ ElMessage.success(
700
+ t(submitData.id ? "common.message.update_success" : "common.message.create_success", {
701
+ resource: t("system.base.config.resource")
702
+ })
703
+ );
704
+ handleCloseDialog();
705
+ refreshTable();
706
+ } finally {
707
+ saving.value = false;
708
+ }
596
709
  }
597
710
 
598
711
  /**
@@ -679,6 +792,15 @@ function handleDelete(selected?: number | string | Array<number | string> | Base
679
792
  </script>
680
793
 
681
794
  <style scoped lang="scss">
795
+ .config-form-value {
796
+ width: 100%;
797
+ min-width: 0;
798
+ > p {
799
+ margin: 0 0 16px;
800
+ color: var(--el-text-color-secondary);
801
+ }
802
+ }
803
+
682
804
  .config-key-cell {
683
805
  cursor: pointer;
684
806
  border-bottom: 1px dashed var(--el-color-info);
@@ -723,4 +845,17 @@ function handleDelete(selected?: number | string | Array<number | string> | Base
723
845
  max-width: 100%;
724
846
  height: auto;
725
847
  }
848
+ @media (max-width: 767px) {
849
+ :global(.system-config-dialog .el-col) {
850
+ flex: 0 0 100%;
851
+ max-width: 100%;
852
+ }
853
+ :global(.system-config-dialog .el-form-item) {
854
+ flex-direction: column;
855
+ }
856
+ :global(.system-config-dialog .el-form-item__label) {
857
+ justify-content: flex-start;
858
+ width: auto !important;
859
+ }
860
+ }
726
861
  </style>
@@ -21,11 +21,7 @@
21
21
  @close="handleCloseDialog"
22
22
  >
23
23
  <template #i18ns>
24
- <DynamicI18nEditor
25
- v-model="i18nValues"
26
- :source="formData.name"
27
- :maxlength="50"
28
- />
24
+ <DynamicI18nEditor v-model="i18nValues" :source="formData.name" :maxlength="50" />
29
25
  </template>
30
26
  </FormDialog>
31
27
  </div>
@@ -124,6 +120,7 @@ const statusOptions = computed<ProFormOption[]>(() => [
124
120
  const formFields = computed<ProFormField[]>(() => [
125
121
  {
126
122
  prop: "name",
123
+ suffixSlotName: "i18ns",
127
124
  label: t("system.base.dict.field.name"),
128
125
  component: "input",
129
126
  props: { placeholder: t("system.base.dict.placeholder.name") }
@@ -134,7 +131,6 @@ const formFields = computed<ProFormField[]>(() => [
134
131
  component: "input",
135
132
  props: { placeholder: t("system.base.dict.placeholder.code") }
136
133
  },
137
- { prop: "i18ns", label: t("system.base.i18n.field.i18ns"), component: "slot", slotName: "i18ns" },
138
134
  { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value }
139
135
  ]);
140
136
 
@@ -261,7 +257,7 @@ async function handleOpenDialog(dictId?: number) {
261
257
 
262
258
  const data = await defBaseDictService.GetBaseDict({ id: dictId });
263
259
  Object.assign(formData, data);
264
- i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
260
+ i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
265
261
  }
266
262
 
267
263
  /**
@@ -283,7 +279,7 @@ function resetForm() {
283
279
  formData.name = "";
284
280
  formData.i18ns = [];
285
281
  formData.status = Status.STATUS_ENABLE;
286
- i18nValues.value = normalizeDynamicI18ns(undefined);
282
+ i18nValues.value = normalizeDynamicI18ns(undefined);
287
283
  }
288
284
 
289
285
  /**
@@ -297,7 +293,8 @@ function handleSubmit() {
297
293
  submitData.i18ns = serializeDynamicI18ns(
298
294
  i18nValues.value,
299
295
  I18nTargetType.I18N_TARGET_TYPE_BASE_DICT_NAME,
300
- submitData.id
296
+ submitData.id,
297
+ submitData.name
301
298
  );
302
299
  const request = submitData.id
303
300
  ? defBaseDictService.UpdateBaseDict({ base_dict: submitData })
@@ -36,11 +36,7 @@
36
36
  </div>
37
37
  </template>
38
38
  <template #i18ns>
39
- <DynamicI18nEditor
40
- v-model="i18nValues"
41
- :source="formData.label"
42
- :maxlength="100"
43
- />
39
+ <DynamicI18nEditor v-model="i18nValues" :source="formData.label" :maxlength="100" />
44
40
  </template>
45
41
  </FormDialog>
46
42
  </div>
@@ -147,6 +143,7 @@ const statusOptions = computed<ProFormOption[]>(() => [
147
143
  const formFields = computed<ProFormField[]>(() => [
148
144
  {
149
145
  prop: "label",
146
+ suffixSlotName: "i18ns",
150
147
  label: t("system.base.dict.item.field.label"),
151
148
  component: "input",
152
149
  props: { placeholder: t("system.base.dict.item.placeholder.label") }
@@ -157,13 +154,6 @@ const formFields = computed<ProFormField[]>(() => [
157
154
  component: "input",
158
155
  props: { placeholder: t("system.base.dict.item.placeholder.value") }
159
156
  },
160
- {
161
- prop: "i18ns",
162
- label: t("system.base.i18n.field.i18ns"),
163
- component: "slot",
164
- slotName: "i18ns",
165
- colSpan: 24
166
- },
167
157
  {
168
158
  prop: "sort",
169
159
  label: t("common.field.sort"),
@@ -330,7 +320,7 @@ async function handleOpenDialog(dictItemId?: number) {
330
320
 
331
321
  const data = await defBaseDictItemService.GetBaseDictItem({ id: dictItemId });
332
322
  Object.assign(formData, data);
333
- i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
323
+ i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
334
324
  }
335
325
 
336
326
  /**
@@ -355,7 +345,7 @@ function resetForm() {
355
345
  formData.tag_type = "";
356
346
  formData.sort = 1;
357
347
  formData.status = Status.STATUS_ENABLE;
358
- i18nValues.value = normalizeDynamicI18ns(undefined);
348
+ i18nValues.value = normalizeDynamicI18ns(undefined);
359
349
  }
360
350
 
361
351
  /**
@@ -370,7 +360,8 @@ function handleSubmit() {
370
360
  submitData.i18ns = serializeDynamicI18ns(
371
361
  i18nValues.value,
372
362
  I18nTargetType.I18N_TARGET_TYPE_BASE_DICT_ITEM_LABEL,
373
- submitData.id
363
+ submitData.id,
364
+ submitData.label
374
365
  );
375
366
  const request = submitData.id
376
367
  ? defBaseDictItemService.UpdateBaseDictItem({ base_dict_item: submitData })
@@ -15,11 +15,7 @@
15
15
  @close="handleCloseDialog"
16
16
  >
17
17
  <template #i18ns>
18
- <DynamicI18nEditor
19
- v-model="i18nValues"
20
- :source="formData.name"
21
- :maxlength="50"
22
- />
18
+ <DynamicI18nEditor v-model="i18nValues" :source="formData.name" :maxlength="50" />
23
19
  </template>
24
20
  </FormDialog>
25
21
  </div>
@@ -215,7 +211,11 @@ function renderOperationCell(scope: RenderScope<BaseJob>) {
215
211
  );
216
212
  }
217
213
 
218
- if (row.status === Status.STATUS_ENABLE && (row.entry_id === undefined || row.entry_id === 0) && BUTTONS.value["base:job:start"]) {
214
+ if (
215
+ row.status === Status.STATUS_ENABLE &&
216
+ (row.entry_id === undefined || row.entry_id === 0) &&
217
+ BUTTONS.value["base:job:start"]
218
+ ) {
219
219
  actionNodes.push(
220
220
  h(
221
221
  ElButton,
@@ -249,7 +249,11 @@ function renderOperationCell(scope: RenderScope<BaseJob>) {
249
249
  );
250
250
  }
251
251
 
252
- if (row.status === Status.STATUS_ENABLE && (row.entry_id === undefined || row.entry_id === 0) && BUTTONS.value["base:job:exec"]) {
252
+ if (
253
+ row.status === Status.STATUS_ENABLE &&
254
+ (row.entry_id === undefined || row.entry_id === 0) &&
255
+ BUTTONS.value["base:job:exec"]
256
+ ) {
253
257
  actionNodes.push(
254
258
  h(
255
259
  ElButton,
@@ -298,17 +302,11 @@ function renderOperationCell(scope: RenderScope<BaseJob>) {
298
302
  const formFields = computed<ProFormField[]>(() => [
299
303
  {
300
304
  prop: "name",
305
+ suffixSlotName: "i18ns",
301
306
  label: t("system.base.job.field.name"),
302
307
  component: "input",
303
308
  props: { placeholder: t("system.base.job.placeholder.name") }
304
309
  },
305
- {
306
- prop: "i18ns",
307
- label: t("system.base.i18n.field.i18ns"),
308
- component: "slot",
309
- slotName: "i18ns",
310
- colSpan: 24
311
- },
312
310
  {
313
311
  prop: "invoke_target",
314
312
  label: t("system.base.job.field.invoke_target"),
@@ -427,7 +425,7 @@ async function handleOpenDialog(jobId?: number) {
427
425
 
428
426
  const data = await defBaseJobService.GetBaseJob({ id: jobId });
429
427
  Object.assign(formData, data);
430
- i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
428
+ i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[]);
431
429
  }
432
430
 
433
431
  /**
@@ -451,7 +449,7 @@ function resetForm() {
451
449
  formData.cron_expression = "";
452
450
  formData.status = Status.STATUS_ENABLE;
453
451
  formData.i18ns = [];
454
- i18nValues.value = normalizeDynamicI18ns(undefined);
452
+ i18nValues.value = normalizeDynamicI18ns(undefined);
455
453
  }
456
454
 
457
455
  /**
@@ -465,7 +463,8 @@ function handleSubmit() {
465
463
  submitData.i18ns = serializeDynamicI18ns(
466
464
  i18nValues.value,
467
465
  I18nTargetType.I18N_TARGET_TYPE_BASE_JOB_NAME,
468
- submitData.id
466
+ submitData.id,
467
+ submitData.name
469
468
  );
470
469
  const request = submitData.id
471
470
  ? defBaseJobService.UpdateBaseJob({ base_job: submitData })
@@ -136,6 +136,12 @@ const formFields = computed<ProFormField[]>(() => [
136
136
  component: "input-number",
137
137
  props: { min: 1, max: 1440, precision: 0 }
138
138
  },
139
+ {
140
+ prop: "allow_concurrent_login",
141
+ label: t("system.base.login_policy.field.allow_concurrent_login"),
142
+ component: "switch",
143
+ props: { activeText: t("common.status.enabled"), inactiveText: t("common.status.disabled") }
144
+ },
139
145
  {
140
146
  prop: "password_min_length",
141
147
  label: t("system.base.login_policy.field.password_min_length"),
@@ -160,6 +166,12 @@ const formFields = computed<ProFormField[]>(() => [
160
166
  component: "input-number",
161
167
  props: { min: 0, max: 3650, precision: 0 }
162
168
  },
169
+ {
170
+ prop: "mfa_remember_days",
171
+ label: t("system.base.login_policy.field.mfa_remember_days"),
172
+ component: "input-number",
173
+ props: { min: 0, max: 90, precision: 0 }
174
+ },
163
175
  {
164
176
  prop: "initial_password",
165
177
  label: t("system.base.login_policy.field.initial_password"),
@@ -182,6 +194,7 @@ const formRules = computed(() => ({
182
194
  { required: true, message: t("system.base.login_policy.validation.password_min_complexity_classes"), trigger: "change" }
183
195
  ],
184
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" }]
185
198
  }));
186
199
 
187
200
  const columns = computed<ColumnProps[]>(() => [
@@ -207,6 +220,18 @@ const columns = computed<ColumnProps[]>(() => [
207
220
  },
208
221
  { prop: "max_failed_attempts", label: t("system.base.login_policy.field.max_failed_attempts"), width: 110, align: "right" },
209
222
  { prop: "lock_duration_minutes", label: t("system.base.login_policy.field.lock_duration_minutes"), width: 110, align: "right" },
223
+ {
224
+ prop: "allow_concurrent_login",
225
+ label: t("system.base.login_policy.field.allow_concurrent_login"),
226
+ width: 130,
227
+ cellType: "status",
228
+ statusProps: {
229
+ activeValue: true,
230
+ inactiveValue: false,
231
+ activeText: t("common.status.enabled"),
232
+ inactiveText: t("common.status.disabled")
233
+ }
234
+ },
210
235
  { prop: "password_min_length", label: t("system.base.login_policy.field.password_min_length"), width: 110, align: "right" },
211
236
  { prop: "password_history_count", label: t("system.base.login_policy.field.password_history_count"), width: 110, align: "right" },
212
237
  {
@@ -216,6 +241,7 @@ const columns = computed<ColumnProps[]>(() => [
216
241
  align: "right"
217
242
  },
218
243
  { prop: "password_max_age_days", label: t("system.base.login_policy.field.password_max_age_days"), width: 110, align: "right" },
244
+ { prop: "mfa_remember_days", label: t("system.base.login_policy.field.mfa_remember_days"), width: 130, align: "right" },
219
245
  {
220
246
  prop: "status",
221
247
  label: t("common.field.status"),
@@ -312,10 +338,12 @@ function defaultForm(): BaseLoginPolicyFormState {
312
338
  user_id: 0,
313
339
  max_failed_attempts: 5,
314
340
  lock_duration_minutes: 15,
341
+ allow_concurrent_login: false,
315
342
  password_min_length: 8,
316
343
  password_history_count: 3,
317
344
  password_min_complexity_classes: 3,
318
345
  password_max_age_days: 90,
346
+ mfa_remember_days: 0,
319
347
  initial_password: "",
320
348
  status: Status.STATUS_ENABLE,
321
349
  rules: []