# 2026-09-17 ## 修复:合作伙伴分类删除报「order_by 不能为空」 - 现象:`base/othercompany` 删除分类 → 「分类数据检查失败:order_by 不能为空」。 - 根因:`onCategoryDelete` 的守卫查询调 `pageDataApi`(`/data/page`)**漏传 `orderBy`**; 后端 `DataService.page` 用 `getRequiredString(params,"order_by")`,`DbUtils.buildPageOrderBy` 对空值抛「order_by 不能为空」。`/data/loaddata` 的 order_by 是可选的,`/data/page` 是必填 (分页需要确定性排序),所以同类守卫在 `views/system/user` 用 loaddata 没问题、这里用 page 就炸。 - 改动:`src/views/base/othercompany/index.vue` 守卫查询加 `orderBy: 'b_id ASC'`; `tests/views/othercompany.spec.js` 新增回归用例断言 pageDataApi 的入参(含 orderBy)。 全套 10 个用例通过;oxlint 干净(oxfmt 全仓库既有 format issues,未动)。 - 已核对仓库内另 3 处 `pageDataApi` 调用(FileListPanel / useLookupOptions / FmsModuleListPage)都传了 orderBy。 ## 新增:UI 组件库全局配置(uiConfig) - 背景:组件库此前**没有任何全局配置层**(`ui/index.js` 只是具名导出,无 `install`/`app.use`; 组件间只有 form/form-group/radio-group/tree/dropdown 五个局部 provide)。Form 的 `layout` 等默认值硬编码在 prop 里,想改只能逐处传。 - 新增 `fms-vue/src/components/ui/config.js`:`uiConfig`(reactive)+ `setUIConfig(patch)`(按组件维度浅合并) + `resetUIConfig()`;三者也从 `@/components/ui` 具名导出。 - 回落顺序统一为 **自身 prop > 全局配置 > 组件内置默认**。凡要支持全局覆盖的 prop, `default` 必须改成 `undefined` 且 validator 放行 `undefined`(Vue 会校验 default 值)。 - Form(`form/form.vue`):`layout`/`labelAlign`/`labelWidth`/`validateTrigger` 改为经 `resolvedXxx` computed 回落,provide 下发的是**回落后的最终值**,FormItem 不用再管全局配置; FormItem 独立使用(无 Form 包裹)时也读一次 `uiConfig`。 - 语言联动写在 `src/App.vue`:`watch(() => i18nStore.locale)` → `layout = /^zh/i.test(locale) ? 'horizontal' : 'vertical'` (中文横排、其他语言竖排),`immediate: true` 覆盖持久化 locale 的刷新场景。 - 存量 8 处 `layout="vertical"` 已全部删除(login、base/othercompany、system/user、 menu-management/MenuBasicPanel、module-management 的 Basic/AutoCode/FormPreview、FmsModuleEditModal), 统一跟随语言;`ui/demo/form.vue` 保留(它是组件展示页,故意演示各布局)。 风险点:FmsModuleEditModal(columns=24 网格)与 FormPreview(columns=48)在中文下变横排可能拥挤,待目测。 - 测试:`tests/components/form.spec.js` 新增 5 例(全局默认、prop 覆盖、局部合并、validateTrigger、独立 FormItem), 15 例全通过;oxlint `--deny-warnings` 干净;`vite build` 通过。 - 已知非本次引入:`tests/views/login.spec.js` 套件级失败(favicon.svg URL 解析,环境问题,收集 0 用例); `module-list-components.spec.js` 的 `.filter-joiner`/`.filter-row` 断言是过期基线。 ## 修复:顶栏语言切换不生效(i18n 只有 locale,没有译文) - 根因:`setMessages` 在 `src/` 下**从无调用点** → `messagesRef` 永远为空,`t(key, fallback)` 恒返回中文兜底; 顶栏按钮只是把 `locale` 在 zh-CN/en-US 间翻一下,界面毫无变化。 另查库:`s_i18n_type` 有 zh-CN(默认)/en-US;`s_i18n` **134 行全是 zh-CN,en-US 为 0 行**。 - 改动: - `stores/i18n.js` 新增 `loadMessages(locale, force)`:查 `s_i18n`(`b_canuse = 1 and b_locale = N'..'`, `sqlQuote` 转义单引号),按 locale 缓存 + 并发 Promise 复用 + 失败静默;`applyMessages` 只认**当前** locale (防止请求回来时语言已被切走导致串台),合并顺序 **前端内置 < 库表译文**;`clearMessages` 顺带清缓存。 - 新增 `src/i18n/builtin-messages.js`:内置 en-US 的 `common.*`(45 条,代码里已用 `t('common.x','中文')` 约定)。 中文不内置(fallback 即中文)。库里登记同名 key 可覆盖内置。 - `App.vue` 的 locale watcher 增加 `i18nStore.loadMessages(locale)`;`router/index.js` 守卫在 `loadLanguages()` 后再 `loadMessages()` 兜首次进入。 - 顶栏:按钮改为 Dropdown,语种取自 `s_i18n_type` 清单(不再硬编码互切),当前项用 `shortcut: '✓'` 标出 (Dropdown item 没有 active 态)。 - 测试新增 12 例:`tests/stores/i18n-messages.spec.js`(7)、`tests/components/app-topbar-language.spec.js`(3)、 `tests/unit/app-locale-sync.spec.js`(2)。全量 497 通过 / 13 失败(**均为既有基线**: login 套件 + router-auth 3 例都是 `favicon.svg` 环境问题——`views/login/index.vue:98` 的 ``; 其余 9 例是查询面板改版后的过期断言)。 - 注:`vite build` 冒烟本次被用户拒绝执行(含 find -delete),改用 vitest 挂载 App/AppTopbar 验证编译与行为。 ## 查询区改用 Form/FormItem(跟随语言布局) - 现象:切中文后查询条件区仍是上下结构。原因:`FmsQueryToolbar.vue` **没用 Form**,是自己写的 `