@liujitcn/kratos-admin-system 0.0.28 → 0.0.31

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 (135) hide show
  1. package/README.md +19 -2
  2. package/dist/package/declarations/src/api/base/notification.d.ts +24 -0
  3. package/dist/package/declarations/src/api/system/base_audit_log.d.ts +55 -0
  4. package/dist/package/declarations/src/api/system/base_dashboard.d.ts +14 -0
  5. package/dist/package/declarations/src/api/system/base_file.d.ts +13 -0
  6. package/dist/package/declarations/src/api/system/base_i18n.d.ts +5 -5
  7. package/dist/package/declarations/src/api/system/base_login_policy.d.ts +10 -0
  8. package/dist/package/declarations/src/api/system/base_message.d.ts +24 -0
  9. package/dist/package/declarations/src/api/system/base_message_category.d.ts +21 -0
  10. package/dist/package/declarations/src/api/system/base_session.d.ts +11 -0
  11. package/dist/package/declarations/src/api/system/oauth_client.d.ts +24 -0
  12. package/dist/package/declarations/src/components/AuditLogTable.vue.d.ts +45 -0
  13. package/dist/package/declarations/src/components/DynamicI18nCell.vue.d.ts +16 -0
  14. package/dist/package/declarations/src/components/DynamicI18nEditor.vue.d.ts +20 -0
  15. package/dist/package/declarations/src/components/auditLog.d.ts +9 -0
  16. package/dist/package/declarations/src/components/dynamicI18n.d.ts +38 -0
  17. package/dist/package/declarations/src/locales/generated.d.ts +1364 -68
  18. package/dist/package/declarations/src/rpc/base/v1/login.d.ts +149 -0
  19. package/dist/package/declarations/src/rpc/base/v1/notification.d.ts +281 -0
  20. package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +25 -0
  21. package/dist/package/declarations/src/rpc/base/v1/oauth_client.d.ts +23 -0
  22. package/dist/package/declarations/src/rpc/system/admin/v1/base_audit_log.d.ts +640 -0
  23. package/dist/package/declarations/src/rpc/system/admin/v1/base_config.d.ts +3 -3
  24. package/dist/package/declarations/src/rpc/system/admin/v1/base_dashboard.d.ts +60 -0
  25. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +4 -4
  26. package/dist/package/declarations/src/rpc/system/admin/v1/base_file.d.ts +73 -0
  27. package/dist/package/declarations/src/rpc/system/admin/v1/base_i18n.d.ts +27 -23
  28. package/dist/package/declarations/src/rpc/system/admin/v1/base_job.d.ts +5 -0
  29. package/dist/package/declarations/src/rpc/system/admin/v1/base_login_policy.d.ts +51 -0
  30. package/dist/package/declarations/src/rpc/system/admin/v1/base_menu.d.ts +2 -2
  31. package/dist/package/declarations/src/rpc/system/admin/v1/base_message.d.ts +193 -0
  32. package/dist/package/declarations/src/rpc/system/admin/v1/base_message_category.d.ts +125 -0
  33. package/dist/package/declarations/src/rpc/system/admin/v1/base_session.d.ts +33 -0
  34. package/dist/package/declarations/src/rpc/system/admin/v1/base_user.d.ts +3 -3
  35. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen.d.ts +1 -1
  36. package/dist/package/declarations/src/rpc/system/admin/v1/oauth_client.d.ts +145 -0
  37. package/dist/package/declarations/src/views/base/api-log/index.vue.d.ts +3 -0
  38. package/dist/package/declarations/src/views/base/dashboard/index.vue.d.ts +3 -0
  39. package/dist/package/declarations/src/views/base/data-access-log/index.vue.d.ts +3 -0
  40. package/dist/package/declarations/src/views/base/file/index.vue.d.ts +3 -0
  41. package/dist/package/declarations/src/views/base/login-log/index.vue.d.ts +3 -0
  42. package/dist/package/declarations/src/views/base/login-policy/index.vue.d.ts +3 -0
  43. package/dist/package/declarations/src/views/base/message/index.vue.d.ts +3 -0
  44. package/dist/package/declarations/src/views/base/message-category/index.vue.d.ts +3 -0
  45. package/dist/package/declarations/src/views/base/oauth-client/index.vue.d.ts +3 -0
  46. package/dist/package/declarations/src/views/base/operation-log/index.vue.d.ts +3 -0
  47. package/dist/package/declarations/src/views/base/permission-log/index.vue.d.ts +3 -0
  48. package/dist/package/declarations/src/views/base/policy-evaluation-log/index.vue.d.ts +3 -0
  49. package/dist/package/declarations/src/views/message/inbox/index.vue.d.ts +3 -0
  50. package/dist/package/declarations/src/views/profile/components/session.vue.d.ts +3 -0
  51. package/dist/package/src/api/base/notification.ts +69 -0
  52. package/dist/package/src/api/base/sse.ts +4 -4
  53. package/dist/package/src/api/system/auth.ts +1 -0
  54. package/dist/package/src/api/system/base_audit_log.ts +168 -0
  55. package/dist/package/src/api/system/base_dashboard.ts +55 -0
  56. package/dist/package/src/api/system/base_file.ts +43 -0
  57. package/dist/package/src/api/system/base_i18n.ts +12 -12
  58. package/dist/package/src/api/system/base_login_policy.ts +32 -0
  59. package/dist/package/src/api/system/base_message.ts +70 -0
  60. package/dist/package/src/api/system/base_message_category.ts +57 -0
  61. package/dist/package/src/api/system/base_session.ts +33 -0
  62. package/dist/package/src/api/system/oauth_client.ts +102 -0
  63. package/dist/package/src/components/AuditLogTable.vue +105 -0
  64. package/dist/package/src/components/{DynamicTranslationCell.vue → DynamicI18nCell.vue} +50 -50
  65. package/dist/package/src/components/{DynamicTranslationEditor.vue → DynamicI18nEditor.vue} +45 -45
  66. package/dist/package/src/components/Notification.vue +196 -0
  67. package/dist/package/src/components/auditLog.ts +46 -0
  68. package/dist/package/src/components/{dynamicTranslation.ts → dynamicI18n.ts} +15 -15
  69. package/dist/package/src/locales/README.md +5 -3
  70. package/dist/package/src/locales/en-US.json +345 -21
  71. package/dist/package/src/locales/ja-JP.json +347 -23
  72. package/dist/package/src/locales/zh-CN.json +343 -19
  73. package/dist/package/src/locales/zh-TW.json +346 -22
  74. package/dist/package/src/module.ts +5 -2
  75. package/dist/package/src/rpc/base/v1/login.ts +172 -0
  76. package/dist/package/src/rpc/base/v1/notification.ts +315 -0
  77. package/dist/package/src/rpc/base/v1/oauth.ts +25 -0
  78. package/dist/package/src/rpc/base/v1/oauth_client.ts +33 -0
  79. package/dist/package/src/rpc/system/admin/v1/base_audit_log.ts +737 -0
  80. package/dist/package/src/rpc/system/admin/v1/base_config.ts +3 -3
  81. package/dist/package/src/rpc/system/admin/v1/base_dashboard.ts +81 -0
  82. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +4 -4
  83. package/dist/package/src/rpc/system/admin/v1/base_file.ts +88 -0
  84. package/dist/package/src/rpc/system/admin/v1/base_i18n.ts +27 -23
  85. package/dist/package/src/rpc/system/admin/v1/base_job.ts +5 -0
  86. package/dist/package/src/rpc/system/admin/v1/base_login_policy.ts +63 -0
  87. package/dist/package/src/rpc/system/admin/v1/base_menu.ts +2 -2
  88. package/dist/package/src/rpc/system/admin/v1/base_message.ts +236 -0
  89. package/dist/package/src/rpc/system/admin/v1/base_message_category.ts +149 -0
  90. package/dist/package/src/rpc/system/admin/v1/base_session.ts +44 -0
  91. package/dist/package/src/rpc/system/admin/v1/base_user.ts +3 -3
  92. package/dist/package/src/rpc/system/admin/v1/code_gen.ts +1 -1
  93. package/dist/package/src/rpc/system/admin/v1/oauth_client.ts +174 -0
  94. package/dist/package/src/views/ai/chat/components/ChatPanel.vue +2 -2
  95. package/dist/package/src/views/ai/chat/message.ts +7 -3
  96. package/dist/package/src/views/base/api-log/index.vue +83 -0
  97. package/dist/package/src/views/base/config/index.vue +41 -41
  98. package/dist/package/src/views/base/dashboard/index.vue +200 -0
  99. package/dist/package/src/views/base/data-access-log/index.vue +84 -0
  100. package/dist/package/src/views/base/dict/index.vue +23 -23
  101. package/dist/package/src/views/base/dict/item.vue +25 -25
  102. package/dist/package/src/views/base/file/index.vue +119 -0
  103. package/dist/package/src/views/base/job/index.vue +62 -7
  104. package/dist/package/src/views/base/language/index.vue +2 -1
  105. package/dist/package/src/views/base/login-log/index.vue +92 -0
  106. package/dist/package/src/views/base/login-policy/index.vue +219 -0
  107. package/dist/package/src/views/base/menu/index.vue +23 -23
  108. package/dist/package/src/views/base/message/index.vue +582 -0
  109. package/dist/package/src/views/base/message-category/index.vue +356 -0
  110. package/dist/package/src/views/base/oauth-client/index.vue +411 -0
  111. package/dist/package/src/views/base/operation-log/index.vue +82 -0
  112. package/dist/package/src/views/base/permission-log/index.vue +85 -0
  113. package/dist/package/src/views/base/policy-evaluation-log/index.vue +82 -0
  114. package/dist/package/src/views/message/inbox/index.vue +249 -0
  115. package/dist/package/src/views/profile/components/base.vue +6 -5
  116. package/dist/package/src/views/profile/components/password.vue +2 -2
  117. package/dist/package/src/views/profile/components/security.vue +475 -62
  118. package/dist/package/src/views/profile/components/session.vue +153 -0
  119. package/dist/package/src/views/profile/index.vue +35 -22
  120. package/dist/package/src/views/tool/code-gen/code-preview/index.vue +9 -9
  121. package/dist/package/src/views/tool/code-gen/columns/index.vue +1 -1
  122. package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +8 -8
  123. package/dist/package/src/views/tool/code-gen/config.ts +1 -0
  124. package/dist/package/src/views/tool/code-gen/table/index.vue +7 -7
  125. package/dist/package/src/views/tool/ops-monitoring/index.vue +25 -21
  126. package/package.json +2 -2
  127. package/dist/package/declarations/src/api/system/base_log.d.ts +0 -9
  128. package/dist/package/declarations/src/components/DynamicTranslationCell.vue.d.ts +0 -16
  129. package/dist/package/declarations/src/components/DynamicTranslationEditor.vue.d.ts +0 -20
  130. package/dist/package/declarations/src/components/dynamicTranslation.d.ts +0 -38
  131. package/dist/package/declarations/src/rpc/system/admin/v1/base_log.d.ts +0 -87
  132. package/dist/package/src/api/system/base_log.ts +0 -32
  133. package/dist/package/src/rpc/system/admin/v1/base_log.ts +0 -101
  134. package/dist/package/src/views/base/log/index.vue +0 -339
  135. /package/dist/package/declarations/src/{views/base/log/index.vue.d.ts → components/Notification.vue.d.ts} +0 -0
@@ -56,16 +56,16 @@
56
56
  inline-prompt
57
57
  />
58
58
  </template>
59
- <template #nameTranslations>
60
- <DynamicTranslationEditor
61
- v-model="nameTranslationValues"
59
+ <template #nameI18ns>
60
+ <DynamicI18nEditor
61
+ v-model="nameI18nValues"
62
62
  :source="formData.name"
63
63
  :maxlength="100"
64
64
  />
65
65
  </template>
66
- <template #valueTranslations>
67
- <DynamicTranslationEditor
68
- v-model="valueTranslationValues"
66
+ <template #valueI18ns>
67
+ <DynamicI18nEditor
68
+ v-model="valueI18nValues"
69
69
  :source="formData.value"
70
70
  :maxlength="10000"
71
71
  multiline
@@ -78,8 +78,6 @@
78
78
  <script setup lang="ts">
79
79
  import { computed, h, reactive, ref } from "vue";
80
80
  import { useDebounceFn } from "@vueuse/core";
81
- import { ElImage, ElMessage, ElMessageBox, ElTag, ElTooltip } from "element-plus";
82
- import { CirclePlus, Delete, EditPen, RefreshLeft } from "@element-plus/icons-vue";
83
81
  import type { ColumnProps, HeaderActionProps, ProTableInstance } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
84
82
  import ProTable from "@liujitcn/kratos-admin-core/components/ProTable";
85
83
  import FormDialog from "@liujitcn/kratos-admin-core/components/Dialog/FormDialog.vue";
@@ -99,15 +97,15 @@ import type { BaseI18n } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1
99
97
  import { BaseConfigSite } from "@liujitcn/kratos-admin-system/rpc/base/v1/config";
100
98
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
101
99
  import { BaseConfigType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_config";
102
- import { TranslationTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
100
+ import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
103
101
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
104
102
  import { t } from "@liujitcn/kratos-admin-core";
105
- import DynamicTranslationEditor from "@liujitcn/kratos-admin-system/components/DynamicTranslationEditor.vue";
106
- import DynamicTranslationCell from "@liujitcn/kratos-admin-system/components/DynamicTranslationCell.vue";
103
+ import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/DynamicI18nEditor.vue";
104
+ import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/DynamicI18nCell.vue";
107
105
  import {
108
106
  getEditableLanguageOptions,
109
- type DynamicTranslationValue
110
- } from "@liujitcn/kratos-admin-system/components/dynamicTranslation";
107
+ type DynamicI18nValue
108
+ } from "@liujitcn/kratos-admin-system/components/dynamicI18n";
111
109
 
112
110
  /** 系统配置编辑表单状态,新增时枚举字段保持为空,避免把未知值 0 显示为下拉文本。 */
113
111
  type BaseConfigFormState = Omit<BaseConfigForm, "site" | "type"> & {
@@ -147,16 +145,16 @@ const formData = reactive<BaseConfigFormState>({
147
145
  /** 状态 */
148
146
  status: Status.STATUS_ENABLE,
149
147
  /** 配置名称非主语言翻译。 */
150
- name_translations: [],
148
+ name_i18ns: [],
151
149
  /** 配置文本或富文本值的非主语言翻译。 */
152
- value_translations: []
150
+ value_i18ns: []
153
151
  });
154
152
 
155
153
  /** 将配置值翻译记录转换为编辑器值,缺少记录时保留可编辑的空行。 */
156
- function normalizeConfigTranslations(targetType: TranslationTargetType): DynamicTranslationValue[] {
157
- const records = targetType === TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_NAME
158
- ? formData.name_translations
159
- : formData.value_translations;
154
+ function normalizeConfigI18ns(targetType: I18nTargetType): DynamicI18nValue[] {
155
+ const records = targetType === I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME
156
+ ? formData.name_i18ns
157
+ : formData.value_i18ns;
160
158
  return getEditableLanguageOptions()
161
159
  .map(item => item.value)
162
160
  .map(locale => {
@@ -170,7 +168,7 @@ function normalizeConfigTranslations(targetType: TranslationTargetType): Dynamic
170
168
  }
171
169
 
172
170
  /** 保存指定目标类型的编辑器值,并保留其他字段的翻译。 */
173
- function updateConfigTranslations(targetType: TranslationTargetType, values: DynamicTranslationValue[]) {
171
+ function updateConfigI18ns(targetType: I18nTargetType, values: DynamicI18nValue[]) {
174
172
  const next = values.map(
175
173
  item =>
176
174
  ({
@@ -180,21 +178,21 @@ function updateConfigTranslations(targetType: TranslationTargetType, values: Dyn
180
178
  name: item.text
181
179
  }) as BaseI18n
182
180
  );
183
- if (targetType === TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_NAME) {
184
- formData.name_translations = next;
181
+ if (targetType === I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME) {
182
+ formData.name_i18ns = next;
185
183
  } else {
186
- formData.value_translations = next;
184
+ formData.value_i18ns = next;
187
185
  }
188
186
  }
189
187
 
190
- const nameTranslationValues = computed<DynamicTranslationValue[]>({
191
- get: () => normalizeConfigTranslations(TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_NAME),
192
- set: values => updateConfigTranslations(TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_NAME, values)
188
+ const nameI18nValues = computed<DynamicI18nValue[]>({
189
+ get: () => normalizeConfigI18ns(I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME),
190
+ set: values => updateConfigI18ns(I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME, values)
193
191
  });
194
192
 
195
- const valueTranslationValues = computed<DynamicTranslationValue[]>({
196
- get: () => normalizeConfigTranslations(TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_VALUE),
197
- set: values => updateConfigTranslations(TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_VALUE, values)
193
+ const valueI18nValues = computed<DynamicI18nValue[]>({
194
+ get: () => normalizeConfigI18ns(I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_VALUE),
195
+ set: values => updateConfigI18ns(I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_VALUE, values)
198
196
  });
199
197
 
200
198
  const rules = computed(() => ({
@@ -259,7 +257,9 @@ const statusOptions = computed<ProFormOption[]>(() => [
259
257
 
260
258
  /** 字典类系统配置与字典编码的映射关系。 */
261
259
  const BASE_CONFIG_DICT_CODE_MAP: Record<string, string> = {
262
- captchaType: "captcha_type"
260
+ captchaType: "captcha_type",
261
+ securityMfaPolicy: "security_mfa_policy",
262
+ securityMfaMethod: "mfa_method"
263
263
  };
264
264
 
265
265
  /** 当前字典类配置对应的字典编码,未配置映射时允许退回手动输入。 */
@@ -334,17 +334,17 @@ const formFields = computed<ProFormField[]>(() => [
334
334
  visible: model => model.type == BaseConfigType.BASE_CONFIG_TYPE_BOOLEAN
335
335
  },
336
336
  {
337
- prop: "translations",
338
- label: t("system.base.translation.field.name_translations"),
337
+ prop: "i18ns",
338
+ label: t("system.base.i18n.field.name_i18ns"),
339
339
  component: "slot",
340
- slotName: "nameTranslations",
340
+ slotName: "nameI18ns",
341
341
  colSpan: 24
342
342
  },
343
343
  {
344
- prop: "translations",
345
- label: t("system.base.translation.field.value_translations"),
344
+ prop: "i18ns",
345
+ label: t("system.base.i18n.field.value_i18ns"),
346
346
  component: "slot",
347
- slotName: "valueTranslations",
347
+ slotName: "valueI18ns",
348
348
  visible: model =>
349
349
  model.type == BaseConfigType.BASE_CONFIG_TYPE_TEXT || model.type == BaseConfigType.BASE_CONFIG_TYPE_RICH_TEXT,
350
350
  colSpan: 24
@@ -431,11 +431,11 @@ const columns = computed<ColumnProps[]>(() => [
431
431
 
432
432
  /** 渲染系统配置名称翻译预览。 */
433
433
  function renderConfigNameCell(row: BaseConfig) {
434
- return h(DynamicTranslationCell, {
434
+ return h(DynamicI18nCell, {
435
435
  source: row.name,
436
- targetType: TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_CONFIG_NAME,
436
+ targetType: I18nTargetType.I18N_TARGET_TYPE_BASE_CONFIG_NAME,
437
437
  targetId: row.id,
438
- translations: row.translations
438
+ i18ns: row.i18ns
439
439
  });
440
440
  }
441
441
 
@@ -573,8 +573,8 @@ function resetForm() {
573
573
  formData.type = undefined;
574
574
  formData.key = "";
575
575
  formData.value = "";
576
- formData.name_translations = [];
577
- formData.value_translations = [];
576
+ formData.name_i18ns = [];
577
+ formData.value_i18ns = [];
578
578
  formData.status = Status.STATUS_ENABLE;
579
579
  }
580
580
 
@@ -0,0 +1,200 @@
1
+ <template>
2
+ <main class="dashboard-page">
3
+ <header class="dashboard-header">
4
+ <div>
5
+ <h1>{{ t("system.dashboard.title") }}</h1>
6
+ <p>{{ t("system.dashboard.updated_at", { time: updatedAt }) }}</p>
7
+ </div>
8
+ <el-button :loading="loading" @click="loadDashboard">
9
+ <el-icon><Refresh /></el-icon>
10
+ {{ t("core.table.refresh") }}
11
+ </el-button>
12
+ </header>
13
+
14
+ <el-skeleton v-if="loading && !overview" :rows="3" animated />
15
+ <template v-else>
16
+ <section class="metric-grid" :aria-label="t('system.dashboard.overview')">
17
+ <el-card v-for="metric in metrics" :key="metric.key" shadow="never" class="metric-card">
18
+ <span class="metric-label">{{ metric.label }}</span>
19
+ <strong class="metric-value">{{ metric.value }}</strong>
20
+ </el-card>
21
+ </section>
22
+
23
+ <section class="chart-grid">
24
+ <el-card shadow="never" class="chart-card chart-card-wide">
25
+ <template #header>{{ t("system.dashboard.login_trend") }}</template>
26
+ <div class="chart-wrap"><ECharts :option="loginTrendOption" height="320" /></div>
27
+ </el-card>
28
+ <el-card shadow="never" class="chart-card">
29
+ <template #header>{{ t("system.dashboard.login_distribution") }}</template>
30
+ <div class="chart-wrap"><ECharts :option="loginDistributionOption" height="320" /></div>
31
+ </el-card>
32
+ <el-card shadow="never" class="chart-card">
33
+ <template #header>{{ t("system.dashboard.operation_distribution") }}</template>
34
+ <div class="chart-wrap"><ECharts :option="operationDistributionOption" height="320" /></div>
35
+ </el-card>
36
+ </section>
37
+ </template>
38
+ </main>
39
+ </template>
40
+
41
+ <script setup lang="ts">
42
+ import { computed, onMounted, ref } from "vue";
43
+ import ECharts from "@liujitcn/kratos-admin-core/components/ECharts/index.vue";
44
+ import { defBaseDashboardService } from "@liujitcn/kratos-admin-system/api/system/base_dashboard";
45
+ import type {
46
+ BaseDashboardDistributionItem,
47
+ BaseDashboardOverview,
48
+ BaseDashboardTrendPoint
49
+ } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_dashboard";
50
+ import { t } from "@liujitcn/kratos-admin-core";
51
+
52
+ const loading = ref(false);
53
+ const overview = ref<BaseDashboardOverview>();
54
+ const trend = ref<BaseDashboardTrendPoint[]>([]);
55
+ const loginDistribution = ref<BaseDashboardDistributionItem[]>([]);
56
+ const operationDistribution = ref<BaseDashboardDistributionItem[]>([]);
57
+ const updatedAt = ref("");
58
+
59
+ const metrics = computed(() => [
60
+ { key: "users", label: t("system.dashboard.users"), value: overview.value?.user_count ?? 0 },
61
+ { key: "roles", label: t("system.dashboard.roles"), value: overview.value?.role_count ?? 0 },
62
+ { key: "logins", label: t("system.dashboard.today_logins"), value: overview.value?.today_login_count ?? 0 },
63
+ { key: "operations", label: t("system.dashboard.today_operations"), value: overview.value?.today_operation_count ?? 0 }
64
+ ]);
65
+
66
+ const loginTrendOption = computed(() => ({
67
+ tooltip: { trigger: "axis" as const },
68
+ grid: { left: 40, right: 20, top: 24, bottom: 32 },
69
+ xAxis: { type: "category" as const, boundaryGap: false, data: trend.value.map((item) => item.date) },
70
+ yAxis: { type: "value" as const, minInterval: 1 },
71
+ series: [{ type: "line" as const, smooth: true, data: trend.value.map((item) => item.count), areaStyle: {} }]
72
+ }));
73
+
74
+ const loginDistributionOption = computed(() => distributionOption(loginDistribution.value));
75
+ const operationDistributionOption = computed(() => distributionOption(operationDistribution.value));
76
+
77
+ async function loadDashboard() {
78
+ loading.value = true;
79
+ try {
80
+ const [overviewResponse, trendResponse, loginResponse, operationResponse] = await Promise.all([
81
+ defBaseDashboardService.GetBaseDashboardOverview({}),
82
+ defBaseDashboardService.GetBaseDashboardLoginTrend({ days: 7 }),
83
+ defBaseDashboardService.GetBaseDashboardLoginDistribution({}),
84
+ defBaseDashboardService.GetBaseDashboardOperationDistribution({})
85
+ ]);
86
+ overview.value = overviewResponse;
87
+ trend.value = trendResponse.points ?? [];
88
+ loginDistribution.value = loginResponse.items ?? [];
89
+ operationDistribution.value = operationResponse.items ?? [];
90
+ updatedAt.value = new Date().toLocaleString();
91
+ } catch {
92
+ ElMessage.error(t("system.dashboard.load_failed"));
93
+ } finally {
94
+ loading.value = false;
95
+ }
96
+ }
97
+
98
+ /** 将审计技术枚举名转换为当前语言的展示文案。 */
99
+ function distributionItemLabel(label: string) {
100
+ const mappings = [
101
+ ["BASE_OPERATION_ACTION_", "system.base.audit.operation_action."],
102
+ ["BASE_AUDIT_RESULT_", "system.base.audit.result."]
103
+ ];
104
+ const mapping = mappings.find(([prefix]) => label.startsWith(prefix));
105
+ if (!mapping) return label;
106
+ const value = label.slice(mapping[0].length).toLowerCase();
107
+ return value === "unspecified" ? t("common.message.unknown") : t(`${mapping[1]}${value}`);
108
+ }
109
+
110
+ /** 创建使用本地化图例的分布图配置。 */
111
+ function distributionOption(items: BaseDashboardDistributionItem[]) {
112
+ return {
113
+ tooltip: { trigger: "item" as const },
114
+ legend: { bottom: 0, type: "scroll" as const },
115
+ series: [{ type: "pie" as const, radius: ["38%", "68%"] as [string, string], center: ["50%", "45%"] as [string, string], data: items.map((item) => ({ name: distributionItemLabel(item.label), value: item.count })) }]
116
+ };
117
+ }
118
+
119
+ onMounted(loadDashboard);
120
+ </script>
121
+
122
+ <style scoped>
123
+ .dashboard-page {
124
+ padding: 20px;
125
+ }
126
+
127
+ .dashboard-header {
128
+ display: flex;
129
+ align-items: center;
130
+ justify-content: space-between;
131
+ gap: 16px;
132
+ margin-bottom: 20px;
133
+ }
134
+
135
+ .dashboard-header h1 {
136
+ margin: 0;
137
+ color: var(--el-text-color-primary);
138
+ font-size: 22px;
139
+ font-weight: 600;
140
+ }
141
+
142
+ .dashboard-header p {
143
+ margin: 6px 0 0;
144
+ color: var(--el-text-color-secondary);
145
+ font-size: 13px;
146
+ }
147
+
148
+ .metric-grid,
149
+ .chart-grid {
150
+ display: grid;
151
+ gap: 16px;
152
+ }
153
+
154
+ .metric-grid {
155
+ grid-template-columns: repeat(4, minmax(0, 1fr));
156
+ margin-bottom: 16px;
157
+ }
158
+
159
+ .metric-card :deep(.el-card__body) {
160
+ display: flex;
161
+ flex-direction: column;
162
+ gap: 10px;
163
+ min-height: 92px;
164
+ justify-content: center;
165
+ }
166
+
167
+ .metric-label {
168
+ color: var(--el-text-color-secondary);
169
+ font-size: 13px;
170
+ }
171
+
172
+ .metric-value {
173
+ color: var(--el-text-color-primary);
174
+ font-size: 28px;
175
+ line-height: 1;
176
+ }
177
+
178
+ .chart-grid {
179
+ grid-template-columns: repeat(2, minmax(0, 1fr));
180
+ }
181
+
182
+ .chart-card-wide {
183
+ grid-column: 1 / -1;
184
+ }
185
+
186
+ .chart-wrap {
187
+ height: 320px;
188
+ }
189
+
190
+ @media (max-width: 960px) {
191
+ .metric-grid,
192
+ .chart-grid {
193
+ grid-template-columns: 1fr;
194
+ }
195
+
196
+ .chart-card-wide {
197
+ grid-column: auto;
198
+ }
199
+ }
200
+ </style>
@@ -0,0 +1,84 @@
1
+ <template>
2
+ <AuditLogTable ref="page" :config="config" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { computed, ref } from "vue";
7
+ import type { ColumnProps } from "@liujitcn/kratos-admin-core/components/ProTable/interface";
8
+ import { t } from "@liujitcn/kratos-admin-core";
9
+ import { buildPageRequest } from "@liujitcn/kratos-admin-core/table";
10
+ import AuditLogTable, { type AuditLogTableConfig } from "@liujitcn/kratos-admin-system/components/AuditLogTable.vue";
11
+ import { auditDateSearch, auditDetailColumn, auditEnumLabel, createAuditEnumOptions } from "@liujitcn/kratos-admin-system/components/auditLog";
12
+ import { defBaseDataAccessLogService } from "@liujitcn/kratos-admin-system/api/system/base_audit_log";
13
+ import { BaseAuditResult, BaseDataAccessType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_audit_log";
14
+ import type { BaseDataAccessLog, PageBaseDataAccessLogRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_audit_log";
15
+
16
+ defineOptions({ name: "BaseDataAccessLog", inheritAttrs: false });
17
+
18
+ const page = ref<InstanceType<typeof AuditLogTable>>();
19
+ const resultOptions = computed(() => createAuditEnumOptions([
20
+ [BaseAuditResult.BASE_AUDIT_RESULT_SUCCESS, t("system.base.audit.result.success")],
21
+ [BaseAuditResult.BASE_AUDIT_RESULT_FAILURE, t("system.base.audit.result.failure")],
22
+ [BaseAuditResult.BASE_AUDIT_RESULT_ERROR, t("system.base.audit.result.error")]
23
+ ]));
24
+ const accessTypeOptions = computed(() => createAuditEnumOptions([
25
+ [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_LIST, t("system.base.audit.access_type.list")],
26
+ [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_DETAIL, t("system.base.audit.access_type.detail")],
27
+ [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_QUERY, t("system.base.audit.access_type.query")],
28
+ [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_EXPORT, t("system.base.audit.access_type.export")],
29
+ [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_DOWNLOAD, t("system.base.audit.access_type.download")],
30
+ [BaseDataAccessType.BASE_DATA_ACCESS_TYPE_IMPORT, t("system.base.audit.access_type.import")]
31
+ ]));
32
+ const columns = computed<ColumnProps[]>(() => [
33
+ { prop: "resource_type", label: t("system.base.audit.field.resource_type"), minWidth: 150, search: { el: "input" } },
34
+ { prop: "table_name", label: t("system.base.audit.field.table_name"), minWidth: 150 },
35
+ { prop: "access_type", label: t("system.base.audit.field.access_type"), minWidth: 120, search: { el: "select", enum: accessTypeOptions.value }, render: scope => auditEnumLabel(accessTypeOptions.value, (scope.row as BaseDataAccessLog).access_type) },
36
+ { prop: "affected_rows", label: t("system.base.audit.field.affected_rows"), minWidth: 110 },
37
+ { prop: "sensitive", label: t("system.base.audit.field.sensitive"), minWidth: 110, search: { el: "switch" }, render: scope => (scope.row as BaseDataAccessLog).sensitive ? t("common.value.yes") : t("common.value.no") },
38
+ { prop: "result", label: t("system.base.audit.field.result"), minWidth: 110, search: { el: "select", enum: resultOptions.value }, render: scope => auditEnumLabel(resultOptions.value, (scope.row as BaseDataAccessLog).result) },
39
+ { prop: "occurred_at", label: t("system.base.audit.field.occurred_at"), minWidth: 190, search: auditDateSearch(t) },
40
+ auditDetailColumn(t("common.action.view"), id => page.value?.handleOpenDialog(id))
41
+ ]);
42
+
43
+ const config = computed<AuditLogTableConfig>(() => ({
44
+ columns: columns.value,
45
+ detailTitle: t("system.base.audit.data_access.title.detail"),
46
+ closeText: t("common.action.close"),
47
+ detailFields: [
48
+ { key: "id", label: t("system.base.audit.field.id") },
49
+ { key: "tenant_id", label: t("system.base.audit.field.tenant_id") },
50
+ { key: "tenant_code", label: t("system.base.audit.field.tenant_code") },
51
+ { key: "user_id", label: t("system.base.audit.field.user_id") },
52
+ { key: "user_name", label: t("system.base.audit.field.user_name") },
53
+ { key: "resource_type", label: t("system.base.audit.field.resource_type") },
54
+ { key: "resource_id", label: t("system.base.audit.field.resource_id") },
55
+ { key: "access_type", label: t("system.base.audit.field.access_type") },
56
+ { key: "data_source", label: t("system.base.audit.field.data_source") },
57
+ { key: "table_name", label: t("system.base.audit.field.table_name") },
58
+ { key: "field_scope", label: t("system.base.audit.field.field_scope"), span: 2, code: true },
59
+ { key: "data_scope", label: t("system.base.audit.field.data_scope") },
60
+ { key: "affected_rows", label: t("system.base.audit.field.affected_rows") },
61
+ { key: "sensitive", label: t("system.base.audit.field.sensitive") },
62
+ { key: "sql_digest", label: t("system.base.audit.field.sql_digest") },
63
+ { key: "sql_text", label: t("system.base.audit.field.sql_text"), span: 2, code: true },
64
+ { key: "result", label: t("system.base.audit.field.result") },
65
+ { key: "reason_code", label: t("system.base.audit.field.reason_code") },
66
+ { key: "latency_ms", label: t("system.base.audit.field.latency_ms") },
67
+ { key: "request_id", label: t("system.base.audit.field.request_id") },
68
+ { key: "trace_id", label: t("system.base.audit.field.trace_id") },
69
+ { key: "occurred_at", label: t("system.base.audit.field.occurred_at") },
70
+ { key: "created_at", label: t("system.base.audit.field.created_at") }
71
+ ],
72
+ request: requestTable,
73
+ get: getDetail
74
+ }));
75
+
76
+ async function requestTable(params: Record<string, unknown>) {
77
+ const response = await defBaseDataAccessLogService.PageBaseDataAccessLog(buildPageRequest(params as unknown as PageBaseDataAccessLogRequest));
78
+ return { list: response.base_data_access_logs as unknown as Record<string, unknown>[], total: response.total };
79
+ }
80
+
81
+ async function getDetail(id: number) {
82
+ return (await defBaseDataAccessLogService.GetBaseDataAccessLog({ id })) as unknown as Record<string, unknown>;
83
+ }
84
+ </script>
@@ -20,9 +20,9 @@
20
20
  @confirm="handleSubmit"
21
21
  @close="handleCloseDialog"
22
22
  >
23
- <template #translations>
24
- <DynamicTranslationEditor
25
- v-model="translationValues"
23
+ <template #i18ns>
24
+ <DynamicI18nEditor
25
+ v-model="i18nValues"
26
26
  :source="formData.name"
27
27
  :maxlength="50"
28
28
  />
@@ -50,17 +50,17 @@ import { loadEnabledBaseLanguages } from "@liujitcn/kratos-admin-system/api/syst
50
50
  import type { BaseDict, BaseDictForm, PageBaseDictRequest } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_dict";
51
51
  import router, { navigateTo } from "@liujitcn/kratos-admin-core/navigation";
52
52
  import { Status } from "@liujitcn/kratos-admin-system/rpc/common/v1/enum";
53
- import { TranslationTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
53
+ import { I18nTargetType } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
54
54
  import { buildPageRequest, normalizeSelectedIds } from "@liujitcn/kratos-admin-core/table";
55
55
  import { t } from "@liujitcn/kratos-admin-core";
56
- import DynamicTranslationEditor from "@liujitcn/kratos-admin-system/components/DynamicTranslationEditor.vue";
57
- import DynamicTranslationCell from "@liujitcn/kratos-admin-system/components/DynamicTranslationCell.vue";
56
+ import DynamicI18nEditor from "@liujitcn/kratos-admin-system/components/DynamicI18nEditor.vue";
57
+ import DynamicI18nCell from "@liujitcn/kratos-admin-system/components/DynamicI18nCell.vue";
58
58
  import {
59
- normalizeDynamicTranslations,
60
- serializeDynamicTranslations,
61
- type DynamicTranslationRecord,
62
- type DynamicTranslationValue
63
- } from "@liujitcn/kratos-admin-system/components/dynamicTranslation";
59
+ normalizeDynamicI18ns,
60
+ serializeDynamicI18ns,
61
+ type DynamicI18nRecord,
62
+ type DynamicI18nValue
63
+ } from "@liujitcn/kratos-admin-system/components/dynamicI18n";
64
64
 
65
65
  defineOptions({
66
66
  name: "BaseDict",
@@ -70,7 +70,7 @@ defineOptions({
70
70
  const { BUTTONS } = useAuthButtons();
71
71
  const proTable = ref<ProTableInstance>();
72
72
  const formDialogRef = ref<InstanceType<typeof FormDialog>>();
73
- const translationValues = ref<DynamicTranslationValue[]>(normalizeDynamicTranslations(undefined, "name"));
73
+ const i18nValues = ref<DynamicI18nValue[]>(normalizeDynamicI18ns(undefined, "name"));
74
74
  const dialog = reactive({
75
75
  editing: false,
76
76
  visible: false
@@ -84,7 +84,7 @@ const formData = reactive<BaseDictForm>({
84
84
  /** 字典名称 */
85
85
  name: "",
86
86
  /** 非主语言翻译 */
87
- translations: [],
87
+ i18ns: [],
88
88
  /** 状态 */
89
89
  status: Status.STATUS_ENABLE
90
90
  });
@@ -134,18 +134,18 @@ const formFields = computed<ProFormField[]>(() => [
134
134
  component: "input",
135
135
  props: { placeholder: t("system.base.dict.placeholder.code") }
136
136
  },
137
- { prop: "translations", label: t("system.base.translation.field.translations"), component: "slot", slotName: "translations" },
137
+ { prop: "i18ns", label: t("system.base.i18n.field.i18ns"), component: "slot", slotName: "i18ns" },
138
138
  { prop: "status", label: t("common.field.status"), component: "radio-group", options: statusOptions.value }
139
139
  ]);
140
140
 
141
141
  /** 渲染字典名称翻译预览,并复用当前页面的编辑弹窗。 */
142
142
  function renderDictNameCell(scope: RenderScope<BaseDict>) {
143
143
  const row = scope.row;
144
- return h(DynamicTranslationCell, {
144
+ return h(DynamicI18nCell, {
145
145
  source: row.name,
146
- targetType: TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_DICT,
146
+ targetType: I18nTargetType.I18N_TARGET_TYPE_BASE_DICT_NAME,
147
147
  targetId: row.id,
148
- translations: row.translations
148
+ i18ns: row.i18ns
149
149
  });
150
150
  }
151
151
 
@@ -261,7 +261,7 @@ async function handleOpenDialog(dictId?: number) {
261
261
 
262
262
  const data = await defBaseDictService.GetBaseDict({ id: dictId });
263
263
  Object.assign(formData, data);
264
- translationValues.value = normalizeDynamicTranslations(data.translations as DynamicTranslationRecord[], "name");
264
+ i18nValues.value = normalizeDynamicI18ns(data.i18ns as DynamicI18nRecord[], "name");
265
265
  }
266
266
 
267
267
  /**
@@ -281,9 +281,9 @@ function resetForm() {
281
281
  formData.id = 0;
282
282
  formData.code = "";
283
283
  formData.name = "";
284
- formData.translations = [];
284
+ formData.i18ns = [];
285
285
  formData.status = Status.STATUS_ENABLE;
286
- translationValues.value = normalizeDynamicTranslations(undefined, "name");
286
+ i18nValues.value = normalizeDynamicI18ns(undefined, "name");
287
287
  }
288
288
 
289
289
  /**
@@ -294,9 +294,9 @@ function handleSubmit() {
294
294
  if (!isValid) return;
295
295
 
296
296
  const submitData = JSON.parse(JSON.stringify(formData)) as BaseDictForm;
297
- submitData.translations = serializeDynamicTranslations(
298
- translationValues.value,
299
- TranslationTargetType.TRANSLATION_TARGET_TYPE_BASE_DICT,
297
+ submitData.i18ns = serializeDynamicI18ns(
298
+ i18nValues.value,
299
+ I18nTargetType.I18N_TARGET_TYPE_BASE_DICT_NAME,
300
300
  submitData.id
301
301
  );
302
302
  const request = submitData.id