@liujitcn/kratos-admin-system 0.0.26 → 0.0.28

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 (71) hide show
  1. package/dist/package/declarations/src/api/system/base_i18n.d.ts +10 -0
  2. package/dist/package/declarations/src/api/system/code_gen_i18n.d.ts +1 -1
  3. package/dist/package/declarations/src/api/system/runtime_log.d.ts +13 -0
  4. package/dist/package/declarations/src/api/system/runtime_log_sse.d.ts +8 -0
  5. package/dist/package/declarations/src/components/DynamicTranslationCell.vue.d.ts +3 -3
  6. package/dist/package/declarations/src/components/dynamicTranslation.d.ts +1 -1
  7. package/dist/package/declarations/src/locales/generated.d.ts +1057 -0
  8. package/dist/package/declarations/src/rpc/common/v1/enum.d.ts +15 -6
  9. package/dist/package/declarations/src/rpc/system/admin/v1/base_api.d.ts +10 -1
  10. package/dist/package/declarations/src/rpc/system/admin/v1/base_config.d.ts +4 -4
  11. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +5 -5
  12. package/dist/package/declarations/src/rpc/system/admin/v1/{base_translation.d.ts → base_i18n.d.ts} +3 -3
  13. package/dist/package/declarations/src/rpc/system/admin/v1/base_menu.d.ts +3 -3
  14. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_column.d.ts +1 -1
  15. package/dist/package/declarations/src/rpc/system/admin/v1/code_gen_table.d.ts +1 -1
  16. package/dist/package/declarations/src/rpc/system/admin/v1/ops_monitoring.d.ts +4 -0
  17. package/dist/package/declarations/src/rpc/system/admin/v1/project_document.d.ts +6 -0
  18. package/dist/package/declarations/src/rpc/system/admin/v1/runtime_log.d.ts +96 -0
  19. package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue.d.ts +1 -1
  20. package/dist/package/declarations/src/views/tool/runtime-log/index.vue.d.ts +3 -0
  21. package/dist/package/src/api/base/sse.ts +3 -2
  22. package/dist/package/src/api/system/{base_translation.ts → base_i18n.ts} +5 -5
  23. package/dist/package/src/api/system/code_gen_i18n.ts +1 -1
  24. package/dist/package/src/api/system/runtime_log.ts +80 -0
  25. package/dist/package/src/api/system/runtime_log_sse.ts +40 -0
  26. package/dist/package/src/components/Ai.vue +9 -2
  27. package/dist/package/src/components/DynamicTranslationCell.vue +9 -9
  28. package/dist/package/src/components/DynamicTranslationEditor.vue +3 -3
  29. package/dist/package/src/components/dynamicTranslation.ts +1 -1
  30. package/dist/package/src/locales/en-US.json +33 -2
  31. package/dist/package/src/locales/generated.ts +2 -0
  32. package/dist/package/src/locales/ja-JP.json +964 -0
  33. package/dist/package/src/locales/zh-CN.json +33 -2
  34. package/dist/package/src/locales/zh-TW.json +33 -2
  35. package/dist/package/src/rpc/common/v1/enum.ts +16 -6
  36. package/dist/package/src/rpc/system/admin/v1/base_api.ts +11 -1
  37. package/dist/package/src/rpc/system/admin/v1/base_config.ts +4 -4
  38. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +5 -5
  39. package/dist/package/src/rpc/system/admin/v1/{base_translation.ts → base_i18n.ts} +4 -4
  40. package/dist/package/src/rpc/system/admin/v1/base_menu.ts +3 -3
  41. package/dist/package/src/rpc/system/admin/v1/code_gen_column.ts +1 -1
  42. package/dist/package/src/rpc/system/admin/v1/code_gen_table.ts +1 -1
  43. package/dist/package/src/rpc/system/admin/v1/ops_monitoring.ts +4 -0
  44. package/dist/package/src/rpc/system/admin/v1/project_document.ts +6 -0
  45. package/dist/package/src/rpc/system/admin/v1/runtime_log.ts +113 -0
  46. package/dist/package/src/views/ai/chat/message.ts +12 -2
  47. package/dist/package/src/views/base/api/index.vue +20 -20
  48. package/dist/package/src/views/base/config/index.vue +11 -11
  49. package/dist/package/src/views/base/dept/index.vue +8 -8
  50. package/dist/package/src/views/base/dict/index.vue +9 -9
  51. package/dist/package/src/views/base/dict/item.vue +9 -9
  52. package/dist/package/src/views/base/job/index.vue +11 -11
  53. package/dist/package/src/views/base/language/index.vue +9 -9
  54. package/dist/package/src/views/base/menu/index.vue +14 -9
  55. package/dist/package/src/views/base/post/index.vue +8 -8
  56. package/dist/package/src/views/base/role/index.vue +8 -8
  57. package/dist/package/src/views/base/tenant/index.vue +8 -8
  58. package/dist/package/src/views/base/user/index.vue +8 -8
  59. package/dist/package/src/views/tool/api-doc/index.vue +14 -6
  60. package/dist/package/src/views/tool/code-gen/code-preview/index.vue +17 -0
  61. package/dist/package/src/views/tool/code-gen/columns/index.vue +8 -53
  62. package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +97 -15
  63. package/dist/package/src/views/tool/code-gen/components/CodeGenProgressDialog.vue +3 -12
  64. package/dist/package/src/views/tool/code-gen/preview/index.vue +3 -6
  65. package/dist/package/src/views/tool/code-gen/proto/index.vue +7 -8
  66. package/dist/package/src/views/tool/code-gen/table/index.vue +34 -2
  67. package/dist/package/src/views/tool/ops-monitoring/index.vue +153 -49
  68. package/dist/package/src/views/tool/project-doc/index.vue +9 -4
  69. package/dist/package/src/views/tool/runtime-log/index.vue +883 -0
  70. package/package.json +2 -2
  71. package/dist/package/declarations/src/api/system/base_translation.d.ts +0 -10
@@ -166,7 +166,7 @@ const formData = reactive<BaseUserFormState>({
166
166
  /** 头像 */
167
167
  avatar: "",
168
168
  /** 用户状态 */
169
- status: Status.ENABLE,
169
+ status: Status.STATUS_ENABLE,
170
170
  /** 备注名 */
171
171
  remark: ""
172
172
  });
@@ -273,8 +273,8 @@ const baseRoleOptions = ref<SelectOptionResponse_Option[]>([]);
273
273
  const basePostOptions = ref<SelectOptionResponse_Option[]>([]);
274
274
  const tenantOptions = ref<SelectOptionResponse_Option[]>([]);
275
275
  const statusOptions = computed<ProFormOption[]>(() => [
276
- { label: t("common.status.enabled"), value: Status.ENABLE },
277
- { label: t("common.status.disabled"), value: Status.DISABLE }
276
+ { label: t("common.status.enabled"), value: Status.STATUS_ENABLE },
277
+ { label: t("common.status.disabled"), value: Status.STATUS_DISABLE }
278
278
  ]);
279
279
  const resetPwdFields = computed<ProFormField[]>(() => [
280
280
  {
@@ -442,8 +442,8 @@ const columns = computed<ColumnProps[]>(() => [
442
442
  search: { el: "select" },
443
443
  cellType: "status",
444
444
  statusProps: {
445
- activeValue: Status.ENABLE,
446
- inactiveValue: Status.DISABLE,
445
+ activeValue: Status.STATUS_ENABLE,
446
+ inactiveValue: Status.STATUS_DISABLE,
447
447
  activeText: t("common.status.enabled"),
448
448
  inactiveText: t("common.status.disabled"),
449
449
  disabled: scope => isProtectedManagementUser(scope.row as BaseUser) || !BUTTONS.value["base:user:status"],
@@ -690,7 +690,7 @@ function resetForm() {
690
690
  formData.pwd = "";
691
691
  formData.gender = 3;
692
692
  formData.avatar = "";
693
- formData.status = Status.ENABLE;
693
+ formData.status = Status.STATUS_ENABLE;
694
694
  formData.remark = "";
695
695
  baseRoleOptions.value = [];
696
696
  basePostOptions.value = [];
@@ -768,8 +768,8 @@ async function handleBeforeSetStatus(row: BaseUser) {
768
768
  return false;
769
769
  }
770
770
 
771
- const nextStatus = row.status === Status.ENABLE ? Status.DISABLE : Status.ENABLE;
772
- const action = t(nextStatus === Status.ENABLE ? "common.status.enabled" : "common.status.disabled");
771
+ const nextStatus = row.status === Status.STATUS_ENABLE ? Status.STATUS_DISABLE : Status.STATUS_ENABLE;
772
+ const action = t(nextStatus === Status.STATUS_ENABLE ? "common.status.enabled" : "common.status.disabled");
773
773
  const userName = row.nick_name || row.user_name || `ID:${row.id}`;
774
774
  try {
775
775
  await ElMessageBox.confirm(t("system.base.user.message.confirm_status", { action, name: userName }), t("common.title.notice"), {
@@ -27,15 +27,16 @@
27
27
  <script setup lang="ts">
28
28
  import SwaggerUIBundle from "swagger-ui-dist/swagger-ui-bundle.js";
29
29
  import "swagger-ui-dist/swagger-ui.css";
30
+ import { DEFAULT_LOCALE, t, useLocaleStore } from "@liujitcn/kratos-admin-core";
30
31
  import { getLocaleRequestHeaders, getRequestAccessToken } from "@liujitcn/kratos-admin-core/request";
31
32
  import { defBaseApiService } from "@liujitcn/kratos-admin-system/api/system/base_api";
32
33
  import type { OpenApiServiceOption } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_api";
33
- import { t } from "@liujitcn/kratos-admin-core";
34
34
 
35
35
  const swaggerRootRef = ref<HTMLElement>();
36
36
  const loading = ref(true);
37
37
  const documents = ref<OpenApiServiceOption[]>([]);
38
38
  const selectedDocumentKey = ref("");
39
+ const { locale } = useLocaleStore();
39
40
 
40
41
  /** 初始化携带当前登录令牌的 Swagger UI。 */
41
42
  function initializeSwaggerUI(documentKey: string) {
@@ -44,9 +45,10 @@ function initializeSwaggerUI(documentKey: string) {
44
45
 
45
46
  loading.value = true;
46
47
  swaggerRoot.replaceChildren();
48
+ const localePath = locale.value === DEFAULT_LOCALE ? "" : `/${encodeURIComponent(locale.value)}`;
47
49
  SwaggerUIBundle({
48
50
  domNode: swaggerRoot,
49
- url: `/api/docs/openapi/${encodeURIComponent(documentKey)}`,
51
+ url: `/api/docs/openapi/${encodeURIComponent(documentKey)}${localePath}`,
50
52
  deepLinking: true,
51
53
  displayOperationId: true,
52
54
  displayRequestDuration: true,
@@ -84,16 +86,18 @@ function handleDocumentChange(documentKey: string) {
84
86
 
85
87
  /** 加载可访问的 OpenAPI 文档并初始化默认文档。 */
86
88
  async function loadOpenAPIDocuments() {
89
+ loading.value = true;
87
90
  try {
88
91
  const response = await defBaseApiService.OptionOpenApiService({});
89
92
  documents.value = response.list;
90
- const defaultDocument = response.list[0];
91
- if (!defaultDocument) {
93
+ const selectedDocument = response.list.find(document => document.key === selectedDocumentKey.value) ?? response.list[0];
94
+ if (!selectedDocument) {
95
+ selectedDocumentKey.value = "";
92
96
  loading.value = false;
93
97
  return;
94
98
  }
95
- selectedDocumentKey.value = defaultDocument.key;
96
- initializeSwaggerUI(defaultDocument.key);
99
+ selectedDocumentKey.value = selectedDocument.key;
100
+ initializeSwaggerUI(selectedDocument.key);
97
101
  } catch {
98
102
  loading.value = false;
99
103
  }
@@ -103,6 +107,10 @@ onMounted(() => {
103
107
  loadOpenAPIDocuments();
104
108
  });
105
109
 
110
+ watch(locale, () => {
111
+ loadOpenAPIDocuments();
112
+ });
113
+
106
114
  onBeforeUnmount(() => {
107
115
  swaggerRootRef.value?.replaceChildren();
108
116
  });
@@ -134,6 +134,23 @@ async function handleGenerate() {
134
134
  ElMessage.warning(t("system.code.gen.table.message.disabled", { name: table.value.name }));
135
135
  return;
136
136
  }
137
+ if (missingTranslations.value.length) {
138
+ try {
139
+ await ElMessageBox.alert(
140
+ t("system.code.gen.preview.message.missing_translations", {
141
+ items: missingTranslations.value.join(t("system.code.gen.preview.value.list_separator"))
142
+ }),
143
+ t("common.title.warning"),
144
+ {
145
+ confirmButtonText: t("common.action.close"),
146
+ type: "warning"
147
+ }
148
+ );
149
+ } catch {
150
+ // 关闭提示框与点击关闭按钮语义一致。
151
+ }
152
+ return;
153
+ }
137
154
  try {
138
155
  await ElMessageBox.confirm(
139
156
  t("system.code.gen.table.dialog.generate_one", { name: table.value.name }),
@@ -272,7 +272,7 @@
272
272
  <ProDialog
273
273
  v-model="optionDialog.visible"
274
274
  :title="optionDialogTitle"
275
- width="min(560px, calc(100vw - 32px))"
275
+ width="560px"
276
276
  destroy-on-close
277
277
  :show-close="false"
278
278
  :close-on-click-modal="false"
@@ -1287,7 +1287,6 @@ onBeforeUnmount(() => {
1287
1287
  border-radius: var(--admin-page-radius);
1288
1288
  box-shadow: var(--admin-page-shadow);
1289
1289
  }
1290
-
1291
1290
  :deep(.code-gen-toolbar) {
1292
1291
  display: flex;
1293
1292
  flex-wrap: wrap;
@@ -1296,13 +1295,11 @@ onBeforeUnmount(() => {
1296
1295
  justify-content: flex-end;
1297
1296
  margin-bottom: 14px;
1298
1297
  }
1299
-
1300
1298
  .code-gen-column-pane {
1301
1299
  display: flex;
1302
1300
  flex-direction: column;
1303
1301
  gap: 14px;
1304
1302
  }
1305
-
1306
1303
  .code-gen-column-toolbar {
1307
1304
  justify-content: space-between;
1308
1305
  padding: 12px 14px;
@@ -1310,7 +1307,6 @@ onBeforeUnmount(() => {
1310
1307
  border: 1px solid var(--admin-page-card-border-soft);
1311
1308
  border-radius: var(--admin-page-radius);
1312
1309
  }
1313
-
1314
1310
  .code-gen-column-toolbar__meta {
1315
1311
  display: flex;
1316
1312
  flex-wrap: wrap;
@@ -1319,54 +1315,45 @@ onBeforeUnmount(() => {
1319
1315
  min-width: 0;
1320
1316
  color: var(--admin-page-text-secondary);
1321
1317
  }
1322
-
1323
1318
  .code-gen-column-toolbar__meta strong {
1324
1319
  font-size: 14px;
1325
1320
  color: var(--admin-page-text-primary);
1326
1321
  }
1327
-
1328
1322
  .code-gen-column-toolbar__meta span {
1329
1323
  padding: 3px 8px;
1330
1324
  overflow: hidden;
1325
+ text-overflow: ellipsis;
1331
1326
  font-size: 12px;
1332
1327
  line-height: 18px;
1333
- text-overflow: ellipsis;
1334
1328
  white-space: nowrap;
1335
1329
  background: var(--admin-page-card-bg);
1336
1330
  border: 1px solid var(--admin-page-card-border-soft);
1337
1331
  border-radius: 999px;
1338
1332
  }
1339
-
1340
1333
  .code-gen-column-toolbar__table-name {
1341
1334
  max-width: 220px;
1342
1335
  }
1343
-
1344
1336
  .code-gen-column-toolbar__table-comment {
1345
1337
  max-width: 280px;
1346
1338
  }
1347
-
1348
1339
  .code-gen-column-toolbar__actions {
1349
1340
  display: flex;
1350
- gap: 8px;
1351
1341
  flex-shrink: 0;
1342
+ gap: 8px;
1352
1343
  margin-left: auto;
1353
1344
  }
1354
-
1355
1345
  .code-gen-column-table {
1356
1346
  overflow: hidden;
1357
1347
  border-radius: var(--admin-page-radius);
1358
1348
  }
1359
-
1360
1349
  :deep(.code-gen-column-table .el-table__header th) {
1361
1350
  color: var(--admin-page-text-secondary);
1362
1351
  background: var(--admin-page-card-bg-soft);
1363
1352
  }
1364
-
1365
1353
  :deep(.code-gen-column-table .el-table__cell) {
1366
1354
  padding: 8px 0;
1367
1355
  vertical-align: middle;
1368
1356
  }
1369
-
1370
1357
  .code-gen-field-cell,
1371
1358
  .code-gen-field-trigger,
1372
1359
  .code-gen-field-order {
@@ -1375,48 +1362,39 @@ onBeforeUnmount(() => {
1375
1362
  align-items: center;
1376
1363
  min-width: 0;
1377
1364
  }
1378
-
1379
1365
  .code-gen-field-cell {
1380
1366
  justify-content: space-between;
1381
1367
  }
1382
-
1383
1368
  .code-gen-field-trigger {
1384
1369
  flex: 1;
1385
1370
  min-height: 28px;
1386
1371
  cursor: help;
1387
1372
  }
1388
-
1389
1373
  .code-gen-field-order {
1390
- gap: 4px;
1391
1374
  flex-shrink: 0;
1375
+ gap: 4px;
1392
1376
  }
1393
-
1394
1377
  .code-gen-field-order__index {
1395
1378
  min-width: 18px;
1396
1379
  font-size: 12px;
1397
1380
  color: var(--admin-page-text-secondary);
1398
1381
  text-align: right;
1399
1382
  }
1400
-
1401
1383
  .code-gen-field-order__drag {
1402
1384
  width: 24px;
1403
1385
  height: 24px;
1404
1386
  padding: 0;
1405
1387
  cursor: grab;
1406
1388
  }
1407
-
1408
1389
  .code-gen-field-order__drag:active {
1409
1390
  cursor: grabbing;
1410
1391
  }
1411
-
1412
1392
  :deep(.code-gen-column-sortable-ghost > td) {
1413
1393
  background: var(--admin-page-card-bg-soft);
1414
1394
  }
1415
-
1416
1395
  :deep(.code-gen-column-sortable-chosen > td) {
1417
1396
  background: var(--admin-page-card-bg-soft);
1418
1397
  }
1419
-
1420
1398
  .code-gen-config-cell,
1421
1399
  .code-gen-comment-editor,
1422
1400
  .code-gen-static-options__header,
@@ -1426,54 +1404,45 @@ onBeforeUnmount(() => {
1426
1404
  gap: 8px;
1427
1405
  align-items: center;
1428
1406
  }
1429
-
1430
1407
  .code-gen-comment-editor {
1431
1408
  flex-wrap: nowrap;
1432
1409
  }
1433
-
1434
1410
  .code-gen-comment-editor .el-input {
1435
1411
  min-width: 0;
1436
1412
  }
1437
-
1438
1413
  .code-gen-field-trigger__name {
1439
1414
  flex-shrink: 0;
1440
1415
  max-width: 135px;
1441
1416
  overflow: hidden;
1417
+ text-overflow: ellipsis;
1442
1418
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
1443
1419
  font-size: 13px;
1444
1420
  font-weight: 700;
1445
1421
  color: var(--admin-page-text-primary);
1446
- text-overflow: ellipsis;
1447
1422
  white-space: nowrap;
1448
1423
  }
1449
-
1450
1424
  .code-gen-field-popover {
1451
1425
  display: grid;
1452
1426
  gap: 12px;
1453
1427
  }
1454
-
1455
1428
  .code-gen-field-popover__header {
1456
1429
  display: grid;
1457
1430
  gap: 3px;
1458
1431
  }
1459
-
1460
1432
  .code-gen-field-popover__header strong,
1461
1433
  .code-gen-field-popover__types b {
1462
1434
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
1463
1435
  color: var(--admin-page-text-primary);
1464
1436
  }
1465
-
1466
1437
  .code-gen-field-popover__header span {
1467
1438
  font-size: 12px;
1468
1439
  color: var(--admin-page-text-secondary);
1469
1440
  }
1470
-
1471
1441
  .code-gen-field-popover__types {
1472
1442
  display: grid;
1473
1443
  grid-template-columns: repeat(2, minmax(0, 1fr));
1474
1444
  gap: 7px 12px;
1475
1445
  }
1476
-
1477
1446
  .code-gen-field-popover__types div {
1478
1447
  display: grid;
1479
1448
  grid-template-columns: 52px minmax(0, 1fr);
@@ -1482,40 +1451,33 @@ onBeforeUnmount(() => {
1482
1451
  min-width: 0;
1483
1452
  font-size: 12px;
1484
1453
  }
1485
-
1486
1454
  .code-gen-field-popover__types span {
1487
1455
  color: var(--admin-page-text-secondary);
1488
1456
  }
1489
-
1490
1457
  .code-gen-field-popover__types b {
1491
1458
  overflow: hidden;
1492
- font-size: 12px;
1493
1459
  text-overflow: ellipsis;
1460
+ font-size: 12px;
1494
1461
  white-space: nowrap;
1495
1462
  }
1496
-
1497
1463
  .code-gen-field-popover__flags {
1498
1464
  display: flex;
1465
+ flex-wrap: wrap;
1499
1466
  gap: 6px;
1500
1467
  align-items: center;
1501
- flex-wrap: wrap;
1502
1468
  }
1503
-
1504
1469
  .code-gen-config-cell .el-select {
1505
1470
  width: 124px;
1506
1471
  }
1507
-
1508
1472
  .code-gen-config-cell .el-checkbox {
1509
1473
  margin-right: 0;
1510
1474
  }
1511
-
1512
1475
  .code-gen-option-dialog,
1513
1476
  .code-gen-static-options,
1514
1477
  .code-gen-static-options__list {
1515
1478
  display: grid;
1516
1479
  gap: 10px;
1517
1480
  }
1518
-
1519
1481
  .code-gen-config-dialog__header {
1520
1482
  display: flex;
1521
1483
  gap: 12px;
@@ -1523,41 +1485,34 @@ onBeforeUnmount(() => {
1523
1485
  justify-content: space-between;
1524
1486
  width: 100%;
1525
1487
  }
1526
-
1527
1488
  .code-gen-popover-form__row {
1528
1489
  display: grid;
1529
1490
  grid-template-columns: 92px minmax(0, 1fr);
1530
1491
  gap: 10px;
1531
1492
  align-items: center;
1532
1493
  }
1533
-
1534
1494
  .code-gen-popover-form__label {
1535
1495
  font-size: 12px;
1536
1496
  color: var(--admin-page-text-secondary);
1537
1497
  }
1538
-
1539
1498
  .code-gen-static-options {
1540
1499
  padding-top: 2px;
1541
1500
  }
1542
-
1543
1501
  .code-gen-static-options__header {
1544
1502
  justify-content: space-between;
1545
1503
  }
1546
-
1547
1504
  .code-gen-static-options__item {
1548
1505
  flex-wrap: nowrap;
1549
1506
  }
1550
-
1551
1507
  .code-gen-static-options__item .el-input {
1552
1508
  min-width: 0;
1553
1509
  }
1554
1510
 
1555
1511
  @media (width <= 900px) {
1556
1512
  .code-gen-column-toolbar {
1557
- align-items: flex-start;
1558
1513
  flex-direction: column;
1514
+ align-items: flex-start;
1559
1515
  }
1560
-
1561
1516
  .code-gen-column-toolbar__actions {
1562
1517
  margin-left: 0;
1563
1518
  }
@@ -17,28 +17,59 @@
17
17
  {{ t("system.code.gen.i18n.status.missing") }}
18
18
  </el-tag>
19
19
  </div>
20
- <el-input
21
- :model-value="localeValue(locale.value).comment"
22
- :placeholder="t('system.code.gen.i18n.placeholder.comment', { source: sourceComment || '-' })"
23
- maxlength="255"
24
- @update:model-value="value => updateLocale(locale.value, 'comment', value)"
25
- />
26
- <el-input
27
- v-if="showLeftTreeComment"
28
- :model-value="localeValue(locale.value).left_tree_comment"
29
- :placeholder="t('system.code.gen.i18n.placeholder.left_tree_comment', { source: sourceLeftTreeComment || '-' })"
30
- maxlength="255"
31
- @update:model-value="value => updateLocale(locale.value, 'left_tree_comment', value)"
32
- />
20
+ <div class="code-gen-locale-editor__control">
21
+ <el-input
22
+ :model-value="localeValue(locale.value).comment"
23
+ :placeholder="t('system.code.gen.i18n.placeholder.comment', { source: sourceComment || '-' })"
24
+ :disabled="isTranslating(locale.value, 'comment')"
25
+ maxlength="255"
26
+ @update:model-value="value => updateLocale(locale.value, 'comment', value)"
27
+ />
28
+ <el-button
29
+ class="code-gen-locale-editor__translate"
30
+ link
31
+ type="primary"
32
+ size="small"
33
+ :icon="Promotion"
34
+ :loading="isTranslating(locale.value, 'comment')"
35
+ :disabled="!canTranslate(locale.value, 'comment', sourceComment)"
36
+ @click="handleTranslate(locale.value, 'comment', sourceComment, locale.label)"
37
+ >
38
+ {{ t("system.base.translation.action.translate") }}
39
+ </el-button>
40
+ </div>
41
+ <div v-if="showLeftTreeComment" class="code-gen-locale-editor__control">
42
+ <el-input
43
+ :model-value="localeValue(locale.value).left_tree_comment"
44
+ :placeholder="t('system.code.gen.i18n.placeholder.left_tree_comment', { source: sourceLeftTreeComment || '-' })"
45
+ :disabled="isTranslating(locale.value, 'left_tree_comment')"
46
+ maxlength="255"
47
+ @update:model-value="value => updateLocale(locale.value, 'left_tree_comment', value)"
48
+ />
49
+ <el-button
50
+ class="code-gen-locale-editor__translate"
51
+ link
52
+ type="primary"
53
+ size="small"
54
+ :icon="Promotion"
55
+ :loading="isTranslating(locale.value, 'left_tree_comment')"
56
+ :disabled="!canTranslate(locale.value, 'left_tree_comment', sourceLeftTreeComment)"
57
+ @click="handleTranslate(locale.value, 'left_tree_comment', sourceLeftTreeComment, locale.label)"
58
+ >
59
+ {{ t("system.base.translation.action.translate") }}
60
+ </el-button>
61
+ </div>
33
62
  </div>
34
63
  </div>
35
64
  </template>
36
65
 
37
66
  <script setup lang="ts">
38
- import { computed } from "vue";
67
+ import { computed, ref } from "vue";
68
+ import { Promotion } from "@element-plus/icons-vue";
39
69
  import { t } from "@liujitcn/kratos-admin-core";
70
+ import { defBaseI18nService } from "@liujitcn/kratos-admin-system/api/system/base_i18n";
40
71
  import { loadEnabledBaseLanguages, useEnabledBaseLanguages } from "@liujitcn/kratos-admin-system/api/system/base_language";
41
- import type { CodeGenLocaleConfig } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_translation";
72
+ import type { CodeGenLocaleConfig } from "@liujitcn/kratos-admin-system/rpc/system/admin/v1/base_i18n";
42
73
 
43
74
  /** 代码生成多语言编辑器属性。 */
44
75
  interface CodeGenLocaleEditorProps {
@@ -63,6 +94,7 @@ const emit = defineEmits<{
63
94
  }>();
64
95
 
65
96
  const { languages } = useEnabledBaseLanguages();
97
+ const translatingField = ref("");
66
98
  void loadEnabledBaseLanguages();
67
99
 
68
100
  const editableLocales = computed(() =>
@@ -92,6 +124,33 @@ function updateLocale(locale: string, field: keyof CodeGenLocaleConfig, value: s
92
124
  next.set(locale, { ...localeValue(locale), [field]: value });
93
125
  emit("update:modelValue", next);
94
126
  }
127
+
128
+ /** 判断指定语言字段是否正在翻译。 */
129
+ function isTranslating(locale: string, field: keyof CodeGenLocaleConfig) {
130
+ return translatingField.value === `${locale}:${field}`;
131
+ }
132
+
133
+ /** 判断指定语言字段当前是否允许自动翻译。 */
134
+ function canTranslate(locale: string, field: keyof CodeGenLocaleConfig, source: string) {
135
+ return Boolean(source) && !localeValue(locale)[field] && !translatingField.value;
136
+ }
137
+
138
+ /** 翻译指定语言的单个代码生成描述。 */
139
+ async function handleTranslate(locale: string, field: keyof CodeGenLocaleConfig, source: string, language: string) {
140
+ if (!canTranslate(locale, field, source)) return;
141
+ translatingField.value = `${locale}:${field}`;
142
+ try {
143
+ const response = await defBaseI18nService.DraftBaseTranslation({ source, locale });
144
+ const translation = response.translations.find(item => item.locale === locale)?.translation;
145
+ if (!translation) throw new Error("translation not found");
146
+ updateLocale(locale, field, translation);
147
+ ElMessage.success(t("system.base.translation.message.translate_success", { language }));
148
+ } catch {
149
+ ElMessage.error(t("system.base.translation.message.translate_failed", { language }));
150
+ } finally {
151
+ translatingField.value = "";
152
+ }
153
+ }
95
154
  </script>
96
155
 
97
156
  <style scoped lang="scss">
@@ -115,4 +174,27 @@ function updateLocale(locale: string, field: keyof CodeGenLocaleConfig, value: s
115
174
  font-weight: 600;
116
175
  color: var(--el-text-color-primary);
117
176
  }
177
+
178
+ .code-gen-locale-editor__control {
179
+ position: relative;
180
+ display: flex;
181
+ align-items: center;
182
+ width: 100%;
183
+ }
184
+
185
+ .code-gen-locale-editor__control :deep(.el-input) {
186
+ flex: 1;
187
+ }
188
+
189
+ .code-gen-locale-editor__control :deep(.el-input__suffix) {
190
+ padding-right: 78px;
191
+ }
192
+
193
+ .code-gen-locale-editor__translate {
194
+ position: absolute;
195
+ z-index: 1;
196
+ top: 50%;
197
+ right: 8px;
198
+ transform: translateY(-50%);
199
+ }
118
200
  </style>
@@ -2,7 +2,7 @@
2
2
  <ProDialog
3
3
  :model-value="modelValue"
4
4
  :title="t('system.code.gen.progress.title')"
5
- width="min(1080px, 94vw)"
5
+ width="1080px"
6
6
  top="4vh"
7
7
  :close-on-click-modal="false"
8
8
  :show-footer="false"
@@ -287,7 +287,6 @@ onBeforeUnmount(stopTracking);
287
287
  .progress-dialog {
288
288
  min-height: 220px;
289
289
  }
290
-
291
290
  .task-heading,
292
291
  .table-heading,
293
292
  .task-meta {
@@ -295,40 +294,33 @@ onBeforeUnmount(stopTracking);
295
294
  gap: 12px;
296
295
  align-items: center;
297
296
  }
298
-
299
297
  .task-heading {
300
298
  justify-content: space-between;
301
299
  margin-bottom: 14px;
302
300
  }
303
-
304
301
  .task-heading > div {
305
302
  display: flex;
306
303
  gap: 12px;
307
304
  align-items: baseline;
308
305
  }
309
-
310
306
  .task-meta {
311
307
  flex-wrap: wrap;
312
308
  justify-content: space-between;
313
309
  margin: 10px 0 18px;
314
- color: var(--el-text-color-secondary);
315
310
  font-size: 13px;
311
+ color: var(--el-text-color-secondary);
316
312
  }
317
-
318
313
  .table-progress-list {
319
314
  max-height: 54vh;
320
315
  overflow: auto;
321
316
  }
322
-
323
317
  .table-heading {
324
318
  width: 100%;
325
319
  padding-right: 16px;
326
320
  }
327
-
328
321
  .table-heading strong {
329
322
  margin-right: auto;
330
323
  }
331
-
332
324
  .table-message {
333
325
  display: flex;
334
326
  gap: 6px;
@@ -336,11 +328,10 @@ onBeforeUnmount(stopTracking);
336
328
  margin: 0 0 10px;
337
329
  color: var(--el-text-color-secondary);
338
330
  }
339
-
340
331
  .table-message span {
341
332
  min-width: 0;
333
+ overflow-wrap: break-word;
342
334
  white-space: pre-wrap;
343
- word-break: break-word;
344
335
  }
345
336
  </style>
346
337
 
@@ -54,7 +54,7 @@
54
54
  v-model="dialog.visible"
55
55
  ref="formDialogRef"
56
56
  :title="dialogTitle"
57
- width="min(920px, calc(100vw - 32px))"
57
+ width="920px"
58
58
  top="4vh"
59
59
  :model="previewFormModel"
60
60
  :fields="formFields"
@@ -837,32 +837,29 @@ onMounted(() => {
837
837
  display: flex;
838
838
  flex-direction: column;
839
839
  width: 100%;
840
- height: 100%;
841
840
  min-width: 0;
841
+ height: 100%;
842
842
  min-height: 0;
843
843
  overflow: hidden;
844
844
  }
845
-
846
845
  .code-gen-page-preview__table,
847
846
  .code-gen-left-tree-preview {
848
847
  min-width: 0;
849
848
  min-height: 0;
850
849
  overflow: hidden;
851
850
  }
852
-
853
851
  .code-gen-left-tree-preview__table {
854
852
  min-width: 0;
855
853
  min-height: 0;
856
854
  }
857
-
858
855
  :deep(.code-gen-page-preview-table) {
859
856
  --el-table-header-bg-color: var(--el-fill-color-light);
860
857
  }
861
858
 
862
859
  @media (width <= 768px) {
863
860
  :deep(.el-dialog .el-col-12) {
864
- max-width: 100%;
865
861
  flex: 0 0 100%;
862
+ max-width: 100%;
866
863
  }
867
864
  }
868
865
  </style>