yh-i18n 2.2.21 → 2.2.22
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/excelTool.ts +35 -21
- package/list.vue +70 -66
- package/package.json +1 -1
package/excelTool.ts
CHANGED
|
@@ -5,6 +5,33 @@ import http from '@/libs/api.request';
|
|
|
5
5
|
import {useI18nStore} from './index';
|
|
6
6
|
|
|
7
7
|
const verificationCode = 'lkyhtranslateexcel';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 解析翻译内容,将 JSON 字符串解析并合并到 item 对象中
|
|
11
|
+
* @param item 翻译项对象
|
|
12
|
+
* @param localKeys 本地语言键列表
|
|
13
|
+
* @returns 处理后的翻译项对象
|
|
14
|
+
*/
|
|
15
|
+
export function parseTranslateContent(item: any, localKeys: string[]): any {
|
|
16
|
+
try {
|
|
17
|
+
let content = JSON.parse(item.content);
|
|
18
|
+
let keys = Object.keys(content);
|
|
19
|
+
|
|
20
|
+
keys.forEach((key) => {
|
|
21
|
+
let val = content[key];
|
|
22
|
+
item[key] = val;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
localKeys.forEach((k) => {
|
|
26
|
+
if (!keys.includes(k)) {
|
|
27
|
+
item[k] = '';
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('解析翻译内容失败:', error);
|
|
32
|
+
}
|
|
33
|
+
return item;
|
|
34
|
+
}
|
|
8
35
|
export async function exportExcel(total) {
|
|
9
36
|
const loading = ElLoading.service({
|
|
10
37
|
lock: true,
|
|
@@ -24,23 +51,7 @@ export async function exportExcel(total) {
|
|
|
24
51
|
.then((res) => {
|
|
25
52
|
let localKeys = i18nStore.localList.map((item) => item.value);
|
|
26
53
|
let {records} = res.data.data;
|
|
27
|
-
records = records.map((item) =>
|
|
28
|
-
try {
|
|
29
|
-
let content = JSON.parse(item.content);
|
|
30
|
-
let keys = Object.keys(content);
|
|
31
|
-
|
|
32
|
-
keys.forEach((key) => {
|
|
33
|
-
let val = content[key];
|
|
34
|
-
item[key] = val;
|
|
35
|
-
});
|
|
36
|
-
localKeys.forEach((k) => {
|
|
37
|
-
if (!keys.includes(k)) {
|
|
38
|
-
item[k] = '';
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
} catch (error) {}
|
|
42
|
-
return item;
|
|
43
|
-
});
|
|
54
|
+
records = records.map((item) => parseTranslateContent(item, localKeys));
|
|
44
55
|
return records;
|
|
45
56
|
});
|
|
46
57
|
loading.setText('正在序列化表格数据……');
|
|
@@ -77,8 +88,8 @@ export async function exportExcel(total) {
|
|
|
77
88
|
sheet.addRow(title);
|
|
78
89
|
sheet.addRows(
|
|
79
90
|
records.map((item) => {
|
|
80
|
-
let {
|
|
81
|
-
let row = [
|
|
91
|
+
let {id, name} = item;
|
|
92
|
+
let row = [id, name];
|
|
82
93
|
Config.i18nList.forEach((valKey) => {
|
|
83
94
|
row.push(item[valKey]);
|
|
84
95
|
});
|
|
@@ -201,6 +212,7 @@ export async function importExcel(e, getDataList) {
|
|
|
201
212
|
message: '您选择的文件不是系统导出的文件',
|
|
202
213
|
type: 'warning',
|
|
203
214
|
});
|
|
215
|
+
e.target.value = '';
|
|
204
216
|
return false;
|
|
205
217
|
}
|
|
206
218
|
const loading = ElLoading.service({
|
|
@@ -215,14 +227,14 @@ export async function importExcel(e, getDataList) {
|
|
|
215
227
|
let dataList: any[] = [];
|
|
216
228
|
sheet.getRows(2, len)?.forEach((row) => {
|
|
217
229
|
let id = row.getCell(1).value;
|
|
218
|
-
let
|
|
230
|
+
let name = row.getCell(2).value;
|
|
219
231
|
let content: any = {};
|
|
220
232
|
Config.i18nList.forEach((item, index) => {
|
|
221
233
|
content[item] = row.getCell(index + 3).value;
|
|
222
234
|
});
|
|
223
235
|
dataList.push({
|
|
224
236
|
id,
|
|
225
|
-
|
|
237
|
+
name,
|
|
226
238
|
content: JSON.stringify(content),
|
|
227
239
|
});
|
|
228
240
|
});
|
|
@@ -250,6 +262,8 @@ export async function importExcel(e, getDataList) {
|
|
|
250
262
|
getDataList();
|
|
251
263
|
} catch (error) {
|
|
252
264
|
ElMessage.error('导入保存翻译数据遇到错误:', error.message);
|
|
265
|
+
} finally {
|
|
266
|
+
e.target.value = '';
|
|
253
267
|
}
|
|
254
268
|
}
|
|
255
269
|
}
|
package/list.vue
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<el-form inline>
|
|
6
6
|
<el-form-item :label="ct('翻译键名')">
|
|
7
7
|
<el-input
|
|
8
|
-
v-model="listForm.
|
|
8
|
+
v-model="listForm.name"
|
|
9
9
|
@keyup.enter.stop.prevent="getDataList(true)"
|
|
10
10
|
:placeholder="ct('键入以筛选键名')"></el-input>
|
|
11
11
|
</el-form-item>
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
ref="i18nList"
|
|
49
49
|
stripe
|
|
50
50
|
:data="dataList"
|
|
51
|
-
row-key="
|
|
51
|
+
row-key="id"
|
|
52
52
|
@row-click="rowClickHandler">
|
|
53
53
|
<el-table-column
|
|
54
54
|
type="selection"
|
|
@@ -76,13 +76,13 @@
|
|
|
76
76
|
<el-button
|
|
77
77
|
link
|
|
78
78
|
type="danger"
|
|
79
|
-
@click="delOne(row.
|
|
79
|
+
@click="delOne(row.id)">
|
|
80
80
|
{{ ct('删除') }}
|
|
81
81
|
</el-button>
|
|
82
82
|
</template>
|
|
83
83
|
</el-table-column>
|
|
84
84
|
<el-table-column
|
|
85
|
-
prop="
|
|
85
|
+
prop="name"
|
|
86
86
|
min-width="140"
|
|
87
87
|
fixed="left"
|
|
88
88
|
:label="ct('翻译键名')"></el-table-column>
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
@close="cancelForm"
|
|
108
108
|
:close-on-click-modal="false"
|
|
109
109
|
draggable
|
|
110
|
-
:title="formData.
|
|
110
|
+
:title="formData.id ? ct('编辑翻译') : ct('新增翻译')">
|
|
111
111
|
<vxe-form
|
|
112
112
|
title-align="right"
|
|
113
113
|
title-width="100px"
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
title-colon
|
|
116
116
|
:data="formData"
|
|
117
117
|
:items="formItems"
|
|
118
|
-
:rules="
|
|
118
|
+
:rules="formRules"></vxe-form>
|
|
119
119
|
<template #footer>
|
|
120
120
|
<div class="yh-i18n-form-actions">
|
|
121
121
|
<el-button
|
|
@@ -146,16 +146,16 @@
|
|
|
146
146
|
</el-dialog>
|
|
147
147
|
</template>
|
|
148
148
|
<script setup lang="ts">
|
|
149
|
-
import {reactive, ref, onMounted, watch} from 'vue';
|
|
149
|
+
import {reactive, ref, onMounted, onUnmounted, watch} from 'vue';
|
|
150
150
|
import {ElLoadingService, ElMessage, ElMessageBox} from 'element-plus';
|
|
151
151
|
import {useI18nStore, ct} from 'yh-i18n';
|
|
152
152
|
import http from '@/libs/api.request';
|
|
153
153
|
import {VxeFormInstance, VxeFormPropTypes} from 'vxe-table';
|
|
154
|
-
import {exportExcel, importExcel} from './excelTool';
|
|
154
|
+
import {exportExcel, importExcel, parseTranslateContent} from './excelTool';
|
|
155
155
|
|
|
156
156
|
interface TranslateItem {
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
id?: string;
|
|
158
|
+
name: string;
|
|
159
159
|
content: string;
|
|
160
160
|
[key: string]: any;
|
|
161
161
|
}
|
|
@@ -167,7 +167,7 @@ interface ListColumn {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
interface SaveData {
|
|
170
|
-
|
|
170
|
+
name: string;
|
|
171
171
|
content: Record<string, string> | string;
|
|
172
172
|
id?: string;
|
|
173
173
|
}
|
|
@@ -180,7 +180,7 @@ const deleteUrl = '/translate/deleteTranslate';
|
|
|
180
180
|
|
|
181
181
|
const i18nList = ref();
|
|
182
182
|
const listForm = reactive({
|
|
183
|
-
|
|
183
|
+
name: '',
|
|
184
184
|
pageNum: 1,
|
|
185
185
|
pageSize: 10,
|
|
186
186
|
total: 0,
|
|
@@ -188,7 +188,7 @@ const listForm = reactive({
|
|
|
188
188
|
const listColumns = reactive<ListColumn[]>([]);
|
|
189
189
|
const dataList = ref<TranslateItem[]>([]);
|
|
190
190
|
function getDataList(isReset = false) {
|
|
191
|
-
let {
|
|
191
|
+
let {name, pageNum, pageSize} = listForm;
|
|
192
192
|
if (isReset) {
|
|
193
193
|
pageNum = 1;
|
|
194
194
|
}
|
|
@@ -200,7 +200,7 @@ function getDataList(isReset = false) {
|
|
|
200
200
|
url: '/translate/select',
|
|
201
201
|
method: 'post',
|
|
202
202
|
data: {
|
|
203
|
-
|
|
203
|
+
name,
|
|
204
204
|
pageNum,
|
|
205
205
|
pageSize,
|
|
206
206
|
},
|
|
@@ -208,28 +208,14 @@ function getDataList(isReset = false) {
|
|
|
208
208
|
.then((res) => {
|
|
209
209
|
let localKeys = i18nStore.localList.map((item) => item.value);
|
|
210
210
|
let {records, total} = res.data.data;
|
|
211
|
-
records = records.map((item) =>
|
|
212
|
-
try {
|
|
213
|
-
let content = JSON.parse(item.content);
|
|
214
|
-
let keys = Object.keys(content);
|
|
215
|
-
|
|
216
|
-
keys.forEach((key) => {
|
|
217
|
-
let val = content[key];
|
|
218
|
-
item[key] = val;
|
|
219
|
-
});
|
|
220
|
-
localKeys.forEach((k) => {
|
|
221
|
-
if (!keys.includes(k)) {
|
|
222
|
-
item[k] = '';
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
} catch (error) {
|
|
226
|
-
console.error('解析翻译内容失败:', error);
|
|
227
|
-
}
|
|
228
|
-
return item;
|
|
229
|
-
});
|
|
211
|
+
records = records.map((item) => parseTranslateContent(item, localKeys));
|
|
230
212
|
dataList.value = records;
|
|
231
213
|
listForm.total = total;
|
|
232
214
|
})
|
|
215
|
+
.catch((error) => {
|
|
216
|
+
ElMessage.error('获取数据失败');
|
|
217
|
+
console.error('获取列表数据失败:', error);
|
|
218
|
+
})
|
|
233
219
|
.finally(() => {
|
|
234
220
|
loading.close();
|
|
235
221
|
});
|
|
@@ -253,7 +239,7 @@ function rowClickHandler(row) {
|
|
|
253
239
|
}
|
|
254
240
|
|
|
255
241
|
function resetList() {
|
|
256
|
-
listForm.
|
|
242
|
+
listForm.name = '';
|
|
257
243
|
listForm.pageNum = 1;
|
|
258
244
|
listForm.total = 0;
|
|
259
245
|
getDataList();
|
|
@@ -262,16 +248,16 @@ function resetList() {
|
|
|
262
248
|
const langList = Object.keys(i18nStore.langList);
|
|
263
249
|
const formDataIndex = ref<number>();
|
|
264
250
|
const formData = reactive<TranslateItem>({
|
|
265
|
-
|
|
251
|
+
name: '',
|
|
266
252
|
content: '',
|
|
267
253
|
});
|
|
268
254
|
const formShow = ref(false);
|
|
269
|
-
|
|
255
|
+
|
|
270
256
|
function cancelForm() {
|
|
271
257
|
vxeFormRef?.value?.reset();
|
|
272
258
|
vxeFormRef?.value?.clearValidate();
|
|
273
259
|
formDataIndex.value = void 0;
|
|
274
|
-
formData.id =
|
|
260
|
+
formData.id = undefined;
|
|
275
261
|
formShow.value = false;
|
|
276
262
|
}
|
|
277
263
|
|
|
@@ -289,6 +275,13 @@ function prevOne() {
|
|
|
289
275
|
|
|
290
276
|
function editOne(item, index) {
|
|
291
277
|
formDataIndex.value = index;
|
|
278
|
+
// 先清空表单数据,除了 id
|
|
279
|
+
for (const key in formData) {
|
|
280
|
+
if (key !== 'id') {
|
|
281
|
+
delete formData[key];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// 然后将新项目的数据复制到表单
|
|
292
285
|
for (const key in item) {
|
|
293
286
|
if (Object.prototype.hasOwnProperty.call(item, key)) {
|
|
294
287
|
const val = item[key];
|
|
@@ -311,18 +304,18 @@ function nextOne() {
|
|
|
311
304
|
}
|
|
312
305
|
|
|
313
306
|
function saveOne() {
|
|
314
|
-
let isAdd = !formData.
|
|
307
|
+
let isAdd = !formData.id;
|
|
315
308
|
let url = updateUrl;
|
|
316
309
|
vxeFormRef?.value?.validate().then((errMap) => {
|
|
317
310
|
if (!errMap) {
|
|
318
311
|
let data: SaveData = {
|
|
319
|
-
|
|
312
|
+
name: formData.name,
|
|
320
313
|
content: {},
|
|
321
314
|
};
|
|
322
315
|
if (isAdd) {
|
|
323
316
|
url = insertUrl;
|
|
324
317
|
} else {
|
|
325
|
-
data.id = formData.
|
|
318
|
+
data.id = formData.id;
|
|
326
319
|
}
|
|
327
320
|
for (const key in formData) {
|
|
328
321
|
if (key !== 'key' && langList.includes(key)) {
|
|
@@ -344,10 +337,12 @@ function saveOne() {
|
|
|
344
337
|
getDataList();
|
|
345
338
|
cancelForm();
|
|
346
339
|
} else {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
340
|
+
if (formDataIndex.value !== undefined && formDataIndex.value !== null) {
|
|
341
|
+
dataList.value[formDataIndex.value] = {
|
|
342
|
+
...formData,
|
|
343
|
+
};
|
|
344
|
+
nextOne();
|
|
345
|
+
}
|
|
351
346
|
}
|
|
352
347
|
} else {
|
|
353
348
|
ElMessage.error(res.data.msg);
|
|
@@ -380,7 +375,8 @@ function delOne(id) {
|
|
|
380
375
|
|
|
381
376
|
function delMore() {
|
|
382
377
|
ElMessageBox.confirm('确认删除选中的翻译记录吗?').then(async () => {
|
|
383
|
-
|
|
378
|
+
const selectedRows = i18nList.value?.getSelectionRows();
|
|
379
|
+
const ids = selectedRows?.map((row) => row.id) || [];
|
|
384
380
|
if (ids && ids.length) {
|
|
385
381
|
let len = ids.length;
|
|
386
382
|
let loading = ElLoadingService({
|
|
@@ -399,9 +395,11 @@ function delMore() {
|
|
|
399
395
|
});
|
|
400
396
|
} catch (error) {
|
|
401
397
|
ElMessage.error(`删除第 ${i + 1} 条记录失败`);
|
|
398
|
+
console.error(`删除第 ${i + 1} 条记录失败:`, error);
|
|
402
399
|
}
|
|
403
400
|
}
|
|
404
401
|
loading.close();
|
|
402
|
+
ElMessage.success(`删除完成,共 ${len} 条记录`);
|
|
405
403
|
getDataList();
|
|
406
404
|
}
|
|
407
405
|
});
|
|
@@ -409,7 +407,7 @@ function delMore() {
|
|
|
409
407
|
|
|
410
408
|
const formItems = reactive<VxeFormPropTypes.Items>([
|
|
411
409
|
{
|
|
412
|
-
field: '
|
|
410
|
+
field: 'name',
|
|
413
411
|
span: 24,
|
|
414
412
|
title: '翻译键值',
|
|
415
413
|
itemRender: {
|
|
@@ -419,8 +417,8 @@ const formItems = reactive<VxeFormPropTypes.Items>([
|
|
|
419
417
|
},
|
|
420
418
|
]);
|
|
421
419
|
|
|
422
|
-
const
|
|
423
|
-
|
|
420
|
+
const formRules = reactive<VxeFormPropTypes.Rules>({
|
|
421
|
+
name: [{required: true, type: 'string', message: '请输入翻译键值'}],
|
|
424
422
|
});
|
|
425
423
|
|
|
426
424
|
let needInit = true;
|
|
@@ -453,26 +451,32 @@ watch(
|
|
|
453
451
|
}
|
|
454
452
|
);
|
|
455
453
|
|
|
454
|
+
const handleKeydown = (e: KeyboardEvent) => {
|
|
455
|
+
let {key, ctrlKey, altKey} = e;
|
|
456
|
+
if (key === 's' && ctrlKey) {
|
|
457
|
+
e.preventDefault();
|
|
458
|
+
e.stopPropagation();
|
|
459
|
+
saveOne();
|
|
460
|
+
}
|
|
461
|
+
if (key === 'ArrowRight' && (ctrlKey || altKey)) {
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
e.stopPropagation();
|
|
464
|
+
nextOne();
|
|
465
|
+
}
|
|
466
|
+
if (key === 'ArrowLeft' && (ctrlKey || altKey)) {
|
|
467
|
+
e.preventDefault();
|
|
468
|
+
e.stopPropagation();
|
|
469
|
+
prevOne();
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
|
|
456
473
|
onMounted(() => {
|
|
457
474
|
getDataList();
|
|
458
|
-
window.addEventListener('keydown',
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
saveOne();
|
|
464
|
-
}
|
|
465
|
-
if (key === 'ArrowRight' && (ctrlKey || altKey)) {
|
|
466
|
-
e.preventDefault();
|
|
467
|
-
e.stopPropagation();
|
|
468
|
-
nextOne();
|
|
469
|
-
}
|
|
470
|
-
if (key === 'ArrowLeft' && (ctrlKey || altKey)) {
|
|
471
|
-
e.preventDefault();
|
|
472
|
-
e.stopPropagation();
|
|
473
|
-
prevOne();
|
|
474
|
-
}
|
|
475
|
-
});
|
|
475
|
+
window.addEventListener('keydown', handleKeydown);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
onUnmounted(() => {
|
|
479
|
+
window.removeEventListener('keydown', handleKeydown);
|
|
476
480
|
});
|
|
477
481
|
</script>
|
|
478
482
|
<style lang="scss">
|