@liujitcn/kratos-taro-app-core 0.0.43 → 0.0.45

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/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.43",
10
+ "version": "0.0.45",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
package/src/bootstrap.ts CHANGED
@@ -58,7 +58,10 @@ export function bootstrapKratosTaroApp(options: KratosTaroBootstrapOptions): voi
58
58
  bootstrapped = true
59
59
  syncH5DocumentTitle()
60
60
  registerLocaleChangeHandler(initializeAppNavigation)
61
- registerLocaleChangeHandler(() => useSettingStore.getState().loadData())
61
+ registerLocaleChangeHandler(async () => {
62
+ await useSettingStore.getState().loadData()
63
+ await initializeAppNavigation()
64
+ })
62
65
  registerLocaleChangeHandler(syncH5DocumentTitle)
63
66
  startUserStoreEventBridge()
64
67
  registerUserStoreExtension({
@@ -67,4 +70,7 @@ export function bootstrapKratosTaroApp(options: KratosTaroBootstrapOptions): voi
67
70
  onSilentLogout: initializeAppNavigation,
68
71
  })
69
72
  useUserStore.getState().hydrate()
73
+ void useSettingStore.getState().loadData().then(() => initializeAppNavigation()).catch((error) => {
74
+ console.warn('application configuration unavailable', error)
75
+ })
70
76
  }
package/src/navigation.ts CHANGED
@@ -8,6 +8,7 @@ import { buildMenuTree } from './navigation-tree.mjs'
8
8
  import { hasValidToken } from './utils/auth'
9
9
  import { navigateToLogin } from './utils/navigation'
10
10
  import { getCurrentLocale, t } from './locales'
11
+ import { useSettingStore } from './stores'
11
12
 
12
13
  /** 移动菜单访问模式。 */
13
14
  export type AppMenuAccess = 'PUBLIC' | 'GUEST_ONLY' | 'AUTHENTICATED'
@@ -219,9 +220,9 @@ export function setAppNavigationAdapter(nextAdapter: AppNavigationAdapter): void
219
220
  export async function initializeAppNavigation(): Promise<void> {
220
221
  const cacheKey = resolveCacheKey()
221
222
  const cached = readCachedMenus(cacheKey)
222
- useAppNavigation.setState(createNavigationState(cached ?? localizedDefaultAppMenus(), false))
223
+ useAppNavigation.setState(createNavigationState(filterUnavailableMenus(cached ?? localizedDefaultAppMenus()), false))
223
224
  try {
224
- const nextMenus = normalizeMenuResponse(await adapter.list())
225
+ const nextMenus = filterUnavailableMenus(normalizeMenuResponse(await adapter.list()))
225
226
  validateMenus(nextMenus)
226
227
  Taro.setStorageSync(cacheKey, nextMenus)
227
228
  useAppNavigation.setState(createNavigationState(nextMenus, true))
@@ -231,6 +232,12 @@ export async function initializeAppNavigation(): Promise<void> {
231
232
  }
232
233
  }
233
234
 
235
+ /** 根据运行时能力过滤不可用的移动端入口。 */
236
+ function filterUnavailableMenus(nextMenus: AppMenu[]): AppMenu[] {
237
+ if (useSettingStore.getState().aiEnabled) return nextMenus
238
+ return nextMenus.filter((menu) => menu.viewKey !== 'AI')
239
+ }
240
+
234
241
  /** 使用已经校验的整份配置进行原子切换。 */
235
242
  export function installAppNavigation(nextMenus: AppMenu[]): void {
236
243
  validateMenus(nextMenus)
@@ -247,6 +254,7 @@ export function resolveAppRoute(rawRoute: string): ResolvedAppRoute | undefined
247
254
  if (!params) continue
248
255
  const physicalRoute = resolveStaticView(menu.viewKey)
249
256
  if (!physicalRoute) return
257
+ if (menu.viewKey === 'AI' && !useSettingStore.getState().aiEnabled) return
250
258
  return {
251
259
  menu,
252
260
  physicalRoute,
@@ -38,6 +38,8 @@ export interface ConfigItem {
38
38
  export interface GetConfigResponse {
39
39
  /** 系统配置列表 */
40
40
  configs: ConfigItem[];
41
+ /** AI 助手是否可用 */
42
+ ai_enabled: boolean;
41
43
  }
42
44
 
43
45
  /** Base系统配置公共服务 */
@@ -12,6 +12,7 @@ const REQUIRED_APP_CONFIGS = [
12
12
  /** 应用配置状态及操作。 */
13
13
  export interface SettingStoreState {
14
14
  data?: Map<string, string>
15
+ aiEnabled: boolean
15
16
  getData: (key: string) => string | undefined
16
17
  loadData: () => Promise<void>
17
18
  }
@@ -21,13 +22,20 @@ let loading: Promise<void> | undefined
21
22
  /** 应用配置 Zustand Store。 */
22
23
  export const useSettingStore = create<SettingStoreState>((set, get) => ({
23
24
  data: undefined,
25
+ aiEnabled: false,
24
26
  getData(key) {
25
27
  return get().data?.get(key)
26
28
  },
27
29
  async loadData() {
28
30
  if (loading) return loading
29
31
  loading = (async () => {
30
- const response = await defConfigService.GetConfig({ site: BaseConfigSite.BASE_CONFIG_SITE_APP })
32
+ let response
33
+ try {
34
+ response = await defConfigService.GetConfig({ site: BaseConfigSite.BASE_CONFIG_SITE_APP })
35
+ } catch {
36
+ set({ aiEnabled: false })
37
+ return
38
+ }
31
39
  const nextData = new Map(response.configs.map((item) => [item.key, item.value]))
32
40
  const missing = REQUIRED_APP_CONFIGS.filter(({ key }) => !nextData.get(key))
33
41
  if (missing.length) {
@@ -37,7 +45,7 @@ export const useSettingStore = create<SettingStoreState>((set, get) => ({
37
45
  }),
38
46
  )
39
47
  }
40
- set({ data: nextData })
48
+ set({ data: nextData, aiEnabled: response.ai_enabled === true })
41
49
  })()
42
50
  try {
43
51
  await loading
@@ -8,6 +8,7 @@ import {
8
8
  } from '../../../navigation'
9
9
  import type { BootstrapViewKey } from '../../../module'
10
10
  import { useI18n } from '../../../locales'
11
+ import { useSettingStore } from '../../../stores'
11
12
 
12
13
  /** 启动与错误状态页。 */
13
14
  export default function StatusPage() {
@@ -20,17 +21,31 @@ export default function StatusPage() {
20
21
  setState(nextState)
21
22
  setDetail(options?.detail ? decodeURIComponent(options.detail) : '')
22
23
  if (options?.bootstrap !== '1') return
23
- void initializeAppNavigation()
24
+ void useSettingStore
25
+ .getState()
26
+ .loadData()
27
+ .catch(() => undefined)
28
+ .then(() => initializeAppNavigation())
24
29
  .then(() => {
25
30
  navigateAppRoute(options?.route ? decodeURIComponent(options.route) : 'app/home', {
26
31
  replace: true,
27
32
  })
28
33
  })
29
34
  .catch((error: unknown) => {
30
- launchAppStatus('CONFIG_ERROR', error instanceof Error ? error.message : String(error))
35
+ launchAppStatus('CONFIG_ERROR', resolveErrorMessage(error))
31
36
  })
32
37
  })
33
38
 
34
39
  const title = state === 'BOOTSTRAP_LOADING' ? t('core.status.loading') : t(`core.status.${state}`)
35
40
  return <BootstrapStatus title={title} detail={detail} />
36
41
  }
42
+
43
+ /** 将请求错误转换为可展示的文本,避免直接显示 Object。 */
44
+ function resolveErrorMessage(error: unknown): string {
45
+ if (error instanceof Error) return error.message
46
+ if (typeof error === 'string') return error
47
+ if (error && typeof error === 'object' && 'message' in error) {
48
+ return String((error as { message?: unknown }).message || '')
49
+ }
50
+ return ''
51
+ }