@liujitcn/kratos-uni-app-core 0.0.21 → 0.0.23
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 +1 -1
- package/dist/module.mjs +653 -670
- package/dist/vite.mjs +5 -3
- package/package.json +1 -1
- package/src/api/base/language.ts +5 -5
- package/src/bootstrap.ts +1 -1
- package/src/locales/README.md +2 -2
- package/src/locales/en-US.json +65 -68
- package/src/locales/es-ES.json +88 -91
- package/src/locales/fr-FR.json +92 -95
- package/src/locales/generated.ts +22 -0
- package/src/locales/index.ts +48 -67
- package/src/locales/ja-JP.json +78 -81
- package/src/locales/ko-KR.json +87 -90
- package/src/locales/zh-CN.json +65 -68
- package/src/locales/zh-TW.json +65 -68
- package/src/module.ts +3 -17
- package/src/navigation.ts +32 -13
- package/src/rpc/base/v1/config.ts +12 -1
- package/src/rpc/base/v1/language.ts +7 -13
- package/src/rpc/base/v1/login.ts +14 -1
- package/src/stores/modules/setting.ts +3 -3
- package/src/utils/file.ts +2 -2
- package/src/utils/http.ts +5 -5
- package/src/utils/passwordCrypto.ts +14 -14
- package/src/views/pages/index/index.vue +12 -12
- package/src/views/pages/login/login.vue +47 -33
- package/src/views/pages/login/protocal.vue +2 -2
- package/src/views/pages/status/index.vue +9 -8
- package/src/views/pages/webview/webview.vue +4 -4
- package/src/vite.ts +4 -3
- package/src/rpc/base/v1/enum.ts +0 -54
- package/src/rpc/system/common/v1/enum.ts +0 -80
package/src/locales/zh-TW.json
CHANGED
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
"common.action.login": "登入",
|
|
6
6
|
"common.action.logout": "退出登入",
|
|
7
7
|
"common.action.new": "新建",
|
|
8
|
-
"common.action.
|
|
9
|
-
"common.action.retry": "重試",
|
|
8
|
+
"common.action.open_in_new_window": "新視窗開啟",
|
|
10
9
|
"common.action.save": "儲存",
|
|
11
|
-
"common.action.search": "搜尋",
|
|
12
10
|
"common.field.language": "語言",
|
|
13
11
|
"common.language.en-US": "English",
|
|
14
12
|
"common.language.ja-JP": "日本語",
|
|
@@ -18,93 +16,92 @@
|
|
|
18
16
|
"common.language.fr-FR": "法語",
|
|
19
17
|
"common.language.es-ES": "西班牙語",
|
|
20
18
|
"common.message.loading": "正在載入",
|
|
21
|
-
"common.message.
|
|
22
|
-
"common.message.
|
|
19
|
+
"common.message.network_error": "網路錯誤,換個網路試試",
|
|
20
|
+
"common.message.request_error": "請求錯誤",
|
|
23
21
|
"common.message.unknown": "暫時無法處理,請稍後重試",
|
|
24
22
|
"common.title.notice": "提示",
|
|
25
|
-
"core.auth.
|
|
26
|
-
"core.auth.
|
|
23
|
+
"core.auth.login_again": "重新登入",
|
|
24
|
+
"core.auth.session_expired": "當前頁面已失效,請重新登入",
|
|
27
25
|
"core.config.missing": "移動端配置缺失:{names}",
|
|
28
|
-
"core.crypto.
|
|
29
|
-
"core.crypto.
|
|
30
|
-
"core.crypto.
|
|
31
|
-
"core.crypto.
|
|
32
|
-
"core.crypto.
|
|
33
|
-
"core.crypto.
|
|
34
|
-
"core.crypto.
|
|
26
|
+
"core.crypto.base64_decode_unsupported": "當前環境不支援 Base64 解碼",
|
|
27
|
+
"core.crypto.base64_encode_unsupported": "當前環境不支援 Base64 編碼",
|
|
28
|
+
"core.crypto.encrypt_failed": "密碼加密失敗",
|
|
29
|
+
"core.crypto.password_required": "密碼不能為空",
|
|
30
|
+
"core.crypto.password_too_long": "密碼長度超出限制",
|
|
31
|
+
"core.crypto.public_key_invalid": "公鑰格式無效",
|
|
32
|
+
"core.crypto.random_failed": "隨機數生成失敗",
|
|
35
33
|
"core.crypto.unsupported": "當前環境不支援密碼加密",
|
|
36
|
-
"core.file.
|
|
37
|
-
"core.home.
|
|
38
|
-
"core.home.
|
|
39
|
-
"core.home.
|
|
40
|
-
"core.home.
|
|
41
|
-
"core.home.
|
|
34
|
+
"core.file.upload_failed": "上傳失敗",
|
|
35
|
+
"core.home.account_capability": "賬戶能力",
|
|
36
|
+
"core.home.account_capability_description": "個人資料、應用設定與智慧助手入口已保留",
|
|
37
|
+
"core.home.cross_platform": "跨端頁面",
|
|
38
|
+
"core.home.cross_platform_description": "同一套頁面程式碼適配 H5 和微信小程式",
|
|
39
|
+
"core.home.demo_scope": "演示範圍",
|
|
42
40
|
"core.home.framework": "應用框架",
|
|
43
41
|
"core.home.language": "開發語言",
|
|
44
|
-
"core.home.
|
|
45
|
-
"core.home.
|
|
46
|
-
"core.home.
|
|
47
|
-
"core.home.
|
|
48
|
-
"core.home.
|
|
49
|
-
"core.home.
|
|
50
|
-
"core.home.
|
|
51
|
-
"core.login.
|
|
52
|
-
"core.login.
|
|
53
|
-
"core.login.
|
|
54
|
-
"core.login.
|
|
55
|
-
"core.login.
|
|
56
|
-
"core.login.
|
|
57
|
-
"core.login.
|
|
42
|
+
"core.home.main_title": "應用框架示例",
|
|
43
|
+
"core.home.state_management": "狀態管理",
|
|
44
|
+
"core.home.static_home": "靜態首頁",
|
|
45
|
+
"core.home.static_home_description": "當前首頁用於展示框架資訊,不依賴業務介面",
|
|
46
|
+
"core.home.style_solution": "樣式方案",
|
|
47
|
+
"core.home.sub_title": "保留通用導航與個人中心體驗",
|
|
48
|
+
"core.home.tech_stack": "當前技術棧",
|
|
49
|
+
"core.login.agree_prefix": "我已閱讀並同意",
|
|
50
|
+
"core.login.agree_separator": "和",
|
|
51
|
+
"core.login.behavior_click": "請按順序點選文字",
|
|
52
|
+
"core.login.behavior_loading": "載入中...",
|
|
53
|
+
"core.login.behavior_puzzle": "請拖動滑塊完成拼圖",
|
|
54
|
+
"core.login.behavior_rotate": "拖動滑塊,將內圈圖片轉正",
|
|
55
|
+
"core.login.bind_wechat": "登入並繫結微信",
|
|
58
56
|
"core.login.captcha": "請輸入驗證碼",
|
|
59
|
-
"core.login.
|
|
60
|
-
"core.login.
|
|
61
|
-
"core.login.
|
|
62
|
-
"core.login.
|
|
63
|
-
"core.login.
|
|
64
|
-
"core.login.
|
|
65
|
-
"core.login.
|
|
66
|
-
"core.login.loginSuccess": "登入成功",
|
|
57
|
+
"core.login.captcha_load_failed": "驗證碼載入失敗",
|
|
58
|
+
"core.login.captcha_type_missing": "登入驗證碼型別未配置",
|
|
59
|
+
"core.login.captcha_type_name": "登入驗證碼型別",
|
|
60
|
+
"core.login.captcha_type_response_missing": "驗證碼介面未返回型別",
|
|
61
|
+
"core.login.captcha_write_failed": "驗證碼圖片寫入失敗",
|
|
62
|
+
"core.login.default_sub_title": "歡迎使用本應用",
|
|
63
|
+
"core.login.login_success": "登入成功",
|
|
67
64
|
"core.login.password": "請輸入密碼",
|
|
68
65
|
"core.login.privacy": "《隱私協議》",
|
|
69
|
-
"core.login.
|
|
70
|
-
"core.login.
|
|
66
|
+
"core.login.protocol_missing": "服務條款和隱私協議未配置",
|
|
67
|
+
"core.login.protocol_prompt": "請先閱讀並勾選協議內容,點選確定後將自動勾選並繼續登入",
|
|
71
68
|
"core.login.service": "《服務條款》",
|
|
72
69
|
"core.login.tenant": "請輸入租戶編號",
|
|
73
|
-
"core.login.
|
|
74
|
-
"core.login.
|
|
75
|
-
"core.login.
|
|
70
|
+
"core.login.user_name": "請輸入使用者名稱或手機號",
|
|
71
|
+
"core.login.user_name_mobile": "請輸入使用者名稱/手機號碼",
|
|
72
|
+
"core.login.user_name_password": "請輸入使用者名稱和密碼",
|
|
76
73
|
"core.login.wechat": "微信一鍵登入",
|
|
77
|
-
"core.login.
|
|
78
|
-
"core.login.
|
|
74
|
+
"core.login.wechat_bind_tip": "該微信尚未繫結,請登入已有賬號完成繫結",
|
|
75
|
+
"core.login.wechat_failed": "微信登入失敗,請稍後重試",
|
|
79
76
|
"core.navigation.home": "首頁",
|
|
80
77
|
"core.navigation.error.access": "選單訪問模式無效:{access}",
|
|
81
|
-
"core.navigation.error.
|
|
78
|
+
"core.navigation.error.child_tab": "只有移動端二級選單可以作為 tab:{name}",
|
|
82
79
|
"core.navigation.error.cycle": "移動端選單存在迴圈父級:{name}",
|
|
83
80
|
"core.navigation.error.identity": "選單 id、name 或 app/ 路徑無效",
|
|
84
|
-
"core.navigation.error.
|
|
85
|
-
"core.navigation.error.
|
|
86
|
-
"core.navigation.error.
|
|
87
|
-
"core.navigation.error.
|
|
88
|
-
"core.navigation.error.
|
|
89
|
-
"core.navigation.error.
|
|
90
|
-
"core.navigation.error.
|
|
91
|
-
"core.navigation.error.
|
|
92
|
-
"core.navigation.error.
|
|
81
|
+
"core.navigation.error.item_object": "選單項不是物件",
|
|
82
|
+
"core.navigation.error.list_missing": "選單響應缺少扁平列表",
|
|
83
|
+
"core.navigation.error.name_prefix": "選單名稱必須使用 App 字首:{name}",
|
|
84
|
+
"core.navigation.error.parent_invalid": "移動端選單父級編號無效:{name}",
|
|
85
|
+
"core.navigation.error.parent_missing": "選單缺少父級編號:{name}",
|
|
86
|
+
"core.navigation.error.parent_not_found": "移動端選單父級不存在:{name}",
|
|
87
|
+
"core.navigation.error.response_object": "選單響應不是物件",
|
|
88
|
+
"core.navigation.error.root_tab": "移動端二級選單必須作為 tab:{name}",
|
|
89
|
+
"core.navigation.error.tab_count": "tabBar 只能配置 0 或 2-5 項",
|
|
93
90
|
"core.navigation.error.unique": "選單 id、name、path 必須唯一",
|
|
94
|
-
"core.navigation.error.
|
|
91
|
+
"core.navigation.error.view_key": "未註冊 viewKey:{viewKey}",
|
|
95
92
|
"core.navigation.my": "我的",
|
|
96
93
|
"core.navigation.protocol": "協議詳情",
|
|
97
|
-
"core.protocol.
|
|
98
|
-
"core.protocol.
|
|
94
|
+
"core.protocol.load_failed": "移動端配置載入失敗",
|
|
95
|
+
"core.protocol.not_configured": "{title}未配置,暫時無法檢視",
|
|
99
96
|
"core.protocol.privacy": "隱私協議",
|
|
100
97
|
"core.protocol.service": "服務條款",
|
|
101
98
|
"core.status.CONFIG_ERROR": "導航配置無效",
|
|
102
|
-
"core.status.
|
|
99
|
+
"core.status.forbidden": "暫無訪問許可權",
|
|
103
100
|
"core.status.NOT_FOUND": "頁面不存在",
|
|
104
|
-
"core.status.
|
|
105
|
-
"core.status.
|
|
101
|
+
"core.status.offline": "網路不可用",
|
|
102
|
+
"core.status.page_unavailable": "頁面暫不可用",
|
|
106
103
|
"core.status.loading": "正在載入",
|
|
107
|
-
"core.webview.
|
|
108
|
-
"core.webview.
|
|
109
|
-
"core.webview.
|
|
104
|
+
"core.webview.embed_blocked": "當前 H5 頁面可能被目標站點限制嵌入",
|
|
105
|
+
"core.webview.invalid_url": "缺少有效連結地址",
|
|
106
|
+
"core.webview.open_failed": "連結無法開啟"
|
|
110
107
|
}
|
package/src/module.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { corePages } from './pages'
|
|
2
2
|
import type { LocaleMessages, SupportedLocale } from './locales'
|
|
3
3
|
|
|
4
|
-
// Core
|
|
5
|
-
import
|
|
6
|
-
import coreJaJP from './locales/ja-JP.json'
|
|
7
|
-
import coreZhCN from './locales/zh-CN.json'
|
|
8
|
-
import coreZhTW from './locales/zh-TW.json'
|
|
9
|
-
import coreKoKR from './locales/ko-KR.json'
|
|
10
|
-
import coreFrFR from './locales/fr-FR.json'
|
|
11
|
-
import coreEsES from './locales/es-ES.json'
|
|
4
|
+
// Core 语言包由同步脚本生成并注册,供 uni-app 公共页面、请求工具和基础组件使用。
|
|
5
|
+
import { LOCALE_MESSAGES } from './locales/generated'
|
|
12
6
|
|
|
13
7
|
/** bootstrap 可见状态键。 */
|
|
14
8
|
export type BootstrapViewKey =
|
|
@@ -94,13 +88,5 @@ export const coreModule = defineKratosAppModule({
|
|
|
94
88
|
USER_DEFAULT: 'static/tabs/user_default.png',
|
|
95
89
|
USER_SELECTED: 'static/tabs/user_selected.png',
|
|
96
90
|
},
|
|
97
|
-
messages:
|
|
98
|
-
'zh-CN': coreZhCN,
|
|
99
|
-
'zh-TW': coreZhTW,
|
|
100
|
-
'ko-KR': coreKoKR,
|
|
101
|
-
'fr-FR': coreFrFR,
|
|
102
|
-
'es-ES': coreEsES,
|
|
103
|
-
'en-US': coreEnUS,
|
|
104
|
-
'ja-JP': coreJaJP,
|
|
105
|
-
},
|
|
91
|
+
messages: LOCALE_MESSAGES,
|
|
106
92
|
})
|
package/src/navigation.ts
CHANGED
|
@@ -117,7 +117,7 @@ const createDefaultMenus = (): AppMenu[] => [
|
|
|
117
117
|
name: 'AppAi',
|
|
118
118
|
path: 'app/ai',
|
|
119
119
|
viewKey: 'AI',
|
|
120
|
-
title: t('system.ai.
|
|
120
|
+
title: t('system.ai.chat_title'),
|
|
121
121
|
access: 'AUTHENTICATED',
|
|
122
122
|
inTabBar: false,
|
|
123
123
|
},
|
|
@@ -135,6 +135,7 @@ const createDefaultMenus = (): AppMenu[] => [
|
|
|
135
135
|
|
|
136
136
|
const menus = ref<AppMenu[]>([])
|
|
137
137
|
const ready = ref(false)
|
|
138
|
+
let tabNavigationTarget: string | undefined
|
|
138
139
|
let adapter: AppNavigationAdapter = {
|
|
139
140
|
list: () => defBaseMenuService.ListBaseMenu(),
|
|
140
141
|
}
|
|
@@ -208,13 +209,31 @@ export function navigateAppRoute(rawRoute: string, options: { replace?: boolean
|
|
|
208
209
|
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
209
210
|
.join('&')
|
|
210
211
|
const url = `/${resolved.physicalRoute}${query ? `?${query}` : ''}`
|
|
211
|
-
if (
|
|
212
|
+
if (resolved.menu.inTabBar) {
|
|
213
|
+
navigateTabRoute(url)
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
if (options.replace) {
|
|
212
217
|
uni.reLaunch({ url })
|
|
213
218
|
return
|
|
214
219
|
}
|
|
215
220
|
uni.navigateTo({ url, fail: () => uni.reLaunch({ url }) })
|
|
216
221
|
}
|
|
217
222
|
|
|
223
|
+
/** 切换 tab 页面,避免当前页重复跳转和并发重建页面栈。 */
|
|
224
|
+
function navigateTabRoute(url: string): void {
|
|
225
|
+
const targetRoute = url.slice(1).split('?', 1)[0]
|
|
226
|
+
const pages = getCurrentPages()
|
|
227
|
+
const currentPage = pages[pages.length - 1]
|
|
228
|
+
if (currentPage?.route === targetRoute || tabNavigationTarget) return
|
|
229
|
+
|
|
230
|
+
tabNavigationTarget = targetRoute
|
|
231
|
+
const release = () => {
|
|
232
|
+
if (tabNavigationTarget === targetRoute) tabNavigationTarget = undefined
|
|
233
|
+
}
|
|
234
|
+
uni.reLaunch({ url, success: release, fail: release, complete: release })
|
|
235
|
+
}
|
|
236
|
+
|
|
218
237
|
/** 获取导航响应式状态。 */
|
|
219
238
|
export function useAppNavigation() {
|
|
220
239
|
const menuTree = computed<AppMenuNode[]>(() => buildMenuTree(menus.value, APP_MENU_ROOT_ID))
|
|
@@ -255,15 +274,15 @@ function readCachedMenus(cacheKey: string): AppMenu[] | undefined {
|
|
|
255
274
|
function normalizeMenuResponse(response: unknown): AppMenu[] {
|
|
256
275
|
if (Array.isArray(response)) return response.map(normalizeMenu)
|
|
257
276
|
if (!response || typeof response !== 'object')
|
|
258
|
-
throw new Error(t('core.navigation.error.
|
|
277
|
+
throw new Error(t('core.navigation.error.response_object'))
|
|
259
278
|
const record = response as Record<string, unknown>
|
|
260
279
|
const list = record.items ?? record.list ?? record.data
|
|
261
|
-
if (!Array.isArray(list)) throw new Error(t('core.navigation.error.
|
|
280
|
+
if (!Array.isArray(list)) throw new Error(t('core.navigation.error.list_missing'))
|
|
262
281
|
return list.map(normalizeMenu)
|
|
263
282
|
}
|
|
264
283
|
|
|
265
284
|
function normalizeMenu(value: unknown): AppMenu {
|
|
266
|
-
if (!value || typeof value !== 'object') throw new Error(t('core.navigation.error.
|
|
285
|
+
if (!value || typeof value !== 'object') throw new Error(t('core.navigation.error.item_object'))
|
|
267
286
|
const item = value as Record<string, unknown>
|
|
268
287
|
const meta = (item.meta ?? {}) as Record<string, unknown>
|
|
269
288
|
const app = (meta.app ?? item.app ?? {}) as Record<string, unknown>
|
|
@@ -298,13 +317,13 @@ function validateMenus(nextMenus: AppMenu[]): void {
|
|
|
298
317
|
throw new Error(t('core.navigation.error.identity'))
|
|
299
318
|
}
|
|
300
319
|
if (!menu.name.startsWith('App')) {
|
|
301
|
-
throw new Error(t('core.navigation.error.
|
|
320
|
+
throw new Error(t('core.navigation.error.name_prefix', { name: menu.name }))
|
|
302
321
|
}
|
|
303
322
|
if (!['PUBLIC', 'GUEST_ONLY', 'AUTHENTICATED'].includes(menu.access)) {
|
|
304
323
|
throw new Error(t('core.navigation.error.access', { access: menu.access }))
|
|
305
324
|
}
|
|
306
325
|
if (!resolveStaticView(menu.viewKey)) {
|
|
307
|
-
throw new Error(t('core.navigation.error.
|
|
326
|
+
throw new Error(t('core.navigation.error.view_key', { viewKey: menu.viewKey }))
|
|
308
327
|
}
|
|
309
328
|
if (ids.has(menu.id) || names.has(menu.name) || paths.has(menu.path)) {
|
|
310
329
|
throw new Error(t('core.navigation.error.unique'))
|
|
@@ -316,13 +335,13 @@ function validateMenus(nextMenus: AppMenu[]): void {
|
|
|
316
335
|
const menuMap = new Map(nextMenus.map((menu) => [menu.id, menu]))
|
|
317
336
|
for (const menu of nextMenus) {
|
|
318
337
|
if (menu.parentId === undefined) {
|
|
319
|
-
throw new Error(t('core.navigation.error.
|
|
338
|
+
throw new Error(t('core.navigation.error.parent_missing', { name: menu.name }))
|
|
320
339
|
}
|
|
321
340
|
if (menu.parentId === APP_MENU_ROOT_ID) {
|
|
322
|
-
if (!menu.inTabBar) throw new Error(t('core.navigation.error.
|
|
341
|
+
if (!menu.inTabBar) throw new Error(t('core.navigation.error.root_tab', { name: menu.name }))
|
|
323
342
|
continue
|
|
324
343
|
}
|
|
325
|
-
if (menu.inTabBar) throw new Error(t('core.navigation.error.
|
|
344
|
+
if (menu.inTabBar) throw new Error(t('core.navigation.error.child_tab', { name: menu.name }))
|
|
326
345
|
const visited = new Set<number>([menu.id])
|
|
327
346
|
let parentId = menu.parentId
|
|
328
347
|
while (parentId !== APP_MENU_ROOT_ID) {
|
|
@@ -330,13 +349,13 @@ function validateMenus(nextMenus: AppMenu[]): void {
|
|
|
330
349
|
throw new Error(t('core.navigation.error.cycle', { name: menu.name }))
|
|
331
350
|
visited.add(parentId)
|
|
332
351
|
const parent = menuMap.get(parentId)
|
|
333
|
-
if (!parent) throw new Error(t('core.navigation.error.
|
|
352
|
+
if (!parent) throw new Error(t('core.navigation.error.parent_not_found', { name: menu.name }))
|
|
334
353
|
if (parent.parentId === undefined) {
|
|
335
|
-
throw new Error(t('core.navigation.error.
|
|
354
|
+
throw new Error(t('core.navigation.error.parent_invalid', { name: menu.name }))
|
|
336
355
|
}
|
|
337
356
|
parentId = parent.parentId
|
|
338
357
|
}
|
|
339
358
|
}
|
|
340
359
|
const tabCount = nextMenus.filter((menu) => menu.parentId === APP_MENU_ROOT_ID).length
|
|
341
|
-
if (tabCount === 1 || tabCount > 5) throw new Error(t('core.navigation.error.
|
|
360
|
+
if (tabCount === 1 || tabCount > 5) throw new Error(t('core.navigation.error.tab_count'))
|
|
342
361
|
}
|
|
@@ -5,7 +5,18 @@
|
|
|
5
5
|
// source: base/v1/config.proto
|
|
6
6
|
|
|
7
7
|
/* eslint-disable */
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
/** 系统配置位置。 */
|
|
10
|
+
export enum BaseConfigSite {
|
|
11
|
+
/** BASE_CONFIG_SITE_UNSPECIFIED - 未指定系统配置位置。 */
|
|
12
|
+
BASE_CONFIG_SITE_UNSPECIFIED = 0,
|
|
13
|
+
/** BASE_CONFIG_SITE_SYSTEM - 系统内使用。 */
|
|
14
|
+
BASE_CONFIG_SITE_SYSTEM = 1,
|
|
15
|
+
/** BASE_CONFIG_SITE_ADMIN - 管理端。 */
|
|
16
|
+
BASE_CONFIG_SITE_ADMIN = 2,
|
|
17
|
+
/** BASE_CONFIG_SITE_APP - 移动端。 */
|
|
18
|
+
BASE_CONFIG_SITE_APP = 3,
|
|
19
|
+
}
|
|
9
20
|
|
|
10
21
|
/** 获取系统配置条件 */
|
|
11
22
|
export interface GetConfigRequest {
|
|
@@ -6,32 +6,26 @@
|
|
|
6
6
|
|
|
7
7
|
/* eslint-disable */
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
export interface
|
|
9
|
+
/** 查询语言选项请求参数。 */
|
|
10
|
+
export interface OptionLanguageRequest {
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/**
|
|
13
|
+
/** 语言选择项。 */
|
|
14
14
|
export interface LanguageItem {
|
|
15
15
|
/** 标准语言代码 */
|
|
16
16
|
language_code: string;
|
|
17
|
-
/** 语言名称 */
|
|
18
|
-
language_name: string;
|
|
19
17
|
/** 本地语言名称 */
|
|
20
18
|
native_name: string;
|
|
21
|
-
/** 排序,值越小越靠前 */
|
|
22
|
-
sort: number;
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
/**
|
|
26
|
-
export interface
|
|
21
|
+
/** 当前支持的语言选项查询结果。 */
|
|
22
|
+
export interface OptionLanguageResponse {
|
|
27
23
|
/** 当前支持的语言列表 */
|
|
28
24
|
languages: LanguageItem[];
|
|
29
|
-
/** 主语言代码 */
|
|
30
|
-
primary_language_code: string;
|
|
31
25
|
}
|
|
32
26
|
|
|
33
27
|
/** 语言公共服务。 */
|
|
34
28
|
export interface LanguageService {
|
|
35
|
-
/**
|
|
36
|
-
|
|
29
|
+
/** 查询当前支持的语言选项。 */
|
|
30
|
+
OptionLanguage(request: OptionLanguageRequest): Promise<OptionLanguageResponse>;
|
|
37
31
|
}
|
package/src/rpc/base/v1/login.ts
CHANGED
|
@@ -7,7 +7,20 @@
|
|
|
7
7
|
/* eslint-disable */
|
|
8
8
|
import type { PasswordCrypto } from "../../common/v1/types";
|
|
9
9
|
import type { Empty } from "../../google/protobuf/empty";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
/** 密码加密场景枚举。 */
|
|
12
|
+
export enum PasswordCryptoScene {
|
|
13
|
+
/** PASSWORD_CRYPTO_SCENE_UNSPECIFIED - 未指定密码加密场景。 */
|
|
14
|
+
PASSWORD_CRYPTO_SCENE_UNSPECIFIED = 0,
|
|
15
|
+
/** PASSWORD_CRYPTO_SCENE_LOGIN - 登录密码加密场景。 */
|
|
16
|
+
PASSWORD_CRYPTO_SCENE_LOGIN = 1,
|
|
17
|
+
/** PASSWORD_CRYPTO_SCENE_CREATE_BASE_USER - 新增后台用户密码加密场景。 */
|
|
18
|
+
PASSWORD_CRYPTO_SCENE_CREATE_BASE_USER = 2,
|
|
19
|
+
/** PASSWORD_CRYPTO_SCENE_RESET_BASE_USER_PASSWORD - 重置后台用户密码加密场景。 */
|
|
20
|
+
PASSWORD_CRYPTO_SCENE_RESET_BASE_USER_PASSWORD = 3,
|
|
21
|
+
/** PASSWORD_CRYPTO_SCENE_UPDATE_USER_PASSWORD - 个人修改密码加密场景。 */
|
|
22
|
+
PASSWORD_CRYPTO_SCENE_UPDATE_USER_PASSWORD = 4,
|
|
23
|
+
}
|
|
11
24
|
|
|
12
25
|
/** 验证码获取条件 */
|
|
13
26
|
export interface CaptchaRequest {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { defConfigService } from '../../api/base/config'
|
|
2
2
|
import { defineStore } from 'pinia'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
|
-
import { BaseConfigSite } from '../../rpc/base/v1/
|
|
4
|
+
import { BaseConfigSite } from '../../rpc/base/v1/config'
|
|
5
5
|
import { t } from '../../locales'
|
|
6
6
|
|
|
7
7
|
const REQUIRED_APP_CONFIGS = [
|
|
8
8
|
{ key: 'serviceProtocol', nameKey: 'core.protocol.service' },
|
|
9
9
|
{ key: 'privacyProtocol', nameKey: 'core.protocol.privacy' },
|
|
10
|
-
{ key: 'captchaType', nameKey: 'core.login.
|
|
10
|
+
{ key: 'captchaType', nameKey: 'core.login.captcha_type_name' },
|
|
11
11
|
] as const
|
|
12
12
|
|
|
13
13
|
export const useSettingStore = defineStore('setting', () => {
|
|
@@ -27,7 +27,7 @@ export const useSettingStore = defineStore('setting', () => {
|
|
|
27
27
|
|
|
28
28
|
const request = (async () => {
|
|
29
29
|
const res = await defConfigService.GetConfig({
|
|
30
|
-
site: BaseConfigSite.
|
|
30
|
+
site: BaseConfigSite.BASE_CONFIG_SITE_APP,
|
|
31
31
|
})
|
|
32
32
|
const nextData = new Map<string, string>()
|
|
33
33
|
res.configs.forEach((item) => {
|
package/src/utils/file.ts
CHANGED
|
@@ -22,7 +22,7 @@ export const uploadFile = async (fileType: string, filePath: string): Promise<Fi
|
|
|
22
22
|
if (res.statusCode === 200) {
|
|
23
23
|
return JSON.parse(res.data) as FileInfo
|
|
24
24
|
} else {
|
|
25
|
-
throw new Error(t('core.file.
|
|
25
|
+
throw new Error(t('core.file.upload_failed'))
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -58,7 +58,7 @@ export const multiUploadFile = async (fileType: string, files: any): Promise<Fil
|
|
|
58
58
|
const data = JSON.parse(res.data) as MultiUploadFileResponse
|
|
59
59
|
return data.files
|
|
60
60
|
} else {
|
|
61
|
-
await uni.showToast({ icon: 'error', title: t('core.file.
|
|
61
|
+
await uni.showToast({ icon: 'error', title: t('core.file.upload_failed') })
|
|
62
62
|
return []
|
|
63
63
|
}
|
|
64
64
|
}
|
package/src/utils/http.ts
CHANGED
|
@@ -224,7 +224,7 @@ export const http = <T>(options: HttpRequestOptions) => {
|
|
|
224
224
|
// 其他错误 -> 根据后端错误信息轻提示
|
|
225
225
|
void uni.showToast({
|
|
226
226
|
icon: 'none',
|
|
227
|
-
title: responseData.message || t('common.message.
|
|
227
|
+
title: responseData.message || t('common.message.request_error'),
|
|
228
228
|
})
|
|
229
229
|
reject(res)
|
|
230
230
|
}
|
|
@@ -233,7 +233,7 @@ export const http = <T>(options: HttpRequestOptions) => {
|
|
|
233
233
|
fail(err) {
|
|
234
234
|
void uni.showToast({
|
|
235
235
|
icon: 'none',
|
|
236
|
-
title: t('common.message.
|
|
236
|
+
title: t('common.message.network_error'),
|
|
237
237
|
})
|
|
238
238
|
reject(err)
|
|
239
239
|
},
|
|
@@ -384,9 +384,9 @@ async function promptRelogin() {
|
|
|
384
384
|
try {
|
|
385
385
|
const modalRes = await uni.showModal({
|
|
386
386
|
title: t('common.title.notice'),
|
|
387
|
-
content: t('core.auth.
|
|
387
|
+
content: t('core.auth.session_expired'),
|
|
388
388
|
showCancel: false,
|
|
389
|
-
confirmText: t('core.auth.
|
|
389
|
+
confirmText: t('core.auth.login_again'),
|
|
390
390
|
})
|
|
391
391
|
|
|
392
392
|
if (!modalRes.confirm) {
|
|
@@ -411,7 +411,7 @@ function handleAuthExpiredByMode(authMode: AuthMode, url: string, responseData:
|
|
|
411
411
|
if (authMode !== 'optional') {
|
|
412
412
|
void uni.showToast({
|
|
413
413
|
icon: 'none',
|
|
414
|
-
title: responseData.message || t('common.message.
|
|
414
|
+
title: responseData.message || t('common.message.request_error'),
|
|
415
415
|
})
|
|
416
416
|
}
|
|
417
417
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defLoginService } from '../api/base/login'
|
|
2
2
|
import { t } from '../locales'
|
|
3
|
-
import { PasswordCryptoScene } from '../rpc/base/v1/
|
|
3
|
+
import { PasswordCryptoScene } from '../rpc/base/v1/login'
|
|
4
4
|
import type { PasswordCrypto } from '../rpc/common/v1/types'
|
|
5
5
|
|
|
6
6
|
// #ifdef MP-WEIXIN
|
|
@@ -20,7 +20,7 @@ function pemToArrayBuffer(pem: string) {
|
|
|
20
20
|
.replace(/\s/g, '')
|
|
21
21
|
const decode = globalThis.atob
|
|
22
22
|
if (!decode) {
|
|
23
|
-
throw new Error(t('core.crypto.
|
|
23
|
+
throw new Error(t('core.crypto.base64_decode_unsupported'))
|
|
24
24
|
}
|
|
25
25
|
const binary = decode(base64)
|
|
26
26
|
const buffer = new Uint8Array(binary.length)
|
|
@@ -39,7 +39,7 @@ function arrayBufferToBase64(buffer: ArrayBuffer) {
|
|
|
39
39
|
}
|
|
40
40
|
const encode = globalThis.btoa
|
|
41
41
|
if (!encode) {
|
|
42
|
-
throw new Error(t('core.crypto.
|
|
42
|
+
throw new Error(t('core.crypto.base64_encode_unsupported'))
|
|
43
43
|
}
|
|
44
44
|
return encode(binary)
|
|
45
45
|
}
|
|
@@ -66,7 +66,7 @@ function getMiniRandomBytes(length: number) {
|
|
|
66
66
|
resolve(randomValues)
|
|
67
67
|
},
|
|
68
68
|
fail: ({ errMsg }) => {
|
|
69
|
-
reject(new Error(errMsg || t('core.crypto.
|
|
69
|
+
reject(new Error(errMsg || t('core.crypto.random_failed')))
|
|
70
70
|
},
|
|
71
71
|
})
|
|
72
72
|
})
|
|
@@ -81,7 +81,7 @@ type DerNode = {
|
|
|
81
81
|
/** 读取 DER 编码节点,用于解析 RSA SubjectPublicKeyInfo。 */
|
|
82
82
|
function readDerNode(data: Uint8Array, offset: number): DerNode {
|
|
83
83
|
if (offset + 2 > data.length) {
|
|
84
|
-
throw new Error(t('core.crypto.
|
|
84
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
85
85
|
}
|
|
86
86
|
const tag = data[offset]
|
|
87
87
|
const firstLengthByte = data[offset + 1]
|
|
@@ -90,7 +90,7 @@ function readDerNode(data: Uint8Array, offset: number): DerNode {
|
|
|
90
90
|
if (firstLengthByte & 0x80) {
|
|
91
91
|
const lengthByteCount = firstLengthByte & 0x7f
|
|
92
92
|
if (lengthByteCount === 0 || valueOffset + lengthByteCount > data.length) {
|
|
93
|
-
throw new Error(t('core.crypto.
|
|
93
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
94
94
|
}
|
|
95
95
|
length = 0
|
|
96
96
|
for (let index = 0; index < lengthByteCount; index += 1) {
|
|
@@ -100,7 +100,7 @@ function readDerNode(data: Uint8Array, offset: number): DerNode {
|
|
|
100
100
|
}
|
|
101
101
|
const end = valueOffset + length
|
|
102
102
|
if (end > data.length) {
|
|
103
|
-
throw new Error(t('core.crypto.
|
|
103
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
104
104
|
}
|
|
105
105
|
return {
|
|
106
106
|
tag,
|
|
@@ -129,13 +129,13 @@ function parseMiniRsaPublicKey(publicKey: string): [Uint8Array, Uint8Array] {
|
|
|
129
129
|
const algorithm = readDerNode(subjectPublicKeyInfo.value, 0)
|
|
130
130
|
const bitString = readDerNode(subjectPublicKeyInfo.value, algorithm.next)
|
|
131
131
|
if (bitString.tag !== 0x03 || bitString.value[0] !== 0) {
|
|
132
|
-
throw new Error(t('core.crypto.
|
|
132
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
133
133
|
}
|
|
134
134
|
const rsaPublicKey = readDerNode(bitString.value, 1)
|
|
135
135
|
const modulus = readDerNode(rsaPublicKey.value, 0)
|
|
136
136
|
const exponent = readDerNode(rsaPublicKey.value, modulus.next)
|
|
137
137
|
if (modulus.tag !== 0x02 || exponent.tag !== 0x02) {
|
|
138
|
-
throw new Error(t('core.crypto.
|
|
138
|
+
throw new Error(t('core.crypto.public_key_invalid'))
|
|
139
139
|
}
|
|
140
140
|
return [trimDerInteger(modulus.value), trimDerInteger(exponent.value)]
|
|
141
141
|
}
|
|
@@ -153,7 +153,7 @@ function generateMgf1Mask(crypto: MiniCrypto, seed: Uint8Array, length: number)
|
|
|
153
153
|
counter[3] = index
|
|
154
154
|
let block = hash.reset().process(seed).process(counter).finish().result
|
|
155
155
|
if (!block) {
|
|
156
|
-
throw new Error(t('core.crypto.
|
|
156
|
+
throw new Error(t('core.crypto.encrypt_failed'))
|
|
157
157
|
}
|
|
158
158
|
const target = mask.subarray(index * hash.HASH_SIZE)
|
|
159
159
|
if (block.length > target.length) {
|
|
@@ -190,14 +190,14 @@ async function encryptMiniProgramPassword(
|
|
|
190
190
|
const dataBlockLength = keySize - hash.HASH_SIZE - 1
|
|
191
191
|
const paddingLength = dataBlockLength - aesKey.length - hash.HASH_SIZE - 1
|
|
192
192
|
if (paddingLength < 0) {
|
|
193
|
-
throw new Error(t('core.crypto.
|
|
193
|
+
throw new Error(t('core.crypto.password_too_long'))
|
|
194
194
|
}
|
|
195
195
|
const encodedMessage = new Uint8Array(keySize)
|
|
196
196
|
const maskedSeed = encodedMessage.subarray(1, hash.HASH_SIZE + 1)
|
|
197
197
|
const dataBlock = encodedMessage.subarray(hash.HASH_SIZE + 1)
|
|
198
198
|
const labelHash = hash.reset().process(new Uint8Array()).finish().result
|
|
199
199
|
if (!labelHash) {
|
|
200
|
-
throw new Error(t('core.crypto.
|
|
200
|
+
throw new Error(t('core.crypto.encrypt_failed'))
|
|
201
201
|
}
|
|
202
202
|
dataBlock.set(labelHash, 0)
|
|
203
203
|
dataBlock.set(aesKey, hash.HASH_SIZE + paddingLength + 1)
|
|
@@ -215,7 +215,7 @@ async function encryptMiniProgramPassword(
|
|
|
215
215
|
new crypto.BigNumber(encodedMessage),
|
|
216
216
|
).result
|
|
217
217
|
if (!encryptedKey) {
|
|
218
|
-
throw new Error(t('core.crypto.
|
|
218
|
+
throw new Error(t('core.crypto.encrypt_failed'))
|
|
219
219
|
}
|
|
220
220
|
const ciphertext = crypto.AES_GCM.encrypt(plaintext, aesKey, iv)
|
|
221
221
|
return {
|
|
@@ -235,7 +235,7 @@ export async function encryptPassword(
|
|
|
235
235
|
): Promise<PasswordCrypto> {
|
|
236
236
|
const plainPassword = password.trim()
|
|
237
237
|
if (!plainPassword) {
|
|
238
|
-
throw new Error(t('core.crypto.
|
|
238
|
+
throw new Error(t('core.crypto.password_required'))
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
const publicKeyResponse = await defLoginService.PasswordPublicKey({ scene })
|