构建: - 新增 tools/build.js:junction HBuilderX 工具链,CLI 构建 h5/mp-weixin - vue 指向补丁版 @dcloudio/uni-h5-vue(官方 npm vue 不导出 isInSSRComponentSetup) - 设 HX_APP_ROOT 避免退化成 H5 空壳产物;产物完整性校验 校验工具: - 新增 check-cloud-methods.js:acorn 解析云对象方法,比对 94 处调用点 - 新增 check-android-contract.js:Kotlin 侧云对象契约校验 - audit-project.js 修 downloadFile 误报(注释未剥离);tools/ 排除出扫描 - package.json 声明此前隐式依赖的 acorn 功能: - 补 uni-cms-articles.getPublishedArticles(安卓端依赖但此前不存在) - 修 u-parse <audio> 引用已移除组件导致 H5 构建失败
413 lines
22 KiB
Markdown
413 lines
22 KiB
Markdown
# 下一步计划 · 文章闭环收尾 + 工具链打通
|
||
|
||
> 交接对象:下一个接手的模型 / 工程师。
|
||
> 本文档分两部分:**A. 本轮实际做完的事**(含验证证据),**B. 还没做的清单**(含具体做法)。
|
||
> 前置计划:`.zcode/plans/plan-sess_cd5437b2-dd23-478b-bfec-f4cce1ee4b10.md`(架构决策与 7 步实施步骤,已全部落地)。
|
||
|
||
---
|
||
|
||
## A. 本轮完成清单(本次会话实测,非推断)
|
||
|
||
### A1. 文章编辑→存储→渲染闭环(上一轮遗留,本轮核对确认已落地)
|
||
|
||
| # | 内容 | 落点 | 核对方式 |
|
||
|---|---|---|---|
|
||
| 1 | 数据适配层 `normalizeCmsList` / `cmsLstToDelta` / `createVoteId` / `getArticleText` / `getArticleImages` / `hasRenderableContent` | `uniCloud-alipay/cloudfunctions/uni-cms-articles/content-adapter.js`(170 行,含空块过滤、媒体字符串归一、投票最少 2 项) | 已读全文 + `check-article-flow.js` 通过 |
|
||
| 2 | 云对象 add/update 契约:mobile 缺 content 时服务端生成兼容 Delta;update 用 `valueOrExisting` 合并缺省字段;发布强制 `hasRenderableContent`;vote_id 自动生成 | `uni-cms-articles/index.obj.js` | 已读全文 |
|
||
| 3 | schema:`content` 从 `required` 移除(现为 `['user_id','title']`);read 权限收敛为 `doc.article_status == 1 \|\| (auth.uid != null && ('admin' in auth.role \|\| doc.user_id == auth.uid))` | `uni-cms-articles.schema.json` | 程序化解析确认 |
|
||
| 4 | 审核覆盖:`content \|\| cmsLst` 双通道;mobile 不依赖 content 返回正文;`content.ops` 缺失时降级不抛异常 | `uni-cms-articles.schema.ext.js` | 已读 `afterRead` 全文 |
|
||
| 5 | 移动编辑器:首块文字可加载(`editText.vue:97` 无 `if (index && ...)` 假值陷阱,`:137` 用 `Number.isInteger`);`{...oldItem}` 保留媒体字段;小标题写回;封面统一字符串数组 | `pages2/editCms/*.vue` | 逐处 grep 确认 |
|
||
| 6 | 详情渲染:mobile 分支输出 text/title;`render-article-detail/*` 兼容 `data.value` 与 `data.attributes.src`;列表递归 children;移除 Vue2 `this.$set`;`wx.` 已用 `#ifdef MP-WEIXIN` 包裹;`100wv/60hv` 全部清零 | `uni_modules/uni-cms-article/**` | grep 确认 0 命中 |
|
||
| 7 | 媒体删除鉴权:admin 放行;普通作者必须带 `article_id` 且文件确实被该文章引用 | `ext-storage-co/index.obj.js:65-82` | 已读实现 |
|
||
|
||
### A2. 本轮新修的问题
|
||
|
||
**① `ext-storage-co.downloadFile()` 审计告警 = 误报,已从根上修掉**
|
||
|
||
真因:`tools/audit-project.js` 的 `WRITE_METHOD_RE` 不剥离 `//` 注释,
|
||
把文件里**被注释掉的** `async downloadFile()` 当成活方法,报「未校验登录态」。
|
||
|
||
修法(已落地):新增 `blankLineComments()`,用**等长空格**替换行注释——
|
||
保持字节偏移不变,所以 `lineAt()` 行号和 `src.slice()` 切片仍然正确。
|
||
`sectionCloudAuth` 内所有正则改跑 `scanned`,`lineAt` 仍传原始 `src`。
|
||
|
||
> ⚠️ 不要改成直接 `src.replace(...)` 后再切片——偏移会错位,行号全乱。
|
||
|
||
**② 新增 `tools/check-cloud-methods.js`——云对象方法存在性校验**
|
||
|
||
补的是一层**原本完全没人管的静态盲区**:`audit-project.js` 只校验
|
||
`importObject` 引用的「云函数文件」是否存在,**不校验方法名**。
|
||
方法名写错在静态审计里 0 报错,只在运行时炸 `xxx is not a function`。
|
||
|
||
- 用 `acorn` 解析 `module.exports` 对象字面量取顶层方法名
|
||
- 支持两种导出形态:对象字面量 / `module.exports = require('./functions')`(递归解析 require 链,深度上限 3)
|
||
- 同时发现随插件分发的云对象(`uni-id-co` / `uni-pay-co` / `uni-captcha-co` / `uni-media-library-co`)
|
||
- 4 组内联样本自测:对象字面量 / 默认对象参数 / 注释里的假方法 / 字符串里的花括号
|
||
- **实测结果:18 个云对象、94 处调用点,0 错误**
|
||
|
||
被它拦下的真实问题(均已确认无碍):
|
||
- `article_info` 缺 `getInfo` / `isSelectVote` / `getCmsArticleLog` → 实际都有,是我第一版正则提取器漏了
|
||
- `uni-media-library-co` 缺 6 个方法 → 该云对象是 `module.exports = require('./functions')` 转出,加了 require 链解析后正常
|
||
|
||
**③ 新增 `tools/check-android-contract.js`——安卓端 × 云对象契约校验**
|
||
|
||
`android/` 是独立 Kotlin 工程,通过 URL 化 HTTP 网关调云对象,同样有方法名漂移风险。
|
||
|
||
- 从 Kotlin 源码抽 `callChecked/callRaw("云对象","方法")` 调用对(70 个文件、44 处调用点、去重 43 个)
|
||
- **做了反例测试**:故意把 `getPublishedArticles` 改成 `getPublishedArticlesXX` → 脚本正确报错;还原后恢复 0 错误
|
||
|
||
**④ `package.json` 声明了此前隐式依赖的 `acorn`**
|
||
|
||
`check-cloud-methods.js` 用了 `acorn`,但它是**未声明的传递依赖**——
|
||
一次 `npm install` 就会把它剪掉,脚本随即 `Cannot find module 'acorn'`。
|
||
现已写入 `devDependencies`(`^8.11.3`)并补了 npm scripts。
|
||
|
||
**⑤ 补上安卓端依赖的 `getPublishedArticles`(真实功能缺口)**
|
||
|
||
`android/README.md` 要求部署该方法,`ArticleRepository.kt:34` 优先调用它,
|
||
**但云函数里根本不存在**——安卓首页/搜索永远只能回退到「仅本人文章」,游客拿到空列表。
|
||
|
||
已实现(`uni-cms-articles/index.obj.js`):
|
||
- 公开、无需登录;`article_status = 1` 过滤
|
||
- 支持 `offset` / `limit`(上限 100)、`category_id`、`keyword`
|
||
- **keyword 做了正则转义**(`escapeRegExp`),避免用户输入被当正则执行
|
||
- **投影只取列表字段,刻意不取 `content`**:因为 `schema.ext` 的 `afterRead`
|
||
在读取 `content` 字段时会顺带给 `view_count` 加 1,列表页不该把「出现在首页」
|
||
算成一次阅读
|
||
- 排序 `publish_date desc`,附带 `total`
|
||
|
||
**⑥ 修掉 H5 构建的硬阻塞:`u-parse` 引用已被移除的 `<audio>` 组件**
|
||
|
||
`uni_modules/uview-ui/components/u-parse/node/node.vue` 用了 `<audio>`,
|
||
但新版 uni-h5 已不再导出 `Audio` 组件,H5 端编译直接失败:
|
||
|
||
```
|
||
"Audio" is not exported by "@dcloudio/uni-h5/dist/uni-h5.es.js"
|
||
```
|
||
|
||
改为普通 `view` 承载(保留 id/class/style 以维持排版),并写明了原因。
|
||
这是 vendor 文件,但**不修就构建不出来**,属于必要最小改动。
|
||
|
||
**注**:`components/cu-editor/cu-editor.vue:182` 也有 `<audio>`,但该组件全项目无引用,
|
||
且它不在构建路径上(H5 构建已通过),所以没动——**留着记录,别顺手改**。
|
||
|
||
### A3. 打通 HBuilderX CLI 构建(本轮最大产出)
|
||
|
||
这是原来完全没解决的事:**只能靠 HBuilderX GUI 点按钮,无法命令行/CI 构建**。
|
||
现在 `node tools/build.js -p h5` 直接可跑。
|
||
|
||
#### 踩过的 5 个坑(按发现顺序)
|
||
|
||
| # | 现象 | 真因 | 解法 |
|
||
|---|---|---|---|
|
||
| 1 | `ENOENT: ...\t\src\manifest.json` | uni CLI 默认按标准 CLI 工程布局找 `src/`,HBuilderX 工程根目录才是 `UNI_INPUT_DIR` | 设 `UNI_INPUT_DIR` / `UNI_OUTPUT_DIR` |
|
||
| 2 | 找不到 `@dcloudio/*` | 项目 `node_modules` 是 **Vue2 时代的残缺安装**(只有 4 个 @dcloudio 包),Vue3 工具链只随 HBuilderX 分发 | 把 HBuilderX 工具链目录 **junction** 进项目 `node_modules` |
|
||
| 3 | `Preprocessor dependency "sass" not found` | sass 在另一个插件目录 `plugins/compile-dart-sass/` | 单独 junction |
|
||
| 4 | `"isInSSRComponentSetup" is not exported by vue` | **关键**:官方 npm `vue` 3.x 不导出这个符号,但 `@dcloudio/uni-app` 从 `'vue'` 导入它。uni-app 用的是**打过补丁的运行时** `@dcloudio/uni-h5-vue`(`dist/vue.runtime.esm.js`,确实导出该符号)。uni 的 resolveId 插件本应把 `vue` 别名过去,但没拦住 | 把 `node_modules/vue` **直接 junction 到 `@dcloudio/uni-h5-vue`** |
|
||
| 5 | 构建"成功"但产物是 H5 空壳(无 `app.json`、无业务分包) | 缺 `HX_APP_ROOT` 时 `uni-cli-shared` 的 `isInHBuilderX()` 返回 false,退化成非 HBuilderX 模块解析路径 | 设 `HX_APP_ROOT` + `UNI_HBUILDERX_PLUGINS` |
|
||
|
||
附带:系统 node v24 跑 vite 会报 `Invalid or incompatible cached data (cachedDataRejected)`,
|
||
改用 **HBuilderX 自带的 node**(`plugins/node/node.exe`,v22.22.2)即稳定。
|
||
|
||
#### 交付物:`tools/build.js`
|
||
|
||
- 幂等:每次跑自动建联接,已存在的跳过(重跑 `新建 0 个`)
|
||
- `--doctor` 环境体检(含验证补丁版 vue 是否真的导出 `isInSSRComponentSetup`)
|
||
- `--link-only` 只建联接
|
||
- `--report` 打印产物体积明细
|
||
- **产物校验**:构建退出码为 0 不代表产物可用——脚本会检查
|
||
mp 必须有 `app.json`/`app.js`/`app.wxss`,H5 必须有 `index.html`,且 JS 文件数必须 > 0
|
||
|
||
npm scripts:`npm run build:h5` / `npm run build:mp-weixin` / `npm run verify` / `npm run verify:quick`
|
||
|
||
#### 实测证据
|
||
|
||
```
|
||
$ node tools/build.js -p h5 --report
|
||
✓ 构建完成(90 个 JS 文件)
|
||
产物目录:unpackage/dist/build/web
|
||
assets/ 2335.9 KB
|
||
static/ 312.1 KB
|
||
合计 2791.1 KB
|
||
|
||
$ node tools/build.js -p mp-weixin
|
||
✓ 构建完成(335 个 JS 文件)
|
||
→ app.json / app.js / app.wxss 齐全,pages2 等业务分包完整
|
||
```
|
||
|
||
H5 产物里 `editCms` / `editText` / `smallTitle` / `vote` / `editSetting` / `preview`
|
||
各自的 chunk 都在,7 个 chunk 含 `cmsLst`,说明文章链路真的编译进去了:
|
||
|
||
```
|
||
pages2-editCms-editCms.Cc0kHD0h.js
|
||
pages2-editCms-editText.CLBQkN2p.js
|
||
pages2-editCms-smallTitle.D2I257SK.js
|
||
pages2-editCms-vote.EUryHJH3.js
|
||
...
|
||
```
|
||
|
||
用本地静态服务器验证过 `HTTP 200`(`index.html` 1095 B、主 bundle 749754 B、
|
||
`editCms` chunk 12164 B)。
|
||
|
||
### A4. 验证门禁现状
|
||
|
||
```
|
||
$ node tools/verify.js
|
||
【检查器自测】
|
||
✓ 静态审计自测
|
||
✓ Vue 校验自测
|
||
✓ 文章内容适配自测
|
||
✓ 云对象方法校验自测
|
||
【项目检查】
|
||
✓ 静态审计 0 错误 / 11 警告 ← 原 12,误报已修
|
||
✓ Vue SFC 校验 0 错误 / 49 警告
|
||
✓ 云对象方法校验 0 错误 / 1 警告 ← 新增
|
||
✓ 安卓端契约校验 0 错误 / 0 警告 ← 新增
|
||
【数据与资源】13 项全 ✓(schema 63 文件有效、db_init 9 表)
|
||
═══════════════════════════════════════════
|
||
✓ 全部通过
|
||
```
|
||
|
||
---
|
||
|
||
## B. 未完成清单
|
||
|
||
### P0-1 · 提交工作区(最高优先)
|
||
|
||
**为什么**:19 个改动文件 + 5 个新源文件全裸奔在工作区,一次误操作就全丢。
|
||
|
||
```bash
|
||
cd C:/Users/12914/Desktop/t
|
||
|
||
git add -A
|
||
git status --short
|
||
git diff --cached --stat
|
||
|
||
git commit -m "feat: 打通 HBuilderX CLI 构建 + 修复文章闭环静态盲区
|
||
|
||
构建:
|
||
- 新增 tools/build.js:junction HBuilderX 工具链,CLI 构建 h5/mp-weixin
|
||
- vue 指向补丁版 @dcloudio/uni-h5-vue(官方 npm vue 不导出 isInSSRComponentSetup)
|
||
- 设 HX_APP_ROOT 避免退化成 H5 空壳产物;产物完整性校验
|
||
|
||
校验工具:
|
||
- 新增 check-cloud-methods.js:acorn 解析云对象方法,比对 94 处调用点
|
||
- 新增 check-android-contract.js:Kotlin 侧云对象契约校验
|
||
- audit-project.js 修 downloadFile 误报(注释未剥离);tools/ 排除出扫描
|
||
- package.json 声明此前隐式依赖的 acorn
|
||
|
||
功能:
|
||
- 补 uni-cms-articles.getPublishedArticles(安卓端依赖但此前不存在)
|
||
- 修 u-parse <audio> 引用已移除组件导致 H5 构建失败"
|
||
|
||
git log --oneline -1
|
||
```
|
||
|
||
**注意**:
|
||
- `.zcode/` 已加入 `.gitignore`(本次已做),不要提交。
|
||
- CRLF 警告是仓库既有配置,不影响提交,别改 `core.autocrlf`。
|
||
- `unpackage/` 与 `package-lock.json` 本来就在 `.gitignore`,构建产物不会入库。
|
||
- `private.wxb4c2c6c51ecba864.key` 已在 `.gitignore`,确认没被 `git add -A` 带进去。
|
||
|
||
### P0-2 · 补厚内容适配契约测试(最大的测试空心区)
|
||
|
||
`tools/check-article-flow.js` 只有 44 行、4 组断言,原计划第 8 步列的 7 条要求中
|
||
**a/b/c/d/e/f/g 六条测不到——因为逻辑还埋在 .vue 组件里,Node 侧无法引用**。
|
||
|
||
| 缺失断言 | 逻辑现状位置 |
|
||
|---|---|
|
||
| a. 编辑首个文字块(index=0)不被清空 | `editText.vue:97-108` |
|
||
| b. 视频改说明后 `src/poster/duration` 仍在 | `editCms.vue` 的 video 文字编辑分支 |
|
||
| c. 小标题能写入 `cmsLst`(`type:'title'`) | `smallTitle.vue:120-140` |
|
||
| d. 封面始终是字符串数组 `['','','']` | `editSetting.vue` |
|
||
| e. mobile 发布 payload 同时含 `cmsLst` + `content` | `preview.vue:404-420` |
|
||
| f. 5 种块在预览/详情分流后都有渲染目标 | 预览与详情模板分支 |
|
||
| g. `hasRenderableContent` 对空/纯空块的判定 | 已在 adapter,但只测了正例 |
|
||
|
||
**关键:先抽纯函数,再写断言。** 在 `content-adapter.js` 追加
|
||
`mergeCmsItem` / `normalizeThumbnail` / `buildPublishPayload`,
|
||
把组件里的内联逻辑改为调用它们(行为不变),然后补齐 a–g 共 ≥10 组断言。
|
||
|
||
**抽取时别弄丢已修好的地方**:
|
||
- `editText.vue:97` 是 `if (cms && cms.cmsLst && cms.cmsLst[index])`(没有 `if (index && ...)` 的假值陷阱)
|
||
- `editText.vue:137` 用 `Number.isInteger(Number(index))`
|
||
- `editText.vue:102` 已在用 `{ ...oldItem, text, html, delta }` 合并
|
||
- `smallTitle.vue:133` 用 `editingIndex.value >= 0`
|
||
|
||
### P0-3 · 端到端 QA(唯一能真证明「闭环」的一步)
|
||
|
||
构建能过 ≠ 功能正常。静态脚本只能证明数据层;保存/预览/发布/详情是跨端运行时行为。
|
||
|
||
**本轮已排除的**:浏览器自动化(`mcp__node_repl__js` 未在本会话提供),
|
||
所以只能做到「H5 产物可服务 + chunk 齐全」,**真正的页面渲染与交互没人验证过**。
|
||
|
||
环境:HBuilderX(或用 `node tools/build.js -p h5` 出产物后起静态服务器)+
|
||
关联 `uniCloud-alipay` 服务空间,上传 `cloudfunctions` 与 `database`。
|
||
|
||
| # | 操作 | 期望 |
|
||
|---|---|---|
|
||
| 1 | 新建 mobile 文章:标题 + 首块文字 + 小标题 + 图片 + 视频(填说明) + 投票 | 存草稿成功 |
|
||
| 2 | 退出编辑页重新进入 | **首块文字仍在**(回归 a);小标题在;视频说明在;封面是字符串 |
|
||
| 3 | **打开已有文字的文章,不点任何东西直接保存** | 原文不变(见 P1-2) |
|
||
| 4 | 点预览 | 5 种块各渲染一次,**不重复渲染**(历史上 u-parse + 单独渲染会重复) |
|
||
| 5 | 发布 | 请求 payload 同时含 `cmsLst` 与 `content`;`vote_id` 非空 |
|
||
| 6 | 打开详情页 | 全部块可见;视频可播;投票可提交并计数 |
|
||
| 7 | 匿名/未登录,用草稿 `_id` 直连读 | **被拒**(read 权限表达式生效) |
|
||
| 8 | 换封面:先让上传失败(断网) | 旧封面仍在,文章引用未被改坏 |
|
||
| 9 | 普通作者删**自己**文章的图 | 成功 |
|
||
| 10 | 普通作者拿 A 文章 `article_id` 删 B 文章的文件 | **失败**「文件不是该文章引用资源」 |
|
||
| 11 | 老 PC 文章(`edit_type != 'mobile'`,content-only)打开详情 | 走官方 renderer,**不被 mobile 分支污染、不被兜底清空** |
|
||
| 12 | H5/小程序启动控制台 | 无 `wx is not defined`、无 `$set` 报错、无非法单位 |
|
||
| 13 | **安卓端首页(未部署 getPublishedArticles 时 vs 部署后)** | 部署前回退「仅本人」;部署后游客可见已发布文章 |
|
||
|
||
**注意第 11 条**:`afterRead` 对 PC 文章有兜底
|
||
`if (!article.content || !Array.isArray(article.content.ops)) { article.content = { ops: [] } }`,
|
||
要验证老文章**不会因此静默变空白正文**。若发现被清空,改成「保留原值 + 记日志」。
|
||
|
||
### P1-1 · 内容审核链路未真跑(本地脚本覆盖不到)
|
||
|
||
`schema.ext.js` 的 `beforeAdd` / `beforeUpdate` / `afterRead` 只在 uniCloud 运行时执行。
|
||
|
||
做法:控制台/真机发一条含敏感词 + 一张违规图的 payload,确认
|
||
文本命中抛错、图片命中抛错、**mobile 文章只填 `cmsLst` 不填 `content` 也要被审到**。
|
||
记录请求 id 与返回。
|
||
|
||
### P1-2 · 编辑器空内容覆盖保护(残留边界风险)
|
||
|
||
`pages2/editCms/editText.vue:100-108`(已核对):`fail` 分支已经不覆盖原内容,
|
||
但 `success` 分支在「editor ready 但内容未 hydrate」时会用空串把原文字抹掉。
|
||
|
||
```js
|
||
const nextText = text || ''
|
||
const hadContent = Boolean(oldItem.text || oldItem.html)
|
||
const gotContent = Boolean(nextText || html || (delta && delta.ops && delta.ops.length))
|
||
if (hadContent && !gotContent) {
|
||
console.warn('编辑器内容为空,跳过覆盖以防丢稿')
|
||
await back()
|
||
return
|
||
}
|
||
```
|
||
|
||
同一守卫在 `smallTitle.vue` 的 `getContents` 成功回调里也要加。
|
||
**验收**:P0-3 用例 3。
|
||
|
||
### P1-3 · 安卓端真实可跑性未验证
|
||
|
||
`tools/check-android-contract.js` 只证明**方法名对得上**,不证明能跑。
|
||
|
||
现状盘点(本轮查明):
|
||
- 工具链齐:JDK 17(`android-tools/jdk17/jdk-17.0.20+8`)、Gradle 8.7(`android-tools/gradle-8.7`)、Android SDK(`android-tools/sdk`,build-tools 34.0.0)
|
||
- AVD 存在:`dsh_api34` / `test_avd`
|
||
- `gradle projects` 已跑通(`Root project 'junge-liaoliang'` → `Project ':app'`)
|
||
- **但 `android/` 没有 `gradlew` wrapper**,只能用外部 gradle;`adb devices` 当前无设备
|
||
|
||
做法:
|
||
```bash
|
||
# 1) 起模拟器
|
||
cd C:/Users/12914/Desktop/t/android
|
||
export JAVA_HOME="C:/Users/12914/Desktop/android-tools/jdk17/jdk-17.0.20+8"
|
||
"/c/Users/12914/Desktop/android-tools/sdk/emulator/emulator.exe" -avd dsh_api34 &
|
||
"/c/Users/12914/Desktop/android-tools/sdk/platform-tools/adb.exe" devices
|
||
|
||
# 2) 构建 debug
|
||
"/c/Users/12914/Desktop/android-tools/gradle-8.7/bin/gradle.bat" :app:assembleDebug
|
||
|
||
# 3) 装并跑,对着 uniCloud 空间验证 getPublishedArticles 真能返回数据
|
||
```
|
||
**先确认 `UNICLOUD_BASE_URL`**:`android/app/build.gradle.kts:21` 当前是
|
||
`https://env-00jxt5y29hrd.dev-hz.cloudbasefunction.cn`——需确认这是控制台里
|
||
真实开通 URL 化的域名,否则所有接口都会失败。
|
||
|
||
**另一个要留意的集成点**:`uni-cms-articles.schema.ext.js` 的 `afterRead` 开头有
|
||
|
||
```js
|
||
if (!config.clientAppIds || !config.clientAppIds.length) throw new Error(...)
|
||
if (!config.clientAppIds.includes(clientInfo.appId)) return // ← 静默跳过
|
||
```
|
||
|
||
当前 `uni-cms-config/uni-cms/config.json` 里 `clientAppIds = ["__UNI__EF95AB3"]`,
|
||
与 `manifest.json` 的 appid 一致,所以小程序/H5 正常。
|
||
|
||
但从安卓经 URL 化网关调用时 `clientInfo.appId` 很可能是空值 →
|
||
`includes(undefined)` 为 false → **`afterRead` 直接 return,整段内容后处理被跳过**
|
||
(解锁内容、`content_images`、`view_count` 自增都不会执行)。
|
||
|
||
对 `getPublishedArticles` 无影响(它本来就不取 `content`)。
|
||
但要确认 `article_info.getDetail` 从安卓调用时返回的 `content` 是否仍是**未处理的原始 Delta**——
|
||
如果是,安卓端要么自己处理,要么得把安卓的 appId 加进 `clientAppIds`。
|
||
这是 P1-3 真跑时要专门看一眼的点。
|
||
|
||
### P2-1 · 编码类警告(独立问题,别混进文章链路提交)
|
||
|
||
| 文件 | 问题 | 处理 |
|
||
|---|---|---|
|
||
| `hx_page.html` | UTF-8 BOM | 已在 `.gitignore`(构建产物)→ 给 audit 加 ignore 白名单 |
|
||
| `uni_modules/uni-pagination/components/uni-pagination/i18n/es.json` | 非法 UTF-8(GBK/二次编码损坏) | 独立修:从 `git show HEAD:<path>` 取原文重存 UTF-8 |
|
||
|
||
### P2-2 · `check-vue.js` 49 条警告 = 全部不在范围内
|
||
|
||
分布:`uni_modules` 36 / `components` 12 / `pages3` 1。
|
||
全是第三方或 Vue2 遗留写法(`beforeDestroy`、`filters`、`this.$set`、`<script lang="uts">`)。
|
||
**结论:不改**。顺手改会引入回归,且会让文章闭环的提交 diff 失焦。登记为「既有基线」。
|
||
|
||
同理 `components/thorui/**` 的 `this.$set`(12 处)也不要动。
|
||
|
||
---
|
||
|
||
## C. 建议执行顺序
|
||
|
||
```
|
||
P0-1 提交工作区 ← 先做,锁住本轮成果
|
||
↓
|
||
P0-2 抽纯函数 + 补断言 ← 纯本地,可离线
|
||
↓
|
||
P1-2 编辑器空覆盖守卫 ← 小改动,配合 P0-2 一起测
|
||
↓
|
||
P0-3 端到端 QA ← 需要 HBuilderX + 服务空间,真正验收
|
||
↓
|
||
P1-3 安卓端真跑
|
||
↓
|
||
P1-1 审核链路真跑
|
||
↓
|
||
P2 编码/警告清理(可选)
|
||
```
|
||
|
||
---
|
||
|
||
## D. 验收标准
|
||
|
||
1. ✅ 新建 mobile 文章:标题+文字+小标题+图片+视频+投票,能存草稿、重开、预览、发布
|
||
2. ✅ 发布后详情所有块可见,文字/小标题不消失,视频可播,投票可提交
|
||
3. ✅ 编辑旧文章的首个文字块、视频说明、封面、模板、音乐后,其他字段不丢
|
||
4. ✅ 上传失败旧媒体保留;普通作者只能处理自己文章的媒体
|
||
5. ✅ 匿名用户只能看已发布文章,不能按已知 ID 读草稿
|
||
6. ✅ H5/App/微信小程序不因 `wx`、Vue2 `$set`、非法单位、空图片地址崩溃
|
||
7. ✅ 现有 PC/标准 `content` 文章继续走官方 renderer,不被 mobile 逻辑破坏
|
||
8. ✅ `node tools/build.js -p h5` 与 `-p mp-weixin` 均产出完整产物
|
||
9. ✅ `node tools/verify.js` 全绿(4 自测 + 4 检查 + 13 数据项)
|
||
10. ⬜ `check-article-flow.js` 断言组数 ≥10,覆盖 a–g(**待做**)
|
||
11. ⬜ 工作区已提交(**待做**)
|
||
12. ⬜ 安卓端在模拟器上真实跑通首页文章流(**待做**)
|
||
|
||
---
|
||
|
||
## E. 环境备忘(本轮实测)
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| Node | v24.19.0(跑 `tools/*.js` 可以;**跑 vite 构建不行**,要用 HBuilderX 的 node) |
|
||
| HBuilderX 构建 node | `C:/Program Files/HBuilderX/HBuilderX/plugins/node/node.exe` (v22.22.2) |
|
||
| HBuilderX | `C:/Program Files/HBuilderX/HBuilderX`(编译器 5.15,Vue3) |
|
||
| JDK | `C:/Users/12914/Desktop/android-tools/jdk17/jdk-17.0.20+8` |
|
||
| Gradle | `C:/Users/12914/Desktop/android-tools/gradle-8.7/bin/gradle.bat` |
|
||
| Android SDK | `C:/Users/12914/Desktop/android-tools/sdk`(build-tools 34.0.0,AVD `dsh_api34`) |
|
||
| 当前分支 | `test`(主分支 `main`) |
|
||
| `.zcode/` | 工具链运行产物,已 ignore |
|
||
| 端口 | 5173 被**别的项目**(english-drill)占用;adb 用 5037 |
|
||
|
||
**不要做的事**:
|
||
- 不要在项目根跑 `npm install`——会按 Vue2 时代的 `package.json` 剪掉联接,
|
||
需要重跑 `node tools/build.js --link-only` 恢复(本项目是 HBuilderX 工程,不是标准 CLI 工程)
|
||
- 不要改 `vite.config.js`(HBuilderX 需要它指向 HBX 工具链)
|
||
- 不要动 `unpackage/`(构建产物,已 ignore)
|