@liujitcn/kratos-admin-system 0.0.39 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/package/declarations/src/api/system/admin/v1/base_config.d.ts +1 -5
- package/dist/package/declarations/src/components/DynamicI18nCell.vue.d.ts +2 -8
- package/dist/package/declarations/src/components/DynamicI18nEditor.vue.d.ts +20 -3
- package/dist/package/declarations/src/components/dynamicI18n.d.ts +2 -2
- package/dist/package/declarations/src/locales/generated.d.ts +5797 -5813
- package/dist/package/declarations/src/rpc/system/admin/v1/base_config.d.ts +4 -40
- package/dist/package/declarations/src/utils/code-gen-progress.d.ts +3 -0
- package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenGenerateConfirm.vue.d.ts +11 -0
- package/dist/package/declarations/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue.d.ts +5 -9
- package/dist/package/declarations/src/views/tool/code-gen/config.d.ts +3 -0
- package/dist/package/src/api/system/admin/v1/base_config.ts +0 -20
- package/dist/package/src/components/DynamicI18nCell.vue +55 -220
- package/dist/package/src/components/DynamicI18nEditor.vue +150 -146
- package/dist/package/src/components/dynamicI18n.ts +10 -6
- package/dist/package/src/config/index.ts +1 -3
- package/dist/package/src/locales/en-US.json +1430 -1434
- package/dist/package/src/locales/ja-JP.json +1430 -1434
- package/dist/package/src/locales/zh-CN.json +1429 -1433
- package/dist/package/src/locales/zh-TW.json +1429 -1433
- package/dist/package/src/module.ts +0 -1
- package/dist/package/src/rpc/system/admin/v1/base_config.ts +3 -43
- package/dist/package/src/utils/code-gen-progress.ts +15 -0
- package/dist/package/src/views/base/config/index.vue +183 -48
- package/dist/package/src/views/base/dict/index.vue +6 -9
- package/dist/package/src/views/base/dict/item.vue +6 -15
- package/dist/package/src/views/base/job/index.vue +16 -17
- package/dist/package/src/views/base/menu/index.vue +78 -15
- package/dist/package/src/views/tool/code-gen/columns/index.vue +17 -25
- package/dist/package/src/views/tool/code-gen/components/CodeGenGenerateConfirm.vue +115 -0
- package/dist/package/src/views/tool/code-gen/components/CodeGenLocaleEditor.vue +27 -186
- package/dist/package/src/views/tool/code-gen/components/CodeGenProgressDialog.vue +2 -0
- package/dist/package/src/views/tool/code-gen/config.ts +15 -1
- package/dist/package/src/views/tool/code-gen/table/index.vue +69 -40
- package/package.json +3 -2
- package/dist/package/declarations/src/config/database-backup.d.ts +0 -12
- package/dist/package/declarations/src/views/base/runtime-config/index.vue.d.ts +0 -3
- package/dist/package/src/config/database-backup.ts +0 -57
- package/dist/package/src/views/base/runtime-config/index.vue +0 -479
|
@@ -1,197 +1,201 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<el-
|
|
5
|
-
type="primary"
|
|
6
|
-
size="small"
|
|
7
|
-
:icon="Promotion"
|
|
8
|
-
:loading="translating"
|
|
9
|
-
:disabled="!canTranslate"
|
|
10
|
-
@click="handleBatchTranslate"
|
|
11
|
-
>
|
|
12
|
-
{{ t("system.base.i18n.action.batch_translate") }}
|
|
13
|
-
</el-button>
|
|
14
|
-
</div>
|
|
15
|
-
<div v-for="item in localValues" :key="item.locale" class="i18n-editor__row">
|
|
16
|
-
<div class="i18n-editor__heading">
|
|
17
|
-
<span>{{ getLanguageLabel(item.locale) }}</span>
|
|
18
|
-
</div>
|
|
19
|
-
<div class="i18n-editor__control" :class="{ 'i18n-editor__control--multiline': multiline }">
|
|
20
|
-
<el-input
|
|
21
|
-
:model-value="item.text"
|
|
22
|
-
:maxlength="maxlength"
|
|
23
|
-
:type="multiline ? 'textarea' : 'text'"
|
|
24
|
-
:rows="multiline ? 6 : undefined"
|
|
25
|
-
:disabled="translating || translatingLocale === item.locale"
|
|
26
|
-
show-word-limit
|
|
27
|
-
:placeholder="t('system.base.i18n.placeholder.text', { language: getLanguageLabel(item.locale) })"
|
|
28
|
-
@update:model-value="value => updateText(item.locale, value)"
|
|
29
|
-
/>
|
|
2
|
+
<template v-if="enabled">
|
|
3
|
+
<slot name="trigger" :open="openDialog">
|
|
4
|
+
<el-tooltip :content="t('system.base.i18n.field.i18ns')" placement="top" :show-after="250">
|
|
30
5
|
<el-button
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
6
|
+
:icon="Languages"
|
|
7
|
+
:disabled="disabled"
|
|
8
|
+
:aria-label="t('system.base.i18n.field.i18ns')"
|
|
9
|
+
aria-haspopup="dialog"
|
|
10
|
+
:aria-expanded="visible"
|
|
11
|
+
@click="openDialog"
|
|
12
|
+
/>
|
|
13
|
+
</el-tooltip>
|
|
14
|
+
</slot>
|
|
15
|
+
<ProDialog
|
|
16
|
+
v-model="visible"
|
|
17
|
+
:title="t('system.base.i18n.field.i18ns')"
|
|
18
|
+
width="min(800px, calc(100vw - 32px))"
|
|
19
|
+
append-to-body
|
|
20
|
+
destroy-on-close
|
|
21
|
+
:confirm-loading="translating"
|
|
22
|
+
:show-footer="!readonly"
|
|
23
|
+
@confirm="confirmChanges"
|
|
24
|
+
@close="closeDialog"
|
|
25
|
+
>
|
|
26
|
+
<div class="i18n-editor">
|
|
27
|
+
<div v-if="!readonly" class="i18n-editor__toolbar">
|
|
28
|
+
<el-button
|
|
29
|
+
type="primary"
|
|
30
|
+
:loading="translating && !translatingLocale"
|
|
31
|
+
:disabled="!source || translating"
|
|
32
|
+
@click="translate()"
|
|
33
|
+
>
|
|
34
|
+
{{ t("system.base.i18n.action.batch_translate") }}
|
|
35
|
+
</el-button>
|
|
36
|
+
</div>
|
|
37
|
+
<el-form label-position="right" label-width="100px" @submit.prevent>
|
|
38
|
+
<el-form-item
|
|
39
|
+
v-for="item in draftValues"
|
|
40
|
+
:key="item.locale"
|
|
41
|
+
:label="getLanguageLabel(item.locale)"
|
|
42
|
+
:for="`${inputId}-${item.locale}`"
|
|
43
|
+
>
|
|
44
|
+
<div class="i18n-editor__control">
|
|
45
|
+
<el-input
|
|
46
|
+
:id="`${inputId}-${item.locale}`"
|
|
47
|
+
:model-value="item.text || source"
|
|
48
|
+
:maxlength="maxlength"
|
|
49
|
+
:type="multiline ? 'textarea' : 'text'"
|
|
50
|
+
:rows="multiline ? 5 : undefined"
|
|
51
|
+
:disabled="translating || readonly"
|
|
52
|
+
show-word-limit
|
|
53
|
+
@update:model-value="value => (item.text = value)"
|
|
54
|
+
/>
|
|
55
|
+
<el-button
|
|
56
|
+
v-if="!readonly"
|
|
57
|
+
link
|
|
58
|
+
type="primary"
|
|
59
|
+
:loading="translatingLocale === item.locale"
|
|
60
|
+
:disabled="!source || translating"
|
|
61
|
+
@click="translate(item.locale)"
|
|
62
|
+
>
|
|
63
|
+
{{ t("system.base.i18n.action.translate") }}
|
|
64
|
+
</el-button>
|
|
65
|
+
</div>
|
|
66
|
+
</el-form-item>
|
|
67
|
+
</el-form>
|
|
42
68
|
</div>
|
|
43
|
-
</
|
|
44
|
-
</
|
|
69
|
+
</ProDialog>
|
|
70
|
+
</template>
|
|
45
71
|
</template>
|
|
46
72
|
|
|
47
73
|
<script setup lang="ts">
|
|
48
|
-
import { computed, ref, watch } from "vue";
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import
|
|
74
|
+
import { computed, ref, useId, watch } from "vue";
|
|
75
|
+
import { Languages } from "@lucide/vue";
|
|
76
|
+
import { t } from "@liujitcn/kratos-admin-core";
|
|
77
|
+
import ProDialog from "@liujitcn/kratos-admin-core/components/Dialog/ProDialog.vue";
|
|
52
78
|
import { defBaseI18nService } from "@liujitcn/kratos-admin-system/api/system/admin/v1/base_i18n";
|
|
53
|
-
import { getLanguageLabel, type DynamicI18nValue } from "./dynamicI18n";
|
|
79
|
+
import { getEditableLanguageOptions, getLanguageLabel, type DynamicI18nValue } from "./dynamicI18n";
|
|
54
80
|
|
|
55
|
-
/**
|
|
81
|
+
/** 字段旁国际化入口及本地草稿编辑弹窗。 */
|
|
56
82
|
interface DynamicI18nEditorProps {
|
|
57
83
|
modelValue: DynamicI18nValue[];
|
|
58
|
-
/** 当前语言源文本。 */
|
|
59
84
|
source?: string;
|
|
60
85
|
maxlength?: number;
|
|
61
86
|
multiline?: boolean;
|
|
87
|
+
disabled?: boolean;
|
|
88
|
+
readonly?: boolean;
|
|
62
89
|
}
|
|
63
|
-
|
|
64
90
|
const props = withDefaults(defineProps<DynamicI18nEditorProps>(), {
|
|
65
91
|
source: "",
|
|
66
92
|
maxlength: 100,
|
|
67
|
-
multiline: false
|
|
93
|
+
multiline: false,
|
|
94
|
+
disabled: false,
|
|
95
|
+
readonly: false
|
|
68
96
|
});
|
|
69
|
-
|
|
70
|
-
const { locale: currentLocale } = useLocaleStore();
|
|
71
97
|
const emit = defineEmits<{ "update:modelValue": [value: DynamicI18nValue[]] }>();
|
|
72
|
-
const
|
|
98
|
+
const enabled = computed(() => getEditableLanguageOptions().length > 0);
|
|
99
|
+
const inputId = useId();
|
|
100
|
+
const visible = ref(false);
|
|
101
|
+
const draftValues = ref<DynamicI18nValue[]>([]);
|
|
73
102
|
const translating = ref(false);
|
|
74
103
|
const translatingLocale = ref("");
|
|
75
|
-
|
|
104
|
+
let requestVersion = 0;
|
|
76
105
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
value => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
);
|
|
106
|
+
/** 打开编辑窗口,未填写译文使用原值展示,不提前写入主表单。 */
|
|
107
|
+
function openDialog() {
|
|
108
|
+
draftValues.value = getEditableLanguageOptions().map(({ value }) => ({
|
|
109
|
+
locale: value,
|
|
110
|
+
id: props.modelValue.find(item => item.locale === value)?.id ?? 0,
|
|
111
|
+
text: props.modelValue.find(item => item.locale === value)?.text ?? ""
|
|
112
|
+
}));
|
|
113
|
+
visible.value = true;
|
|
114
|
+
}
|
|
84
115
|
|
|
85
|
-
/**
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
emit("update:modelValue",
|
|
116
|
+
/** 将用户确认的译文交给主表单,实际保存由主表单负责。 */
|
|
117
|
+
function confirmChanges() {
|
|
118
|
+
if (translating.value) return;
|
|
119
|
+
const editable = new Set(draftValues.value.map(item => item.locale));
|
|
120
|
+
emit("update:modelValue", [
|
|
121
|
+
...props.modelValue.filter(item => !editable.has(item.locale)),
|
|
122
|
+
...draftValues.value.map(item => ({ ...item }))
|
|
123
|
+
]);
|
|
124
|
+
visible.value = false;
|
|
90
125
|
}
|
|
91
126
|
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
127
|
+
/** 关闭时丢弃草稿并使尚未返回的翻译结果失效。 */
|
|
128
|
+
function closeDialog() {
|
|
129
|
+
requestVersion++;
|
|
130
|
+
translating.value = false;
|
|
131
|
+
translatingLocale.value = "";
|
|
132
|
+
draftValues.value = [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** 用当前原文翻译指定语言或全部目标语言,成功结果直接替换草稿。 */
|
|
136
|
+
async function translate(locale?: string) {
|
|
137
|
+
if (!props.source || translating.value) return;
|
|
138
|
+
const version = ++requestVersion;
|
|
139
|
+
const source = props.source;
|
|
95
140
|
translating.value = true;
|
|
141
|
+
translatingLocale.value = locale ?? "";
|
|
96
142
|
try {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
emit("update:modelValue", values);
|
|
108
|
-
}
|
|
109
|
-
if (failed) {
|
|
110
|
-
ElMessage.warning(
|
|
111
|
-
t("system.base.i18n.message.batch_translate_partial", {
|
|
112
|
-
success: i18ns.size,
|
|
113
|
-
failed
|
|
114
|
-
})
|
|
115
|
-
);
|
|
116
|
-
} else {
|
|
117
|
-
ElMessage.success(t("system.base.i18n.message.batch_translate_success", { count: i18ns.size }));
|
|
143
|
+
const response = await defBaseI18nService.DraftBaseI18n({ source, locale });
|
|
144
|
+
if (version !== requestVersion || source !== props.source || !visible.value) return;
|
|
145
|
+
const targets = draftValues.value.filter(item => !locale || item.locale === locale);
|
|
146
|
+
const results = new Map(response.i18ns.filter(item => item.i18n).map(item => [item.locale, item.i18n]));
|
|
147
|
+
let success = 0;
|
|
148
|
+
for (const item of targets) {
|
|
149
|
+
const text = results.get(item.locale);
|
|
150
|
+
if (text === undefined) continue;
|
|
151
|
+
item.text = text;
|
|
152
|
+
success++;
|
|
118
153
|
}
|
|
154
|
+
const failed = targets.length - success;
|
|
155
|
+
if (failed) ElMessage.warning(t("system.base.i18n.message.batch_translate_partial", { success, failed }));
|
|
156
|
+
else ElMessage.success(t("system.base.i18n.message.batch_translate_success", { count: success }));
|
|
119
157
|
} catch {
|
|
120
|
-
ElMessage.error(t("system.base.i18n.message.batch_translate_failed"));
|
|
158
|
+
if (version === requestVersion) ElMessage.error(t("system.base.i18n.message.batch_translate_failed"));
|
|
121
159
|
} finally {
|
|
122
|
-
|
|
160
|
+
if (version === requestVersion) {
|
|
161
|
+
translating.value = false;
|
|
162
|
+
translatingLocale.value = "";
|
|
163
|
+
}
|
|
123
164
|
}
|
|
124
165
|
}
|
|
125
166
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (!i18n) throw new Error("i18n not found");
|
|
135
|
-
const values = localValues.value.map(value => (value.locale === locale ? { ...value, text: i18n } : value));
|
|
136
|
-
localValues.value = values;
|
|
137
|
-
emit("update:modelValue", values);
|
|
138
|
-
ElMessage.success(t("system.base.i18n.message.translate_success", { language: getLanguageLabel(locale) }));
|
|
139
|
-
} catch {
|
|
140
|
-
ElMessage.error(t("system.base.i18n.message.translate_failed", { language: getLanguageLabel(locale) }));
|
|
141
|
-
} finally {
|
|
167
|
+
watch(enabled, value => {
|
|
168
|
+
if (!value) visible.value = false;
|
|
169
|
+
});
|
|
170
|
+
watch(
|
|
171
|
+
() => props.source,
|
|
172
|
+
() => {
|
|
173
|
+
requestVersion++;
|
|
174
|
+
translating.value = false;
|
|
142
175
|
translatingLocale.value = "";
|
|
143
176
|
}
|
|
144
|
-
|
|
145
|
-
|
|
177
|
+
);
|
|
146
178
|
</script>
|
|
147
179
|
|
|
148
180
|
<style scoped>
|
|
149
181
|
.i18n-editor {
|
|
150
|
-
display:
|
|
151
|
-
|
|
152
|
-
gap: 14px;
|
|
153
|
-
width: 100%;
|
|
182
|
+
display: grid;
|
|
183
|
+
gap: 16px;
|
|
154
184
|
}
|
|
155
185
|
.i18n-editor__toolbar {
|
|
156
186
|
display: flex;
|
|
157
187
|
justify-content: flex-end;
|
|
158
188
|
}
|
|
159
|
-
.i18n-editor__row {
|
|
160
|
-
display: flex;
|
|
161
|
-
flex-direction: column;
|
|
162
|
-
gap: 6px;
|
|
163
|
-
}
|
|
164
|
-
.i18n-editor__heading,
|
|
165
189
|
.i18n-editor__control {
|
|
166
190
|
display: flex;
|
|
167
|
-
gap: 8px;
|
|
168
|
-
align-items: center;
|
|
169
|
-
}
|
|
170
|
-
.i18n-editor__heading {
|
|
171
|
-
color: var(--el-text-color-regular);
|
|
172
|
-
}
|
|
173
|
-
.i18n-editor__control {
|
|
174
|
-
position: relative;
|
|
175
191
|
width: 100%;
|
|
192
|
+
min-width: 0;
|
|
193
|
+
align-items: flex-start;
|
|
194
|
+
gap: 12px;
|
|
176
195
|
}
|
|
177
|
-
.i18n-editor__control :deep(.el-input)
|
|
196
|
+
.i18n-editor__control :deep(.el-input),
|
|
197
|
+
.i18n-editor__control :deep(.el-textarea) {
|
|
178
198
|
flex: 1;
|
|
179
|
-
|
|
180
|
-
.i18n-editor__control--multiline :deep(.el-textarea__inner) {
|
|
181
|
-
padding-right: 78px;
|
|
182
|
-
}
|
|
183
|
-
.i18n-editor__control:not(.i18n-editor__control--multiline) :deep(.el-input__suffix) {
|
|
184
|
-
padding-right: 78px;
|
|
185
|
-
}
|
|
186
|
-
.i18n-editor__translate {
|
|
187
|
-
position: absolute;
|
|
188
|
-
z-index: 1;
|
|
189
|
-
top: 50%;
|
|
190
|
-
right: 8px;
|
|
191
|
-
transform: translateY(-50%);
|
|
192
|
-
}
|
|
193
|
-
.i18n-editor__control--multiline .i18n-editor__translate {
|
|
194
|
-
top: 8px;
|
|
195
|
-
transform: none;
|
|
199
|
+
min-width: 0;
|
|
196
200
|
}
|
|
197
201
|
</style>
|
|
@@ -11,9 +11,9 @@ export interface DynamicI18nValue {
|
|
|
11
11
|
|
|
12
12
|
/** DynamicI18nRecord 描述三类动态资源翻译共有字段。 */
|
|
13
13
|
export interface DynamicI18nRecord extends Omit<DynamicI18nValue, "text"> {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
target_type: I18nTargetType;
|
|
15
|
+
target_id: number;
|
|
16
|
+
name: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/** DynamicLanguageOption 动态翻译编辑器显示的语言选项。 */
|
|
@@ -52,11 +52,15 @@ export function normalizeDynamicI18ns(
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/** serializeDynamicI18ns
|
|
55
|
+
/** serializeDynamicI18ns 按启用语言序列化译文,未填写时保存原值。 */
|
|
56
56
|
export function serializeDynamicI18ns(
|
|
57
57
|
values: DynamicI18nValue[],
|
|
58
58
|
targetType: I18nTargetType,
|
|
59
|
-
targetId: number
|
|
59
|
+
targetId: number,
|
|
60
|
+
source: string
|
|
60
61
|
): Array<{ id: number; target_type: I18nTargetType; target_id: number; locale: string; name: string }> {
|
|
61
|
-
return
|
|
62
|
+
return getEditableLanguageOptions().map(({ value: locale }) => {
|
|
63
|
+
const item = values.find(value => value.locale === locale);
|
|
64
|
+
return { id: item?.id ?? 0, target_type: targetType, target_id: targetId, locale, name: item?.text || source };
|
|
65
|
+
});
|
|
62
66
|
}
|
|
@@ -13,9 +13,7 @@ export type {
|
|
|
13
13
|
} from "./types";
|
|
14
14
|
|
|
15
15
|
/** Admin 内置运行配置定义集合。 */
|
|
16
|
-
export const runtimeConfigDefinitions = shallowReactive<RuntimeConfigDefinition[]>([
|
|
17
|
-
baseLogFallbackConfig
|
|
18
|
-
]);
|
|
16
|
+
export const runtimeConfigDefinitions = shallowReactive<RuntimeConfigDefinition[]>([baseLogFallbackConfig]);
|
|
19
17
|
|
|
20
18
|
/** 注册外部业务模块提供的运行配置定义。 */
|
|
21
19
|
export function registerRuntimeConfig(definition: RuntimeConfigDefinition) {
|