diff --git a/docs/mobile-ui-code-review-2026-10-04.md b/docs/mobile-ui-code-review-2026-10-04.md new file mode 100644 index 0000000..5868d36 --- /dev/null +++ b/docs/mobile-ui-code-review-2026-10-04.md @@ -0,0 +1,513 @@ +# 移动端布局与工程一致性评审 + +**综合评分:6.5 / 10,按严格命名、职责和样式一致性标准评估。** + +复核日期:2026-10-06。初版日期:2026-10-04。代码基线仍为 `1e3954c`。本文已根据命名长度与 UnoCSS 使用边界的反馈再次修订,文件名保留初次创建日期;目标名称、目录和代码片段都是后续调整建议。评分沿用上一轮,不因这次风格约定修改而反复变动。 + +我认可初版的大部分事实判断,但不完全认可其评价尺度。扫码异常处理、旧组件参数、重复内边距、模板检查缺口都有代码依据;退出按钮位置、社区卡片顺序、圆角和阴影则存在产品取舍。不能将一种审美偏好包装成客观缺陷,也不能将未实测的遮挡写成已发生的故障。 + +初版的综合 6.8 分适用于一般维护标准,“命名一致性 8 分”对本项目的严格要求偏宽。本版将文件命名、函数语义、状态模型、样式归属和例外管理放进同一套标准重新评价。分数变化来自评价标准调整,不代表这两天代码变差。分数属于评审判断,不是自动测评或行业排名。 + +## 1. 评分、范围与判断方式 + +| 维度 | 得分 / 10 | 主要依据 | +| --------------------- | --------: | ---------------------------------------------------------------- | +| 布局职责 | 7.0 | 三类 layout 有合理分工,页面与壳的尺寸责任仍有重叠 | +| 交互完整性 | 6.0 | 退出确认和分页状态具备基础,扫码能力、异常分类与操作互斥存在缺口 | +| 文件、方法与类型命名 | 6.0 | 能读懂,但词汇、动作副作用、实体标识和显示名称没有稳定约定 | +| 样式归属与设计变量 | 6.5 | 有语义色及可读的局部 BEM,全局穿透、工具类别名与使用边界需治理 | +| Vue / TypeScript 约束 | 6.0 | 脚本严格模式存在,模板检查关闭、部分 ref 和 shim 过宽 | +| 注释质量 | 7.5 | 有解释约束的好注释,也有名实不符和重复代码的说明 | + +六项等权平均为 6.5。严格标准下最需要提高的是一致性,不是注释数量或目录数量。 + +评审以本地源码和安装的 `@wot-ui/ui@2.3.2` 为依据。覆盖首页、工作台、个人中心、扫码确认、代表性设置与管理页面,以及 layouts、composables、公共样式、主题和配置。第三方图表代码不纳入项目自身的命名评分。 + +没有新增浏览器截图、微信开发者工具或 App 真机记录。本文用以下标记避免扩大结论: + +- **事实**:能从当前源码或本地依赖直接确认。 +- **风险**:有具体触发条件,实际表现需要运行端验证。 +- **约定**:适合本项目严格要求的推荐标准,不宣称是唯一行业规范。 + +优先级:P1 优先处理行为错误与约束缺口;P2 统一职责和命名;P3 整理低风险细节。代码风格问题不会仅因影响观感而升级为 P1。 + +## 2. 严格标准的核心:名称、行为、归属一致 + +对这个项目,我建议采用以下六条,而不是简单要求“全部名字更长”: + +1. **同一层级、同一概念使用稳定词汇。** 业务导航与界面显隐有稳定动词,登录状态与在线状态分开;CSS 可使用已约定的短 block,不要求逐层展开完整领域名。 +2. **名称必须准确表达能力。** `background` 可以包含渐变,`backgroundColor` 不应暗示可以传任意 background 简写;扫码获取票据也不等于完成登录。 +3. **由完整使用方式判断是否清楚。** `UserAPI.getPage()`、`countdown.start()`已经有上下文,不需要重复成 `UserAPI.getUserPage()`、`countdown.startCountdown()`。 +4. **一个规则有一个负责者。** 页面 gutter、主题变量、导航占位、错误提示都要有确定来源。 +5. **约束优先于注释。** 有限菜单用联合类型;互斥动作使用共享状态;不会执行的参数应删除,不能只补一句说明。 +6. **例外集中、可解释。** 框架入口、第三方 API、生成文件可以遵循自身规则。不要为了表面统一破坏路由或组件契约。 + +名称明确、状态正确、依赖可见、规则可检查,比制造大量小文件和转发函数更符合严格维护需求。 + +## 3. 先定业务词汇,避免改完又混用 + +以下用于区分业务含义,不要求所有名称复制整段词汇。页面标识、局部样式和对象方法可以使用已有上下文。 + +| 概念 | 项目代码建议用词 | 说明 | +| ---------------------- | -------------------------- | ------------------------------------------ | +| 个人中心页面 | `mine` | 沿用现有页面标识,避免只为名称长度迁移词汇 | +| 昵称、头像、部门等资料 | `profile` | 不用来泛指所有账号功能 | +| 密码、手机、邮箱绑定 | `accountSecurity` | 当前 `openAccount()` 打开的实际内容 | +| 登录态和退出 | `session / authentication` | `isAuthenticated` 不等于在线或权限可用 | +| PC 二维码授权流程 | `qrLogin` | 统一方法与类型中的业务词汇 | +| 相机扫描阶段 | `scanner / scan` | 只负责获得二维码内容及进入后续流程 | +| 设置菜单 | `settingsMenu` | 与后台权限菜单 `MenuItem` 区分 | +| 更多操作 | `actionSheet` | 展示名称与动作 ID 独立 | +| 导航栏 | `navbar` | 避免自有名称中 `navBar/navbar` 无规则交替 | +| 导航测量数据 | `navbarMetrics` | 与导航行为、路由跳转区分 | +| 公众号介绍 | `officialAccount` | 当前社区卡片实际跳转到公众号页 | + +`mine`、`work`、`subPages` 保留现有路由含义;`mine` 也可以直接作为个人中心页面样式 block。`qr/dept/perm/bg/desc/nav` 等熟悉缩写纳入项目词汇表,保持一致,不机械展开。第三方 DTO 字段按协议保留。 + +## 4. 文件命名:按文件角色统一,减少无意义入口层 + +### 4.1 推荐规则 + +| 文件角色 | 推荐规则 | 示例 | +| ----------------------------- | ---------------------------- | ---------------------------------------------- | +| 普通 Vue 组件 | PascalCase,体现职责 | `ProfileCard.vue` | +| 路由页面入口 | 沿用现有目录及 `index.vue` | `pages/mine/index.vue` | +| layout 注册文件 | 保留现有小写标识 | `default.vue / tabbar.vue / blank.vue` | +| composable | `useXxx.ts` | `useNavbarMetrics.ts` | +| API、工具、配置、领域类型模块 | kebab-case;简单领域名可单词 | `user.ts / settings-menu.ts / storage-keys.ts` | +| 样式模块 | kebab-case,体现作用 | `theme.scss / layouts.scss` | +| 类型、接口 | PascalCase,领域明确 | `SettingsMenuItem / NavbarMetrics` | +| 第三方和生成文件 | 保持上游规则 | `qiun-data-charts.vue / auto-imports.d.ts` | + +PascalCase 组件文件名是本项目建议采用的约定,不是说现有 kebab-case 本身错误。如果采用这套规则,应覆盖自有普通组件,而不是只改几个喜欢的文件。 + +路由与 layout 入口不应盲目改名。也不必为每个 `index.vue` 再加一个只负责转发的 `AccountCenterPage.vue`,这种拆分增加跳转阅读成本。 + +### 4.2 建议的具体文件调整 + +以下把“统一文件格式”和“纠正语义”分开。已有名称准确时,只调整约定的大小写,不追加业务前缀。 + +| 现有文件 | 推荐目标或处理 | 原因 | +| --------------------------------------------------------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------- | +| [components/app-provider/index.vue](../src/components/app-provider/index.vue) | 采用普通组件文件规则时用 `AppProvider.vue`,保留组件名称 | 负责应用主题和反馈策略;页面实例作用域写进契约,不必靠改名解决 | +| [components/custom-navbar/index.vue](../src/components/custom-navbar/index.vue) | `AppNavbar.vue` | `custom` 只说明不是库组件,`App` 说明是项目导航栏 | +| [mine/components/profile-card.vue](../src/pages/mine/components/profile-card.vue) | `ProfileCard.vue` | `profile-card` 已准确,无需追加 `Summary` 或 `Account` | +| [mine/components/quick-cards.vue](../src/pages/mine/components/quick-cards.vue) | `QuickActions.vue` | 表达快捷操作,不把当前卡片排布固化为组件职责 | +| [mine/components/menu-section.vue](../src/pages/mine/components/menu-section.vue) | `MenuSection.vue` | 页面私有目录已经提供上下文,不必追加 `Settings` | +| [mine/components/community-card.vue](../src/pages/mine/components/community-card.vue) | `OfficialAccountCard.vue` | 实际内容及导航目标是公众号,`community` 范围过宽 | +| [login/components/bind-mobile-popup.vue](../src/pages/login/components/bind-mobile-popup.vue) | `BindMobilePopup.vue` | 当前名称可读,统一格式即可;不要无理由切换 `mobile/phone` | +| [work/components/custom-tree.vue](../src/subPages/work/components/custom-tree.vue) | `TreeView.vue` | 已被部门、菜单、权限页面复用,移除无意义的 `custom` | +| [useNavbar.ts](../src/composables/useNavbar.ts) | `useNavbarMetrics.ts` | 输出设备尺寸与胶囊信息,确实需要区分测量和导航行为 | +| [useScanLogin.ts](../src/composables/useScanLogin.ts) | 保留 `useScanLogin.ts` | 已说明扫码登录入口;公开方法和注释说明扫描后进入确认页 | +| [useCacheCleaner.ts](../src/composables/useCacheCleaner.ts) | 保留 `useCacheCleaner.ts` | 命名已经说明能力,没必要只为词性偏好替换成 Cleanup | + +不再推荐 `ProfileSummaryCard / AccountQuickActions / SettingsMenuSection` 这一组扩展名称。目录、组件名和接口应共同提供上下文,不必各自重复完整业务背景。导出到公共目录后出现实际歧义,再补足必要的领域词。 + +`UserAPI`、`Storage` 不需要仅因个人偏好统一改成另一种大小写。已有文件夹入口也不需要为了“全部扁平”立即迁移;目录内有配套资源时可以保留目录。 + +### 4.3 目录归属与拆文件条件 + +- 仅个人中心使用的组件、菜单配置和视图类型留在 `pages/mine` 附近。 +- 跨多个工作台页面使用的 `TreeView` 留在工作分包,避免只为通用外观移进主包。移动文件时还需检查分包构建产物。 +- 跨不同页面领域使用的导航与 Provider 放 `src/components`。 +- 同一领域多个调用方共享的类型放就近模块;组件私有 Props、内部状态类型留在组件内。 +- `index.ts` 只作为确有价值的模块导出入口,不给每个单文件组件增加一层目录。 +- 不以固定行数作为拆分标准;按独立状态、独立依赖、复用范围和是否可单独理解决定。 + +本文推荐布局保留现有三类。现有 `useTheme()` 大部分方法只转发到 store,应先明确它是否提供额外的组件契约;如果没有,直接使用 store 更清楚,不要因为“所有业务都要有 hook”而保留转发层。 + +## 5. 方法命名:让读者预判副作用 + +### 5.1 动词约定 + +| 前缀或动词 | 表达的行为 | 约束 | +| ----------------------------------- | ------------------------------ | --------------------------------------------------------------- | +| `is / has / can` | 查询或计算判断 | 不发请求、不跳页面、不弹提示 | +| `get / format / parse / build` | 获取已有数据或构造值 | 具体是否同步应由模块契约说明;项目 API 的 `getXxx` 允许远端请求 | +| `fetch` | 发起取数并返回结果 | 页面函数默认不隐式写多处 UI 状态 | +| `load` | 取数并写入当前模块状态 | 命名明确加载对象 | +| `ensure` | 不满足前置条件时进行补齐或引导 | 返回结果及导航副作用要说明 | +| `navigateTo / switchTab / returnTo` | 页面导航 | 不伪装成打开弹窗 | +| `open / close` | 显示或隐藏弹窗、操作面板 | 不同时用来指 URL 导航 | +| `reset` | 恢复初始值 | 区分清空、取消和停止 | +| `sync` | 根据来源刷新已有状态 | 可重复执行,不暗示只初始化一次 | +| `handle` | 适配 UI 事件及其参数 | 不作为所有业务函数的统一前缀 | + +业务动作可直接命名为 `logout / clearCache / confirmQrLogin`。不要为了满足 `handle` 规则再写一个同内容转发方法。 + +### 5.2 当前方法建议 + +| 当前名称 | 推荐目标 | 根据当前行为作出的判断 | +| ------------------------------------- | ----------------------------- | --------------------------------------------------------- | +| `openProfile()` | `navigateToProfile()` | 实际跳资料页 | +| `openAccount()` | `navigateToAccountSecurity()` | 实际跳账号安全页 | +| `openOfficialAccount()` | `navigateToOfficialAccount()` | 实际跳公众号页 | +| `scanLogin()` | `scanForLogin()` | 扫码并进入确认页,尚未完成 PC 登录 | +| `checkLogin()` | `ensureAuthenticated()` | 缺少 token 时会跳登录页;`silent` 分支单独使用 store 判断 | +| `loadUserInfoIfNeeded()` | `ensureUserInfoLoaded()` | 已有资料时跳过,否则加载并写入 store | +| `initActive()`(tabbar) | `syncActiveTab()` | 在 mounted、onShow 都执行,是同步而非一次初始化 | +| `init()`(navbar metrics) | `refreshMetrics()` | 重读设备及胶囊数据,不承担应用初始化 | +| `loadData()`(权限分配) | `loadRolePermissions()` | 明确页面所加载的业务组合 | +| `showActions()` | `openActionSheet()` | 与打开界面动作统一 | +| `handleNavClick()`(导航 composable) | `navigate()` | 对外提供导航能力;UI 事件适配留在使用处 | +| `clear()`(缓存 composable) | `clearCache()` | 避免 destructuring 后丢失对象上下文 | + +单表单组件内部的 `handleSubmit()` 可以保留;包含多个独立表单时应使用 `handlePasswordSubmit / handleEmailBindingSubmit`,或一个明确的业务分发函数。不是所有短名称都需要扩大。 + +`confirmLogout()` 当前弹确认框且执行退出,建议明确流程契约。若改名为 `requestLogout()`,它表示发起完整退出流程;若拆成 `confirmLogout()` 与 `logout()`,前者只返回确认结果,后者执行操作。不要只改名称而保留模糊的双重语义。 + +### 5.3 异步方法必须有一致的结果和错误责任 + +[useActionSheet](../src/composables/useActionSheet.ts) 的 `handler` 类型允许 Promise,但调用时未等待;`confirmAction()` 同一个 catch 覆盖确认取消和业务执行错误,注释却只说用户取消。名称干净也不能消除这个行为歧义。 + +推荐契约:明确谁等待执行、谁处理失败、谁显示提示。取消可静默;业务失败由既定责任方反馈。请求层已有提示时也应说明,不能把失败全部描述为取消。`Promise` 只适合调用方只关心是否成功的场景;需要区分取消、失败和无权限时使用结果联合类型。 + +### 5.4 同类代码采用稳定的写法 + +建议命名业务函数使用函数声明,事件回调、数组回调及 computed getter 使用箭头函数;API 对象保留方法简写。这样可以减少同一文件中同类方法随意混用两种写法。这是项目约定,不是语言正确性要求。 + +SFC 统一按脚本、模板、样式排列;确有 uni-app 组件 options 需求时保留必要的第二个 script,并统一放置位置。脚本内部按依赖导入、页面声明、Props/事件、状态、派生值、动作、生命周期组织。只在段落较长时添加分节注释,不在每个 ref 前写“状态定义”。 + +格式细节交给现有 Prettier。不要再用人工规则与仓库已有的双引号、分号、缩进设置相互竞争。 + +## 6. 状态、类型与事件:标识不是显示文字 + +### 6.1 变量与类型调整 + +| 当前名称或模型 | 推荐目标 | 说明 | +| ---------------------------------- | ---------------------------------------- | ---------------------------------------------------------- | +| `name`(个人卡片 prop) | `displayName` | 与账号 `username` 区分 | +| `avatar`(个人卡片 prop) | 可保留;需要区分图片对象时用 `avatarUrl` | 在图片接口中含义明确,不要求所有字符串字段都加类型后缀 | +| `avatarShow` | `isCropperVisible` | 当前组件只有一个裁剪弹层,不必再重复 Avatar | +| `active`(tabbar) | `activePath` | 当前值是路径;tabbar 已提供上下文 | +| `visibleGridList` | `visibleGroups` | 表达筛选后的分组,不把当前 grid 排布写进数据名 | +| `MenuItem`(个人中心导出类型) | `SettingsMenuItem` | 导出后可能与后台菜单实体混淆;纯私有类型可以用 `MenuItem` | +| `DialogType / dialog`(账号页) | `SecurityAction / popup` | 枚举表达安全动作,对象表达弹层;避免与 Wot Dialog 实例混淆 | +| `bgColor`(自有 navbar prop) | `background` | 当前允许渐变,不能用 color 限定含义 | +| `navBarHeight`(自有测量接口) | `contentHeightPx` | 区分内容高度和包含状态栏的总高度 | +| `totalHeight`(自有测量接口) | `totalHeightPx` | 对外尺寸声明单位 | +| `menuButtonLeft` | `capsuleLeftPx` | 强调是坐标,不是左插槽宽度 | +| `countdown`(秒数 ref) | `remainingSeconds` | 表达数值含义,区别于倒计时控制对象 | +| `duration`(倒计时入参) | `durationSeconds` | 公开参数明确单位 | +| `TOAST_DURATION` | `RETURN_DELAY_MS` | 实际控制延迟返回,没有设置 toast duration | +| `colorWithAlpha / colorWithAlpha2` | `heroStartColor / heroEndColor` | 表达渐变端点,避免编号代表业务含义 | + +是否补词取决于歧义,不取决于名称是否足够“完整”。公开单位接口、多个单位共存或脱离上下文使用的值优先加单位;局部清楚的 `width` 可以保留。 + +`isLoading` 不是禁用词。单一取数模块可以用它;扫码确认页有加载、确认、取消等阶段,建议用一个有限状态 `status` 管理互斥关系,只有存在多个状态对象时再加 `qrLogin` 前缀。 + +### 6.2 两处比大小写更重要的问题 + +**问题一:在线与登录混淆。** [个人卡片](../src/pages/mine/components/profile-card.vue) 第 6 行用 `isAuthenticated` 控制 `profile-card__online-dot`。有 token 不证明用户在线。若保留这个装饰,应命名为认证状态标识;若用户可能理解成实时在线状态,建议删除,除非接入真实在线数据。 + +**问题二:操作菜单把 label 当作 ID。** [useActionSheet](../src/composables/useActionSheet.ts) 第 34 行使用 `menu.name` 构建 handler 映射,同名项会覆盖,文案调整也改变分发键。这是身份模型的问题,不只是把 `name` 改成 `label` 就能解决。 + +建议采用稳定的 `id`、可展示的 `label`、负责执行的 `execute`。Wot 的 `name` 字段在适配时填写 label;选中后按稳定 ID 或与 ID 关联的索引分发,不能再次按文案查找。 + +```ts +// 目标模型示意,不是现有实现。 +interface ActionSheetCommand { + id: string; + label: string; + execute: () => void | Promise; +} +``` + +个人中心菜单 key 同样应定义为有限联合类型。导航项与操作项用判别字段区分,例如 `kind: 'route' | 'action'`。将 ID、显示信息、导航目标或业务动作放在同一个受类型约束的配置中,避免 `toolMenus` 和 `menuRoutes` 两份表独立维护。 + +### 6.3 事件用最短、准确的用户意图 + +当前 `` 已经易读,可以保留。无需统一拉长成 `profile-click / qr-login-click`:组件上下文已说明来源,`click` 也不应把事件限定为某一种输入方式。 + +事件用 kebab-case;单词事件保持单词。多个不同扫描入口才区分 `login-scan / payment-scan`。父页面决定导航或业务动作,第三方 `click / select / confirm / update:modelValue` 按库契约保留。 + +组件同时 emit 返回事件并立即调用 `navigateBack()` 时,必须说明事件仅供通知。如果希望父页接管返回,提供明确接管契约,不能让双方都以为自己负责导航。 + +## 7. 样式类:短 block、准确元素、稳定规则 + +上一版将 `profile-card` 扩成 `profile-summary-card`、将个人中心类名全部扩成 `account-center-page__...`,增加了重复信息;“类名完整复制组件名”“每个组件只能一个 block”也过于机械。这些建议收回。严格维护应要求名称准确、归属清楚,而不是名称越长越好。 + +### 7.1 本项目采用的紧凑规则 + +| 对象 | 推荐规则 | 示例 | +| ---------- | -------------------------------------------------- | ------------------------------------------------------- | +| 页面 block | 沿用短而明确的页面标识,不默认追加 `-page` | `home / mine / permissions` | +| 组件 block | 通常 1–2 个词,保留已有准确名称 | `profile-card / menu-section / quick-card / app-navbar` | +| 元素 | `block__element`,优先一个角色词,需要区分时再补词 | `profile-card__info / profile-card__avatar-wrap` | +| 状态或变体 | `block--modifier` 或 `block__element--modifier` | `profile-card--guest / quick-card__icon--primary` | +| 缩写 | 使用小范围固定词汇,避免自造缩写 | `qr / dept / perm / bg / desc / nav` | + +“通常 1–2 个词”是控制重复信息的提示,不是硬性词数上限。确有必要的领域名可以更长。CSS block 不必机械复制组件文件名,例如 `QuickActions.vue` 内已有明确的 `quick-card` 可以保留。 + +`body / main / content / wrap / actions` 都是可用的结构词;只有不能区分用途或错误绑定布局方向时才需要改。`desc` 不必强行展开成 `description`,`bg` 不必一律展开成 `background`。同一含义保持一种写法即可;公开 prop 的 `background` 则需要准确表达可传渐变的能力。 + +一个 Vue 文件可以拥有 `menu-section` 和 `menu-row` 两个职责清楚的 block,不需要为了 BEM 拆出两个组件,也无需登记额外审批。避免同一批节点随意混用数套名字,而不是禁止多个 block。 + +SCSS 可用 `&__info` 等一层展开;避免生成 `block__body__title`,也不要依赖深层 DOM 链来表达元素身份。`scoped` 用于隔离,短 block 用于辨认归属。公共样式、Wot `custom-class`、小程序 shared 样式尤其应使用有辨识度的类名,不裸用 `.header/.button`。 + +### 7.2 修订后的具体类名建议 + +| 现有类名 | 推荐目标或处理 | 原因 | +| ------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------- | +| `.mine-hero / .mine-body` | `.mine__hero / .mine__body` | 在页面根补 `.mine`,统一页面元素写法,保留现有短词 | +| `.community-slot` | `.mine__community` | 属于个人中心页面的摆放区域,无需另造 slot block | +| `.community-slot__bg` | `.mine__hero-bg` | 背景真实归属应移到 Hero,仅改名称不能解决定位依赖 | +| `.loading-center` | `.mine__cache-loading` | 标明用途,避免只有对齐方式的信息 | +| `.profile-card` | **保留** | 已经清楚,无需扩成 profile-summary-card | +| `.profile-card__left` | `.profile-card__avatar-wrap` | 实际是头像及状态点的容器,避免绑定左侧位置 | +| `.profile-card__main` | `.profile-card__info` | 该处明确展示用户信息;main 本身不是禁用词 | +| `.profile-card__scan` | **保留** | 组件内只有一个扫描入口,按钮文案及事件契约说明扫码登录用途 | +| `.profile-card__action` | `.profile-card__login` | 是未登录入口,不是任意操作区 | +| `.profile-card__button` | `.profile-card__login-button` | 区分入口容器与其中按钮 | +| `.profile-card__online-dot` | `.profile-card__auth-dot`,或删除 | 当前显示依据是登录态,没有在线状态数据 | +| `.menu-list` | `.menu-section__list` | 容器归属明确,其余菜单行 block 可以保留 | +| `.menu-row / .menu-row__desc` | **保留** | 行与说明都有明确含义,无需统一扩成 settings-menu-section | +| `.quick-card__icon--info` | `.quick-card__icon--primary` | 修正真实颜色语义即可,不扩大整个 block | +| `.header / .bottom-bar`(权限页) | `.permissions__header / .permissions__actions` | 增加短页面归属,actions 表达操作区域 | +| `.tree-container / .node-content`(权限页) | `.permissions__tree / .permissions__node` | 用途清楚,无需重复 role、page、container | +| `.custom-navbar` | `.app-navbar` | 项目导航栏名称短且明确 | + +保留 `mine-hero` 也不构成运行错误;本表的 BEM 调整是今后整理该模块时统一采用的约定,不建议单独做一轮全项目字符串替换。表中目标均写出完整类名,实际代码不使用省略前缀。 + +### 7.3 跨组件覆盖规则 + +[全局样式](../src/styles/index.scss) 的 `.page .wd-card` 覆盖所有该壳下的 Wot 卡片;`.popup-actions .wd-button`、筛选栏内部 `.wd-*` 规则也依赖库的内部节点。 + +建议依次选择:公开 props → CSS 变量 → `custom-class/custom-style` → 必要且局部限定的深度覆盖。深度覆盖说明具体原因及依赖的内部结构;整理时核对所用库版本。Wot 的 `custom-class` 是组件的样式入口,不能将它等同于普通 view 的 class,需确认目标节点和隔离规则。 + +公共模式只有在确实共享且含义稳定时才抽出。几行重复样式不自动要求新组件、新文件、`pattern-` 前缀或全局 shortcut。全局类使用清楚的业务或模式名,避免为了前缀而加前缀。 + +## 8. UnoCSS:默认最多 3 个工具项,复杂样式进局部类 + +### 8.1 先明确阈值的性质 + +**采用“简单节点最多 3 个 UnoCSS 工具项,4 个及以上默认提取语义类”作为本项目约定。** 这个阈值服务于模板可读性,不能宣称是 UnoCSS 官方规定或所有项目的通用标准。UnoCSS 的机制支持原子类及组合 shortcut,何时提取由项目自行约定。[官方 Shortcuts 文档](https://unocss.dev/config/shortcuts) + +适用范围是自有模板中新增或正在整理的节点;不用为了计数单独批量翻新整个项目。工具类少也可以使用语义类,尤其页面与组件的主要结构应该容易被定位。 + +### 8.2 具体判断与计数 + +| 场景 | 项目规则 | +| ------------------------------------------------------ | --------------------------------------------------- | +| 1–3 个工具项,只表达简单间距、尺寸、排布或单一文字处理 | 可以直接写模板;已有语义类不必删除 | +| 同一节点 4 个及以上工具项 | 默认提取为局部语义类,由该类承担这一组样式 | +| 渐变、伪元素、动效、交互状态、复杂主题配色或平台适配 | 不等到第 4 个,直接用语义类与局部 SCSS | +| 相同组合仅在一个页面内使用 | 先在页面内复用类,不搬进全局配置 | +| 跨组件反复使用且设计含义稳定的组合 | 才考虑公共 shortcut、样式模式或组件;按需要选择一种 | +| 第三方组件已有尺寸、颜色、variant 等公开参数 | 优先使用参数和变量,避免用工具类绕过组件契约 | + +计数规则统一如下: + +1. 数的是**同一节点的 UnoCSS 工具项**,不是 DOM 子元素数、CSS 声明数或 class 总数。`mine__body`、BEM modifier、库自有类不算 UnoCSS 工具项。 +2. 静态 class 与动态绑定一起看;互斥分支按一次渲染可能出现的最大工具项数判断,不能把两个互斥分支相加。例如固定 2 项、每次再选 1 项,仍为 3。 +3. Attributify 的多个值按等价工具项计数,不能将 4 项搬到属性、数组或 computed 后声称只有 1 项。变体工具项本身算 1 项,但复杂交互仍按上表提前提取。 +4. 已有且经过确认的公共 shortcut 算 1 项,因为它代表一个固定契约;不允许为了绕过阈值,把每串工具类临时起名搬进全局。只在一个页面使用的 4 项组合直接放该页面 SCSS。 + +这是可读性边界,不是越少生成 CSS 越好的性能结论。后续自动检查可提示超过阈值的节点,动态绑定、平台分支和真实语义仍需要人工判断。 + +### 8.3 项目现有写法怎么判断 + +| 当前写法及位置 | 判断 | 后续建议 | +| -------------------------------------------------- | ----------------------- | ------------------------------------------------------ | +| 工作台 `class="px-32rpx pt-16rpx"` | 2 项,简单内容留白 | **保留** | +| 工作台图片 `class="w-72rpx h-72rpx rounded-8rpx"` | 3 项,简单尺寸及圆角 | **可以保留**;形成统一图标角色后再命名 | +| 首页 `class="grid grid-cols-2 gap-16rpx m-24rpx"` | 4 项 | 整理时提取 `.home__stats` | +| 首页 `class="w-full h-600rpx px-20rpx box-border"` | 4 项 | 整理时提取 `.chart-wrapper__canvas` | +| 首页 `class="notice-bar m-24rpx"` | 1 个工具项 + 1 个语义类 | **保留**;当前 notice-bar 管内侧视觉,工具项管外侧间距 | +| 个人卡片的渐变、背景滤镜、降级配色 | 复杂视觉组合 | 继续局部 SCSS,不改写成大串工具类 | + +提取的意思是**把一组样式的责任放进有名字的类**,不是在原来的长工具类串前再加一个名字。以首页统计区为例,下面只是后续改法示意: + +```vue + + + +``` + +示例保留当前间距数值以说明等价提取;后续统一设计变量时再使用对应档位。`home` 作为页面 block,不要求为此新建组件或样式文件。 + +### 8.4 语义类、原子类、shortcut 的责任边界 + +允许“语义类 + 少量工具类”,但**同一属性只有一个负责来源**。例如 notice-bar 自己管理背景、圆角、内边距,父页面用 `m-24rpx` 决定它与其他区块的间距,职责清楚。若该类已经管理 margin,就不要再叠加同属性工具项;同时注意 padding、margin 等简写与单边属性的重叠。 + +组件稳定的背景、边框、尺寸状态放该组件样式;父页面管理外部排布。不是所有 CSS 声明都要变成 UnoCSS,也不是用了 UnoCSS 就不能写普通 SCSS。 + +当前 [unocss.config.ts](../unocss.config.ts) 只配置 attributify 和 weapp class transformer,没有接入 directives transformer。因此本文使用现有可用的 scoped SCSS,不把 `@apply` 当作已经可用的方案。UnoCSS 的 `@apply` 需要相应 transformer;若以后选择接入,再按项目实际版本验证构建及端侧效果。[官方 Directives transformer 文档](https://unocss.dev/transformers/directives) + +已有 `.color-primary` 等语义工具类可保留。若迁移到 UnoCSS 规则,应从公共 SCSS 移除重复定义并核对生成结果,不能同名双定义。动态 UnoCSS 类用完整候选值映射,避免运行时拼接无法静态发现的工具类;本地 SCSS modifier 则不需要 UnoCSS safelist。[官方提取说明](https://unocss.dev/guide/extracting) + +**事实:** 配置将 `font-bold` shortcut 指向 `font-semibold`,初版已实际验证其输出为 600。应删除这个重定义,需要 600 时写 `font-semibold`。这是名实不符,不是阈值或长度偏好。 + +`flex-center` 可以作为已约定的高频组合保留。`flex-start / flex-end / flex-between` 还隐含交叉轴居中,若继续使用,应明确固定的 flex 方向与含义;零星使用时直接写 `flex items-center justify-start` 三项即可。不再推荐用 `u-row-start-center` 这类更长的自造名称替代。 + +### 8.5 设计变量不只统一颜色 + +推荐先约束页面 gutter、区块间距、卡片内边距、字号层级、圆角档位和层级。保留少量真正有用途的档位,例如普通控件、普通卡片、沉浸 Hero。不要为每个现有数值造一个 token,从而将随意值永久化。 + +已有 `--color-primary / --color-text-secondary / --z-navbar` 可以保留。主色衍生背景建议使用 `--color-primary-soft` 表达角色,避免 `primary-light` 同时指浅色主题和浅底强度。主题切换时一起更新主色、柔和背景及主色上的前景文字。 + +**事实:** Provider 目前更新 primary 及两种 alpha 值,但 `--color-primary-light` 仍是固定蓝色衍生值。菜单组件的 warning 还映射为 primary,虽然当前配置未使用 warning,也应删除这个错误映射或补齐正确语义。 + +建议 `styles/index.scss` 只负责按顺序装配。基础规则、layout 规则和稳定公共模式有足够独立内容时再拆;`theme.scss` 继续负责明暗变量和明确的 Wot 映射。不创建空文件,也不新建无边界的 `common.scss`。 + +## 9. layout 和核心入口的调整建议 + +### 9.1 保留三类布局,并给尺寸责任定边界 + +| 层 | 应负责 | 应避免 | +| ------------------------------ | ------------------------------------------ | ------------------------------------------- | +| `App.vue / main.ts` | 应用初始化、样式引入、store 与路由接入 | 塞入各页面业务状态 | +| `pages.config.ts / definePage` | 路由、原生导航、layout 选择 | 手工维护生成的 `pages.json` | +| `AppProvider` | 页面主题、反馈组件宿主,消费共享主题 store | 被误认为整个应用唯一常驻实例 | +| `default` | 标准背景、最小高度、统一内容 gutter | 页面再次补同一层 gutter | +| `tabbar` | 主导航和底部内容避让 | 组件 placeholder 与 layout padding 双重补偿 | +| `blank` | Provider;内容尺寸由页面自管 | 把 blank 理解成没有任何基础配置 | +| `AppNavbar + useNavbarMetrics` | 导航呈现、状态栏和胶囊指标 | 同一页面多份互不一致的测量来源 | +| 页面组件 | 内容顺序、局部留白、页面状态 | 借营销卡片管理整个 Hero 的背景范围 | + +**事实:** [网络检测页](../src/subPages/mine/settings/network/index.vue) 在 default 壳的左右 32rpx 上,再加一级 `px-32rpx`,出现双重 gutter。工作台位于全出血 tabbar 壳,在自己的内容区补 32rpx 是合理例外。 + +**风险:** 权限页底部操作栏没有显式安全区处理;自管理页面使用 100vh 的键盘和底部表现需逐端确认。Tab 页已经有安全区及底部 padding,不能说项目没有处理安全区。当前 TabBar 没开 placeholder,也不能把现有补偿判成双重占位。 + +**风险:** 普通内容使用 z-index 200,Wot TabBar 默认 zIndex 为 10;是否遮挡取决于层叠上下文。建议减少普通内容高层级,核对 navbar、tabbar、popup 实际叠放关系,而不是直接将所有值再提高。 + +**事实与风险:** navbar 左容器使用胶囊 left 坐标当宽度、右容器再保留胶囊和操作空间,需核查窄屏收缩;`hasTabbar` 没被实现;重试定时器未清理。先调整真实测量边界,再改名,否则 `leftWidth` 只是变成一个更漂亮的错误名称。 + +### 9.2 退出登录 + +底部、登录后可见、红色描边、二次确认的方案基本合理。文档不再单独给按钮位置一个看似精确的分数,也不建议仅为隐藏退出入口新增设置页。 + +建议补 `isLoggingOut` 或完整退出状态,确认后立即反馈、禁用重复操作;确认框标题用“退出登录”,操作文字明确。远端请求默认可等待到 30 秒,页面不能在此期间完全没有反馈。保留 store 的本地会话清理入口。 + +### 9.3 扫码登录 + +[扫描 composable](../src/composables/useScanLogin.ts) 只检查内容非空;[确认页](../src/subPages/mine/scan-confirm/index.vue) 才调用服务端。入口名称建议“扫码登录”,职责分为扫描、票据验证、用户确认和完成,不增加不必要的中间页面。 + +优先补平台能力判断和错误分类。本地 H5 依赖将 `scanCode` 实现为不支持的 API,而当前入口仍可出现,异常全部被吞掉。取消、权限拒绝、能力不支持和识别失败应分别处理。 + +确认与取消共享互斥状态;完成后直到离开页面都不再允许提交。当前一边 loading 时另一边仍可点,确认成功又会在延迟返回前解除 loading,均可从源码确认。 + +64rpx 热区在 375px 视口下约 32px,建议增加可点击范围并检查窄屏;图标不必同步放大。初次校验应呈现加载态,过期/无效码给可读错误和重新扫码入口。热区目标属于可用性建议,本文不凭尺寸直接做完整可访问性认证。 + +### 9.4 个人中心信息层级 + +若保留开源项目展示定位,公众号卡片靠前有理由;若转为日常业务应用,先展示资料、账号安全和业务消息,再放社区与帮助。顺序应根据任务频率决定。 + +Hero 背景由页面拥有,不依附公众号卡片的中线并固定向上延伸 800rpx。卡片隐藏、改顺序或长文本时,画布不应跟着失去边界。 + +**样式事实:** 个人卡片在不支持 backdrop-filter 时回退到接近白色背景,文字仍固定白色。应将降级背景和前景成对设计,具体平台表现仍需实测。辅助文字多处为 22rpx,应结合真实使用检查可读性;不把所有小字、阴影或大圆角直接判为错误。 + +## 10. 注释:只说明契约、原因和限制 + +好的注释值得保留:[usePagedList](../src/composables/usePagedList.ts) 说明迟到响应和刷新失败策略;[request](../src/utils/request.ts) 说明避免 request/store 循环依赖;工作台解释额外 gutter;权限树解释 flex 与 scroll-view 的高度约束。 + +优先纠正以下内容: + +| 位置 | 注释或名称的问题 | 调整方向 | +| -------------------------------- | ------------------------------ | -------------------------------------------------------- | +| `useScanLogin.ts:6` | 声称跳转前已校验票据 | 说明仅做非空判断,服务端在确认页校验 | +| `useScanLogin.ts:24` | 所有失败都写成用户取消 | 先实现分类,再说明静默条件 | +| `useActionSheet.ts:63` 附近 | 将确认取消和执行失败都归为取消 | 写清异步失败处理责任 | +| `app-provider/index.vue:9` | 只写 default/tabbar 两种壳 | 包括 blank,说明页面实例作用域 | +| `account/index.vue:235` | 文档列出不存在的 ACCOUNT 枚举 | 删除过时成员说明 | +| `useNavbar.ts:43` | hasTabbar 有说明无行为 | 删除无效选项,避免注释承诺不存在的能力 | +| `useCacheCleaner.ts` | 声称只清可重建缓存 | 当前实现是删除保留名单之外所有键,需要调整策略或说明边界 | +| `work/user/index.vue:12` | 注释写 12rpx,公共规则为 16rpx | 不重复抄写可变数值,解释留白目的 | +| `theme.scss / eslint.config.mjs` | 当前实现仍标旧包名 | 当前依赖说明用 @wot-ui/ui,历史说明才保留旧名 | + +推荐公共函数注释只覆盖四项中真正需要的内容:输入单位/格式、返回结果、重要副作用、失败策略。Props 的单位和生命周期契约写在声明处,避免每一行再解释一次。 + +```ts +/** + * 重新读取窗口与胶囊尺寸,公开尺寸单位为 px。 + * 微信端读取失败时有限次重试,卸载时清理重试任务。 + * 不执行页面导航。 + */ +``` + +上例只能在行为实现后使用;当前代码尚未具备卸载清理,不能提前粘贴成现有说明。`#ifdef/#endif` 是编译指令,清理注释时必须保留。 + +## 11. 保留的重要问题与验收标准 + +| 编号 | 问题 | 级别 / 证据 | 后续验收 | +| ---- | ---------------------------------------- | ---------------------------- | --------------------------------------------------------------------- | +| R1 | 扫码平台能力及错误被吞 | P1 / 事实 | H5 无无响应入口;取消静默,其他失败可恢复 | +| R2 | 确认/取消并发及成功后的再提交窗口 | P1 / 事实 | 慢网交替点击只执行一种操作,完成后不可再次提交 | +| R3 | Button 的 plain、type="error" 等旧写法 | P1 / 事实 | 核对 v2 props,清除业务旧参数;Tag 默认样式看似正确不能证明旧参数有效 | +| R4 | 模板检查关闭、表单 ref 与部分 shim 过宽 | P1 / 事实 | 缩小兼容范围,关键错误 prop/方法能被检查捕获 | +| R5 | 玻璃卡片降级配色与导航/底部层级 | P1 验证 / 样式事实及运行风险 | 降级、滚动、胶囊、Home Indicator 和键盘场景有记录 | +| R6 | 退出无过程反馈 | P2 / 事实 | 立即显示状态,重复点击不会重复请求,弱网后按既定策略退出 | +| R7 | 重复 gutter、navbar 责任及无效选项 | P2 / 事实 | 页面对齐,指标来源明确,删除无行为 API | +| R8 | 登录、资料加载和无权限混为一类 | P2 / 事实 | 已登录无权限不再要求重新登录,首页/工作台导航判断一致 | +| R9 | 网络检测文案与行为不符 | P2 / 事实 | 检查业务服务;失败不显示优秀;耗时与失败状态分开 | +| R10 | ActionSheet 的 label 兼作分发 ID | P2 / 事实 | 同名文案或更换文案不改变动作身份,异步错误责任明确 | +| R11 | font-bold 重定义、主色衍生值和语义色错配 | P2 / 事实 | 名称与生成样式一致,主色切换联动,warning 语义正确 | +| R12 | 文件、方法、类名与注释缺少统一约定 | P2–P3 / 约定及名实不符事实 | 按本文词汇与所有权规则整理,例外有清单 | + +R3 证据包括扫码确认、账号安全、主题设置、网络检测和多个 Tag。R4 在 [tsconfig.json](../tsconfig.json) 可见 `strictTemplates: false / skipTemplateCodegen: true`;不能把脚本 type-check 成功解释成模板参数已验证。恢复检查应先复现并缩小兼容问题,不直接删除全部 shim。 + +R8 的首页将 `!isAuthenticated || !hasAnyPerm` 一起跳登录;R9 的微信网络检测 fail 分支仍 resolve,第三方站点耗时也不能证明业务服务可达。前端体验判断不代表后端授权已经审计。 + +## 12. 建议执行顺序:先确定规范,再按模块落地 + +1. **形成基准约定。** 固定短词汇表、文件角色规则、事件与方法语义、短 BEM block、UnoCSS 三项边界、自动导入范围及合法例外。对应 R12。 +2. **先解决行为与类型问题。** R1–R4、R10 优先。更名涉及的实际副作用一起核对,不能只做替换。 +3. **以个人中心作为样板模块。** 文件、Props、菜单模型、导航方法、BEM、Hero 背景归属一起整理,再验证退出和扫码。此时只保留一个命名体系。 +4. **统一 layout 和公共样式。** 处理 gutter、指标、底部避让与组件覆盖边界,运行验证 R5–R7。 +5. **推广到工作台与设置页。** 核对分包、导航权限和网络检测。避免为每个页面再复制一套变体。 +6. **收尾注释和检查规则。** 业务变更之后再同步注释,清理遗留别名,并记录需要保留的第三方/框架例外。 + +提交按模块或独立契约拆分。组件文件迁移可以作为一批易审阅变更;状态重构与运行逻辑另有清晰验证。跨全项目的一次正则重命名容易遗漏自动导入、组件解析和分包引用,不推荐。 + +## 13. 将严格要求变成可执行检查 + +### 可以自动检查 + +- 自有非路由 Vue 文件遵循 PascalCase,排除 framework/layout、第三方与生成文件。 +- 自有选择器遵循约定的 BEM 格式;block 清楚即可,不强制照抄文件名,不要求多 block 登记。 +- 项目业务脚本命名规则按角色配置,避免同一套规则误伤 `UserAPI` 等合法名称。 +- 检查旧 Wot 参数、无效公开字段、宽泛全局选择器,以及改变标准语义的工具类重定义;对超过 3 项的模板节点给出提取提示。 +- 公共类型和事件参数保留检查,兼容例外限定版本和范围。 + +以上是后续检查建议,本次没有新增 lint 规则或 CI。 + +### 必须人工审阅 + +- 名称是否与真实行为一致,而不是只看是否匹配正则。 +- `open` 是否在跳路由,`isOnline` 是否只有 token,`load` 是否悄悄负责多处状态。 +- label 是否参与身份分发,状态组合是否允许矛盾,异步失败有没有明确处理方。 +- gutter、背景、主题和弹层有没有唯一责任来源。 +- 抽出的组件或 composable 是否降低依赖和理解成本。 + +推荐基础框架 hooks 可以保留自动导入;业务 API、store、composable 和工具使用显式 import。当前 [vite.config.ts](../vite.config.ts) 将这些业务目录都加入自动扫描,实际调用又混合显式与隐式导入。严格维护更需要可见依赖;但这项规则无需扩展成“Vue 的每个 ref 都必须显式导入”。 + +样式类检查只负责自有选择器,不能对 Wot 内部类、uni hover-class 和第三方图表施加自有 BEM 命名规则。 + +## 14. 验证记录与交付边界 + +以下记录来自 **2026-10-04 初版评审**,本次文档重写没有重新运行应用检查,也不把历史结果包装成新的测试: + +| 检查 | 初版结果 | 限制 | +| ---------------------------- | -------------------- | --------------------------------------------------- | +| `pnpm check` 中的 type-check | 通过 | 模板生成检查关闭 | +| `pnpm check` 中的 ESLint | 1 处错误 | `src/utils/storage.ts:6` import 换行不符合 Prettier | +| 单独 Stylelint | 通过 | 总检查因 ESLint 失败短路,故单独执行 | +| H5 生产构建 | 通过 | 不证明视觉、扫码及真机交互正确 | +| UnoCSS font-bold 生成核对 | 输出 font-weight:600 | 确认 shortcut 的名实不符 | + +本次只修订同一份文档,核查源码、本地依赖、UnoCSS 官方机制说明、文档格式及引用。没有修改业务代码、配置、组件名或路由。 + +仍建议后续统一同一运行端的版本展示来源,以及提交应用锁文件;它们属于工程可重复性事项,不需要与命名整理捆绑升级依赖。 + +后续每个模块完成时至少回答四个问题:名称是否准确;职责是否有边界;规则是否只有一个来源;错误与运行端限制是否被正确处理。满足这些条件后,再以关键端的实际截图和操作记录验证布局。 diff --git a/docs/naming-audit-2026-10-16.md b/docs/naming-audit-2026-10-16.md new file mode 100644 index 0000000..30bc603 --- /dev/null +++ b/docs/naming-audit-2026-10-16.md @@ -0,0 +1,105 @@ +# 命名与注释审计(2026-10-16) + +对未提交改动文件的命名、类型与注释核查,标准依据 `mobile-ui-code-review-2026-10-04.md` 与 Vue 官方风格指南。 +全部修复后 `pnpm check`(type-check / templates / eslint+prettier / stylelint)通过,旧名残留扫描为 0。 + +## 1. 方法命名(已修复) + +| 文件 | 原名 | 现名 | 依据 | +| --- | --- | --- | --- | +| work/config/index.vue | `showConfigActions` | `openConfigActions` | 打开弹窗用 open | +| work/dict/index.vue | `showDictActions` | `openDictActions` | 同上 | +| work/dict/item/index.vue | `showItemActions` | `openItemActions` | 同上 | +| work/notice/index.vue | `showNoticeActions` | `openNoticeActions` | 同上 | +| work/role/index.vue | `showRoleActions` | `openRoleActions` | 同上 | +| work/user/index.vue | `showUserActions` | `openUserActions` | 同上 | +| work/dict/index.vue | `openDictItemPage` | `navigateToDictItem` | 页面导航不用 open | +| work/role/index.vue | `handleAssignPerm` | `navigateToAssignPerm` | 导航伪装 + handle 滥用 | +| work/dept/index.vue | `handleAddChild` | `openChildDeptDialog` | 打开弹窗,与 `openDeptDialog` 对齐 | +| work/menu/index.vue | `handleAddChild` | `openChildMenuDialog` | 同上 | +| pages/login/index.vue | `handleWechatSilentLogin` | `doWechatSilentLogin` | 与 `doFormLogin` / `doWechatPhoneLogin` 统一 | +| work/user/index.vue | `handleUserSubmit` | `submitUserForm` | 与其余 7 页 `submitXxxForm` 统一 | +| subPages/mine/about/index.vue | `openUrl` | `openExternalUrl` | 非 H5 端实际是复制链接,补行为注释 | +| subPages/mine/settings/theme/index.vue | `showCustomInput` | `openCustomColorInput` | 打开弹窗用 open,与 ref 名区分 | +| subPages/mine/account/index.vue | `handleOpenDialog` | `handleOpenPopup` | 打开的是 wd-popup,术语修正 | +| subPages/mine/profile/index.vue | `openDialog` | `openProfilePopup` | 同上 | + +## 2. 变量与类型(已修复) + +| 文件 | 原名 | 现名 | 依据 | +| --- | --- | --- | --- | +| subPages/mine/profile/complete-profile/index.vue | `cropperVisible` | `isCropperVisible` | 与 profile 页同名概念统一 | +| subPages/mine/settings/theme/index.vue | `showCustomColorInput` | `customColorInputVisible` | 布尔 ref 谓语风格 | +| subPages/mine/profile/index.vue | `dialogState` | `popup` | 与 account 页弹层状态统一 | +| pages/work/index.vue | 本地 `hasPermission` | `isMenuAllowed` | 与 utils 同名但空 perm 语义相反(本地视为公开入口),import 恢复 `hasPermission` 原名 | +| api/notice.ts | `level: string \| number` | `level: string` | 后端 NoticePageVO 为 String;`getLevelText` 参数同步收窄 | + +## 3. api/notice.ts 类型与注释(已修复) + +- 删除 `NoticeItem.priority`:后端 `NoticePageVO` 无此字段,前端零消费。 +- 删除 `NoticeItem.content`:同上,详情内容来自 `NoticeDetail`。 +- `targetType` 注释 `0-全体 1-指定` 改为 `1-全体 2-指定`,对齐 `NoticeTargetEnum`。 +- `publishStatus` 注释 `2已撤回` 改为 `-1-已撤回`,对齐 `NoticePublishStatusEnum` 与页面判断逻辑。 + +## 4. 注释与死代码(已修复) + +- subPages/mine/profile/index.vue:3 条复述变量名的行尾注释(`//用户信息` 等)删除。 +- subPages/mine/profile/index.vue:`profile-last-cell-wrap` 死类名及包裹 view 删除。 +- utils/storage.ts:挂在 `set` 上且不准确的 `/** localStorage 存储 */` 删除。 +- subPages/mine/settings/theme/index.vue:`// 使用主题组合函数` 复述 import 的注释删除。 + +## 5. 保持原样(审计判定不改) + +- `useTheme()` 转发层:是否保留属架构决策,命名本身合规。 +- `usePagedList.fetchPage`:写多处状态但为模块私有实现,注释完备。 +- `OfficialAccountCard` 的 `@open` 事件:注释已声明目标地址由父级决定,事件表达用户意图。 +- `.is-active` / `.is-checked` 状态类:常见实践,与 BEM 并存。 +- 头像选择三处命名(`chooseAvatar` / `handleChooseAvatar` / `handleAvatarUpload`):choose 与 upload 语义有别。 +- account 页 catch 静默取消与解绑失败:行为缺口,非注释错误。 +- 两处文件私有 `interface NavItem`:同名不同构,均为局部类型。 +- `sendVerificationCode` 的 `contactType`:可收窄为 `"MOBILE" | "EMAIL"`,影响小。 +- mine 页 `router.push` 与 `uni.navigateTo` 并存:API 选择,非命名问题。 +- menu 页 `@search` 直绑 `loadMenuList`:规范未强制事件回调必须 handle。 +- dict/item 的 `tagComponentType`:可加 get 前缀,影响小。 + +## 6. 已确认合规的类别 + +- 谓词查询无副作用:`hasPermission`、`isValidMobile`、`isValidCapsuleRect`、`isExpanded` 等。 +- `ensure`:`ensureAuthenticated`、`ensureUserInfoLoaded`。 +- 导航:`navigateToProfile` / `navigateToAccountSecurity` / `navigateToOfficialAccount` 等。 +- 弹窗 open/close:`openXxxDialog` / `closeXxxDialog` / `openResetPwdDialog` / `BindMobilePopup.open`。 +- sync / reset / load / fetch / get / build / format 系列动词与行为一致。 +- `handle` 全部用于模板事件绑定。 +- API 层 `getXxx` 与业务动词(`publish` / `revoke` / `bindMobile` / `unbindSocial` 等)与行为一致。 +- 布尔 ref 谓语风格、单位后缀(`contentHeightPx` 等)、枚举名词化、接口无 I 前缀。 +- BEM 紧凑规则:`app-navbar__content--fixed`、`profile-card__login`、`quick-card__icon--primary`、`permissions__header` 等。 +- 高价值注释保留:usePagedList 迟到响应策略、storage PRESERVED_KEYS 边界、useScanLogin 失败分类等。 + +## 7. 遗留问题(youlai-boot,未改) + +- `NoticeDetailVO.java:36` 注释写「2已撤回」,与 `NoticePublishStatusEnum` 的 `-1` 及实体、查询对象注释矛盾。按约定不动 youlai-boot,需要修复时单独提交。 + +## 8. 评审文档 R1–R12 验收核对(2026-10-16) + +| 编号 | 问题 | 结论 | 证据 | +| --- | --- | --- | --- | +| R1 | 扫码平台能力及错误被吞 | 已关闭 | `useScanLogin.ts` 按平台判断能力并提示,失败区分取消/权限/能力/其他 | +| R2 | 确认与取消并发 | 已关闭 | `scan-confirm` 单一 status 状态机,非 ready 直接返回,finished 后不再接受提交 | +| R3 | Button 旧参数 | 已关闭 | 全量扫描无裸 `plain`、无 `type="error"`,均为 `variant="plain"` | +| R4 | 模板检查关闭、shim 过宽 | 已关闭 | `tsconfig.templates.json` + `scripts/check-templates.mjs` 只统计 src;`wot-ui-component-shims.d.ts` 已删除 | +| R5 | 玻璃卡片降级与层级 | 已关闭 | ProfileCard 恒定玻璃底、`@supports` 内叠加模糊;theme.scss 标注层级表,普通内容 5 / 导航 15 / 全局遮罩 90 | +| R6 | 退出无过程反馈 | 已关闭 | `useLogout` 的 `isLoggingOut` 防重入 + `toast.loading` 过程反馈 | +| R7 | 重复 gutter、navbar 责任 | 已关闭 | 网络页去除重复 `px-32rpx`;`NavbarMetrics` 收缩为实际被消费的 6 项 | +| R8 | 登录与无权限混判 | 已关闭 | 首页未登录展示入口引导、已登录按权限过滤;工作台 `isMenuAllowed` 保留公开入口语义 | +| R9 | 网络检测文案与行为 | 已关闭 | 探测指向接口服务地址,不可达显示「不可访问」,耗时与失败状态分开 | +| R10 | ActionSheet label 兼作 ID | 已关闭 | 命令模型 `id / label / execute`,按索引分发(本轮重构为 `ActionSheet` 组件) | +| R11 | font-bold 重定义、主色衍生、warning 错配 | 已关闭 | `unocss.config.ts` 无 font-bold shortcut;主色衍生由 AppProvider 按所选主色注入;MenuSection 的 tone 映射 `--color-warning` | +| R12 | 命名与注释缺统一约定 | 已关闭 | 本文档 1–4 节;文件名检查落地为 `scripts/check-naming.mjs` | + +## 9. 已接入的自动检查 + +- `scripts/check-templates.mjs`:模板类型检查,只统计 src 下的错误。 +- `scripts/check-naming.mjs`:自有 Vue 文件 PascalCase;路由 `index.vue`、`App.vue`、`layouts`、第三方 `qiun-*` 除外。 +- 两者已加入 `pnpm check`。 + +评审 13 节其余可自动检查项(BEM 选择器格式、旧 Wot 参数、宽泛全局选择器、UnoCSS 工具项阈值提示)暂未实现,保留为人工审阅。