# 常见问题

## 为什么不用第三方组件库？

基础控件基于 Radix 原语自建（`src/components/ui/`），后台语义组件自己实现。理由是：

1. **主题一致性**：颜色只走语义 Token，换配色时不需要跟组件库的主题变量打架；
2. **无障碍可控**：焦点管理、键盘行为、ARIA 属性都在自己手里，出问题能直接修；
3. **包体**：组件库往往带一整套用不到的样式与逻辑，模板只需要后台常用的这些。

代价是要自己维护这些组件，所以才有"组件总览 + 真实落点 + 测试"三件套约束。

## 为什么不引图表库？

折线、柱状、环形、迷你柱、条形、热力、雷达、漏斗、甘特都在 `src/components/charts.tsx` 与
`column-chart.tsx` 里自绘 SVG：跟随语义色、支持深色模式、支持"减少动效"，包体几乎为零。
需要更复杂的图表（地图、金融 K 线、大数据量散点）时，建议在业务侧单独引库，不要改动这一层。

## 文档站为什么用 VitePress？

- **内容就是 Markdown**：`docs/` 是站点根目录，`guide/` 放指南、`components/` 放组件，改文案不用碰 React 代码；
- **主题能力开箱可用**：导航、分组侧栏、目录大纲、深色模式、本地全文搜索都是内置的，不用自己维护一套文档站外壳；
- **构建即校验**：`pnpm docs:build` 会检查死链，链接写错直接构建失败；
- **产物是纯静态文件**：`docs/.vitepress/dist` 丢到任意静态托管即可；
- **依赖边界干净**：只装在 devDependencies，不进应用产物，应用构建（`pnpm build`）与文档构建互不影响。

需要代码分栏、任务清单这类增强时再按需加 VitePress 插件；当前只装了本体，保持依赖最少。

## 为什么偏好只存 localStorage？

主题、配色、无障碍、通知偏好、顶栏操作顺序、侧栏宽度 / 圆角 / 动画 / 布局模式、表格列宽、筛选预设、快捷键
都是"这台设备上的个人偏好"，不需要服务端同步，也不该进 Zustand 的业务状态。所有键名都带
`VITE_APP_STORAGE_PREFIX` 前缀，多后台同域部署时互不干扰。

## 服务端数据为什么进不了 Zustand？

模板刻意不提供请求层：数据获取、缓存、失效策略各业务差异太大，写进来反而会互相打架。
Zustand 只放本地 UI 状态与偏好，接口数据请用业务自己的请求方案（TanStack Query、SWR、自研都可以）。

## 新增页面后菜单没出现？

检查三处：

1. `src/App.tsx` 有没有注册路由；
2. `src/app/navigation.ts` 的 `navigation` 有没有登记 `path` / `label` / `icon`；
3. `navigationGroups` 的 `paths` 有没有把路径放进期望的分组——**未登记的会落到第一个分组**。

## 命令面板搜不到新页面的内容？

命令面板索引的是"渲染出来的页面内容"，上限 400 条，按路由缓存，页面内容变化通过 `MutationObserver` 重建索引。
如果内容由异步请求填充，需要在数据到位后再打开面板；如果页面特别大，可以把索引上限调大或改为分片索引。

## 虚拟滚动的表格为什么必须固定行高？

虚拟滚动靠"行高 × 行数"算总高度和窗口位置。当前实现按固定行高渲染可视窗口（并让表头吸顶），
所以与行内展开互斥；需要动态行高时要改成按行测量 + 滚动锚定，
这是[架构与决策](/guide/architecture)里记录的已知取舍。

## 表格的滚动容器为什么不能随手改成 `overflow-x-auto`？

虚拟滚动依赖**外层容器**作为滚动锚点。给内层 `.table-container` 加横向滚动会把滚动事件抢走，
表头就不再吸顶。改表格样式时先确认虚拟滚动用例（`design-system.spec.ts`）仍然通过。

## `asChild` 和 `loading` 为什么不能一起用？

Radix 的 `Slot` 只接受单个子元素，而加载态需要插入转圈图标。`Button` 现在的处理是：
`asChild` 时只保留禁用语义、不插图标，避免出现"给 Slot 传了两个 children"导致整站崩溃。

## 文案不生效 / 页面显示成了 key？

两种情况：

1. key 没登记进 `src/lib/i18n.ts` —— `pnpm test` 里的 `i18n-keys.test.ts` 会报出来；
2. 文案是动态拼接的 key —— 扫描覆盖不到，需要人工检查 `t()` 的入参。

菜单项可以直接写中文（未登记的 key 原样显示），但组件内部固定文案必须进语言包。

## 顶栏通知为什么固定在第二位？

这是产品约定：通知是最高频的全局入口。用户仍可以在「设置 → 外观 → 顶栏快捷操作」里调整顺序，
新版本新增的入口会按默认位置插回，不会因为用户改过顺序就消失。

## 顶部导航模式下为什么看不到官网入口和品牌字标？

顶部导航（`top`）模式下，官方站点入口与品牌字标会从侧栏移除，避免与顶部导航重复：
侧边菜单由顶部菜单点击展开，面包屑与顶部菜单分两行，右上角只显示头像图标。这是刻意的视觉收敛，
不是渲染缺失。
