@liujitcn/kratos-taro-app-core 0.0.31 → 0.0.33

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/dist/runner.mjs CHANGED
@@ -281,7 +281,7 @@ function restoreBuildTransaction(transaction, transactionFile) {
281
281
  removeEmptyParents(dirname(file), transaction.inputDir);
282
282
  }
283
283
  removeGeneratedStaticFiles(
284
- transaction.generatedStaticFiles ?? [],
284
+ transaction.generatedStaticFiles,
285
285
  resolve(transaction.inputDir, "static")
286
286
  );
287
287
  writeFileSync(transaction.appConfigFile, transaction.originalAppConfig);
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "type": "git",
8
8
  "url": "git@github.com:liujitcn/kratos-admin.git"
9
9
  },
10
- "version": "0.0.31",
10
+ "version": "0.0.33",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
@@ -1,5 +1,5 @@
1
- import { http } from '../../utils/http'
2
- import type { ConfigService, GetConfigRequest, GetConfigResponse } from '../../rpc/base/v1/config'
1
+ import { http } from '../../../utils/http'
2
+ import type { ConfigService, GetConfigRequest, GetConfigResponse } from '../../../rpc/base/v1/config'
3
3
 
4
4
  const CONFIG_URL = '/v1/base/config'
5
5
 
@@ -3,10 +3,10 @@ import type {
3
3
  DownloadFileRequest,
4
4
  FileInfo,
5
5
  MultiUploadFileResponse,
6
- } from '../../rpc/base/v1/file'
7
- import { uploadFile, uploadFileList } from '../../utils/file'
8
- import { getLocaleRequestHeaders, t } from '../../locales'
9
- import { getRequestAccessToken, requestBaseURL } from '../../utils/http'
6
+ } from '../../../rpc/base/v1/file'
7
+ import { uploadFile, uploadFileList } from '../../../utils/file'
8
+ import { getLocaleRequestHeaders, t } from '../../../locales'
9
+ import { getRequestAccessToken, requestBaseURL } from '../../../utils/http'
10
10
 
11
11
  const FILE_URL = '/v1/base/file'
12
12
 
@@ -1,5 +1,5 @@
1
- import { http } from '../../utils/http'
2
- import type { LanguageService, OptionLanguageRequest, OptionLanguageResponse } from '../../rpc/base/v1/language'
1
+ import { http } from '../../../utils/http'
2
+ import type { LanguageService, OptionLanguageRequest, OptionLanguageResponse } from '../../../rpc/base/v1/language'
3
3
 
4
4
  const LANGUAGE_URL = '/v1/base/language'
5
5
 
@@ -1,4 +1,4 @@
1
- import { http } from '../../utils/http'
1
+ import { http } from '../../../utils/http'
2
2
  import type {
3
3
  CaptchaRequest,
4
4
  CaptchaResponse,
@@ -12,8 +12,8 @@ import type {
12
12
  VerifyCaptchaRequest,
13
13
  VerifyCaptchaResponse,
14
14
  LoginService,
15
- } from '../../rpc/base/v1/login'
16
- import type { Empty } from '../../rpc/google/protobuf/empty'
15
+ } from '../../../rpc/base/v1/login'
16
+ import type { Empty } from '../../../rpc/google/protobuf/empty'
17
17
 
18
18
  const CAPTCHA_URL = '/v1/base/captcha'
19
19
  const CAPTCHA_VERIFY_URL = '/v1/base/captcha/verify'
@@ -1,5 +1,5 @@
1
- import { http } from '../../utils/http'
2
- import type { LoginResponse } from '../../rpc/base/v1/login'
1
+ import { http } from '../../../utils/http'
2
+ import type { LoginResponse } from '../../../rpc/base/v1/login'
3
3
  import type {
4
4
  BeginMfaDisableRequest,
5
5
  BeginMfaDisableResponse,
@@ -18,8 +18,8 @@ import type {
18
18
  RecoveryCodesResponse,
19
19
  RegenerateMfaRecoveryCodesRequest,
20
20
  VerifyMfaRequest,
21
- } from '../../rpc/base/v1/mfa'
22
- import type { Empty } from '../../rpc/google/protobuf/empty'
21
+ } from '../../../rpc/base/v1/mfa'
22
+ import type { Empty } from '../../../rpc/google/protobuf/empty'
23
23
 
24
24
  const MFA_URL = '/v1/base/mfa'
25
25
 
@@ -1,4 +1,4 @@
1
- import { http } from '../../utils/http'
1
+ import { http } from '../../../utils/http'
2
2
  import type {
3
3
  CreateOauthAuthorizationRequest,
4
4
  CreateOauthAuthorizationResponse,
@@ -19,8 +19,8 @@ import type {
19
19
  ListOauthProviderResponse,
20
20
  OauthService,
21
21
  UnbindOauthAccountRequest,
22
- } from '../../rpc/base/v1/oauth'
23
- import type { Empty } from '../../rpc/google/protobuf/empty'
22
+ } from '../../../rpc/base/v1/oauth'
23
+ import type { Empty } from '../../../rpc/google/protobuf/empty'
24
24
 
25
25
  const OAUTH_PROVIDER_URL = '/v1/base/oauth/provider'
26
26
  const OAUTH_AUTHORIZATION_URL = '/v1/base/oauth/authorization'
@@ -1,26 +1,20 @@
1
- import { http } from '../../utils/http'
1
+ import { http } from '../../../../utils/http'
2
2
  import {
3
3
  type AuthService,
4
4
  type BindUserPhoneRequest,
5
5
  type BindUserPhoneResponse,
6
+ type GetUserProfileRequest,
7
+ type UpdateUserProfileRequest,
6
8
  type UserProfileForm,
7
- } from '../../rpc/system/app/v1/auth'
8
- import type { Empty } from '../../rpc/google/protobuf/empty'
9
+ } from '../../../../rpc/system/app/v1/auth'
10
+ import type { Empty } from '../../../../rpc/google/protobuf/empty'
9
11
 
10
12
  const AUTH_URL = '/v1/app/auth'
11
13
 
12
- /** 获取用户资料请求兼容空请求结构。 */
13
- type GetUserProfileRequestCompat = Empty
14
-
15
- /** 更新用户资料请求兼容新旧两种表单包裹方式。 */
16
- type UpdateUserProfileRequestCompat = Partial<UserProfileForm> & {
17
- user_profile?: UserProfileForm
18
- }
19
-
20
14
  /** 用户认证资料服务 */
21
15
  export class AuthServiceImpl implements AuthService {
22
16
  /** 获取已登录用户资料 */
23
- GetUserProfile(request: GetUserProfileRequestCompat): Promise<UserProfileForm> {
17
+ GetUserProfile(request: GetUserProfileRequest): Promise<UserProfileForm> {
24
18
  return http<UserProfileForm>({
25
19
  url: `${AUTH_URL}/profile`,
26
20
  method: 'GET',
@@ -30,13 +24,12 @@ export class AuthServiceImpl implements AuthService {
30
24
  }
31
25
 
32
26
  /** 修改个人中心用户信息 */
33
- UpdateUserProfile(request: UpdateUserProfileRequestCompat): Promise<Empty> {
34
- const userProfile = request.user_profile ?? (request as UserProfileForm)
27
+ UpdateUserProfile(request: UpdateUserProfileRequest): Promise<Empty> {
35
28
  return http<Empty>({
36
29
  url: `${AUTH_URL}/profile`,
37
30
  method: 'PUT',
38
31
  authMode: 'required',
39
- data: userProfile,
32
+ data: request.user_profile,
40
33
  })
41
34
  }
42
35
 
@@ -1,9 +1,9 @@
1
- import { http } from '../../utils/http'
1
+ import { http } from '../../../../utils/http'
2
2
  import type {
3
3
  BaseAreaService,
4
4
  TreeBaseAreaRequest,
5
5
  TreeBaseAreaResponse,
6
- } from '../../rpc/system/app/v1/base_area'
6
+ } from '../../../../rpc/system/app/v1/base_area'
7
7
 
8
8
  const BASE_AREA_URL = '/v1/app/base/area'
9
9
 
@@ -0,0 +1,17 @@
1
+ import { http } from '../../../../utils/http'
2
+ import type { BaseDictForm, BaseDictService, GetBaseDictRequest } from '../../../../rpc/system/app/v1/base_dict'
3
+
4
+ const BASE_DICT_URL = '/v1/app/base/dict'
5
+
6
+ /** 字典服务 */
7
+ export class BaseDictServiceImpl implements BaseDictService {
8
+ /** 查询单个字典 */
9
+ GetBaseDict(request: GetBaseDictRequest): Promise<BaseDictForm> {
10
+ return http<BaseDictForm>({
11
+ url: `${BASE_DICT_URL}/${request.code}`,
12
+ method: 'GET',
13
+ })
14
+ }
15
+ }
16
+
17
+ export const defBaseDictService = new BaseDictServiceImpl()
@@ -1,5 +1,5 @@
1
- import { http } from '../../utils/http'
2
- import type { ListBaseMenuResponse } from '../../rpc/system/app/v1/base_menu'
1
+ import { http } from '../../../../utils/http'
2
+ import type { ListBaseMenuResponse } from '../../../../rpc/system/app/v1/base_menu'
3
3
 
4
4
  /** 远端移动菜单服务。 */
5
5
  export class BaseMenuServiceImpl {
package/src/bootstrap.ts CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  registerLocaleMessages,
17
17
  t,
18
18
  } from './locales'
19
- import { defLanguageService } from './api/base/language'
19
+ import { defLanguageService } from './api/base/v1/language'
20
20
 
21
21
  /** Taro 应用启动参数。 */
22
22
  export interface KratosTaroBootstrapOptions {
@@ -34,26 +34,50 @@
34
34
  .kratos-tab-bar__message-icon {
35
35
  position: relative;
36
36
  width: 22PX;
37
- height: 16PX;
38
- margin-bottom: 8PX;
37
+ height: 18PX;
38
+ margin-bottom: 6PX;
39
39
  border: 2PX solid #9aa4b2;
40
- border-radius: 3PX;
40
+ border-radius: 6PX;
41
41
  box-sizing: border-box;
42
42
  }
43
+ .kratos-tab-bar__message-icon::before {
44
+ position: absolute;
45
+ top: 5PX;
46
+ left: 4PX;
47
+ width: 3PX;
48
+ height: 3PX;
49
+ border-radius: 50%;
50
+ background: #9aa4b2;
51
+ box-shadow:
52
+ 5PX 0 #9aa4b2,
53
+ 10PX 0 #9aa4b2;
54
+ content: '';
55
+ }
43
56
 
44
57
  .kratos-tab-bar__message-icon::after {
45
58
  position: absolute;
46
- top: 1PX;
47
- left: 4PX;
48
- width: 9PX;
49
- height: 9PX;
59
+ bottom: -5PX;
60
+ left: 3PX;
61
+ width: 7PX;
62
+ height: 7PX;
50
63
  border-right: 2PX solid #9aa4b2;
51
64
  border-bottom: 2PX solid #9aa4b2;
65
+ background: #fff;
52
66
  content: '';
53
67
  transform: rotate(45deg);
54
68
  }
55
69
 
56
- .kratos-tab-bar__message-icon--active,
70
+ .kratos-tab-bar__message-icon--active {
71
+ border-color: #27ba9b;
72
+ }
73
+
74
+ .kratos-tab-bar__message-icon--active::before {
75
+ background: #27ba9b;
76
+ box-shadow:
77
+ 5PX 0 #27ba9b,
78
+ 10PX 0 #27ba9b;
79
+ }
80
+
57
81
  .kratos-tab-bar__message-icon--active::after {
58
82
  border-color: #27ba9b;
59
83
  }
@@ -64,15 +88,12 @@
64
88
 
65
89
  .kratos-tab-bar__badge {
66
90
  position: absolute;
67
- top: 2PX;
68
- right: calc(50% - 22PX);
69
- min-width: 14PX;
70
- height: 14PX;
71
- padding: 0 3PX;
72
- border-radius: 8PX;
91
+ top: 0;
92
+ right: calc(50% - 19PX);
93
+ width: 10PX;
94
+ height: 10PX;
95
+ box-sizing: border-box;
96
+ border: 2PX solid #fff;
97
+ border-radius: 50%;
73
98
  background: #e5484d;
74
- color: #fff;
75
- font-size: 9PX;
76
- line-height: 14PX;
77
- text-align: center;
78
99
  }
@@ -38,7 +38,9 @@ export function KratosTabBar({ route }: KratosTabBarProps) {
38
38
  {!icon && item.viewKey === 'MESSAGE_INBOX' ? (
39
39
  <View className={`kratos-tab-bar__message-icon${active ? ' kratos-tab-bar__message-icon--active' : ''}`} />
40
40
  ) : null}
41
- {item.viewKey === 'MESSAGE_INBOX' && messageBadge ? <Text className='kratos-tab-bar__badge'>{messageBadge}</Text> : null}
41
+ {item.viewKey === 'MESSAGE_INBOX' && messageBadge ? (
42
+ <View className='kratos-tab-bar__badge' aria-hidden='true' />
43
+ ) : null}
42
44
  <Text className={active ? 'kratos-tab-bar__text--active' : ''}>{item.title}</Text>
43
45
  </View>
44
46
  )
@@ -97,12 +97,9 @@
97
97
  "core.navigation.error.child_tab": "Only second-level app menus can be tabs: {name}",
98
98
  "core.navigation.error.cycle": "Menu parent cycle detected: {name}",
99
99
  "core.navigation.error.identity": "Menu id, name, or app/ path is invalid",
100
- "core.navigation.error.item_object": "Menu item is not an object",
101
- "core.navigation.error.list_missing": "Menu response does not contain a flat list",
102
100
  "core.navigation.error.name_prefix": "Menu name must start with App: {name}",
103
101
  "core.navigation.error.parent_missing": "Menu parent id is missing: {name}",
104
102
  "core.navigation.error.parent_not_found": "Menu parent was not found: {name}",
105
- "core.navigation.error.response_object": "Menu response is not an object",
106
103
  "core.navigation.error.root_tab": "Second-level app menu must be a tab: {name}",
107
104
  "core.navigation.error.tab_count": "tabBar must contain 0 or 2-5 items",
108
105
  "core.navigation.error.unique": "Menu id, name, and path must be unique",
@@ -97,12 +97,9 @@
97
97
  "core.navigation.error.child_tab": "モバイル セカンダリ メニューのみがタブとして使用できます: {name}",
98
98
  "core.navigation.error.cycle": "モバイル メニューにはループの親があります: {name}",
99
99
  "core.navigation.error.identity": "メニュー ID、名前、またはアプリ/パスが無効です",
100
- "core.navigation.error.item_object": "メニュー項目はオブジェクトではありません",
101
- "core.navigation.error.list_missing": "メニュー応答にフラット リストがありません",
102
100
  "core.navigation.error.name_prefix": "メニュー名にはアプリの接頭辞を使用する必要があります: {name}",
103
101
  "core.navigation.error.parent_missing": "メニューに親番号がありません: {name}",
104
102
  "core.navigation.error.parent_not_found": "モバイル メニューの親が存在しません: {name}",
105
- "core.navigation.error.response_object": "メニュー応答はオブジェクトではありません",
106
103
  "core.navigation.error.root_tab": "モバイル セカンダリ メニューはタブとして使用する必要があります: {name}",
107
104
  "core.navigation.error.tab_count": "tabBar は 0 または 2 ~ 5 個の項目のみを設定できます",
108
105
  "core.navigation.error.unique": "メニュー ID、名前、パスは一意である必要があります",
@@ -97,12 +97,9 @@
97
97
  "core.navigation.error.child_tab": "只有移动端二级菜单可以作为 tab:{name}",
98
98
  "core.navigation.error.cycle": "移动端菜单存在循环父级:{name}",
99
99
  "core.navigation.error.identity": "菜单 id、name 或 app/ 路径无效",
100
- "core.navigation.error.item_object": "菜单项不是对象",
101
- "core.navigation.error.list_missing": "菜单响应缺少扁平列表",
102
100
  "core.navigation.error.name_prefix": "菜单名称必须使用 App 前缀:{name}",
103
101
  "core.navigation.error.parent_missing": "菜单缺少父级编号:{name}",
104
102
  "core.navigation.error.parent_not_found": "移动端菜单父级不存在:{name}",
105
- "core.navigation.error.response_object": "菜单响应不是对象",
106
103
  "core.navigation.error.root_tab": "移动端二级菜单必须作为 tab:{name}",
107
104
  "core.navigation.error.tab_count": "tabBar 只能配置 0 或 2-5 项",
108
105
  "core.navigation.error.unique": "菜单 id、name、path 必须唯一",
@@ -97,12 +97,9 @@
97
97
  "core.navigation.error.child_tab": "只有移動端二級選單可以作為 tab:{name}",
98
98
  "core.navigation.error.cycle": "移動端選單存在迴圈父級:{name}",
99
99
  "core.navigation.error.identity": "選單 id、name 或 app/ 路徑無效",
100
- "core.navigation.error.item_object": "選單項不是物件",
101
- "core.navigation.error.list_missing": "選單響應缺少扁平列表",
102
100
  "core.navigation.error.name_prefix": "選單名稱必須使用 App 字首:{name}",
103
101
  "core.navigation.error.parent_missing": "選單缺少父級編號:{name}",
104
102
  "core.navigation.error.parent_not_found": "移動端選單父級不存在:{name}",
105
- "core.navigation.error.response_object": "選單響應不是物件",
106
103
  "core.navigation.error.root_tab": "移動端二級選單必須作為 tab:{name}",
107
104
  "core.navigation.error.tab_count": "tabBar 只能配置 0 或 2-5 項",
108
105
  "core.navigation.error.unique": "選單 id、name、path 必須唯一",
package/src/navigation.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import Taro, { getCurrentPages } from '@tarojs/taro'
2
2
  import { create } from 'zustand'
3
- import { defBaseMenuService } from './api/base/menu'
3
+ import { defBaseMenuService } from './api/system/app/v1/base_menu'
4
+ import type { BaseMenu, ListBaseMenuResponse } from './rpc/system/app/v1/base_menu'
4
5
  import { resolveStaticView } from './module'
5
6
  import { matchLogicalPath, parseLogicalQuery } from './navigation-pattern.mjs'
6
7
  import { buildMenuTree } from './navigation-tree.mjs'
@@ -33,7 +34,7 @@ export interface AppMenuNode extends AppMenu {
33
34
  /** 菜单获取适配器。 */
34
35
  export interface AppNavigationAdapter {
35
36
  /** 获取扁平移动菜单配置。 */
36
- list(): Promise<unknown>
37
+ list(): Promise<ListBaseMenuResponse>
37
38
  }
38
39
 
39
40
  /** 逻辑路由解析结果。 */
@@ -72,11 +73,11 @@ export function setAppMenuBadge(viewKey: string, count: number): void {
72
73
  const ANONYMOUS_CACHE_KEY = 'kratos-taro-app:navigation:anonymous'
73
74
  const AUTHENTICATED_CACHE_KEY = 'kratos-taro-app:navigation:authenticated'
74
75
  /** 固定移动端菜单根目录编号。 */
75
- export const APP_MENU_ROOT_ID = 999
76
+ export const APP_MENU_ROOT_ID = 99000000
76
77
  /** 本地兜底移动菜单。 */
77
78
  export const defaultAppMenus: AppMenu[] = [
78
79
  {
79
- id: 99901,
80
+ id: 99010000,
80
81
  parentId: APP_MENU_ROOT_ID,
81
82
  name: 'AppHome',
82
83
  path: 'app/home',
@@ -88,7 +89,7 @@ export const defaultAppMenus: AppMenu[] = [
88
89
  selectedIcon: 'HOME_SELECTED',
89
90
  },
90
91
  {
91
- id: 9990904,
92
+ id: 99040000,
92
93
  parentId: APP_MENU_ROOT_ID,
93
94
  name: 'AppMessage',
94
95
  path: 'app/message',
@@ -100,7 +101,7 @@ export const defaultAppMenus: AppMenu[] = [
100
101
  selectedIcon: 'MESSAGE_SELECTED',
101
102
  },
102
103
  {
103
- id: 99909,
104
+ id: 99090000,
104
105
  parentId: APP_MENU_ROOT_ID,
105
106
  name: 'AppMy',
106
107
  path: 'app/my',
@@ -112,8 +113,8 @@ export const defaultAppMenus: AppMenu[] = [
112
113
  selectedIcon: 'USER_SELECTED',
113
114
  },
114
115
  {
115
- id: 9990101,
116
- parentId: 99901,
116
+ id: 99010100,
117
+ parentId: 99010000,
117
118
  name: 'AppLogin',
118
119
  path: 'app/login',
119
120
  viewKey: 'LOGIN',
@@ -122,8 +123,8 @@ export const defaultAppMenus: AppMenu[] = [
122
123
  inTabBar: false,
123
124
  },
124
125
  {
125
- id: 999010101,
126
- parentId: 9990101,
126
+ id: 99010101,
127
+ parentId: 99010100,
127
128
  name: 'AppProtocol',
128
129
  path: 'app/protocol/:type',
129
130
  viewKey: 'PROTOCOL',
@@ -132,8 +133,8 @@ export const defaultAppMenus: AppMenu[] = [
132
133
  inTabBar: false,
133
134
  },
134
135
  {
135
- id: 9990901,
136
- parentId: 99909,
136
+ id: 99090100,
137
+ parentId: 99090000,
137
138
  name: 'AppProfile',
138
139
  path: 'app/profile',
139
140
  viewKey: 'PROFILE',
@@ -142,8 +143,8 @@ export const defaultAppMenus: AppMenu[] = [
142
143
  inTabBar: false,
143
144
  },
144
145
  {
145
- id: 9990902,
146
- parentId: 99909,
146
+ id: 99090200,
147
+ parentId: 99090000,
147
148
  name: 'AppSettings',
148
149
  path: 'app/settings',
149
150
  viewKey: 'SETTINGS',
@@ -152,8 +153,8 @@ export const defaultAppMenus: AppMenu[] = [
152
153
  inTabBar: false,
153
154
  },
154
155
  {
155
- id: 9990903,
156
- parentId: 99909,
156
+ id: 99090300,
157
+ parentId: 99090000,
157
158
  name: 'AppAi',
158
159
  path: 'app/ai',
159
160
  viewKey: 'AI',
@@ -162,8 +163,8 @@ export const defaultAppMenus: AppMenu[] = [
162
163
  inTabBar: false,
163
164
  },
164
165
  {
165
- id: 9990102,
166
- parentId: 99901,
166
+ id: 99010200,
167
+ parentId: 99010000,
167
168
  name: 'AppWebView',
168
169
  path: 'app/webview',
169
170
  viewKey: 'WEBVIEW',
@@ -186,6 +187,7 @@ const defaultMenuTitleKeys: Record<string, string> = {
186
187
 
187
188
  let tabNavigationTarget: string | undefined
188
189
  const nativeTabViewKeys = ['HOME', 'PROFILE_HOME']
190
+ const resetTabViewKeys = ['MESSAGE_INBOX']
189
191
 
190
192
  function localizedDefaultAppMenus(): AppMenu[] {
191
193
  return defaultAppMenus.map((menu) => ({
@@ -254,10 +256,7 @@ export function resolveAppRoute(rawRoute: string): ResolvedAppRoute | undefined
254
256
  }
255
257
 
256
258
  /** 跳转逻辑路由,并执行登录访问控制。 */
257
- export function navigateAppRoute(
258
- rawRoute: string,
259
- options: { replace?: boolean } = {},
260
- ): void {
259
+ export function navigateAppRoute(rawRoute: string, options: { replace?: boolean } = {}): void {
261
260
  const resolved = resolveAppRoute(rawRoute)
262
261
  if (!resolved) {
263
262
  launchAppStatus('NOT_FOUND')
@@ -320,9 +319,15 @@ function navigateTabRoute(url: string): void {
320
319
  if (tabNavigationTarget === targetRoute) tabNavigationTarget = undefined
321
320
  }
322
321
  if (nativeTabViewKeys.some((viewKey) => resolveStaticView(viewKey) === targetRoute)) {
323
- void Taro.switchTab({ url }).then(release).catch(() => {
324
- navigateTabRouteInStack(url, targetRoute, pages, currentIndex, release)
325
- })
322
+ void Taro.switchTab({ url })
323
+ .then(release)
324
+ .catch(() => {
325
+ navigateTabRouteInStack(url, targetRoute, pages, currentIndex, release)
326
+ })
327
+ return
328
+ }
329
+ if (resetTabViewKeys.some((viewKey) => resolveStaticView(viewKey) === targetRoute)) {
330
+ void Taro.reLaunch({ url }).then(release, release)
326
331
  return
327
332
  }
328
333
  navigateTabRouteInStack(url, targetRoute, pages, currentIndex, release)
@@ -347,10 +352,7 @@ function navigateTabRouteInStack(
347
352
  }
348
353
 
349
354
  /** 打开可替换的状态视图。 */
350
- export function launchAppStatus(
351
- state: import('./module').BootstrapViewKey,
352
- detail = '',
353
- ): void {
355
+ export function launchAppStatus(state: import('./module').BootstrapViewKey, detail = ''): void {
354
356
  const route = resolveStaticView(state) ?? 'pages/status/index'
355
357
  const query = `state=${encodeURIComponent(state)}${detail ? `&detail=${encodeURIComponent(detail)}` : ''}`
356
358
  void Taro.reLaunch({ url: `/${route}?${query}` })
@@ -365,47 +367,32 @@ function readCachedMenus(cacheKey: string): AppMenu[] | undefined {
365
367
  const cached = Taro.getStorageSync<unknown>(cacheKey)
366
368
  if (!Array.isArray(cached)) return
367
369
  try {
368
- const normalized = cached.map(normalizeMenu)
369
- validateMenus(normalized)
370
- return normalized
370
+ const cachedMenus = cached as AppMenu[]
371
+ validateMenus(cachedMenus)
372
+ return cachedMenus
371
373
  } catch {
372
374
  Taro.removeStorageSync(cacheKey)
373
375
  }
374
376
  }
375
377
 
376
- function normalizeMenuResponse(response: unknown): AppMenu[] {
377
- if (Array.isArray(response)) return response.map(normalizeMenu)
378
- if (!response || typeof response !== 'object') throw new Error(t('core.navigation.error.response_object'))
379
- const record = response as Record<string, unknown>
380
- const list = record.items ?? record.list ?? record.data
381
- if (!Array.isArray(list)) throw new Error(t('core.navigation.error.list_missing'))
382
- return list.map(normalizeMenu)
378
+ function normalizeMenuResponse(response: ListBaseMenuResponse): AppMenu[] {
379
+ return response.items.map(normalizeMenu)
383
380
  }
384
381
 
385
- function normalizeMenu(value: unknown): AppMenu {
386
- if (!value || typeof value !== 'object') throw new Error(t('core.navigation.error.item_object'))
387
- const item = value as Record<string, unknown>
388
- const meta = (item.meta ?? {}) as Record<string, unknown>
389
- const app = (meta.app ?? item.app ?? {}) as Record<string, unknown>
382
+ function normalizeMenu(item: BaseMenu): AppMenu {
383
+ const meta = item.meta
384
+ const app = meta?.app
390
385
  return {
391
- id: Number(item.id),
392
- parentId:
393
- item.parent_id === undefined && item.parentId === undefined
394
- ? undefined
395
- : Number(item.parent_id ?? item.parentId),
396
- name: String(item.name ?? ''),
397
- path: String(item.path ?? ''),
398
- viewKey: String(app.view_key ?? app.viewKey ?? item.view_key ?? item.viewKey ?? ''),
399
- title: String(meta.title ?? item.title ?? ''),
400
- access: String(app.access ?? 'AUTHENTICATED') as AppMenuAccess,
401
- inTabBar: Boolean(app.in_tab_bar ?? app.inTabBar),
402
- icon: typeof meta.icon === 'string' ? meta.icon : undefined,
403
- selectedIcon:
404
- typeof app.selected_icon === 'string'
405
- ? app.selected_icon
406
- : typeof app.selectedIcon === 'string'
407
- ? app.selectedIcon
408
- : undefined,
386
+ id: item.id,
387
+ parentId: item.parent_id,
388
+ name: item.name,
389
+ path: item.path,
390
+ viewKey: app?.view_key ?? '',
391
+ title: meta?.title ?? '',
392
+ access: (app?.access ?? 'AUTHENTICATED') as AppMenuAccess,
393
+ inTabBar: app?.in_tab_bar ?? false,
394
+ icon: meta?.icon,
395
+ selectedIcon: app?.selected_icon,
409
396
  }
410
397
  }
411
398
 
@@ -446,10 +433,12 @@ function validateMenus(nextMenus: AppMenu[]): void {
446
433
  const visited = new Set<number>([menu.id])
447
434
  let parentId = menu.parentId
448
435
  while (parentId !== APP_MENU_ROOT_ID) {
449
- if (visited.has(parentId)) throw new Error(t('core.navigation.error.cycle', { name: menu.name }))
436
+ if (visited.has(parentId))
437
+ throw new Error(t('core.navigation.error.cycle', { name: menu.name }))
450
438
  visited.add(parentId)
451
439
  const parent = menuMap.get(parentId)
452
- if (!parent?.parentId) throw new Error(t('core.navigation.error.parent_not_found', { name: menu.name }))
440
+ if (!parent?.parentId)
441
+ throw new Error(t('core.navigation.error.parent_not_found', { name: menu.name }))
453
442
  parentId = parent.parentId
454
443
  }
455
444
  }
@@ -22,6 +22,8 @@ export enum PasswordCryptoScene {
22
22
  PASSWORD_CRYPTO_SCENE_UPDATE_USER_PASSWORD = 4,
23
23
  /** PASSWORD_CRYPTO_SCENE_MFA - 多因素认证敏感操作场景。 */
24
24
  PASSWORD_CRYPTO_SCENE_MFA = 5,
25
+ /** PASSWORD_CRYPTO_SCENE_CONFIGURE_PASSWORD_POLICY - 密码策略初始化密码配置场景。 */
26
+ PASSWORD_CRYPTO_SCENE_CONFIGURE_PASSWORD_POLICY = 6,
25
27
  }
26
28
 
27
29
  /**
@@ -107,7 +109,7 @@ export interface RefreshTokenRequest {
107
109
  export interface RefreshTokenResponse {
108
110
  /** 访问令牌,必选项。 */
109
111
  access_token: string;
110
- /** 更新令牌,用来获取下一次的访问令牌,可选项。 */
112
+ /** 更新令牌;管理端 Cookie-only 请求不在响应体返回,应用端请求可返回。 */
111
113
  refresh_token: string;
112
114
  /** 令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。 */
113
115
  token_type: string;
@@ -135,7 +137,7 @@ export interface LoginRequest {
135
137
  export interface LoginResponse {
136
138
  /** 访问令牌,必选项。 */
137
139
  access_token: string;
138
- /** 更新令牌,用来获取下一次的访问令牌,可选项。 */
140
+ /** 更新令牌;管理端 Cookie-only 请求不在响应体返回,应用端请求可返回。 */
139
141
  refresh_token: string;
140
142
  /** 令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。 */
141
143
  token_type: string;
@@ -6,6 +6,7 @@
6
6
 
7
7
  /* eslint-disable */
8
8
  import type { Empty } from "../../../google/protobuf/empty";
9
+ import type { BaseUserIDType } from "../../common/v1/common";
9
10
 
10
11
  /** 获取用户资料请求参数 */
11
12
  export interface GetUserProfileRequest {
@@ -21,6 +22,12 @@ export interface UserProfileForm {
21
22
  gender: number;
22
23
  /** 手机号 */
23
24
  phone: string;
25
+ /** 邮箱 */
26
+ email: string;
27
+ /** 证件类型:枚举【BaseUserIDType】 */
28
+ id_type: BaseUserIDType;
29
+ /** 证件号 */
30
+ id_code: string;
24
31
  /** 头像 */
25
32
  avatar: string;
26
33
  }
@@ -0,0 +1,35 @@
1
+ // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
+ // versions:
3
+ // protoc-gen-ts_proto v2.11.8
4
+ // protoc unknown
5
+ // source: system/common/v1/common.proto
6
+
7
+ /* eslint-disable */
8
+
9
+ /** 系统公共用户相关枚举。 */
10
+ export enum BaseUserIDType {
11
+ /** BASE_USER_ID_TYPE_UNSPECIFIED - 未指定证件类型。 */
12
+ BASE_USER_ID_TYPE_UNSPECIFIED = 0,
13
+ /** BASE_USER_ID_TYPE_ID_CARD - 居民身份证。 */
14
+ BASE_USER_ID_TYPE_ID_CARD = 1,
15
+ /** BASE_USER_ID_TYPE_PASSPORT - 护照。 */
16
+ BASE_USER_ID_TYPE_PASSPORT = 2,
17
+ /** BASE_USER_ID_TYPE_HK_MACAO_PERMIT - 港澳居民来往内地通行证。 */
18
+ BASE_USER_ID_TYPE_HK_MACAO_PERMIT = 3,
19
+ /** BASE_USER_ID_TYPE_TAIWAN_PERMIT - 台湾居民来往大陆通行证。 */
20
+ BASE_USER_ID_TYPE_TAIWAN_PERMIT = 4,
21
+ /** BASE_USER_ID_TYPE_FOREIGN_PERMANENT_RESIDENCE - 外国人永久居留身份证。 */
22
+ BASE_USER_ID_TYPE_FOREIGN_PERMANENT_RESIDENCE = 5,
23
+ /** BASE_USER_ID_TYPE_OTHER - 其他证件。 */
24
+ BASE_USER_ID_TYPE_OTHER = 6,
25
+ }
26
+
27
+ /** 用户密码修改状态。 */
28
+ export enum BaseUserPasswordChangeStatus {
29
+ /** BASE_USER_PASSWORD_CHANGE_STATUS_UNSPECIFIED - 未指定密码修改状态。 */
30
+ BASE_USER_PASSWORD_CHANGE_STATUS_UNSPECIFIED = 0,
31
+ /** BASE_USER_PASSWORD_CHANGE_STATUS_REQUIRED - 当前必须修改密码。 */
32
+ BASE_USER_PASSWORD_CHANGE_STATUS_REQUIRED = 1,
33
+ /** BASE_USER_PASSWORD_CHANGE_STATUS_NOT_REQUIRED - 当前无需修改密码。 */
34
+ BASE_USER_PASSWORD_CHANGE_STATUS_NOT_REQUIRED = 2,
35
+ }
package/src/runner.ts CHANGED
@@ -365,7 +365,7 @@ function restoreBuildTransaction(transaction: BuildTransaction, transactionFile:
365
365
  removeEmptyParents(dirname(file), transaction.inputDir)
366
366
  }
367
367
  removeGeneratedStaticFiles(
368
- transaction.generatedStaticFiles ?? [],
368
+ transaction.generatedStaticFiles,
369
369
  resolve(transaction.inputDir, 'static'),
370
370
  )
371
371
  writeFileSync(transaction.appConfigFile, transaction.originalAppConfig)
@@ -1,5 +1,5 @@
1
1
  import { create } from 'zustand'
2
- import { defConfigService } from '../api/base/config'
2
+ import { defConfigService } from '../api/base/v1/config'
3
3
  import { t } from '../locales'
4
4
  import { BaseConfigSite } from '../rpc/base/v1/config'
5
5
 
@@ -1,11 +1,11 @@
1
1
  import Taro from '@tarojs/taro'
2
2
  import { create } from 'zustand'
3
- import { defLoginService } from '../api/base/login'
4
- import { defOauthService } from '../api/base/oauth'
5
- import { defAuthService } from '../api/system/auth'
3
+ import { defLoginService } from '../api/base/v1/login'
4
+ import { defOauthService } from '../api/base/v1/oauth'
5
+ import { defAuthService } from '../api/system/app/v1/auth'
6
6
  import type { LoginRequest, LoginResponse } from '../rpc/base/v1/login'
7
7
  import type { VerifyMfaRequest } from '../rpc/base/v1/mfa'
8
- import { defMfaService } from '../api/base/mfa'
8
+ import { defMfaService } from '../api/base/v1/mfa'
9
9
  import type {
10
10
  BindOauthSessionRequest,
11
11
  CreateOauthSessionRequest,
package/src/utils/http.ts CHANGED
@@ -33,9 +33,6 @@ const NO_AUTH_URL_SET = new Set([
33
33
  CONFIG_URL,
34
34
  LANGUAGE_URL,
35
35
  PASSWORD_PUBLIC_KEY_URL,
36
- '/auth',
37
- '/login/captcha',
38
- '/auth/token',
39
36
  ])
40
37
  const AUTH_EXPIRED_EXCLUDED_URL_SET = new Set([
41
38
  SESSION_URL,
@@ -43,8 +40,6 @@ const AUTH_EXPIRED_EXCLUDED_URL_SET = new Set([
43
40
  CONFIG_URL,
44
41
  LANGUAGE_URL,
45
42
  PASSWORD_PUBLIC_KEY_URL,
46
- '/auth',
47
- '/login/captcha',
48
43
  ])
49
44
  /** 认证状态被静默清理的事件名。 */
50
45
  export const AUTH_SILENT_LOGOUT_EVENT = 'auth:silent-logout'
@@ -1,6 +1,6 @@
1
1
  import Taro from '@tarojs/taro'
2
2
  import * as miniCrypto from 'asmcrypto.js'
3
- import { defLoginService } from '../api/base/login'
3
+ import { defLoginService } from '../api/base/v1/login'
4
4
  import { t } from '../locales'
5
5
  import { PasswordCryptoScene } from '../rpc/base/v1/login'
6
6
  import type { PasswordCrypto } from '../rpc/common/v1/types'
@@ -223,8 +223,8 @@ export async function encryptPassword(
223
223
  const publicKeyResponse = await defLoginService.PasswordPublicKey({ scene })
224
224
 
225
225
  const cryptoApi = globalThis.crypto
226
- // 微信小程序和局域网 HTTP 页面没有 WebCrypto,使用纯 JavaScript 实现保持协议一致。
227
- if (process.env.TARO_ENV === 'weapp' || !cryptoApi?.subtle) {
226
+ const isSecureContext = typeof window === 'undefined' || window.isSecureContext
227
+ if (process.env.TARO_ENV === 'weapp' || !cryptoApi?.subtle || !isSecureContext) {
228
228
  return encryptPortablePassword(miniCrypto, plainPassword, publicKeyResponse)
229
229
  }
230
230
 
@@ -2,8 +2,8 @@ import { Button, Image, Input, Picker, Text, View } from '@tarojs/components'
2
2
  import Taro, { useLoad } from '@tarojs/taro'
3
3
  import { useEffect, useMemo, useRef, useState } from 'react'
4
4
  import defaultLogo from '@liujitcn/kratos-taro-app-core/static/images/logo_icon.png'
5
- import { defLoginService } from '../../../api/base/login'
6
- import { defMfaService } from '../../../api/base/mfa'
5
+ import { defLoginService } from '../../../api/base/v1/login'
6
+ import { defMfaService } from '../../../api/base/v1/mfa'
7
7
  import { navigateAppRoute } from '../../../navigation'
8
8
  import { LoginStatus, type LoginRequest, type LoginResponse } from '../../../rpc/base/v1/login'
9
9
  import { useSettingStore, useUserStore } from '../../../stores'
@@ -1,24 +0,0 @@
1
- import { http } from '../../utils/http'
2
- import type { BaseDictForm, BaseDictService } from '../../rpc/system/app/v1/base_dict'
3
-
4
- const BASE_DICT_URL = '/v1/app/base/dict'
5
-
6
- /** 字典查询请求兼容结构,支持 code 和旧版 value。 */
7
- type GetBaseDictRequestCompat = {
8
- code?: string
9
- value?: string
10
- }
11
-
12
- /** 字典服务 */
13
- export class BaseDictServiceImpl implements BaseDictService {
14
- /** 查询单个字典 */
15
- GetBaseDict(request: GetBaseDictRequestCompat): Promise<BaseDictForm> {
16
- const code = request.code ?? request.value ?? ''
17
- return http<BaseDictForm>({
18
- url: `${BASE_DICT_URL}/${code}`,
19
- method: 'GET',
20
- })
21
- }
22
- }
23
-
24
- export const defBaseDictService = new BaseDictServiceImpl()