@skyfox2000/webui 1.5.7 → 1.5.10
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/lib/assets/modules/{baseLayout-DfTxHOFc.js → baseLayout-BuQjrozB.js} +9 -9
- package/lib/assets/modules/{file-upload-DTOdV5vM.js → file-upload-DcusqXDb.js} +5 -5
- package/lib/assets/modules/{index-M1qERbea.js → index-BlQB5KSU.js} +2 -2
- package/lib/assets/modules/{index-BwMaOrJT.js → index-CW_ZCHWs.js} +1 -1
- package/lib/assets/modules/index-CekzHbWp.js +114 -0
- package/lib/assets/modules/{menuTabs-DWaBSRNr.js → menuTabs-BYSjomB7.js} +44 -36
- package/lib/assets/modules/{toolIcon-BYnHhAy-.js → toolIcon-D4vAp0qA.js} +1 -1
- package/lib/assets/modules/{upload-template-BKm9mFq8.js → upload-template-NU0Bpg4N.js} +2056 -2176
- package/lib/assets/modules/uploadList-ENSsTfpD.js +472 -0
- package/lib/const/options.d.ts +6 -20
- package/lib/const/stores.d.ts +11 -0
- package/lib/es/AceEditor/index.js +70 -70
- package/lib/es/BasicLayout/index.js +6 -6
- package/lib/es/Error403/index.js +1 -1
- package/lib/es/Error404/index.js +1 -1
- package/lib/es/ExcelForm/index.js +16 -16
- package/lib/es/MenuLayout/index.js +6 -6
- package/lib/es/TemplateFile/index.js +5 -5
- package/lib/es/UploadForm/index.js +5 -5
- package/lib/index.d.ts +2 -1
- package/lib/locales/default.d.ts +137 -115
- package/lib/utils/tools.d.ts +1 -0
- package/lib/webui.css +1 -1
- package/lib/webui.es.js +1692 -1547
- package/package.json +1 -1
- package/src/components/content/dialog/index.vue +1 -0
- package/src/components/content/form/formItem.vue +3 -2
- package/src/components/content/search/index.vue +1 -0
- package/src/components/content/search/searchItem.vue +3 -2
- package/src/components/form/aceEditor/index.vue +5 -3
- package/src/components/form/cascader/index.vue +5 -3
- package/src/components/form/checkbox/index.vue +1 -1
- package/src/components/form/datePicker/index.vue +2 -1
- package/src/components/form/input/index.vue +1 -1
- package/src/components/form/input/inputNumber.vue +3 -1
- package/src/components/form/input/inputPassword.vue +3 -1
- package/src/components/form/propEditor/index.vue +8 -3
- package/src/components/form/radio/index.vue +2 -1
- package/src/components/form/radio/radioStatus.vue +2 -1
- package/src/components/form/switch/index.vue +3 -1
- package/src/components/form/textarea/index.vue +1 -1
- package/src/components/form/timePicker/index.vue +4 -1
- package/src/components/form/treeSelect/index.vue +3 -1
- package/src/components/form/upload/imageList.vue +8 -6
- package/src/components/form/upload/uploadList.vue +6 -5
- package/src/components/layout/datetime/index.vue +15 -4
- package/src/components/layout/header/language.vue +2 -0
- package/src/const/options.ts +76 -52
- package/src/const/stores.ts +58 -0
- package/src/index.ts +2 -0
- package/src/locales/default.ts +145 -123
- package/src/locales/en-US.json +320 -0
- package/src/locales/index.ts +109 -39
- package/src/stores/hostInfo.ts +2 -19
- package/src/stores/userInfo.ts +2 -30
- package/src/utils/options.ts +2 -2
- package/src/utils/tools.ts +88 -83
- package/lib/assets/modules/index-BDoBUrYA.js +0 -114
- package/lib/assets/modules/uploadList-CHvr6Hp1.js +0 -472
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
{
|
|
2
|
+
"webui": {
|
|
3
|
+
"common": {
|
|
4
|
+
"confirm": "Confirm",
|
|
5
|
+
"cancel": "Cancel",
|
|
6
|
+
"yes": "Yes",
|
|
7
|
+
"no": "No",
|
|
8
|
+
|
|
9
|
+
"save": "Save",
|
|
10
|
+
"saveAs": "Save As",
|
|
11
|
+
"delete": "Delete",
|
|
12
|
+
"edit": "Edit",
|
|
13
|
+
"add": "Add",
|
|
14
|
+
"upload": "Upload",
|
|
15
|
+
"download": "Download",
|
|
16
|
+
"preview": "Preview",
|
|
17
|
+
"choose": "Choose",
|
|
18
|
+
"placeholder": "Please enter {0}",
|
|
19
|
+
"pleaseSelect": "Please select",
|
|
20
|
+
"pleaseInput": "Please input",
|
|
21
|
+
"all": "All",
|
|
22
|
+
"success": "Success",
|
|
23
|
+
"failed": "Failed",
|
|
24
|
+
"enable": "Enable",
|
|
25
|
+
"disable": "Disable",
|
|
26
|
+
"male": "Male",
|
|
27
|
+
"female": "Female",
|
|
28
|
+
"online": "Online",
|
|
29
|
+
"offline": "Offline",
|
|
30
|
+
"onlineStatus": "Online",
|
|
31
|
+
"offlineStatus": "Offline",
|
|
32
|
+
"refresh": "Refresh",
|
|
33
|
+
"search": "Search",
|
|
34
|
+
"export": "Export",
|
|
35
|
+
"file": "File",
|
|
36
|
+
"total": "Total {0} records",
|
|
37
|
+
"reset": "Reset",
|
|
38
|
+
"more": "More",
|
|
39
|
+
"moreActions": "More Actions",
|
|
40
|
+
"uploadSave": "Upload & Save"
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
"components": {
|
|
44
|
+
"common": {
|
|
45
|
+
"button": {
|
|
46
|
+
"tooltip": "Tooltip Title"
|
|
47
|
+
},
|
|
48
|
+
"icon": {
|
|
49
|
+
"question": "Question",
|
|
50
|
+
"help": "Help"
|
|
51
|
+
},
|
|
52
|
+
"loading": {
|
|
53
|
+
"loading": "Loading"
|
|
54
|
+
},
|
|
55
|
+
"alert": {
|
|
56
|
+
"info": "Info",
|
|
57
|
+
"warning": "Warning",
|
|
58
|
+
"error": "Error"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"content": {
|
|
62
|
+
"dialog": {
|
|
63
|
+
"fileUpload": "File Upload",
|
|
64
|
+
"templateFileManager": "Template File Manager",
|
|
65
|
+
"close": "Close",
|
|
66
|
+
"uploadFile": "Upload File",
|
|
67
|
+
"chooseExcelFile": "Please select Excel file",
|
|
68
|
+
"chooseCsvFile": "Please select CSV file",
|
|
69
|
+
"chooseExcelOrCsvFile": "Please select Excel or CSV file",
|
|
70
|
+
"noValidationRules": "No validation rules set",
|
|
71
|
+
"fieldMustBeUnique": "The following {0} must be unique",
|
|
72
|
+
"combinationMustBeUnique": "The following combination must be unique",
|
|
73
|
+
"validationRules": "Data validation rules to check",
|
|
74
|
+
"duplicateData": "Duplicate data to validate",
|
|
75
|
+
"validationException": "Validation exception",
|
|
76
|
+
"exportFailed": "Export failed"
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
"excelForm": {
|
|
80
|
+
"uploadAddressNotConfigured": "File upload address not configured!",
|
|
81
|
+
"validationError": "Table data has validation errors, please correct before uploading!",
|
|
82
|
+
"pleaseSelectFileFirst": "Please select a file first!",
|
|
83
|
+
"fileUploadSuccess": "File uploaded successfully, starting business processing!",
|
|
84
|
+
"uploadFailed": "Upload processing failed:",
|
|
85
|
+
"unknownError": "Unknown error",
|
|
86
|
+
"onlyExcelAllowed": "Only Excel files can be uploaded!",
|
|
87
|
+
"onlyCsvAllowed": "Only CSV files can be uploaded!",
|
|
88
|
+
"onlyExcelOrCsvAllowed": "Only Excel or CSV files can be uploaded!",
|
|
89
|
+
"csvProcessingFailed": "CSV file processing failed",
|
|
90
|
+
"gridCtrlNotConfigured": "Grid controller not configured!",
|
|
91
|
+
"fileProcessingFailed": "File processing failed, please check file format!",
|
|
92
|
+
"loadFileFailed": "Failed to load file, please check file format!",
|
|
93
|
+
"fileProcessingError": "File processing error",
|
|
94
|
+
"dataSaveFailed": "Data save failed, please try again later!"
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
"listOperate": {
|
|
98
|
+
"confirmDelete": "Are you sure to delete this record?",
|
|
99
|
+
"more": "More"
|
|
100
|
+
},
|
|
101
|
+
"toolpanel": {
|
|
102
|
+
"tool": "Tools",
|
|
103
|
+
"searchResult": "Search Results",
|
|
104
|
+
"list": "List",
|
|
105
|
+
"grid": "Grid",
|
|
106
|
+
"listView": "List View",
|
|
107
|
+
"gridView": "Grid View",
|
|
108
|
+
"expand": "Expand",
|
|
109
|
+
"collapse": "Collapse",
|
|
110
|
+
"expandPanel": "Expand Panel",
|
|
111
|
+
"collapsePanel": "Collapse Panel",
|
|
112
|
+
"searchPlaceholder": "Search tools..."
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"error": {
|
|
116
|
+
"forbidden": "Sorry, you don't have permission to access this page",
|
|
117
|
+
"pageNotFound": "Sorry, the page you visited does not exist",
|
|
118
|
+
"clickReturn": "Click to return"
|
|
119
|
+
},
|
|
120
|
+
"layout": {
|
|
121
|
+
"header": {
|
|
122
|
+
"exitPlatform": "Exit Platform",
|
|
123
|
+
"exitSystem": "Exit System",
|
|
124
|
+
"confirmExit": "Confirm Exit",
|
|
125
|
+
"exitConfirmMessage": "Are you sure you want to exit the system?"
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"form": {
|
|
129
|
+
"upload": {
|
|
130
|
+
"selectFile": "Select File",
|
|
131
|
+
"selectDirectory": "Select Directory",
|
|
132
|
+
"uploading": "Uploading",
|
|
133
|
+
"uploadComplete": "Upload Complete",
|
|
134
|
+
"uploadFailed": "Upload Failed",
|
|
135
|
+
"pendingUpload": "Pending Upload",
|
|
136
|
+
"onlineOrOffline": "Online or Offline",
|
|
137
|
+
"deleteConfirm": "Are you sure to delete this file?",
|
|
138
|
+
"deleteSuccess": "File deleted successfully!",
|
|
139
|
+
"fileSizeExceeded": "File size exceeds {0}MB limit",
|
|
140
|
+
"maxFileCount": "Maximum {0} files can be uploaded",
|
|
141
|
+
"fileTypeRequired": "File must be {0}",
|
|
142
|
+
"maxFileSize": "Maximum file size {0}MB",
|
|
143
|
+
"maxFileCountMsg": "Maximum {0} files",
|
|
144
|
+
"dataLoading": "Loading data...",
|
|
145
|
+
"loadImageFailed": "Failed to load image:",
|
|
146
|
+
"unsupportedFileType": "Unsupported file type",
|
|
147
|
+
"fileSizeExceedsLimit": "File size exceeds {0}MB limit",
|
|
148
|
+
"maxFilesReached": "Maximum {0} files can be uploaded",
|
|
149
|
+
"onlineOffline": "Online or Offline",
|
|
150
|
+
"chooseFile": "Choose File",
|
|
151
|
+
"chooseDirectory": "Choose Directory",
|
|
152
|
+
"confirmDeleteFile": "Are you sure to delete this file?",
|
|
153
|
+
"fileMustBe": "File must be {0}",
|
|
154
|
+
"singleFileMax": "Maximum single file size {0}MB",
|
|
155
|
+
"maxFiles": "Maximum {0} files",
|
|
156
|
+
"pleaseSelectFile": "Please select a file to upload!",
|
|
157
|
+
"allUploadSuccess": "All files uploaded successfully!",
|
|
158
|
+
"partialUploadFailed": "Upload completed, some files failed to upload!",
|
|
159
|
+
"saveUploadSuccess": "Save successfully uploaded files!",
|
|
160
|
+
"partialUploadFailedCancel": "Upload completed, some files failed to upload, save cancelled!",
|
|
161
|
+
"allUploadFailed": "Upload completed, all files failed to upload!",
|
|
162
|
+
"uploadFailedError": "Upload failed",
|
|
163
|
+
"uploadingStatus": "Uploading",
|
|
164
|
+
"unauthorized": "Unauthorized or authorization expired",
|
|
165
|
+
"invalidJson": "Returned result is not in JSON format",
|
|
166
|
+
"uploadSuccessStatus": "Upload successful",
|
|
167
|
+
"parseJsonError": "Unable to parse returned JSON data",
|
|
168
|
+
"uploadFailedStatusCode": "Upload failed, status code:",
|
|
169
|
+
"uploadFailedNetwork": "Upload failed, network error",
|
|
170
|
+
"uploadCanceled": "Upload cancelled",
|
|
171
|
+
"fileUploadSuccess": "File uploaded successfully!",
|
|
172
|
+
"fileUploadFailed": "File upload failed!"
|
|
173
|
+
},
|
|
174
|
+
"select": {
|
|
175
|
+
"pleaseSelect": "Please select {0}",
|
|
176
|
+
"noData": "No data"
|
|
177
|
+
},
|
|
178
|
+
"aceEditor": {
|
|
179
|
+
"title": "Code Editor"
|
|
180
|
+
},
|
|
181
|
+
"switch": {
|
|
182
|
+
"error": "Switch component must have exactly two options"
|
|
183
|
+
},
|
|
184
|
+
"radio": {
|
|
185
|
+
"noData": "No data",
|
|
186
|
+
"all": "All"
|
|
187
|
+
},
|
|
188
|
+
"autoComplete": {
|
|
189
|
+
"pleaseInputAndSelect": "{0} and select"
|
|
190
|
+
},
|
|
191
|
+
"propEditor": {
|
|
192
|
+
"configName": "Config Name",
|
|
193
|
+
"configValue": "Please enter config value",
|
|
194
|
+
"inputConfigValue": "Please enter {0}"
|
|
195
|
+
},
|
|
196
|
+
"transfer": {
|
|
197
|
+
"pleaseInput": "Please enter {0}"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
"stores": {
|
|
203
|
+
"userInfo": {
|
|
204
|
+
"tokenParseFailed": "Token parsing failed",
|
|
205
|
+
"exiting": "Exiting...",
|
|
206
|
+
"logoutSuccess": "Logged out successfully",
|
|
207
|
+
"authInfoFailed": "Failed to get authorization info",
|
|
208
|
+
"userInfoParseFailed": "User info parsing failed"
|
|
209
|
+
},
|
|
210
|
+
"hostInfo": {
|
|
211
|
+
"loading": "Loading site configuration..."
|
|
212
|
+
},
|
|
213
|
+
"appInfo": {
|
|
214
|
+
"loadAppListFailed": "Failed to load application list"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
"utils": {
|
|
219
|
+
"exportTable": {
|
|
220
|
+
"exportFailed": "Export failed",
|
|
221
|
+
"fileExportFailed": "File export failed, please try again later"
|
|
222
|
+
},
|
|
223
|
+
"formValidate": {
|
|
224
|
+
"required": "Cannot be empty",
|
|
225
|
+
"numberType": "Must be a number",
|
|
226
|
+
"enum": "Must be one of {enum}",
|
|
227
|
+
"stringLen": "Length must be {len}",
|
|
228
|
+
"stringMin": "Length cannot be less than {min}",
|
|
229
|
+
"stringMax": "Length cannot be greater than {max}",
|
|
230
|
+
"stringRange": "Length must be between {min} and {max}",
|
|
231
|
+
"numberLen": "Must be {len}",
|
|
232
|
+
"numberMin": "Cannot be less than {min}",
|
|
233
|
+
"numberMax": "Cannot be greater than {max}",
|
|
234
|
+
"numberRange": "Must be between {min} and {max}",
|
|
235
|
+
"arrayLen": "Length must be {len}",
|
|
236
|
+
"arrayMin": "Length cannot be less than {min}",
|
|
237
|
+
"arrayMax": "Length cannot be greater than {max}",
|
|
238
|
+
"arrayRange": "Length must be between {min} and {max}",
|
|
239
|
+
"formatValidationError": "Error formatting validation message",
|
|
240
|
+
"processValidationError": "Error processing validation rules"
|
|
241
|
+
},
|
|
242
|
+
"fileUpload": {
|
|
243
|
+
"pleaseSelectFile": "Please select a file to upload!",
|
|
244
|
+
"allUploadSuccess": "All files uploaded successfully!",
|
|
245
|
+
"partialUploadFailed": "Upload completed, some files failed to upload!",
|
|
246
|
+
"saveUploadSuccess": "Save successfully uploaded files!",
|
|
247
|
+
"partialUploadFailedCancel": "Upload completed, some files failed to upload, save cancelled!",
|
|
248
|
+
"allUploadFailed": "Upload completed, all files failed to upload!",
|
|
249
|
+
"fileUploadSuccess": "File uploaded successfully!",
|
|
250
|
+
"fileUploadFailed": "File upload failed!"
|
|
251
|
+
},
|
|
252
|
+
"data": {
|
|
253
|
+
"executeSuccess": "Execution successful!",
|
|
254
|
+
"noDataToSave": "Error! No data to save!",
|
|
255
|
+
"saveSuccess": "Save successful!",
|
|
256
|
+
"conditionalDeleteForbidden": "Error! Unconditional data deletion is forbidden!",
|
|
257
|
+
"deleteSuccess": "Delete successful!"
|
|
258
|
+
},
|
|
259
|
+
"download": {
|
|
260
|
+
"downloadFailed": "File download failed!",
|
|
261
|
+
"fileDownloadFailed": "File download failed, please try again later",
|
|
262
|
+
"fileTypeNotSupported": "File type not supported for preview",
|
|
263
|
+
"filePreviewFailed": "File preview failed!"
|
|
264
|
+
},
|
|
265
|
+
"formExcel": {
|
|
266
|
+
"excelNoSheets": "Excel file does not contain worksheets",
|
|
267
|
+
"excelInsufficientData": "Excel file does not contain enough data",
|
|
268
|
+
"validationError": "Error occurred while validating table data",
|
|
269
|
+
"missingDuplicateFields": "Table header missing fields required for duplicate detection",
|
|
270
|
+
"fileNotExcel": "Uploaded file is not an Excel file",
|
|
271
|
+
"processFailed": "Excel file processing failed",
|
|
272
|
+
"validationSuccess": "Data validation successful",
|
|
273
|
+
"duplicateValidationPending": "Duplicate data to validate",
|
|
274
|
+
"validationFailed": "Data validation failed",
|
|
275
|
+
"validationPassed": "Data validation passed",
|
|
276
|
+
"duplicateDetected": "Duplicate data detected",
|
|
277
|
+
"duplicateCheckPassed": "Duplicate check passed"
|
|
278
|
+
},
|
|
279
|
+
"options": {
|
|
280
|
+
"notConfigured": "Options data not configured!"
|
|
281
|
+
},
|
|
282
|
+
"form": {
|
|
283
|
+
"submitValidationFailed": "Validation failed when submitting form!",
|
|
284
|
+
"saveSuccess": "Save successful!",
|
|
285
|
+
"dataAlreadyExists": "Save failed! Data `{0}` already exists!",
|
|
286
|
+
"saveFailed": "Save failed!"
|
|
287
|
+
},
|
|
288
|
+
"excelPreview": {
|
|
289
|
+
"previewUrlNotConfigured": "Preview URL or Excel controller not configured",
|
|
290
|
+
"fileLoadFailed": "File load failed"
|
|
291
|
+
},
|
|
292
|
+
"tools": {
|
|
293
|
+
"noClickHandler": "Click handler not configured!",
|
|
294
|
+
"refreshTable": "Refresh Table",
|
|
295
|
+
"expandSearch": "Expand Search Bar",
|
|
296
|
+
"collapseSearch": "Collapse Search Bar",
|
|
297
|
+
"rowHeight": "Adjust Row Height",
|
|
298
|
+
"showCheckbox": "Show Checkbox",
|
|
299
|
+
"hideCheckbox": "Hide Checkbox",
|
|
300
|
+
"expandRows": "Expand Rows",
|
|
301
|
+
"collapseRows": "Collapse Rows",
|
|
302
|
+
"exportExcel": "Export Excel",
|
|
303
|
+
"exportAllRecords": "All Records",
|
|
304
|
+
"exportSelectedRecords": "Selected Records",
|
|
305
|
+
"exportPDF": "Export PDF",
|
|
306
|
+
"tableHeaderSettings": "Table Header Settings",
|
|
307
|
+
"setFullscreen": "Set Fullscreen",
|
|
308
|
+
"exitFullscreen": "Exit Fullscreen"
|
|
309
|
+
},
|
|
310
|
+
"iconLoader": {
|
|
311
|
+
"networkError": "Network error, unable to load icon library!"
|
|
312
|
+
},
|
|
313
|
+
"formCsv": {
|
|
314
|
+
"csvToExcelFailed": "CSV to Excel conversion failed",
|
|
315
|
+
"csvProcessFailed": "CSV file processing failed",
|
|
316
|
+
"unknownError": "Unknown error"
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
package/src/locales/index.ts
CHANGED
|
@@ -7,22 +7,37 @@ export interface LocaleMessages {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* 深度合并两个对象,确保不修改原始数据,创建新对象
|
|
11
11
|
* @param target 目标对象
|
|
12
12
|
* @param source 源对象
|
|
13
|
-
* @returns
|
|
13
|
+
* @returns 合并后的新对象
|
|
14
14
|
*/
|
|
15
15
|
function deepMerge(target: any, source: any): any {
|
|
16
|
-
|
|
16
|
+
// 创建新的结果对象,确保不修改原始数据
|
|
17
|
+
const result: any = Array.isArray(target) ? [] : {};
|
|
17
18
|
|
|
19
|
+
// 首先复制target的所有属性到新对象
|
|
20
|
+
for (const key in target) {
|
|
21
|
+
if (target.hasOwnProperty(key)) {
|
|
22
|
+
if (typeof target[key] === 'object' && target[key] !== null && !Array.isArray(target[key])) {
|
|
23
|
+
// 如果是对象,递归创建新对象
|
|
24
|
+
result[key] = deepMerge(target[key], {});
|
|
25
|
+
} else {
|
|
26
|
+
// 如果是基本类型或数组,直接复制
|
|
27
|
+
result[key] = Array.isArray(target[key]) ? [...target[key]] : target[key];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 然后合并source的属性
|
|
18
33
|
for (const key in source) {
|
|
19
34
|
if (source.hasOwnProperty(key)) {
|
|
20
35
|
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
|
|
21
36
|
// 如果源值是对象且不是数组,则递归合并
|
|
22
37
|
result[key] = deepMerge(result[key] || {}, source[key]);
|
|
23
38
|
} else {
|
|
24
|
-
//
|
|
25
|
-
result[key] = source[key];
|
|
39
|
+
// 否则直接赋值(对于数组,创建新数组)
|
|
40
|
+
result[key] = Array.isArray(source[key]) ? [...source[key]] : source[key];
|
|
26
41
|
}
|
|
27
42
|
}
|
|
28
43
|
}
|
|
@@ -38,15 +53,20 @@ export let LOCALE_DISPLAY_NAMES: Record<string, string> = {
|
|
|
38
53
|
"zh-CN": "简体中文"
|
|
39
54
|
};
|
|
40
55
|
|
|
41
|
-
// 支持的语言包映射
|
|
42
|
-
const loadedMessages: Record<string, LocaleMessages> = {
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
// 支持的语言包映射 - 初始为空,等待加载
|
|
57
|
+
const loadedMessages: Record<string, LocaleMessages> = {};
|
|
58
|
+
|
|
59
|
+
// 从localStorage获取语言设置
|
|
60
|
+
function getStoredLocale(): string {
|
|
61
|
+
// 从localStorage获取,如果存在就返回,不存在则默认返回中文
|
|
62
|
+
const storedLang = localStorage.getItem("language");
|
|
63
|
+
return storedLang || 'zh-CN';
|
|
64
|
+
}
|
|
45
65
|
|
|
46
|
-
// 创建i18n实例
|
|
66
|
+
// 创建i18n实例 - 初始为空消息
|
|
47
67
|
export const i18n = createI18n({
|
|
48
68
|
legacy: false, // 使用Composition API模式
|
|
49
|
-
locale:
|
|
69
|
+
locale: getStoredLocale(), // 从localStorage获取语言设置
|
|
50
70
|
fallbackLocale: "en-US", // 回退语言
|
|
51
71
|
messages: loadedMessages,
|
|
52
72
|
silentTranslationWarn: true, // 禁用翻译警告
|
|
@@ -58,6 +78,7 @@ export const i18n = createI18n({
|
|
|
58
78
|
|
|
59
79
|
/**
|
|
60
80
|
* 从云端加载语言包
|
|
81
|
+
* 注意:此函数只返回云端数据,不进行合并,合并逻辑在调用方处理
|
|
61
82
|
*/
|
|
62
83
|
async function loadLocaleFromCloud(locale: string): Promise<LocaleMessages> {
|
|
63
84
|
try {
|
|
@@ -66,16 +87,11 @@ async function loadLocaleFromCloud(locale: string): Promise<LocaleMessages> {
|
|
|
66
87
|
throw new Error(`Failed to load locale ${locale}`);
|
|
67
88
|
}
|
|
68
89
|
const cloudMessages = await response.json();
|
|
69
|
-
|
|
70
|
-
// 使用深度合并更新语言包
|
|
71
|
-
if (loadedMessages[locale]) {
|
|
72
|
-
return deepMerge(loadedMessages[locale], cloudMessages);
|
|
73
|
-
}
|
|
74
90
|
return cloudMessages;
|
|
75
91
|
} catch (error) {
|
|
76
92
|
console.error(`Error loading locale ${locale}:`, error);
|
|
77
|
-
//
|
|
78
|
-
return
|
|
93
|
+
// 如果加载失败,返回空对象
|
|
94
|
+
return {};
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
97
|
|
|
@@ -187,35 +203,62 @@ export function getI18nMessages(
|
|
|
187
203
|
|
|
188
204
|
/**
|
|
189
205
|
* 加载语言包 - 使用缓存优先策略
|
|
206
|
+
* 实现合并逻辑:loadLocaleFromCloud未加载前,低defaultLocale+本地缓存高
|
|
207
|
+
* 确保不修改原始数据,创建新对象
|
|
190
208
|
*/
|
|
191
209
|
async function loadLocale(locale: string): Promise<void> {
|
|
192
210
|
// 优先使用缓存
|
|
193
211
|
const cachedMessages = getCachedLocale(locale);
|
|
212
|
+
|
|
213
|
+
// 合并逻辑:低defaultLocale + 本地缓存高
|
|
214
|
+
let finalMessages: LocaleMessages;
|
|
194
215
|
if (cachedMessages) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
216
|
+
// 本地缓存优先级高于defaultLocale,确保创建新对象
|
|
217
|
+
finalMessages = deepMerge(JSON.parse(JSON.stringify(defaultLocale)), cachedMessages);
|
|
218
|
+
|
|
219
|
+
} else {
|
|
220
|
+
// 没有缓存,只有zh-CN才使用defaultLocale
|
|
221
|
+
if (locale === 'zh-CN') {
|
|
222
|
+
finalMessages = JSON.parse(JSON.stringify(defaultLocale));
|
|
223
|
+
|
|
224
|
+
} else {
|
|
225
|
+
// 其他语言没有缓存时,使用空对象
|
|
226
|
+
finalMessages = {};
|
|
198
227
|
|
|
199
|
-
// 异步后台更新:无论是否有缓存,都后台检查更新
|
|
200
|
-
setTimeout(async () => {
|
|
201
|
-
try {
|
|
202
|
-
// 后台异步加载最新语言包并直接更新缓存和内存
|
|
203
|
-
const freshMessages = await loadLocaleFromCloud(locale);
|
|
204
|
-
loadedMessages[locale] = freshMessages;
|
|
205
|
-
i18n.global.setLocaleMessage(locale, freshMessages);
|
|
206
|
-
cacheLocale(locale, freshMessages);
|
|
207
|
-
} catch (error) {
|
|
208
|
-
console.error("[Locale] Background update failed:", error);
|
|
209
228
|
}
|
|
210
|
-
}
|
|
211
|
-
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 存入本地内存和缓存
|
|
232
|
+
loadedMessages[locale] = finalMessages;
|
|
233
|
+
i18n.global.setLocaleMessage(locale, finalMessages);
|
|
234
|
+
cacheLocale(locale, finalMessages);
|
|
235
|
+
|
|
212
236
|
|
|
237
|
+
// 强制加载更新:无论是否有缓存,都强制加载最新语言包
|
|
238
|
+
try {
|
|
239
|
+
// 强制加载最新语言包并直接更新缓存和内存
|
|
240
|
+
const freshMessages = await loadLocaleFromCloud(locale);
|
|
241
|
+
|
|
242
|
+
// 合并逻辑:低defaultLocale + loadLocaleFromCloud高,确保创建新对象
|
|
243
|
+
const updatedMessages = deepMerge(JSON.parse(JSON.stringify(defaultLocale)), freshMessages);
|
|
244
|
+
|
|
245
|
+
loadedMessages[locale] = updatedMessages;
|
|
246
|
+
i18n.global.setLocaleMessage(locale, updatedMessages);
|
|
247
|
+
cacheLocale(locale, updatedMessages);
|
|
248
|
+
|
|
249
|
+
} catch (error) {
|
|
250
|
+
// 加载失败时跳过,不报错
|
|
251
|
+
|
|
252
|
+
}
|
|
253
|
+
}
|
|
213
254
|
/**
|
|
214
255
|
* 初始化语言 - 使用缓存优先+异步后台加载策略
|
|
215
256
|
* @param rootDir 根目录路径,默认为 "/"
|
|
216
|
-
* @param locale
|
|
257
|
+
* @param locale 默认语言,默认从localStorage获取
|
|
217
258
|
*/
|
|
218
|
-
export async function initLang(rootDir: string = "/", locale
|
|
259
|
+
export async function initLang(rootDir: string = "/", locale?: string): Promise<void> {
|
|
260
|
+
|
|
261
|
+
|
|
219
262
|
// 设置根目录路径供其他函数使用
|
|
220
263
|
ROOT_DIR = rootDir;
|
|
221
264
|
|
|
@@ -231,11 +274,12 @@ export async function initLang(rootDir: string = "/", locale: string = "zh-CN"):
|
|
|
231
274
|
// 只有在网络错误等真正异常情况下才记录错误(但仍不显示给用户)
|
|
232
275
|
// fetch的网络错误通常是TypeError,而HTTP错误状态码不会触发catch
|
|
233
276
|
if (error instanceof TypeError) {
|
|
234
|
-
console.error('Network error
|
|
277
|
+
console.error('[Locale] Network error:', error);
|
|
235
278
|
}
|
|
236
279
|
}
|
|
237
280
|
|
|
238
|
-
|
|
281
|
+
// 优先使用localStorage存储的语言,其次使用传入的locale,最后默认使用中文
|
|
282
|
+
const savedLocale = localStorage.getItem("language") || locale || 'zh-CN';
|
|
239
283
|
|
|
240
284
|
// 设置当前语言
|
|
241
285
|
i18n.global.locale.value = savedLocale;
|
|
@@ -243,6 +287,7 @@ export async function initLang(rootDir: string = "/", locale: string = "zh-CN"):
|
|
|
243
287
|
|
|
244
288
|
// 统一调用loadLocale处理缓存,不加载,由后面代码
|
|
245
289
|
await loadLocale(savedLocale);
|
|
290
|
+
|
|
246
291
|
}
|
|
247
292
|
|
|
248
293
|
/**
|
|
@@ -280,10 +325,35 @@ export function $t(key: string, params?: Record<string, any>): string {
|
|
|
280
325
|
try {
|
|
281
326
|
// @ts-ignore
|
|
282
327
|
const result = i18n.global.t(key, params);
|
|
283
|
-
//
|
|
328
|
+
// 如果返回的是翻译键本身,说明没有找到翻译
|
|
329
|
+
if (result === key) {
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
// 检查当前messages是否为空
|
|
333
|
+
const currentMessages = i18n.global.getLocaleMessage(i18n.global.locale.value);
|
|
334
|
+
const isMessagesEmpty = !currentMessages || Object.keys(currentMessages).length === 0;
|
|
335
|
+
|
|
336
|
+
if (isMessagesEmpty) {
|
|
337
|
+
// 从localStorage缓存获取翻译内容
|
|
338
|
+
const cachedMessages = getCachedLocale(i18n.global.locale.value);
|
|
339
|
+
if (cachedMessages) {
|
|
340
|
+
// 使用缓存恢复整个语言包
|
|
341
|
+
const updatedMessages = deepMerge({}, cachedMessages);
|
|
342
|
+
i18n.global.setLocaleMessage(i18n.global.locale.value, updatedMessages);
|
|
343
|
+
cacheLocale(i18n.global.locale.value, updatedMessages);
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
// 重新获取翻译
|
|
348
|
+
const retryResult = i18n.global.t(key, params || {});
|
|
349
|
+
return retryResult === key ? key : retryResult;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
284
353
|
return result;
|
|
285
354
|
} catch (error) {
|
|
286
|
-
//
|
|
355
|
+
// 如果翻译出错,返回原始key
|
|
356
|
+
console.error(`Translation error for key: ${key}`, error);
|
|
287
357
|
return key;
|
|
288
358
|
}
|
|
289
359
|
}
|
package/src/stores/hostInfo.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { HostUrlList } from '@/const/stores';
|
|
1
2
|
import { MicroOpenApis } from '@/utils/micro-openapis';
|
|
2
|
-
import { API_HOST, ApiResponse, httpPost,
|
|
3
|
+
import { API_HOST, ApiResponse, httpPost, ResStatus, SERVER_HOST } from '@skyfox2000/fapi';
|
|
3
4
|
|
|
4
5
|
import { HostInfo, isMicroApp } from '@skyfox2000/microbase';
|
|
5
6
|
|
|
@@ -9,24 +10,6 @@ import { defineStore } from 'pinia';
|
|
|
9
10
|
|
|
10
11
|
// const HOSTINFO_STORE_KEY = 'hostInfoStore';
|
|
11
12
|
|
|
12
|
-
/** 站点相关接口 */
|
|
13
|
-
const HostUrlList: {
|
|
14
|
-
/** 站点信息 */
|
|
15
|
-
host: IUrlInfo;
|
|
16
|
-
} = {
|
|
17
|
-
host: {
|
|
18
|
-
api: 'SITEHOST_API',
|
|
19
|
-
url: '/openapi/RCSiteHostSrv/get',
|
|
20
|
-
fieldMap: {
|
|
21
|
-
hostId: 'Id',
|
|
22
|
-
hostName: 'Title',
|
|
23
|
-
},
|
|
24
|
-
loadingText: '站点配置加载中……',
|
|
25
|
-
// 不显示错误
|
|
26
|
-
hideErrorToast: true,
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
13
|
export const useHostInfo = defineStore('hostInfo', {
|
|
31
14
|
state: (): {
|
|
32
15
|
hostInfo: HostInfo;
|
package/src/stores/userInfo.ts
CHANGED
|
@@ -1,43 +1,15 @@
|
|
|
1
1
|
import { defineStore } from 'pinia';
|
|
2
|
-
import { ApiResponse, httpPost,
|
|
2
|
+
import { ApiResponse, httpPost, ReqParams, ResStatus, setToken } from '@skyfox2000/fapi';
|
|
3
3
|
import message from 'vue-m-message';
|
|
4
4
|
import { isMicroApp, LoginInfo, UserInfo } from '@skyfox2000/microbase';
|
|
5
5
|
import { ref } from 'vue';
|
|
6
6
|
import { useAppInfo } from './appInfo';
|
|
7
7
|
import { MicroOpenApis } from '@/utils/micro-openapis';
|
|
8
8
|
import { $t } from '@/locales/index';
|
|
9
|
+
import { LoginUrlList, TokenError } from '@/const/stores';
|
|
9
10
|
|
|
10
|
-
const TokenError = $t('webui.stores.userInfo.tokenParseFailed');
|
|
11
11
|
export const LoginExpiredError = 1400;
|
|
12
12
|
|
|
13
|
-
/** 登录相关接口 */
|
|
14
|
-
const LoginUrlList: {
|
|
15
|
-
/** 登录信息 */
|
|
16
|
-
login: IUrlInfo;
|
|
17
|
-
/** 获取界面授权 */
|
|
18
|
-
auth: IUrlInfo;
|
|
19
|
-
/** 退出登录 */
|
|
20
|
-
logout: IUrlInfo;
|
|
21
|
-
} = {
|
|
22
|
-
login: {
|
|
23
|
-
api: 'PLATFORM_API',
|
|
24
|
-
url: '/openapi/LoginSrv/login',
|
|
25
|
-
loadingText: false,
|
|
26
|
-
},
|
|
27
|
-
auth: {
|
|
28
|
-
api: 'PLATFORM_API',
|
|
29
|
-
authorize: true,
|
|
30
|
-
url: '/api/RCAccountOpSrv/getPermits',
|
|
31
|
-
loadingText: false,
|
|
32
|
-
},
|
|
33
|
-
logout: {
|
|
34
|
-
api: 'PLATFORM_API',
|
|
35
|
-
authorize: true,
|
|
36
|
-
url: '/api/LoginSrv/logout',
|
|
37
|
-
loadingText: $t('webui.stores.userInfo.exiting'),
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
|
|
41
13
|
/**
|
|
42
14
|
* 登录接口操作
|
|
43
15
|
* @param loginInfo 登录信息
|
package/src/utils/options.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ReqParams,
|
|
9
9
|
ResStatus,
|
|
10
10
|
} from '@skyfox2000/fapi';
|
|
11
|
-
import {$t} from '@/locales/index';
|
|
11
|
+
import { $t } from '@/locales/index';
|
|
12
12
|
import { inject, ref, watch } from 'vue';
|
|
13
13
|
import { OptionItemProps, SelectValue, OptionControl, OptionProps } from '@/typings/option.d';
|
|
14
14
|
import { ProviderKeys } from '@/typings/page.d';
|
|
@@ -69,7 +69,7 @@ const updateOptions = (optionCtrl: OptionControl, data: Record<string, AnyData>[
|
|
|
69
69
|
data = JSON.parse(JSON.stringify(data ?? []));
|
|
70
70
|
if (optionCtrl.all) {
|
|
71
71
|
data.unshift({
|
|
72
|
-
label: '
|
|
72
|
+
label: $t('webui.components.form.radio.all'),
|
|
73
73
|
value: optionCtrl.allValue ?? undefined,
|
|
74
74
|
});
|
|
75
75
|
}
|