@fudanda/admin-antd 2.20261107.1-beta.1 → 2.20261109.1-beta.2

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.
Files changed (130) hide show
  1. package/dist/chunks/ApiTokensPage-w3JGRNQC.js +2 -0
  2. package/dist/chunks/ApiTokensPage-w3JGRNQC.js.map +1 -0
  3. package/dist/chunks/{App-BF96TQ_D.js → App-nh6_qOo8.js} +5 -5
  4. package/dist/chunks/{App-BF96TQ_D.js.map → App-nh6_qOo8.js.map} +1 -1
  5. package/dist/chunks/{AppModal-CLkMJ-96.js → AppModal-CEouaU03.js} +2 -2
  6. package/dist/chunks/{AppModal-CLkMJ-96.js.map → AppModal-CEouaU03.js.map} +1 -1
  7. package/dist/chunks/{ArcBaseAdmin--xQxd4tg.js → ArcBaseAdmin-CX7fQz4x.js} +2 -2
  8. package/dist/chunks/{ArcBaseAdmin--xQxd4tg.js.map → ArcBaseAdmin-CX7fQz4x.js.map} +1 -1
  9. package/dist/chunks/{DepartmentsPage-D6YVegPU.js → DepartmentsPage-BdD9VfDI.js} +2 -2
  10. package/dist/chunks/{DepartmentsPage-D6YVegPU.js.map → DepartmentsPage-BdD9VfDI.js.map} +1 -1
  11. package/dist/chunks/{DictsPage-uV3Uukwc.js → DictsPage-fxBdV1-3.js} +2 -2
  12. package/dist/chunks/{DictsPage-uV3Uukwc.js.map → DictsPage-fxBdV1-3.js.map} +1 -1
  13. package/dist/chunks/{EntityContextRuntime-DbjyzCtY.js → EntityContextRuntime-CMhoj6qe.js} +2 -2
  14. package/dist/chunks/{EntityContextRuntime-DbjyzCtY.js.map → EntityContextRuntime-CMhoj6qe.js.map} +1 -1
  15. package/dist/chunks/EntityContextRuntime-Dc89ZSnM.js +1 -0
  16. package/dist/chunks/{ExportButton-e2ybxuHb.js → ExportButton-DGxB2tcu.js} +2 -2
  17. package/dist/chunks/{ExportButton-e2ybxuHb.js.map → ExportButton-DGxB2tcu.js.map} +1 -1
  18. package/dist/chunks/{FileViewerPreviewPanel-BhI3pTi8.js → FileViewerPreviewPanel-BMZ7FdKV.js} +3 -3
  19. package/dist/chunks/{FileViewerPreviewPanel-BhI3pTi8.js.map → FileViewerPreviewPanel-BMZ7FdKV.js.map} +1 -1
  20. package/dist/chunks/{FilesPage-BI35mStl.js → FilesPage-DrgWELKy.js} +3 -3
  21. package/dist/chunks/{FilesPage-BI35mStl.js.map → FilesPage-DrgWELKy.js.map} +1 -1
  22. package/dist/chunks/IdentitySecurityPage-BjTKvr-O.js +9 -0
  23. package/dist/chunks/IdentitySecurityPage-BjTKvr-O.js.map +1 -0
  24. package/dist/chunks/{LogStatsScaffold-m0vVUXPh.js → LogStatsScaffold-DaB0JeAN.js} +2 -2
  25. package/dist/chunks/{LogStatsScaffold-m0vVUXPh.js.map → LogStatsScaffold-DaB0JeAN.js.map} +1 -1
  26. package/dist/chunks/{LoginLogsPage-BzBUR4Oo.js → LoginLogsPage-VmYC7i6q.js} +2 -2
  27. package/dist/chunks/{LoginLogsPage-BzBUR4Oo.js.map → LoginLogsPage-VmYC7i6q.js.map} +1 -1
  28. package/dist/chunks/{LoginLogsTable-BweUEjQX.js → LoginLogsTable-CULcc_e8.js} +2 -2
  29. package/dist/chunks/{LoginLogsTable-BweUEjQX.js.map → LoginLogsTable-CULcc_e8.js.map} +1 -1
  30. package/dist/chunks/{MarkdownPreviewPanel-C1OKSLmh.js → MarkdownPreviewPanel-CBcPc7Wv.js} +2 -2
  31. package/dist/chunks/{MarkdownPreviewPanel-C1OKSLmh.js.map → MarkdownPreviewPanel-CBcPc7Wv.js.map} +1 -1
  32. package/dist/chunks/{MasterDetailLayout-KVizcSNO.js → MasterDetailLayout-ByIBpmkZ.js} +2 -2
  33. package/dist/chunks/{MasterDetailLayout-KVizcSNO.js.map → MasterDetailLayout-ByIBpmkZ.js.map} +1 -1
  34. package/dist/chunks/{McpSettingsPage-Dhf0CbDN.js → McpSettingsPage-C5V_rj2V.js} +2 -2
  35. package/dist/chunks/{McpSettingsPage-Dhf0CbDN.js.map → McpSettingsPage-C5V_rj2V.js.map} +1 -1
  36. package/dist/chunks/{MemberAssignmentSheet-TYpnyA0z.js → MemberAssignmentSheet-DL0fg1Yf.js} +2 -2
  37. package/dist/chunks/{MemberAssignmentSheet-TYpnyA0z.js.map → MemberAssignmentSheet-DL0fg1Yf.js.map} +1 -1
  38. package/dist/chunks/{MenuCommandPalette-BcvpUfK7.js → MenuCommandPalette-C2PvK3Gh.js} +2 -2
  39. package/dist/chunks/{MenuCommandPalette-BcvpUfK7.js.map → MenuCommandPalette-C2PvK3Gh.js.map} +1 -1
  40. package/dist/chunks/{MenusPage-Dd7OLQYT.js → MenusPage-Bytd1HlW.js} +2 -2
  41. package/dist/chunks/{MenusPage-Dd7OLQYT.js.map → MenusPage-Bytd1HlW.js.map} +1 -1
  42. package/dist/chunks/{MonacoPreviewPanel-BW1j3ZTF.js → MonacoPreviewPanel-BZrNIcFZ.js} +2 -2
  43. package/dist/chunks/{MonacoPreviewPanel-BW1j3ZTF.js.map → MonacoPreviewPanel-BZrNIcFZ.js.map} +1 -1
  44. package/dist/chunks/{NavListPanel-Iz1RCkVw.js → NavListPanel-zwUDIYSP.js} +2 -2
  45. package/dist/chunks/{NavListPanel-Iz1RCkVw.js.map → NavListPanel-zwUDIYSP.js.map} +1 -1
  46. package/dist/chunks/{OperationLogsPage-Dt22tU4I.js → OperationLogsPage-D2BQdGNp.js} +2 -2
  47. package/dist/chunks/{OperationLogsPage-Dt22tU4I.js.map → OperationLogsPage-D2BQdGNp.js.map} +1 -1
  48. package/dist/chunks/{OperationLogsTable-B23Ry-2v.js → OperationLogsTable-DaaON4QR.js} +3 -3
  49. package/dist/chunks/{OperationLogsTable-B23Ry-2v.js.map → OperationLogsTable-DaaON4QR.js.map} +1 -1
  50. package/dist/chunks/{PDFPreviewPanel-kBPz5dQr.js → PDFPreviewPanel-CMmnWBKW.js} +3 -3
  51. package/dist/chunks/{PDFPreviewPanel-kBPz5dQr.js.map → PDFPreviewPanel-CMmnWBKW.js.map} +1 -1
  52. package/dist/chunks/{PositionsPage-BIKYQDB5.js → PositionsPage-CBZITssT.js} +2 -2
  53. package/dist/chunks/{PositionsPage-BIKYQDB5.js.map → PositionsPage-CBZITssT.js.map} +1 -1
  54. package/dist/chunks/{PreferencesSheetBody-D276rrp4.js → PreferencesSheetBody-B0poTPEA.js} +2 -2
  55. package/dist/chunks/{PreferencesSheetBody-D276rrp4.js.map → PreferencesSheetBody-B0poTPEA.js.map} +1 -1
  56. package/dist/chunks/{ProfilePage-DLftC6KZ.js → ProfilePage-DLhacdWt.js} +2 -2
  57. package/dist/chunks/{ProfilePage-DLftC6KZ.js.map → ProfilePage-DLhacdWt.js.map} +1 -1
  58. package/dist/chunks/{ProjectInfoPage-DkuBLC8t.js → ProjectInfoPage-CJpGxpu5.js} +2 -2
  59. package/dist/chunks/{ProjectInfoPage-DkuBLC8t.js.map → ProjectInfoPage-CJpGxpu5.js.map} +1 -1
  60. package/dist/chunks/{RelationPanel-B4BeO0Bz.js → RelationPanel-BsbfEDo2.js} +2 -2
  61. package/dist/chunks/{RelationPanel-B4BeO0Bz.js.map → RelationPanel-BsbfEDo2.js.map} +1 -1
  62. package/dist/chunks/{RolesPage-BhltU2Qm.js → RolesPage-46dzdiah.js} +2 -2
  63. package/dist/chunks/{RolesPage-BhltU2Qm.js.map → RolesPage-46dzdiah.js.map} +1 -1
  64. package/dist/chunks/{SessionConflictModal-3R8jdYkI.js → SessionConflictModal-Bm38eExL.js} +2 -2
  65. package/dist/chunks/{SessionConflictModal-3R8jdYkI.js.map → SessionConflictModal-Bm38eExL.js.map} +1 -1
  66. package/dist/chunks/SettingModuleDetail-BjxUJeH5.js +17 -0
  67. package/dist/chunks/SettingModuleDetail-BjxUJeH5.js.map +1 -0
  68. package/dist/chunks/{SettingsPage-DMzeDrnc.js → SettingsPage-C32Vuizm.js} +2 -2
  69. package/dist/chunks/{SettingsPage-DMzeDrnc.js.map → SettingsPage-C32Vuizm.js.map} +1 -1
  70. package/dist/chunks/{StatCard-C0xSZyiS.js → StatCard-CRPfkSBY.js} +2 -2
  71. package/dist/chunks/{StatCard-C0xSZyiS.js.map → StatCard-CRPfkSBY.js.map} +1 -1
  72. package/dist/chunks/{UserGroupsPage-DTJdszHl.js → UserGroupsPage-08G5MdGm.js} +2 -2
  73. package/dist/chunks/{UserGroupsPage-DTJdszHl.js.map → UserGroupsPage-08G5MdGm.js.map} +1 -1
  74. package/dist/chunks/{UserLogsPanels-z4UhQtgu.js → UserLogsPanels-nbIrMym9.js} +2 -2
  75. package/dist/chunks/{UserLogsPanels-z4UhQtgu.js.map → UserLogsPanels-nbIrMym9.js.map} +1 -1
  76. package/dist/chunks/{UserTransferSelect-BJNUXMhl.js → UserTransferSelect-C8betaWG.js} +2 -2
  77. package/dist/chunks/{UserTransferSelect-BJNUXMhl.js.map → UserTransferSelect-C8betaWG.js.map} +1 -1
  78. package/dist/chunks/{UsersPage--p68X2Yr.js → UsersPage-BjTiNEqF.js} +2 -2
  79. package/dist/chunks/{UsersPage--p68X2Yr.js.map → UsersPage-BjTiNEqF.js.map} +1 -1
  80. package/dist/chunks/{browser-BKLM0ThC-3Xar5rZw.js → browser-BKLM0ThC-Cp7Gi4-F.js} +1 -1
  81. package/dist/chunks/{code-P0HJS_q1.js → code-LswxAr98.js} +1 -1
  82. package/dist/chunks/{direct-engine-BYEscsGg.js → direct-engine-Dv_6v4sx.js} +1 -1
  83. package/dist/chunks/{html-B__1Vr_C.js → html-BokjxlLb.js} +1 -1
  84. package/dist/chunks/{line-DzLRZVEq.js → line-Bqh6atHH.js} +1 -1
  85. package/dist/chunks/{lrc-kf-TilFB.js → lrc-T5e1svZG.js} +1 -1
  86. package/dist/chunks/{markdown-xIo-vnKK.js → markdown-BpWokN1s.js} +1 -1
  87. package/dist/chunks/{patch-BEaX-xYV.js → patch-BYVX5C9G.js} +1 -1
  88. package/dist/chunks/{worker-engine-FCdIQLzN.js → worker-engine-CtUAeI4G.js} +1 -1
  89. package/dist/core/hooks/queries/settings.d.ts +6 -0
  90. package/dist/core/hooks/queries/settings.d.ts.map +1 -1
  91. package/dist/core/hooks/queries/settings.js +34 -25
  92. package/dist/core/hooks/queries/settings.js.map +1 -1
  93. package/dist/core/hooks/useAuth.d.ts +2 -0
  94. package/dist/core/hooks/useAuth.d.ts.map +1 -1
  95. package/dist/core/hooks/useAuth.js.map +1 -1
  96. package/dist/core/index.js +7 -7
  97. package/dist/core/lib/go-auth-api.d.ts +1 -1
  98. package/dist/core/lib/go-auth-api.d.ts.map +1 -1
  99. package/dist/core/lib/go-auth-api.js +12 -8
  100. package/dist/core/lib/go-auth-api.js.map +1 -1
  101. package/dist/core/lib/native-operations.d.ts +85 -4
  102. package/dist/core/lib/native-operations.d.ts.map +1 -1
  103. package/dist/core/lib/native-operations.js +1 -0
  104. package/dist/core/lib/native-operations.js.map +1 -1
  105. package/dist/core/providers/GoAuthProvider.d.ts.map +1 -1
  106. package/dist/core/providers/GoAuthProvider.js +191 -142
  107. package/dist/core/providers/GoAuthProvider.js.map +1 -1
  108. package/dist/core/session-renewal.d.ts +15 -0
  109. package/dist/core/session-renewal.d.ts.map +1 -0
  110. package/dist/core/session-renewal.js +95 -0
  111. package/dist/core/session-renewal.js.map +1 -0
  112. package/dist/core/session-transition.d.ts +2 -0
  113. package/dist/core/session-transition.d.ts.map +1 -1
  114. package/dist/core/session-transition.js +20 -7
  115. package/dist/core/session-transition.js.map +1 -1
  116. package/dist/core/session.d.ts +4 -0
  117. package/dist/core/session.d.ts.map +1 -1
  118. package/dist/core/session.js +88 -61
  119. package/dist/core/session.js.map +1 -1
  120. package/dist/index.js +1 -1
  121. package/dist/{src-C8_bzBi4.js → src-D6UlLiVN.js} +2 -2
  122. package/dist/{src-C8_bzBi4.js.map → src-D6UlLiVN.js.map} +1 -1
  123. package/package.json +9 -9
  124. package/dist/chunks/ApiTokensPage-DiRMgViD.js +0 -2
  125. package/dist/chunks/ApiTokensPage-DiRMgViD.js.map +0 -1
  126. package/dist/chunks/EntityContextRuntime-BOJySc1D.js +0 -1
  127. package/dist/chunks/IdentitySecurityPage-DW5ybVL4.js +0 -9
  128. package/dist/chunks/IdentitySecurityPage-DW5ybVL4.js.map +0 -1
  129. package/dist/chunks/SettingModuleDetail-Dppk9An1.js +0 -17
  130. package/dist/chunks/SettingModuleDetail-Dppk9An1.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingModuleDetail-BjxUJeH5.js","mappings":"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","names":["__iconData","__iconData$1","createLucideIcon","InstantFilterToolbar","refresh","onRefresh","RefreshButton","refreshing","actionsSlot","useRenderedSlot","desktopActions","present","actions","extra","_Fragment","SlotProbe","SearchToolbar","primary","filters","onReset","ResetButton","mobileActions","node","checksOf","schema","c","enumValues","z.ZodLazy","z.ZodEnum","value","z.ZodLiteral","values","z.ZodUnion","options","option","z.ZodIntersection","left","right","describe","current","field","meta","nullable","m","unwrapped","z.ZodType","def","checks","gt","lt","int","bound","step","element","sameValue","a","b","setPath","path","doc","head","rest","child","getPath","acc","seg","SchemaForm","update","onChange","next","renderLeaf","key","inherited","inheritedValue","overridden","revert","allowRevert","disabled","Button","title","info","fieldLabels","control","Switch","v","InputNumber","Select","enumLabels","Input","TagInput","SettingRow","renderShape","entries","shape","name","excludeFields","leaves","groups","Fragment","index","SettingDivider","SettingSection","root","useFlatMenus","useMemo","result","walk","nodes","parents","menuTree","isAdjusted","canOverridePreference","policy","getPreferenceValue","defaultPreferences","PolicyColorInput","preset","THEME_COLOR_PRESETS","entry","color","label","ColorPicker","PreferencePolicyEditor","usePermission","canReadAllMenus","hasPermission","useMenuTree","currentMenus","useCurrentUserMenuTree","flatMenus","useListSearch","INITIAL_FILTERS","settingsKeys","homeOptions","seen","menu","configured","pinyinReady","usePinyinReady","rows","keyword","draftParams","preferenceDefinitions","definition","preferenceGroups","group","describePreferenceCondition","textMatches","adjustedCount","lockedCount","defaultValues","resolvePreferences","updateDefault","setPreferenceValue","resetField","renderControl","kind","BOOLEAN_OPTIONS","renderDescription","applicable","isPreferenceApplicable","Banner","KeywordInput","bind","FilterSelect","GROUP_OPTIONS","Checkbox","setField","event","handleReset","Typography","Empty","fields","Tooltip","Space","RotateCcw","WebsiteSettingsForm","hostBrand","useHostBrand","request","useRef","useEffect","goTransport","AppLogo","Upload","uploading","controller","onUploadingChange","settingsContract","problem","error","Toast","file","ImagePlus","McpSettingsForm","webmcp","useWebMcpControl","displayName","useAdminTitle","endpoint","example","Alert","copyTextWithToast","Link","mcpTools","tool","SettingModuleDetail","SETTINGS_MODULES","module","query","useSettings","save","useSaveSettings","envelope","draft","setDraft","useState","uploadingLogo","setUploadingLogo","dirty","uiValue","savedUi","changedPreferences","forcedChanges","handleSave","data","parsed","settingsWriteOperations","err","GoaError","issue","MasterDetailLayout","Title","Text","Save","Tag","ExternalLink","Spin","previous","patch","foundationSettingSchemas","settingFieldLabels","ENUM_LABELS","CAPTCHA_COMPLEXITY_LABELS"],"ignoreList":[0,1],"sources":["../../../../node_modules/lucide-react/dist/esm/icons/external-link.mjs","../../../../node_modules/lucide-react/dist/esm/icons/image-plus.mjs","../../src/components/list-page/InstantFilterToolbar.tsx","../../src/pages/system/settings/field-labels.ts","../../src/components/settings/SchemaForm.tsx","../../src/layouts/admin/useMenuDerived.ts","../../src/pages/system/settings/PreferencePolicyEditor.tsx","../../src/pages/system/settings/WebsiteSettingsForm.tsx","../../src/pages/system/settings/McpSettingsForm.tsx","../../src/pages/system/settings/SettingModuleDetail.tsx"],"sourcesContent":[null,null,"import type { ReactNode } from 'react';\nimport { SearchToolbar } from \"@/components/SearchToolbar\";\nimport { RefreshButton, ResetButton } from \"@/components/toolbar-controls\";\nimport { SlotProbe } from \"@/components/rendered-slot\";\nimport { useRenderedSlot } from \"@fudanda/react-core/hooks/useRenderedSlot\";\nexport interface InstantFilterToolbarProps {\n /** 主区控件(关键字输入 / 主机或站点等作用域切换),桌面与移动端主区都展示 */\n primary?: ReactNode;\n /** 选中即生效的筛选项:桌面端内联,移动端收进抽屉(抽屉没有「查询」页脚,改值即筛) */\n filters?: ReactNode;\n /** 重新拉取数据;传入即渲染 `RefreshButton`(桌面跟在筛选项后,移动端留在主区) */\n onRefresh?: () => void;\n refreshing?: boolean;\n /** 清空筛选条件;传入即渲染 `ResetButton`,移动端出现在筛选抽屉页脚 */\n onReset?: () => void;\n /** 新增 / 清理等操作:桌面端跟在刷新之后,移动端收进「更多操作」菜单 */\n actions?: ReactNode;\n /** 覆盖移动端更多菜单内容;缺省与 `actions` 相同 */\n mobileActions?: ReactNode;\n /** 只在桌面端展示的说明文字(如「共 N 个监听端口」「规则保存后立即热更新」) */\n extra?: ReactNode;\n filterTitle?: ReactNode;\n actionTitle?: string;\n className?: string;\n}\nconst present = (node: ReactNode) => Boolean(node);\n/**\n * 「边输边筛 + 刷新」型工具栏:进程 / 服务 / 容器 / 端口这类一次取全量、在客户端即时过滤、没有「查询」按钮语义的页面。\n * 与 `ListSearchToolbar` 一样把桌面 / 移动排布写在一处——\n * 桌面:主区 → 筛选项 → 刷新 → 重置 → 操作 → 说明;移动:主区 + 刷新,筛选项进抽屉,操作进更多菜单。\n * 页面不再为 `primary` / `mobilePrimary` 各写一份同样的控件。\n */\nexport function InstantFilterToolbar({ primary, filters, onRefresh, refreshing, onReset, actions, mobileActions, extra, filterTitle, actionTitle, className, }: InstantFilterToolbarProps) {\n const refresh = onRefresh ? <RefreshButton onClick={onRefresh} loading={refreshing}/> : null;\n const actionsSlot = useRenderedSlot();\n const desktopActions = present(actions) || present(extra)\n ? <><SlotProbe ref={actionsSlot.probeRef}>{actions}</SlotProbe>{extra}</>\n : undefined;\n return (<SearchToolbar className={className} primary={(<>\n {primary}\n {filters}\n {refresh}\n {onReset ? <ResetButton onClick={onReset}/> : null}\n </>)} actions={desktopActions} mobilePrimary={(<>\n {primary}\n {refresh}\n </>)} mobileFilters={present(filters) ? filters : undefined}\n // SearchToolbar 对 mobileActions 缺省回落到 actions;说明文字不进更多菜单,且只有操作真的渲染出元素才复用\n mobileActions={mobileActions ?? (actionsSlot.rendered ? actions : false)} filterTitle={filterTitle} actionTitle={actionTitle} onFilterReset={onReset}/>);\n}\n","/** Presentation text for the generated settings fields; validation stays in Goa schemas. */\nexport const settingFieldLabels = {\n captchaEnabled: { title: '登录验证码', description: '开启后登录必须输入图形验证码' },\n captchaComplexity: { title: '验证码复杂度', description: '仅在开启登录验证码后生效' },\n uploadValidateType: { title: '校验真实文件类型', description: '基于 magic bytes 识别,防止伪造 MIME type 绕过校验' },\n uploadAllowedTypes: { title: '允许的 MIME 类型', description: '支持通配符(如 image/*);填 * 或 */* 放行全部类型' },\n uploadMaxSizeMb: { title: '单文件大小上限(MB)', description: '0 表示不限制;超过的上传(含分片)将被拒绝' },\n chunkThresholdMb: { title: '分片上传阈值(MB)', description: '超过该大小的文件走分片上传 + 断点续传,不超过则单请求上传;受反向代理请求体上限约束' },\n chunkSizeMb: { title: '分片大小(MB)', description: '服务端裁定的分片基线,不低于对象存储要求的最小分片;文件过大时自动上调以不超过片数上限' },\n watermark: { title: '水印' },\n 'watermark.enabled': { title: '页面水印', description: '开启后全站叠加水印(防截图泄漏)' },\n 'watermark.content': { title: '水印文本', description: '留空则显示当前用户名' },\n 'watermark.fontSize': { title: '字体大小(px)' },\n 'watermark.opacity': { title: '透明度(1-100)' },\n preferencesEntryEnabled: { title: '偏好设置入口', description: '显示在用户头像下拉菜单,关闭后隐藏“偏好设置”(含锁屏密码设置)' },\n} as const;\n","import { Fragment, type ReactNode } from 'react';\nimport { Button, Input, InputNumber, Select, Switch, TagInput } from \"@/ui\";\nimport * as z from 'zod';\nimport { SettingDivider, SettingRow, SettingSection } from \"@/components/settings/SettingRow\";\n/**\n * 由 Zod 读取 schema 驱动的设置表单:布尔 → Switch、数值 → InputNumber(min / max 取自 schema 约束)、\n * 枚举 → Select、字符串 → Input、字符串数组 → TagInput、嵌套对象 → 分组。\n * 标签 / 说明取字段 `.meta({ title, description })`,新增设置项只改 shared schema,页面零改动。\n *\n * 受控组件:`value` 为完整生效文档,`onChange` 回传替换后的完整文档;`inheritedValue` 用于「已覆盖」标记与「恢复继承」。\n */\nexport interface SchemaFormProps {\n readonly schema: z.ZodType;\n readonly excludeFields?: readonly string[];\n readonly fieldLabels?: Readonly<Record<string, FieldMeta>>;\n readonly value: Record<string, unknown>;\n readonly inheritedValue?: Record<string, unknown>;\n readonly onChange: (next: Record<string, unknown>) => void;\n readonly disabled?: boolean;\n /** 是否显示「恢复继承」操作(租户作用域 / 平台作用域相对默认值均适用) */\n readonly allowRevert?: boolean;\n /** 枚举字段的展示文案:键为字段路径(a.b),值为 value → label;缺省显示原始值 */\n readonly enumLabels?: Record<string, Record<string, string>>;\n}\ninterface FieldMeta {\n title?: string;\n description?: string;\n}\ntype LeafKind = {\n kind: 'boolean';\n} | {\n kind: 'number';\n int: boolean;\n min?: number;\n max?: number;\n nullable: boolean;\n} | {\n kind: 'enum';\n options: string[];\n} | {\n kind: 'string';\n maxLength?: number;\n} | {\n kind: 'string-array';\n maxItems?: number;\n} | {\n kind: 'object';\n shape: Record<string, z.ZodType>;\n} | {\n kind: 'unknown';\n};\ninterface FieldInfo {\n meta: FieldMeta;\n leaf: LeafKind;\n}\ntype Check = {\n check: string;\n value?: number;\n inclusive?: boolean;\n maximum?: number;\n minimum?: number;\n};\nfunction checksOf(schema: z.ZodType): Check[] {\n const checks = (schema.def as {\n checks?: Array<{\n _zod: {\n def: Check;\n };\n }>;\n }).checks ?? [];\n return checks.map((c) => c._zod.def);\n}\nfunction enumValues(schema: z.core.$ZodType): string[] | undefined {\n if (schema instanceof z.ZodLazy) return enumValues(schema.unwrap());\n if (schema instanceof z.ZodEnum) return Object.values(schema.enum).filter((value): value is string => typeof value === 'string');\n if (schema instanceof z.ZodLiteral) {\n const values = [...schema.values];\n return values.every(value => typeof value === 'string') ? values : undefined;\n }\n if (schema instanceof z.ZodUnion) {\n const options = schema.options.map(option => enumValues(option));\n return options.every((option): option is string[] => option !== undefined) ? options.flat() : undefined;\n }\n if (schema instanceof z.ZodIntersection) {\n const left = enumValues(schema.def.left), right = enumValues(schema.def.right);\n return left && right ? left.filter(value => right.includes(value)) : left ?? right;\n }\n return undefined;\n}\n/** 剥掉 default / prefault / optional / nullable 包装;沿途收集第一份 meta 与 nullable 标记 */\nfunction describe(field: z.ZodType): FieldInfo {\n let current = field;\n let meta: FieldMeta = {};\n let nullable = false;\n for (;;) {\n const m = current.meta() as FieldMeta | undefined;\n if (m && (m.title || m.description) && !meta.title)\n meta = { title: m.title, description: m.description };\n if (current instanceof z.ZodLazy) {\n const unwrapped = current.unwrap();\n if (!(unwrapped instanceof z.ZodType)) return { meta, leaf: { kind: 'unknown' } };\n current = unwrapped; continue;\n }\n const def = current.def as {\n type: string;\n innerType?: z.ZodType;\n };\n if (def.type === 'nullable')\n nullable = true;\n if ((def.type === 'default' || def.type === 'prefault' || def.type === 'optional' || def.type === 'nullable') && def.innerType) {\n current = def.innerType;\n continue;\n }\n break;\n }\n const def = current.def as {\n type: string;\n entries?: Record<string, string>;\n element?: z.ZodType;\n };\n const options = enumValues(current);\n if (options?.length) return { meta, leaf: { kind: 'enum', options } };\n switch (def.type) {\n case 'boolean':\n return { meta, leaf: { kind: 'boolean' } };\n case 'number': {\n const checks = checksOf(current);\n const gt = checks.find((c) => c.check === 'greater_than');\n const lt = checks.find((c) => c.check === 'less_than');\n const int = checks.some((c) => c.check === 'number_format') || (current.def as {\n format?: string;\n }).format === 'safeint';\n // 开区间约束(positive() / negative())只能在整数上精确折算成闭区间\n const bound = (c: Check | undefined, step: number) => c?.value === undefined ? undefined : c.inclusive === false && int ? c.value + step : c.value;\n return { meta, leaf: { kind: 'number', int, min: bound(gt, 1), max: bound(lt, -1), nullable } };\n }\n case 'enum':\n return { meta, leaf: { kind: 'enum', options: Object.values(def.entries ?? {}) } };\n case 'string':\n return { meta, leaf: { kind: 'string', maxLength: checksOf(current).find((c) => c.check === 'max_length')?.maximum } };\n case 'array': {\n const element = def.element ? describe(def.element) : null;\n if (element?.leaf.kind === 'string' || element?.leaf.kind === 'enum') {\n return { meta, leaf: { kind: 'string-array', maxItems: checksOf(current).find((c) => c.check === 'max_length')?.maximum } };\n }\n return { meta, leaf: { kind: 'unknown' } };\n }\n case 'object':\n return { meta, leaf: { kind: 'object', shape: (current as z.ZodObject).shape as Record<string, z.ZodType> } };\n default:\n return { meta, leaf: { kind: 'unknown' } };\n }\n}\nfunction sameValue(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\nfunction setPath(doc: Record<string, unknown>, path: string[], value: unknown): Record<string, unknown> {\n if (path.length === 1)\n return { ...doc, [path[0]]: value };\n const [head, ...rest] = path;\n const child = (doc[head] ?? {}) as Record<string, unknown>;\n return { ...doc, [head]: setPath(child, rest, value) };\n}\nfunction getPath(doc: Record<string, unknown> | undefined, path: string[]): unknown {\n return path.reduce<unknown>((acc, seg) => (acc && typeof acc === 'object' ? (acc as Record<string, unknown>)[seg] : undefined), doc);\n}\nexport function SchemaForm({ schema, value, inheritedValue, onChange, disabled, allowRevert = true, enumLabels, excludeFields, fieldLabels }: SchemaFormProps) {\n const update = (path: string[], next: unknown) => onChange(setPath(value, path, next));\n const renderLeaf = (path: string[], info: FieldInfo): ReactNode => {\n const key = path.join('.');\n const current = getPath(value, path);\n const inherited = inheritedValue ? getPath(inheritedValue, path) : undefined;\n const overridden = inheritedValue !== undefined && !sameValue(current, inherited);\n const revert = allowRevert && overridden && !disabled\n ? <Button size=\"small\" theme=\"borderless\" onClick={() => update(path, inherited)}>恢复继承</Button>\n : null;\n const title = info.meta.title ?? fieldLabels?.[key]?.title ?? path[path.length - 1];\n let control: ReactNode;\n switch (info.leaf.kind) {\n case 'boolean':\n control = <Switch checked={Boolean(current)} disabled={disabled} onChange={(v) => update(path, v)}/>;\n break;\n case 'number': {\n const { min, max, int, nullable } = info.leaf;\n control = (<InputNumber style={{ width: 160 }} min={min} max={max} precision={int ? 0 : undefined} disabled={disabled} value={typeof current === 'number' ? current : undefined} placeholder={nullable ? '留空 = 未设置' : undefined} onChange={(v) => {\n if (typeof v === 'number' && Number.isFinite(v))\n update(path, int ? Math.trunc(v) : v);\n else if (nullable)\n update(path, null);\n }}/>);\n break;\n }\n case 'enum':\n control = (<Select style={{ width: 200 }} disabled={disabled} value={typeof current === 'string' ? current : undefined} optionList={info.leaf.options.map((option) => ({ value: option, label: enumLabels?.[key]?.[option] ?? option }))} onChange={(v) => update(path, v)}/>);\n break;\n case 'string':\n control = (<Input style={{ width: 280 }} disabled={disabled} maxLength={info.leaf.maxLength} value={typeof current === 'string' ? current : ''} onChange={(v) => update(path, v)}/>);\n break;\n case 'string-array':\n control = (<TagInput style={{ width: 360, maxWidth: '100%' }} disabled={disabled} max={info.leaf.maxItems} value={Array.isArray(current) ? (current as string[]) : []} allowDuplicates={false} separator={[',', ' ', '\\n']} addOnBlur placeholder=\"输入后按回车添加\" onChange={(v) => update(path, v)}/>);\n break;\n default:\n control = <span style={{ color: 'var(--arc-antd-color-text-2)' }}>该字段类型暂不支持在通用设置页编辑</span>;\n }\n return <SettingRow key={key} title={title} description={info.meta.description ?? fieldLabels?.[key]?.description} control={control} overridden={overridden} extra={revert}/>;\n };\n const renderShape = (shape: Record<string, z.ZodType>, path: string[]): ReactNode => {\n const entries = Object.entries(shape).filter(([name]) => !excludeFields?.includes([...path, name].join('.')));\n const leaves = entries.filter(([, field]) => describe(field).leaf.kind !== 'object');\n const groups = entries.filter(([, field]) => describe(field).leaf.kind === 'object');\n return (<>\n {leaves.map(([name, field], index) => (<Fragment key={name}>\n {index > 0 ? <SettingDivider /> : null}\n {renderLeaf([...path, name], describe(field))}\n </Fragment>))}\n {groups.map(([name, field]) => {\n const info = describe(field);\n if (info.leaf.kind !== 'object')\n return null;\n return (<SettingSection key={name} title={info.meta.title ?? fieldLabels?.[[...path, name].join('.')]?.title ?? name} description={info.meta.description ?? fieldLabels?.[[...path, name].join('.')]?.description}>\n {renderShape(info.leaf.shape, [...path, name])}\n </SettingSection>);\n })}\n </>);\n };\n const root = describe(schema);\n return <div>{root.leaf.kind === 'object' ? renderShape(root.leaf.shape, []) : null}</div>;\n}\n","import { useCallback, useEffect, useMemo } from 'react';\nimport type { Menu } from '@fudanda/shared/identity';\nimport type { FlatMenuItem } from \"@/components/MenuSearchInput\";\nimport type { NavLayout } from \"@fudanda/react-core/hooks/usePreferences\";\nimport { useLucideIconsReady } from \"@/utils/icons\";\nimport { menuToNavItem, findAncestorKeys, findBreadcrumbs, type NavItem, type BreadcrumbData } from \"@/layouts/admin/utils\";\nexport function useFlatMenus(menuTree: Menu[]) {\n const flatMenus = useMemo<FlatMenuItem[]>(() => {\n const result: FlatMenuItem[] = [];\n const walk = (nodes: Menu[], parents: string[]) => {\n for (const node of nodes) {\n if (node.type === 'menu' && node.path && node.status === 'enabled' && node.visible) {\n // 外链内嵌菜单的实际访问路径是内部路由 /embed/{id}(页签/搜索/收藏按此匹配)\n const path = node.isExternal && node.embed ? `/embed/${node.id}` : node.path;\n result.push({ id: node.id, title: node.title, path, icon: node.icon, breadcrumb: parents });\n }\n if (node.children?.length)\n walk(node.children, node.type === 'directory' ? [...parents, node.title] : parents);\n }\n };\n walk(menuTree, []);\n return result;\n }, [menuTree]);\n return flatMenus;\n}\nexport function useBreadcrumbData(menuTree: Menu[], pathname: string, breadcrumbShowHome: boolean | undefined) {\n const currentSectionKeys = useMemo(() => findAncestorKeys(menuTree, pathname), [menuTree, pathname]);\n const breadcrumbs = useMemo(() => findBreadcrumbs(menuTree, pathname), [menuTree, pathname]);\n const displayBreadcrumbs = useMemo<BreadcrumbData[]>(() => {\n if ((breadcrumbShowHome ?? true) && pathname !== '/') {\n // 找到首页菜单的图标(findBreadcrumbs 不包含首页)\n const findHomeIcon = (nodes: Menu[]): string | undefined => {\n for (const node of nodes) {\n if (!node.visible || node.type === 'button')\n continue;\n if (node.type === 'directory' && node.children?.length) {\n const icon = findHomeIcon(node.children);\n if (icon)\n return icon;\n }\n else if (node.path === '/') {\n return node.icon ?? undefined;\n }\n }\n return undefined;\n };\n return [{ title: '首页', path: '/', icon: findHomeIcon(menuTree) }, ...breadcrumbs];\n }\n return breadcrumbs;\n }, [breadcrumbs, breadcrumbShowHome, pathname, menuTree]);\n return { currentSectionKeys, displayBreadcrumbs };\n}\nexport function useNavItems(menuTree: Menu[], chatUnreadCount: number) {\n const iconsReady = useLucideIconsReady();\n // 深层转换(递归遍历整棵菜单树 + 为每个节点创建图标元素)只依赖菜单本身。\n // 聊天未读数每来一条消息就变,若与此处合并会导致整棵导航树被重建。\n const baseNavItems = useMemo(() => menuTree.map(menuToNavItem).filter((item): item is NavItem => item !== null),\n // iconsReady: 图标注册表异步加载完成后重建 nav 项以补齐菜单图标\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [menuTree, iconsReady]);\n // 未读徽标只影响顶层 /chat 一项,浅层重建即可;无未读时直接透传保持引用不变\n const navItems = useMemo(() => {\n if (chatUnreadCount <= 0)\n return baseNavItems;\n if (!baseNavItems.some((item) => item.itemKey === '/chat'))\n return baseNavItems;\n return baseNavItems.map((item) => (item.itemKey === '/chat'\n ? { ...item, badge: { count: chatUnreadCount, overflowCount: 99 } }\n : item));\n }, [baseNavItems, chatUnreadCount]);\n return navItems;\n}\nexport function useMenuMaps(menuTree: Menu[]) {\n const pathMetaMap = useMemo(() => {\n const map = new Map<string, {\n title: string;\n icon?: string;\n }>([\n ['/search', { title: '搜索中心', icon: 'Search' }],\n ]);\n function traverse(nodes: Menu[]) {\n for (const node of nodes) {\n if (node.path && node.title)\n map.set(node.path, { title: node.title, icon: node.icon ?? undefined });\n if (node.children)\n traverse(node.children);\n }\n }\n traverse(menuTree);\n return map;\n }, [menuTree]);\n /**\n * 路径 → 菜单元信息。\n *\n * 带动态参数的页面(`/workflow/designer/1`)在菜单中只登记了父路径,需前缀回退;\n * 且必须取**最长**前缀——`/workflow/forms/designer/5` 同时匹配「表单库」`/workflow/forms`\n * 与「表单设计」`/workflow/forms/designer`,按遍历顺序取首个会命中父级菜单。\n */\n const resolveMeta = useCallback((pathname: string) => {\n const exact = pathMetaMap.get(pathname);\n if (exact)\n return exact;\n let best: {\n title: string;\n icon?: string;\n } | undefined;\n let bestLength = -1;\n for (const [path, meta] of pathMetaMap) {\n if (path.length > bestLength && pathname.startsWith(`${path}/`)) {\n best = meta;\n bestLength = path.length;\n }\n }\n return best;\n }, [pathMetaMap]);\n const resolveTitle = useCallback((pathname: string) => resolveMeta(pathname)?.title ?? pathname, [resolveMeta]);\n /** 页签图标:与标题同一套匹配规则,否则动态参数页面会缺图标 */\n const resolveIcon = useCallback((pathname: string) => resolveMeta(pathname)?.icon, [resolveMeta]);\n return { resolveTitle, resolveIcon };\n}\nexport function useAutoTopKey(navLayout: NavLayout, navItems: NavItem[], pathname: string, setManualTopKey: (key: string | null) => void) {\n const autoTopKey = useMemo(() => {\n if (navLayout !== 'mixed' && navLayout !== 'double')\n return null;\n function contains(items: NavItem[], path: string): boolean {\n return items.some((item) => item.itemKey === path || (item.items ? contains(item.items, path) : false));\n }\n for (const item of navItems) {\n if (contains([item], pathname))\n return item.itemKey;\n }\n return navItems[0]?.itemKey ?? null;\n }, [navLayout, navItems, pathname]);\n useEffect(() => {\n if ((navLayout === 'mixed' || navLayout === 'double') && autoTopKey)\n setManualTopKey(autoTopKey);\n }, [navLayout, autoTopKey, setManualTopKey]);\n return autoTopKey;\n}\nexport function useMixedNavItems(navLayout: NavLayout, navItems: NavItem[], effectiveTopKey: string | null) {\n const mixedTopNavItems = useMemo(\n // 保留 badge 字段:mixed 顶栏由 TopNavWithOverflow 渲染徽标(如聊天未读)\n () => navItems.map(({ itemKey, text, icon, isExternal, badge }) => ({ itemKey, text, icon, isExternal, badge })), [navItems]);\n const mixedSidebarItems = useMemo(() => {\n if (navLayout !== 'mixed')\n return [];\n const top = navItems.find((i) => i.itemKey === effectiveTopKey);\n return top?.items ?? [];\n }, [navLayout, navItems, effectiveTopKey]);\n const doubleSubItems = useMemo(() => {\n if (navLayout !== 'double')\n return [];\n const top = navItems.find((i) => i.itemKey === effectiveTopKey);\n return top?.items ?? [];\n }, [navLayout, navItems, effectiveTopKey]);\n return { mixedTopNavItems, mixedSidebarItems, doubleSubItems };\n}\n// 页面缓存白名单:菜单开启 keepAlive 的路径(外链内嵌菜单取内部路由 /embed/{id})\nexport function useKeepAlivePaths(menuTree: Menu[]) {\n const keepAlivePaths = useMemo(() => {\n const result = new Set<string>();\n const walk = (nodes: Menu[]) => {\n for (const node of nodes) {\n if (node.type === 'menu' && node.keepAlive && node.path && node.status === 'enabled') {\n if (node.isExternal) {\n if (node.embed)\n result.add(`/embed/${node.id}`);\n }\n else {\n result.add(node.path);\n }\n }\n if (node.children?.length)\n walk(node.children);\n }\n };\n walk(menuTree);\n return result;\n }, [menuTree]);\n return keepAlivePaths;\n}\n","import { Fragment, useMemo, type ReactNode } from 'react';\nimport { Banner, Button, Checkbox, ColorPicker, Empty, Input, InputNumber, Select, Space, Switch, Tooltip, Typography } from \"@/ui\";\nimport { RotateCcw } from 'lucide-react';\nimport { canOverridePreference, defaultPreferences, describePreferenceCondition, getPreferenceValue, isPreferenceApplicable, preferenceDefinitions, preferenceGroups, resolvePreferences, setPreferenceValue, type PreferenceDefinition, type PreferenceGroup, type PreferencePath, type PreferencePolicy } from '@fudanda/shared/preferences';\nimport { InstantFilterToolbar } from \"@/components/list-page/InstantFilterToolbar\";\nimport { FilterSelect, KeywordInput } from \"@/components/search-filters\";\nimport { SettingDivider, SettingRow, SettingSection } from \"@/components/settings/SettingRow\";\nimport { useCurrentUserMenuTree, useMenuTree } from \"@fudanda/react-core/hooks/queries/menus\";\nimport { settingsKeys } from \"@fudanda/react-core/hooks/queries/settings\";\nimport { useListSearch } from \"@fudanda/react-core/hooks/useListSearch\";\nimport { usePinyinReady } from \"@fudanda/react-core/hooks/usePinyinReady\";\nimport { textMatches } from \"@fudanda/react-core/utils/pinyin\";\nimport { usePermission } from \"@fudanda/react-core/hooks/usePermission\";\nimport { useFlatMenus } from \"@/layouts/admin/useMenuDerived\";\nimport { THEME_COLOR_PRESETS } from \"@fudanda/react-core/lib/theme-color\";\nimport \"@/pages/system/settings/preference-policy-editor.css\";\ninterface PreferencePolicyEditorProps {\n readonly value: PreferencePolicy;\n readonly onChange: (next: PreferencePolicy) => void;\n readonly disabled?: boolean;\n}\ninterface PolicyFilters {\n keyword: string;\n group?: PreferenceGroup;\n changedOnly: boolean;\n lockedOnly: boolean;\n}\nconst INITIAL_FILTERS: PolicyFilters = { keyword: '', group: undefined, changedOnly: false, lockedOnly: false };\nconst GROUP_OPTIONS = preferenceGroups.map((group) => ({ value: group.id, label: group.label }));\nconst BOOLEAN_OPTIONS = [{ value: 'true', label: '开启' }, { value: 'false', label: '关闭' }];\nfunction isAdjusted(policy: PreferencePolicy, path: PreferencePath): boolean {\n return !canOverridePreference(path, policy)\n || getPreferenceValue(policy.defaults, path) !== getPreferenceValue(defaultPreferences, path);\n}\nfunction PolicyColorInput({ value, disabled, onChange, label }: {\n readonly value: string;\n readonly disabled?: boolean;\n readonly onChange: (next: string) => void;\n readonly label: string;\n}) {\n const preset = THEME_COLOR_PRESETS.find((entry) => entry.key === value);\n const color = preset?.light.primary ?? value;\n const options = THEME_COLOR_PRESETS.map((entry) => ({ value: entry.key, label: entry.name }));\n if (!preset)\n options.push({ value, label: value });\n return (<div className=\"preference-policy-editor__color\">\n <Select aria-label={label} value={value} optionList={options} disabled={disabled} onChange={(next) => {\n if (typeof next === 'string')\n onChange(next);\n }}/>\n <ColorPicker alpha={false} usePopover value={ColorPicker.colorStringToValue(color)} onChange={(next) => {\n if (!disabled)\n onChange(next.hex);\n }}>\n <button type=\"button\" className=\"preference-policy-editor__swatch\" disabled={disabled} aria-label=\"自定义主题色\" title=\"自定义主题色\" style={{ backgroundColor: color }}/>\n </ColorPicker>\n </div>);\n}\n/** 系统偏好草稿编辑器。所有字段始终可配置,适用条件只解释用户端何时生效。 */\nexport function PreferencePolicyEditor({ value, onChange, disabled }: PreferencePolicyEditorProps) {\n const { hasPermission } = usePermission();\n const canReadAllMenus = hasPermission('system:menu:list');\n const menuTree = useMenuTree({ enabled: canReadAllMenus });\n const currentMenus = useCurrentUserMenuTree();\n const flatMenus = useFlatMenus(menuTree.data ?? currentMenus.data ?? []);\n const { draftParams, bind, setField, handleReset } = useListSearch<PolicyFilters>({\n defaults: INITIAL_FILTERS,\n listKey: settingsKeys.module('ui'),\n refetchOnSearch: false,\n });\n const homeOptions = useMemo(() => {\n const options = [{ value: '/', label: '首页(默认)' }];\n const seen = new Set(['/']);\n for (const menu of flatMenus) {\n // 默认首页只接受站内路由;外链内嵌菜单已由 useFlatMenus 转为 /embed/{id}。\n if (!menu.path.startsWith('/') || menu.path.startsWith('//') || seen.has(menu.path))\n continue;\n seen.add(menu.path);\n options.push({ value: menu.path, label: [...menu.breadcrumb, menu.title].join(' / ') });\n }\n const configured = value.defaults.homePath;\n if (!seen.has(configured))\n options.push({ value: configured, label: `${configured}(当前已配置)` });\n return options;\n }, [flatMenus, value.defaults.homePath]);\n // 拼音词典就绪后重算 rows 过滤,补上已输入关键字的拼音命中\n const pinyinReady = usePinyinReady();\n const rows = useMemo(() => {\n void pinyinReady;\n const keyword = draftParams.keyword.trim();\n return preferenceDefinitions.filter((definition) => {\n if (draftParams.group && definition.group !== draftParams.group)\n return false;\n if (draftParams.changedOnly && !isAdjusted(value, definition.path))\n return false;\n if (draftParams.lockedOnly && canOverridePreference(definition.path, value))\n return false;\n if (!keyword)\n return true;\n // 名称 / 路径 / 说明 / 分组 / 适用条件:子串 + 拼音首字母 / 全拼\n return [\n definition.label, definition.path, definition.description,\n preferenceGroups.find((group) => group.id === definition.group)?.label,\n definition.applicableWhen && describePreferenceCondition(definition.applicableWhen),\n ].filter(Boolean).some((field) => textMatches(String(field), keyword));\n });\n }, [draftParams, value, pinyinReady]);\n const adjustedCount = preferenceDefinitions.filter((definition) => isAdjusted(value, definition.path)).length;\n const lockedCount = preferenceDefinitions.filter((definition) => !canOverridePreference(definition.path, value)).length;\n const defaultValues = resolvePreferences(value, {});\n function updateDefault(path: PreferencePath, next: string | number | boolean) {\n onChange({ ...value, defaults: setPreferenceValue(value.defaults, path, next) });\n }\n function resetField(path: PreferencePath) {\n onChange({\n defaults: setPreferenceValue(value.defaults, path, getPreferenceValue(defaultPreferences, path)),\n allowUserOverride: setPreferenceValue(value.allowUserOverride, path, true),\n });\n }\n function renderControl(definition: PreferenceDefinition): ReactNode {\n const { path, kind } = definition;\n const current = getPreferenceValue(value.defaults, path);\n const label = `${definition.label}默认值`;\n if (kind === 'boolean') {\n return <Select aria-label={label} value={String(current)} optionList={BOOLEAN_OPTIONS} disabled={disabled} onChange={(next) => updateDefault(path, next === 'true')}/>;\n }\n if (kind === 'number') {\n return <InputNumber aria-label={label} value={typeof current === 'number' ? current : undefined} min={definition.min} max={definition.max} step={definition.step ?? 1} precision={definition.step && definition.step < 1 ? undefined : 0} suffix={definition.unit} disabled={disabled} onChange={(next) => {\n if (typeof next === 'number' && Number.isFinite(next))\n updateDefault(path, next);\n }}/>;\n }\n if (kind === 'color') {\n return <PolicyColorInput value={String(current)} disabled={disabled} label={label} onChange={(next) => updateDefault(path, next)}/>;\n }\n if (kind === 'home-path') {\n return <Select aria-label={label} value={String(current)} optionList={homeOptions} filter disabled={disabled} loading={canReadAllMenus ? menuTree.isFetching : currentMenus.isFetching} onChange={(next) => {\n if (typeof next === 'string')\n updateDefault(path, next);\n }}/>;\n }\n if (kind === 'select') {\n return <Select<string | number> aria-label={label} value={typeof current === 'number' ? current : String(current)} optionList={[...(definition.options ?? [])]} disabled={disabled} onChange={(next) => {\n if (typeof next === 'string' || typeof next === 'number')\n updateDefault(path, next);\n }}/>;\n }\n return <Input aria-label={label} value={String(current)} disabled={disabled} onChange={(next) => updateDefault(path, next)}/>;\n }\n function renderDescription(definition: PreferenceDefinition): ReactNode {\n const applicable = isPreferenceApplicable(definition.path, defaultValues);\n return (<span className=\"preference-policy-editor__description\">\n {definition.description ? <span>{definition.description}</span> : null}\n {definition.applicableWhen ? <span>适用条件:{describePreferenceCondition(definition.applicableWhen)}</span> : null}\n {!applicable ? <span className=\"preference-policy-editor__hint\">当前系统默认组合不满足条件,满足条件后生效。</span> : null}\n {definition.path === 'homePath' ? <span>用户无权访问指定页面时回到可访问的首页。{!canReadAllMenus ? '当前仅列出你可访问的页面。' : ''}</span> : null}\n </span>);\n }\n return (<div className=\"preference-policy-editor\">\n <SettingSection title=\"偏好策略\" description=\"设置每项偏好的系统默认值,并决定用户是否可以修改。\">\n <Banner type=\"info\" closeIcon={null} className=\"preference-policy-editor__intro\" description=\"禁止用户修改的项目会在个人偏好中隐藏并使用系统值;子项是否显示取决于父项的生效值。更改将在保存后统一生效。\"/>\n <InstantFilterToolbar primary={<KeywordInput placeholder=\"搜索偏好名称 / 说明\" {...bind('keyword')}/>} filters={(<>\n <FilterSelect placeholder=\"全部分组\" items={GROUP_OPTIONS} {...bind('group')}/>\n <Checkbox checked={draftParams.changedOnly} onChange={(event) => setField('changedOnly')(Boolean(event.target.checked))}>仅看已调整</Checkbox>\n <Checkbox checked={draftParams.lockedOnly} onChange={(event) => setField('lockedOnly')(Boolean(event.target.checked))}>仅看禁止修改</Checkbox>\n </>)} onReset={handleReset}/>\n <Typography.Text type=\"tertiary\" size=\"small\">共 {preferenceDefinitions.length} 项 · 已调整 {adjustedCount} 项 · 禁止修改 {lockedCount} 项 · 当前显示 {rows.length} 项</Typography.Text>\n {rows.length === 0 ? <Empty description=\"没有符合筛选条件的偏好\"/> : null}\n {preferenceGroups.map((group) => {\n const fields = rows.filter((definition) => definition.group === group.id);\n if (fields.length === 0)\n return null;\n return (<SettingSection key={group.id} title={group.label}>\n <div className=\"preference-policy-editor__head\" aria-hidden=\"true\">\n <span>偏好设置</span>\n <div className=\"preference-policy-editor__controls\"><span>系统默认值</span><span>用户可修改</span><span /></div>\n </div>\n {fields.map((definition, index) => (<Fragment key={definition.path}>\n {index > 0 ? <SettingDivider /> : null}\n <div className=\"preference-policy-editor__row\" data-preference-path={definition.path}>\n <SettingRow title={definition.label} description={renderDescription(definition)} style={{ flexWrap: 'wrap' }} control={(<div className=\"preference-policy-editor__controls\">\n <div className=\"preference-policy-editor__value\">\n <span className=\"preference-policy-editor__mobile-label\">系统默认值</span>\n {renderControl(definition)}\n </div>\n <div className=\"preference-policy-editor__override\">\n <span className=\"preference-policy-editor__mobile-label\">用户可修改</span>\n <Switch aria-label={`${definition.label}用户可修改`} disabled={disabled} checked={canOverridePreference(definition.path, value)} onChange={(next) => onChange({ ...value, allowUserOverride: setPreferenceValue(value.allowUserOverride, definition.path, next) })}/>\n </div>\n <Tooltip content=\"恢复内置默认值并允许用户修改\">\n <Space>\n <Button theme=\"borderless\" size=\"small\" aria-label={`恢复${definition.label}内置策略`} icon={<RotateCcw size={14}/>} disabled={disabled || !isAdjusted(value, definition.path)} onClick={() => resetField(definition.path)}/>\n </Space>\n </Tooltip>\n </div>)}/>\n </div>\n </Fragment>))}\n </SettingSection>);\n })}\n </SettingSection>\n </div>);\n}\n","import { useEffect, useRef, type ComponentProps } from 'react';\nimport type { ApiWebsiteSettings } from '@fudanda/shared/api/settings';\nimport { settingsContract } from '@fudanda/react-core/lib/native-operations';\nimport { goTransport } from '@fudanda/react-core/lib/go-transport';\nimport { Button, Input, Toast, Upload } from '@/ui';\nimport { ImagePlus } from 'lucide-react';\nimport { SettingDivider, SettingRow } from '@/components/settings/SettingRow';\nimport AppLogo from '@/components/AppLogo';\nimport { useHostBrand } from '@/admin/host-brand';\n\nexport function WebsiteSettingsForm({ value, disabled, uploading, onChange, onUploadingChange }: {\n value: ApiWebsiteSettings;\n disabled: boolean;\n uploading: boolean;\n onChange: (patch: Partial<ApiWebsiteSettings>) => void;\n onUploadingChange: (value: boolean) => void;\n}) {\n const hostBrand = useHostBrand();\n const request = useRef<AbortController | null>(null);\n useEffect(() => () => { request.current?.abort(); }, []);\n const uploadLogo: NonNullable<ComponentProps<typeof Upload>['customRequest']> = options => {\n const controller = new AbortController();\n request.current?.abort();\n request.current = controller;\n onUploadingChange(true);\n void goTransport.upload(settingsContract.uploadLogo, { body: { file: options.file as File } }, { signal: controller.signal })\n .then(result => {\n if (controller.signal.aborted) return;\n onChange({ logoUrl: result.logoUrl });\n options.onSuccess?.(result);\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) return;\n const problem = error instanceof Error ? error : new Error('Logo 上传失败');\n Toast.error(problem.message);\n options.onError?.(problem);\n })\n .finally(() => {\n if (request.current === controller && !controller.signal.aborted) {\n request.current = null;\n onUploadingChange(false);\n }\n });\n return { abort: () => controller.abort() };\n };\n return <>\n <SettingRow title={<label htmlFor=\"website-name\">网站名称</label>} description=\"应用于登录页、管理台和浏览器标题。留空时沿用宿主默认名称。\" control={<Input id=\"website-name\" style={{ width: 280 }} maxLength={80} showClear disabled={disabled} value={value.name} placeholder={hostBrand?.name || '沿用宿主默认名称'} onChange={name => onChange({ name })} />} />\n <SettingDivider />\n <SettingRow title=\"网站 Logo\" description=\"支持 PNG、JPEG,最大 2 MB,尺寸不超过 4096 × 4096。保存后生效。\" control={<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>\n <div style={{ width: 96, height: 96, padding: 12, border: '1px solid var(--arc-antd-color-border)', borderRadius: 'var(--semi-border-radius-medium)', display: 'grid', placeItems: 'center' }}>\n {value.logoUrl ? <img src={goTransport.resolveURL(value.logoUrl)} alt=\"网站 Logo 预览\" style={{ width: '100%', height: '100%', objectFit: 'contain' }} /> : <AppLogo size={64} hostDefault />}\n </div>\n <Upload accept=\"image/png,image/jpeg\" showUploadList={false} disabled={disabled || uploading} customRequest={uploadLogo} beforeUpload={({ file }) => {\n if (Number(file.size) > 2 * 1024 * 1024 || !['image/png', 'image/jpeg'].includes(file.fileInstance?.type ?? '')) {\n Toast.error('请选择不超过 2 MB 的 PNG 或 JPEG 图片');\n return false;\n }\n return true;\n }}><Button icon={<ImagePlus size={14}/>} disabled={disabled || uploading} loading={uploading}>{value.logoUrl ? '更换 Logo' : '上传 Logo'}</Button></Upload>\n {value.logoUrl ? <Button size=\"small\" theme=\"borderless\" disabled={disabled || uploading} onClick={() => onChange({ logoUrl: '' })}>恢复默认 Logo</Button> : <span style={{ color: 'var(--arc-antd-color-text-2)', fontSize: 12 }}>使用宿主默认 Logo</span>}\n </div>} />\n </>;\n}\n","import { Alert, Button, Space, Switch, Typography } from 'antd';\nimport { Link } from 'react-router-dom';\nimport type { ApiMCPSettings } from '@fudanda/shared/api/settings';\nimport { mcpTools } from '@fudanda/shared/api/mcp-tools';\nimport { useAdminTitle } from '@fudanda/react-core/admin/runtime';\nimport { goTransport } from '@fudanda/react-core/lib/go-transport';\nimport { SettingDivider, SettingRow } from '@/components/settings/SettingRow';\nimport { copyTextWithToast } from '@/utils/clipboard';\nimport { useWebMcpControl } from '@/webmcp-control';\n\nexport function McpSettingsForm({ value, disabled, onChange }: {\n value: ApiMCPSettings;\n disabled: boolean;\n onChange: (patch: Partial<ApiMCPSettings>) => void;\n}) {\n const webmcp = useWebMcpControl();\n const displayName = useAdminTitle();\n const endpoint = new URL(goTransport.resolveURL('/api/v1/mcp'), window.location.origin).href;\n const example = JSON.stringify({\n 'http-server-1': {\n transport: 'streamable_http',\n enabled: true,\n display_name: displayName,\n default_open: true,\n url: endpoint,\n headers: { Authorization: 'Bearer <API_KEY>' },\n },\n }, null, 2);\n return <>\n <SettingRow title=\"启用 MCP\" description=\"向外部客户端提供只读工具。保存后立即生效,关闭后拒绝新的 MCP 请求。\"\n control={<Switch aria-label=\"启用 MCP\" checked={value.enabled} disabled={disabled} onChange={enabled => onChange({ enabled })} />} />\n <SettingDivider />\n <SettingRow title=\"启用 WebMCP\" description=\"已登录且未锁屏的管理台自动加载浏览器工具,沿用当前账号权限,删除操作仍需确认。保存后同步到已打开的页面。\"\n control={<Switch aria-label=\"启用 WebMCP\" checked={value.webMcpEnabled} disabled={disabled} onChange={webMcpEnabled => onChange({ webMcpEnabled })} />} />\n {value.webMcpEnabled && webmcp && !webmcp.configured ? <Alert type=\"warning\" title=\"当前宿主尚未接入 WebMCP\" description=\"请先在宿主装配可选的 WebMCP 入口,接入后跟随此系统开关。\" /> : null}\n {webmcp?.status === 'error' ? <Alert type=\"error\" title=\"WebMCP 加载失败\" description=\"请检查管理台资源并刷新页面重试。\" /> : null}\n <Typography.Title level={5}>MCP 连接</Typography.Title>\n <Space wrap style={{ marginBottom: 12 }}>\n <Typography.Text code style={{ overflowWrap: 'anywhere' }}>{endpoint}</Typography.Text>\n <Button onClick={() => void copyTextWithToast(endpoint)}>复制地址</Button>\n </Space>\n <Typography.Paragraph>客户端选择 Streamable HTTP,通过 Authorization 请求头携带 API Key。前往<Link to=\"/system/api-tokens\">AI 与集成 → API Key</Link>创建和管理凭据;可用工具由账号权限与 API Key 范围共同决定。</Typography.Paragraph>\n <Typography.Paragraph type=\"secondary\">将示例中的 <Typography.Text code>{'<API_KEY>'}</Typography.Text> 替换为有效的 API Key 后使用。</Typography.Paragraph>\n <pre aria-label=\"MCP 连接配置示例\" style={{ padding: 16, whiteSpace: 'pre-wrap', overflowWrap: 'anywhere', background: 'var(--arc-antd-color-fill-0)', borderRadius: 'var(--semi-border-radius-medium)' }}>{example}</pre>\n <Button onClick={() => void copyTextWithToast(example)}>复制连接示例</Button>\n <Typography.Title level={5}>只读工具</Typography.Title>\n <ul>{mcpTools.map(tool => <li key={tool.name}><Typography.Text>{tool.title}</Typography.Text> <Typography.Text type=\"secondary\">{tool.name}</Typography.Text></li>)}</ul>\n <Typography.Paragraph type=\"secondary\">MCP 与 WebMCP 独立控制。宿主已配置桌面 Relay 时,桥接跟随 WebMCP 开关启停;连接状态以客户端实际列出工具为准。</Typography.Paragraph>\n </>;\n}\n","import type { ApiSettingModule, ApiUISettings, ApiWebsiteSettings, ApiMCPSettings } from '@fudanda/shared/api/settings';\nimport { settingsWriteOperations } from '@fudanda/react-core/lib/native-operations';\nimport type { SettingsModuleKey } from '@fudanda/react-core/hooks/queries/settings';\nimport { foundationSettingSchemas } from '@fudanda/shared/settings/foundation';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { Banner, Button, Spin, Tag, Toast, Typography } from '@/ui';\nimport { ExternalLink, Save } from 'lucide-react';\nimport { CAPTCHA_COMPLEXITY_LABELS, SETTINGS_MODULES } from '@fudanda/shared/settings';\nimport { getPreferenceValue, preferenceDefinitions } from '@fudanda/shared/preferences';\nimport { MasterDetailLayout } from '@/components/MasterDetailLayout';\nimport { settingFieldLabels } from './field-labels';\nimport { SchemaForm } from '@/components/settings/SchemaForm';\nimport { useSaveSettings, useSettings } from '@fudanda/react-core/hooks/queries/settings';\nimport { GoaError } from '@fudanda/client';\nimport { PreferencePolicyEditor } from './PreferencePolicyEditor';\nimport { WebsiteSettingsForm } from './WebsiteSettingsForm';\nimport { McpSettingsForm } from './McpSettingsForm';\n\nconst { Text, Title } = Typography;\nconst ENUM_LABELS: Record<string, Record<string, string>> = { captchaComplexity: CAPTCHA_COMPLEXITY_LABELS };\n\n/** Shared full-document editor for the general settings list and dedicated pages. */\nexport function SettingModuleDetail({ module, meta }: {\n readonly module: SettingsModuleKey;\n readonly meta: ApiSettingModule;\n}) {\n const def = SETTINGS_MODULES[module];\n const query = useSettings(module);\n const save = useSaveSettings(module);\n const envelope = query.data;\n const [draft, setDraft] = useState<Record<string, unknown> | null>(null);\n const [uploadingLogo, setUploadingLogo] = useState(false);\n useEffect(() => { setDraft(null); setUploadingLogo(false); }, [envelope?.version]);\n const value = useMemo(() => (draft ?? (envelope?.effective as Record<string, unknown> | undefined) ?? null), [draft, envelope]);\n const dirty = draft !== null && JSON.stringify(draft) !== JSON.stringify(envelope?.effective);\n const uiValue = module === 'ui' && value ? value as ApiUISettings : null;\n const savedUi = module === 'ui' && envelope ? envelope.effective as ApiUISettings : null;\n const changedPreferences = uiValue && savedUi ? preferenceDefinitions.filter(({ path }) => getPreferenceValue(uiValue.preferences.defaults, path) !== getPreferenceValue(savedUi.preferences.defaults, path)\n || getPreferenceValue(uiValue.preferences.allowUserOverride, path) !== getPreferenceValue(savedUi.preferences.allowUserOverride, path)) : [];\n const forcedChanges = changedPreferences.filter(({ path }) => uiValue && !getPreferenceValue(uiValue.preferences.allowUserOverride, path)).length;\n async function handleSave() {\n if (!envelope || !value || !meta.canWrite)\n return;\n const data = module === 'website' ? { ...value, name: (value.name as string).trim() } : value;\n const parsed = settingsWriteOperations[module].input.safeParse({ body: { version: envelope.version, data } });\n if (!parsed.success) {\n const issue = parsed.error.issues[0];\n Toast.error(`${issue.path.join('.') || '表单'}:${issue.message}`);\n return;\n }\n try {\n await save.mutateAsync(parsed.data);\n setDraft(null);\n Toast.success('设置已保存');\n }\n catch (err) {\n if (err instanceof GoaError && err.status === 409) {\n setDraft(null);\n void query.refetch();\n }\n }\n }\n return (<MasterDetailLayout.Body padding={24}>\n <div style={{ maxWidth: module === 'ui' ? 1040 : 760 }}>\n <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, marginBottom: 8 }}>\n <div>\n <Title heading={5} style={{ margin: 0 }}>{def.title}</Title>\n <Text type=\"tertiary\">{def.description}</Text>\n </div>\n {!meta.page && meta.canWrite ? (<Button theme=\"solid\" icon={<Save size={14}/>} loading={save.isPending} disabled={!dirty || uploadingLogo} onClick={() => void handleSave()}>保存</Button>) : null}\n </div>\n <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}>\n <Tag color=\"grey\">系统级</Tag>\n {envelope ? <Tag>版本 {envelope.version}</Tag> : null}\n {meta.overriddenCount > 0 ? <Tag color=\"orange\">{meta.overriddenCount} 项覆盖</Tag> : null}\n {envelope?.updatedAt ? <Text type=\"tertiary\" size=\"small\">最后修改 {envelope.updatedAt}</Text> : null}\n </div>\n {meta.page ? (<Banner type=\"info\" closeIcon={null} description={<span>该模块有专用设置页面,请前往<Link to={meta.page} style={{ margin: '0 4px', display: 'inline-flex', alignItems: 'center', gap: 4 }}>{def.title}<ExternalLink size={12}/></Link>修改。</span>}/>) : null}\n {!meta.page && !meta.canWrite ? (<Banner type=\"warning\" closeIcon={null} description={meta.scope === 'platform' ? '平台级设置仅平台管理员可修改,当前为只读。' : '当前账号没有修改权限,当前为只读。'}/>) : null}\n {changedPreferences.length > 0 ? <Banner type=\"info\" closeIcon={null} description={`待保存 ${changedPreferences.length} 项偏好策略,其中 ${forcedChanges} 项将统一使用系统值;允许修改的项目保留用户已有选择。`}/> : null}\n {query.error ? <Banner type=\"danger\" closeIcon={null} description={<span>设置加载失败。<Button theme=\"borderless\" onClick={() => void query.refetch()}>重试</Button></span>} /> : null}\n <Spin spinning={query.isLoading}>\n {envelope && value ? (<>\n {module === 'website' ? <WebsiteSettingsForm key={envelope.version} value={value as ApiWebsiteSettings} disabled={Boolean(meta.page) || !meta.canWrite || save.isPending} uploading={uploadingLogo} onUploadingChange={setUploadingLogo} onChange={patch => setDraft(previous => ({ ...envelope.effective, ...previous, ...patch }))} />\n : module === 'mcp' ? <McpSettingsForm value={value as ApiMCPSettings} disabled={!meta.canWrite || save.isPending} onChange={patch => setDraft({ ...value, ...patch })} />\n : <SchemaForm schema={foundationSettingSchemas[module]} excludeFields={module === 'ui' ? ['preferences'] : undefined} fieldLabels={settingFieldLabels} value={value} inheritedValue={envelope.inherited as Record<string, unknown>} onChange={next => setDraft({ ...value, ...next })} disabled={Boolean(meta.page) || !meta.canWrite} enumLabels={ENUM_LABELS}/>}\n {uiValue ? <PreferencePolicyEditor value={uiValue.preferences} onChange={preferences => setDraft({ ...value, preferences })} disabled={!meta.canWrite}/> : null}\n </>) : null}\n </Spin>\n </div>\n </MasterDetailLayout.Body>);\n}\n"]}
@@ -1,2 +1,2 @@
1
- import{n as e}from"./rolldown-runtime-Bruge11p.js";import{M as t,O as n,b as r,j as i}from"./clipboard-dpqHdCyy.js";import{n as a,t as o}from"./MasterDetailLayout-KVizcSNO.js";import{i as s,n as c,r as l,t as u}from"./SettingModuleDetail-Dppk9An1.js";import{T as d,f,p,w as m}from"./App-BF96TQ_D.js";import{n as h,r as g}from"./NavListPanel-Iz1RCkVw.js";import{useEffect as _,useMemo as v,useState as y}from"react";import{jsx as b,jsxs as x}from"react/jsx-runtime";import{CheckCard as S}from"@ant-design/pro-components";import{useSettingsModules as C}from"@fudanda/admin-antd/core/hooks/queries/settings";import{useUrlSelectionState as w}from"@fudanda/admin-antd/core/hooks/useUrlSelectionState";function T({module:e,active:t,onSelect:r}){let a=()=>{t||r(e.module)};return/* @__PURE__ */ b(S,{className:`settings-module-card`,value:e.module,checked:t,onClick:a,title:/* @__PURE__ */ x(`button`,{type:`button`,className:`settings-module-card__select`,"data-setting-module":e.module,"aria-label":e.title,"aria-current":t?`true`:void 0,onClick:e=>{e.stopPropagation(),a()},children:[/* @__PURE__ */ b(m,{size:16,"aria-hidden":`true`}),/* @__PURE__ */ b(`span`,{children:e.title})]}),subTitle:e.version>0?`v${e.version}`:void 0,description:/* @__PURE__ */ x(`span`,{className:`settings-module-card__meta`,children:[/* @__PURE__ */ b(n,{size:`small`,color:`grey`,children:`系统级`}),e.overriddenCount>0?/* @__PURE__ */ x(n,{size:`small`,color:`orange`,children:[e.overriddenCount,` 项覆盖`]}):null]}),extra:e.page?/* @__PURE__ */ b(i,{content:`有专用设置页面`,children:/* @__PURE__ */ b(`span`,{className:`settings-module-card__external`,"aria-label":`有专用设置页面`,children:/* @__PURE__ */ b(l,{size:14})})}):void 0})}function E(){return(E=e((()=>{s(),d(),t()})))()}function D(){let e=C(),t=v(()=>(e.data??[]).filter(({module:e})=>e!==`identitySecurity`&&e!==`mcp`),[e.data]),[n,i]=w(`module`),[a,s]=y(!1),c=n===null?null:t.find(e=>e.module===n)??null,l=c??(a?null:t[0]??null),d=l?.module??null;return _(()=>{n!==null&&c===null&&e.data&&!e.isFetching&&i(null)},[n,c,e.data,e.isFetching,i]),/* @__PURE__ */ b(`div`,{className:`page-container page-container--stretch`,children:/* @__PURE__ */ b(o,{defaultSize:260,minSize:200,maxSize:400,persistKey:`system-settings`,style:{flex:1,minHeight:0,overflow:`hidden`},showDetail:d!==null,onBack:()=>i(null),onResponsiveChange:s,master:/* @__PURE__ */ b(h,{title:`设置模块`,loading:e.isLoading,rawBody:!0,children:t.length>0?/* @__PURE__ */ b(S.Group,{className:`settings-module-card-group`,value:d??void 0,multiple:!1,children:t.map(e=>/* @__PURE__ */ b(T,{module:e,active:e.module===d,onSelect:i},e.module))}):/* @__PURE__ */ b(`div`,{className:`nav-list-panel__empty`,children:`没有可访问的设置模块`})}),detail:d&&l?/* @__PURE__ */ b(u,{module:d,meta:l},d):/* @__PURE__ */ b(`div`,{style:{padding:48},children:/* @__PURE__ */ b(r,{...f(`NoContent`,120),description:`选择左侧模块查看或修改设置`})})})})}function O(){return(O=e((()=>{t(),p(),a(),g(),E(),c()})))()}O();export{D as default};
2
- //# sourceMappingURL=SettingsPage-DMzeDrnc.js.map
1
+ import{n as e}from"./rolldown-runtime-Bruge11p.js";import{M as t,O as n,b as r,j as i}from"./clipboard-dpqHdCyy.js";import{n as a,t as o}from"./MasterDetailLayout-ByIBpmkZ.js";import{i as s,n as c,r as l,t as u}from"./SettingModuleDetail-BjxUJeH5.js";import{T as d,f,p,w as m}from"./App-nh6_qOo8.js";import{n as h,r as g}from"./NavListPanel-zwUDIYSP.js";import{useEffect as _,useMemo as v,useState as y}from"react";import{jsx as b,jsxs as x}from"react/jsx-runtime";import{CheckCard as S}from"@ant-design/pro-components";import{useSettingsModules as C}from"@fudanda/admin-antd/core/hooks/queries/settings";import{useUrlSelectionState as w}from"@fudanda/admin-antd/core/hooks/useUrlSelectionState";function T({module:e,active:t,onSelect:r}){let a=()=>{t||r(e.module)};return/* @__PURE__ */ b(S,{className:`settings-module-card`,value:e.module,checked:t,onClick:a,title:/* @__PURE__ */ x(`button`,{type:`button`,className:`settings-module-card__select`,"data-setting-module":e.module,"aria-label":e.title,"aria-current":t?`true`:void 0,onClick:e=>{e.stopPropagation(),a()},children:[/* @__PURE__ */ b(m,{size:16,"aria-hidden":`true`}),/* @__PURE__ */ b(`span`,{children:e.title})]}),subTitle:e.version>0?`v${e.version}`:void 0,description:/* @__PURE__ */ x(`span`,{className:`settings-module-card__meta`,children:[/* @__PURE__ */ b(n,{size:`small`,color:`grey`,children:`系统级`}),e.overriddenCount>0?/* @__PURE__ */ x(n,{size:`small`,color:`orange`,children:[e.overriddenCount,` 项覆盖`]}):null]}),extra:e.page?/* @__PURE__ */ b(i,{content:`有专用设置页面`,children:/* @__PURE__ */ b(`span`,{className:`settings-module-card__external`,"aria-label":`有专用设置页面`,children:/* @__PURE__ */ b(l,{size:14})})}):void 0})}function E(){return(E=e((()=>{s(),d(),t()})))()}function D(){let e=C(),t=v(()=>(e.data??[]).filter(({module:e})=>e!==`identitySecurity`&&e!==`mcp`),[e.data]),[n,i]=w(`module`),[a,s]=y(!1),c=n===null?null:t.find(e=>e.module===n)??null,l=c??(a?null:t[0]??null),d=l?.module??null;return _(()=>{n!==null&&c===null&&e.data&&!e.isFetching&&i(null)},[n,c,e.data,e.isFetching,i]),/* @__PURE__ */ b(`div`,{className:`page-container page-container--stretch`,children:/* @__PURE__ */ b(o,{defaultSize:260,minSize:200,maxSize:400,persistKey:`system-settings`,style:{flex:1,minHeight:0,overflow:`hidden`},showDetail:d!==null,onBack:()=>i(null),onResponsiveChange:s,master:/* @__PURE__ */ b(h,{title:`设置模块`,loading:e.isLoading,rawBody:!0,children:t.length>0?/* @__PURE__ */ b(S.Group,{className:`settings-module-card-group`,value:d??void 0,multiple:!1,children:t.map(e=>/* @__PURE__ */ b(T,{module:e,active:e.module===d,onSelect:i},e.module))}):/* @__PURE__ */ b(`div`,{className:`nav-list-panel__empty`,children:`没有可访问的设置模块`})}),detail:d&&l?/* @__PURE__ */ b(u,{module:d,meta:l},d):/* @__PURE__ */ b(`div`,{style:{padding:48},children:/* @__PURE__ */ b(r,{...f(`NoContent`,120),description:`选择左侧模块查看或修改设置`})})})})}function O(){return(O=e((()=>{t(),p(),a(),g(),E(),c()})))()}O();export{D as default};
2
+ //# sourceMappingURL=SettingsPage-C32Vuizm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsPage-DMzeDrnc.js","mappings":"wrBAMA,SAAgBA,EAAmB,CAAE,SAAQ,SAAQ,YAIlD,CACC,IAAMC,MAAe,CAAOC,GAAQC,EAASC,EAAO,MAAM,CAAG,EAC7D,MAAO,kBAACC,EAAD,CACH,UAAU,uBACV,MAAOD,EAAO,OACd,QAASF,EACT,QAASD,EACT,MAAO,kBAAC,SAAD,CACH,KAAK,SACL,UAAU,+BACV,sBAAqBG,EAAO,OAC5B,aAAYA,EAAO,MACnB,eAAcF,EAAS,OAAS,OAChC,QAAS,GAAS,CAAEI,EAAM,gBAAgB,EAAGL,EAAO,CAAG,EANpD,UAQH,kBAACM,EAAD,CAAW,KAAM,GAAI,cAAY,MAAQ,GACzC,kBAAC,OAAD,UAAOH,EAAO,KAAY,EACtB,C,GACR,SAAUA,EAAO,QAAU,EAAI,IAAIA,EAAO,UAAY,OACtD,YAAa,kBAAC,OAAD,CAAM,UAAU,6BAAhB,UACT,kBAACI,EAAD,CAAK,KAAK,QAAQ,MAAM,OAAO,cAAQ,GACtCJ,EAAO,gBAAkB,EAAI,kBAACI,EAAD,CAAK,KAAK,QAAQ,MAAM,SAAxB,UAAkCJ,EAAO,gBAAgB,MAAS,CAAI,OAClG,C,GACN,MAAOA,EAAO,KAAO,kBAACK,EAAD,CAAS,QAAQ,UAClC,2BAAC,OAAD,CAAM,UAAU,iCAAiC,aAAW,UAAU,2BAACC,EAAD,CAAc,KAAM,EAAK,EAAO,EACjG,GAAI,MAChB,EACL,C,gDCrBA,SAAwBC,GAAe,CACnC,IAAMC,EAAeC,EAAmB,EAClCC,EAAUC,OAAeH,EAAa,MAAQ,CAAC,GAAG,QAAQ,CAAE,YAAaR,IAAW,oBAAsBA,IAAW,KAAK,EAAG,CAACQ,EAAa,IAAI,CAAC,EAChJ,CAACI,EAAaC,GAAkBC,EAAqB,QAAQ,EAG7D,CAACC,EAAgBC,GAAqBC,EAAS,EAAK,EAEpDC,EAAeN,IAAgB,KAE/B,KADAF,EAAQ,KAAM,GAAMS,EAAE,SAAWP,CAAW,GAAK,KAEjDQ,EAAaF,IAAiBH,EAAiB,KAAOL,EAAQ,IAAM,MACpEW,EAAsCD,GAAY,QAAU,KAQlE,OANAE,MAAgB,CACRV,IAAgB,MAAQM,IAAiB,MAEzCV,EAAa,MAAQ,CAACA,EAAa,YACnCK,EAAe,IAAI,CAC3B,EAAG,CAACD,EAAaM,EAAcV,EAAa,KAAMA,EAAa,WAAYK,CAAc,CAAC,EAClF,kBAAC,MAAD,CAAK,UAAU,yCACrB,2BAACU,EAAD,CAAoB,YAAa,IAAK,QAAS,IAAK,QAAS,IAAK,WAAW,kBAAkB,MAAO,CAAE,KAAM,EAAG,UAAW,EAAG,SAAU,QAAS,EAAG,WAAYF,IAAc,KAAM,WAAcR,EAAe,IAAI,EAAG,mBAAoBG,EAAmB,OAAS,kBAACQ,EAAD,CAAc,MAAM,OAAO,QAAShB,EAAa,UAAW,WAChU,SAAAE,EAAQ,OAAS,EAAI,kBAACT,EAAU,MAAX,CAAiB,UAAU,6BAA6B,MAAOoB,GAAa,OAAW,SAAU,GACpH,SAAAX,EAAQ,IAAI,GAAQ,kBAACd,EAAD,CAAsC,OAAQ6B,EAAM,OAAQA,EAAK,SAAWJ,EAAW,SAAUR,CAAiB,EAAzFY,EAAK,MAAoF,CAAC,CACzH,GAAI,kBAAC,MAAD,CAAK,UAAU,wBAAwB,qBAAe,EAC/D,GAAI,OAAQJ,GAAaD,EAAa,kBAACM,EAAD,CAAqC,OAAQL,EAAW,KAAMD,CAAY,EAAhDC,CAAgD,EAAK,kBAAC,MAAD,CAAK,MAAO,CAAE,QAAS,EAAG,EACzJ,2BAACM,EAAD,CAAO,GAAIC,EAAkB,YAAa,GAAG,EAAG,YAAY,eAAgB,EACzE,EAAI,EACV,EACT,C","names":["SettingsModuleCard","select","active","onSelect","module","CheckCard","event","Settings2","Tag","Tooltip","ExternalLink","SettingsPage","modulesQuery","useSettingsModules","modules","useMemo","selectedKey","setSelectedKey","useUrlSelectionState","isNarrowLayout","setIsNarrowLayout","useState","explicitMeta","m","activeMeta","activeKey","useEffect","MasterDetailLayout","NavListPanel","item","SettingModuleDetail","Empty","emptyIllustration"],"ignoreList":[],"sources":["../../src/pages/system/settings/SettingsModuleCard.tsx","../../src/pages/system/settings/SettingsPage.tsx"],"sourcesContent":["import { CheckCard } from '@ant-design/pro-components';\nimport type { ApiSettingModule } from '@fudanda/shared/api/settings';\nimport { ExternalLink, Settings2 } from 'lucide-react';\nimport { Tag, Tooltip } from '@/ui';\nimport './settings-module-card.css';\n\nexport function SettingsModuleCard({ module, active, onSelect }: {\n module: ApiSettingModule;\n active: boolean;\n onSelect: (module: ApiSettingModule['module']) => void;\n}) {\n const select = () => { if (!active) onSelect(module.module); };\n return <CheckCard\n className=\"settings-module-card\"\n value={module.module}\n checked={active}\n onClick={select}\n title={<button\n type=\"button\"\n className=\"settings-module-card__select\"\n data-setting-module={module.module}\n aria-label={module.title}\n aria-current={active ? 'true' : undefined}\n onClick={event => { event.stopPropagation(); select(); }}\n >\n <Settings2 size={16} aria-hidden=\"true\" />\n <span>{module.title}</span>\n </button>}\n subTitle={module.version > 0 ? `v${module.version}` : undefined}\n description={<span className=\"settings-module-card__meta\">\n <Tag size=\"small\" color=\"grey\">系统级</Tag>\n {module.overriddenCount > 0 ? <Tag size=\"small\" color=\"orange\">{module.overriddenCount} 项覆盖</Tag> : null}\n </span>}\n extra={module.page ? <Tooltip content=\"有专用设置页面\">\n <span className=\"settings-module-card__external\" aria-label=\"有专用设置页面\"><ExternalLink size={14} /></span>\n </Tooltip> : undefined}\n />;\n}\n","import type { SettingsModuleKey } from '@fudanda/react-core/hooks/queries/settings';\nimport { useEffect, useMemo, useState } from 'react';\nimport { CheckCard } from '@ant-design/pro-components';\nimport { Empty } from \"@/ui\";\nimport { emptyIllustration } from \"@/components/EmptyIllustration\";\nimport { MasterDetailLayout } from \"@/components/MasterDetailLayout\";\nimport { NavListPanel } from \"@/components/NavListPanel\";\nimport { useUrlSelectionState } from \"@fudanda/react-core/hooks/useUrlSelectionState\";\nimport { useSettingsModules } from \"@fudanda/react-core/hooks/queries/settings\";\nimport { SettingsModuleCard } from './SettingsModuleCard';\nimport { SettingModuleDetail } from './SettingModuleDetail';\n/**\n * 通用设置页:左侧模块清单(按权限 / License 过滤),右侧由模块 Zod schema 驱动的表单。\n * 身份安全与 MCP 由独立菜单管理,不再重复列入模块清单。\n * 页面级全局配置表单,不走 useEditModal(无弹窗、保存后不关闭)。\n */\nexport default function SettingsPage() {\n const modulesQuery = useSettingsModules();\n const modules = useMemo(() => (modulesQuery.data ?? []).filter(({ module }) => module !== 'identitySecurity' && module !== 'mcp'), [modulesQuery.data]);\n const [selectedKey, setSelectedKey] = useUrlSelectionState('module');\n // 窄屏单栏下若沿用桌面端「默认选中首项」会直接落到详情,列表反而要点返回才能看到;\n // 布局形态参与选中派生,故用 state\n const [isNarrowLayout, setIsNarrowLayout] = useState(false);\n // URL 深链值优先;无深链时桌面端回退首项(默认选中不入 URL),窄屏不自动选中\n const explicitMeta = selectedKey !== null\n ? modules.find((m) => m.module === selectedKey) ?? null\n : null;\n const activeMeta = explicitMeta ?? (isNarrowLayout ? null : modules[0] ?? null);\n const activeKey: SettingsModuleKey | null = activeMeta?.module ?? null;\n // 清单不分页且无详情接口兜底:等数据落定再判定深链目标不存在(非法 key / 无权限)并清参,避免在途误清\n useEffect(() => {\n if (selectedKey === null || explicitMeta !== null)\n return;\n if (modulesQuery.data && !modulesQuery.isFetching)\n setSelectedKey(null);\n }, [selectedKey, explicitMeta, modulesQuery.data, modulesQuery.isFetching, setSelectedKey]);\n return (<div className=\"page-container page-container--stretch\">\n <MasterDetailLayout defaultSize={260} minSize={200} maxSize={400} persistKey=\"system-settings\" style={{ flex: 1, minHeight: 0, overflow: 'hidden' }} showDetail={activeKey !== null} onBack={() => setSelectedKey(null)} onResponsiveChange={setIsNarrowLayout} master={(<NavListPanel title=\"设置模块\" loading={modulesQuery.isLoading} rawBody>\n {modules.length > 0 ? <CheckCard.Group className=\"settings-module-card-group\" value={activeKey ?? undefined} multiple={false}>\n {modules.map(item => <SettingsModuleCard key={item.module} module={item} active={item.module === activeKey} onSelect={setSelectedKey} />)}\n </CheckCard.Group> : <div className=\"nav-list-panel__empty\">没有可访问的设置模块</div>}\n </NavListPanel>)} detail={activeKey && activeMeta ? <SettingModuleDetail key={activeKey} module={activeKey} meta={activeMeta}/> : (<div style={{ padding: 48 }}>\n <Empty {...emptyIllustration('NoContent', 120)} description=\"选择左侧模块查看或修改设置\"/>\n </div>)}/>\n </div>);\n}\n"]}
1
+ {"version":3,"file":"SettingsPage-C32Vuizm.js","mappings":"wrBAMA,SAAgBA,EAAmB,CAAE,SAAQ,SAAQ,YAIlD,CACC,IAAMC,MAAe,CAAOC,GAAQC,EAASC,EAAO,MAAM,CAAG,EAC7D,MAAO,kBAACC,EAAD,CACH,UAAU,uBACV,MAAOD,EAAO,OACd,QAASF,EACT,QAASD,EACT,MAAO,kBAAC,SAAD,CACH,KAAK,SACL,UAAU,+BACV,sBAAqBG,EAAO,OAC5B,aAAYA,EAAO,MACnB,eAAcF,EAAS,OAAS,OAChC,QAAS,GAAS,CAAEI,EAAM,gBAAgB,EAAGL,EAAO,CAAG,EANpD,UAQH,kBAACM,EAAD,CAAW,KAAM,GAAI,cAAY,MAAQ,GACzC,kBAAC,OAAD,UAAOH,EAAO,KAAY,EACtB,C,GACR,SAAUA,EAAO,QAAU,EAAI,IAAIA,EAAO,UAAY,OACtD,YAAa,kBAAC,OAAD,CAAM,UAAU,6BAAhB,UACT,kBAACI,EAAD,CAAK,KAAK,QAAQ,MAAM,OAAO,cAAQ,GACtCJ,EAAO,gBAAkB,EAAI,kBAACI,EAAD,CAAK,KAAK,QAAQ,MAAM,SAAxB,UAAkCJ,EAAO,gBAAgB,MAAS,CAAI,OAClG,C,GACN,MAAOA,EAAO,KAAO,kBAACK,EAAD,CAAS,QAAQ,UAClC,2BAAC,OAAD,CAAM,UAAU,iCAAiC,aAAW,UAAU,2BAACC,EAAD,CAAc,KAAM,EAAK,EAAO,EACjG,GAAI,MAChB,EACL,C,gDCrBA,SAAwBC,GAAe,CACnC,IAAMC,EAAeC,EAAmB,EAClCC,EAAUC,OAAeH,EAAa,MAAQ,CAAC,GAAG,QAAQ,CAAE,YAAaR,IAAW,oBAAsBA,IAAW,KAAK,EAAG,CAACQ,EAAa,IAAI,CAAC,EAChJ,CAACI,EAAaC,GAAkBC,EAAqB,QAAQ,EAG7D,CAACC,EAAgBC,GAAqBC,EAAS,EAAK,EAEpDC,EAAeN,IAAgB,KAE/B,KADAF,EAAQ,KAAM,GAAMS,EAAE,SAAWP,CAAW,GAAK,KAEjDQ,EAAaF,IAAiBH,EAAiB,KAAOL,EAAQ,IAAM,MACpEW,EAAsCD,GAAY,QAAU,KAQlE,OANAE,MAAgB,CACRV,IAAgB,MAAQM,IAAiB,MAEzCV,EAAa,MAAQ,CAACA,EAAa,YACnCK,EAAe,IAAI,CAC3B,EAAG,CAACD,EAAaM,EAAcV,EAAa,KAAMA,EAAa,WAAYK,CAAc,CAAC,EAClF,kBAAC,MAAD,CAAK,UAAU,yCACrB,2BAACU,EAAD,CAAoB,YAAa,IAAK,QAAS,IAAK,QAAS,IAAK,WAAW,kBAAkB,MAAO,CAAE,KAAM,EAAG,UAAW,EAAG,SAAU,QAAS,EAAG,WAAYF,IAAc,KAAM,WAAcR,EAAe,IAAI,EAAG,mBAAoBG,EAAmB,OAAS,kBAACQ,EAAD,CAAc,MAAM,OAAO,QAAShB,EAAa,UAAW,WAChU,SAAAE,EAAQ,OAAS,EAAI,kBAACT,EAAU,MAAX,CAAiB,UAAU,6BAA6B,MAAOoB,GAAa,OAAW,SAAU,GACpH,SAAAX,EAAQ,IAAI,GAAQ,kBAACd,EAAD,CAAsC,OAAQ6B,EAAM,OAAQA,EAAK,SAAWJ,EAAW,SAAUR,CAAiB,EAAzFY,EAAK,MAAoF,CAAC,CACzH,GAAI,kBAAC,MAAD,CAAK,UAAU,wBAAwB,qBAAe,EAC/D,GAAI,OAAQJ,GAAaD,EAAa,kBAACM,EAAD,CAAqC,OAAQL,EAAW,KAAMD,CAAY,EAAhDC,CAAgD,EAAK,kBAAC,MAAD,CAAK,MAAO,CAAE,QAAS,EAAG,EACzJ,2BAACM,EAAD,CAAO,GAAIC,EAAkB,YAAa,GAAG,EAAG,YAAY,eAAgB,EACzE,EAAI,EACV,EACT,C","names":["SettingsModuleCard","select","active","onSelect","module","CheckCard","event","Settings2","Tag","Tooltip","ExternalLink","SettingsPage","modulesQuery","useSettingsModules","modules","useMemo","selectedKey","setSelectedKey","useUrlSelectionState","isNarrowLayout","setIsNarrowLayout","useState","explicitMeta","m","activeMeta","activeKey","useEffect","MasterDetailLayout","NavListPanel","item","SettingModuleDetail","Empty","emptyIllustration"],"ignoreList":[],"sources":["../../src/pages/system/settings/SettingsModuleCard.tsx","../../src/pages/system/settings/SettingsPage.tsx"],"sourcesContent":["import { CheckCard } from '@ant-design/pro-components';\nimport type { ApiSettingModule } from '@fudanda/shared/api/settings';\nimport { ExternalLink, Settings2 } from 'lucide-react';\nimport { Tag, Tooltip } from '@/ui';\nimport './settings-module-card.css';\n\nexport function SettingsModuleCard({ module, active, onSelect }: {\n module: ApiSettingModule;\n active: boolean;\n onSelect: (module: ApiSettingModule['module']) => void;\n}) {\n const select = () => { if (!active) onSelect(module.module); };\n return <CheckCard\n className=\"settings-module-card\"\n value={module.module}\n checked={active}\n onClick={select}\n title={<button\n type=\"button\"\n className=\"settings-module-card__select\"\n data-setting-module={module.module}\n aria-label={module.title}\n aria-current={active ? 'true' : undefined}\n onClick={event => { event.stopPropagation(); select(); }}\n >\n <Settings2 size={16} aria-hidden=\"true\" />\n <span>{module.title}</span>\n </button>}\n subTitle={module.version > 0 ? `v${module.version}` : undefined}\n description={<span className=\"settings-module-card__meta\">\n <Tag size=\"small\" color=\"grey\">系统级</Tag>\n {module.overriddenCount > 0 ? <Tag size=\"small\" color=\"orange\">{module.overriddenCount} 项覆盖</Tag> : null}\n </span>}\n extra={module.page ? <Tooltip content=\"有专用设置页面\">\n <span className=\"settings-module-card__external\" aria-label=\"有专用设置页面\"><ExternalLink size={14} /></span>\n </Tooltip> : undefined}\n />;\n}\n","import type { SettingsModuleKey } from '@fudanda/react-core/hooks/queries/settings';\nimport { useEffect, useMemo, useState } from 'react';\nimport { CheckCard } from '@ant-design/pro-components';\nimport { Empty } from \"@/ui\";\nimport { emptyIllustration } from \"@/components/EmptyIllustration\";\nimport { MasterDetailLayout } from \"@/components/MasterDetailLayout\";\nimport { NavListPanel } from \"@/components/NavListPanel\";\nimport { useUrlSelectionState } from \"@fudanda/react-core/hooks/useUrlSelectionState\";\nimport { useSettingsModules } from \"@fudanda/react-core/hooks/queries/settings\";\nimport { SettingsModuleCard } from './SettingsModuleCard';\nimport { SettingModuleDetail } from './SettingModuleDetail';\n/**\n * 通用设置页:左侧模块清单(按权限 / License 过滤),右侧由模块 Zod schema 驱动的表单。\n * 身份安全与 MCP 由独立菜单管理,不再重复列入模块清单。\n * 页面级全局配置表单,不走 useEditModal(无弹窗、保存后不关闭)。\n */\nexport default function SettingsPage() {\n const modulesQuery = useSettingsModules();\n const modules = useMemo(() => (modulesQuery.data ?? []).filter(({ module }) => module !== 'identitySecurity' && module !== 'mcp'), [modulesQuery.data]);\n const [selectedKey, setSelectedKey] = useUrlSelectionState('module');\n // 窄屏单栏下若沿用桌面端「默认选中首项」会直接落到详情,列表反而要点返回才能看到;\n // 布局形态参与选中派生,故用 state\n const [isNarrowLayout, setIsNarrowLayout] = useState(false);\n // URL 深链值优先;无深链时桌面端回退首项(默认选中不入 URL),窄屏不自动选中\n const explicitMeta = selectedKey !== null\n ? modules.find((m) => m.module === selectedKey) ?? null\n : null;\n const activeMeta = explicitMeta ?? (isNarrowLayout ? null : modules[0] ?? null);\n const activeKey: SettingsModuleKey | null = activeMeta?.module ?? null;\n // 清单不分页且无详情接口兜底:等数据落定再判定深链目标不存在(非法 key / 无权限)并清参,避免在途误清\n useEffect(() => {\n if (selectedKey === null || explicitMeta !== null)\n return;\n if (modulesQuery.data && !modulesQuery.isFetching)\n setSelectedKey(null);\n }, [selectedKey, explicitMeta, modulesQuery.data, modulesQuery.isFetching, setSelectedKey]);\n return (<div className=\"page-container page-container--stretch\">\n <MasterDetailLayout defaultSize={260} minSize={200} maxSize={400} persistKey=\"system-settings\" style={{ flex: 1, minHeight: 0, overflow: 'hidden' }} showDetail={activeKey !== null} onBack={() => setSelectedKey(null)} onResponsiveChange={setIsNarrowLayout} master={(<NavListPanel title=\"设置模块\" loading={modulesQuery.isLoading} rawBody>\n {modules.length > 0 ? <CheckCard.Group className=\"settings-module-card-group\" value={activeKey ?? undefined} multiple={false}>\n {modules.map(item => <SettingsModuleCard key={item.module} module={item} active={item.module === activeKey} onSelect={setSelectedKey} />)}\n </CheckCard.Group> : <div className=\"nav-list-panel__empty\">没有可访问的设置模块</div>}\n </NavListPanel>)} detail={activeKey && activeMeta ? <SettingModuleDetail key={activeKey} module={activeKey} meta={activeMeta}/> : (<div style={{ padding: 48 }}>\n <Empty {...emptyIllustration('NoContent', 120)} description=\"选择左侧模块查看或修改设置\"/>\n </div>)}/>\n </div>);\n}\n"]}