diff --git a/docs/superpowers/specs/2026-08-11-mobile-oa-start-approval-design.md b/docs/superpowers/specs/2026-08-11-mobile-oa-start-approval-design.md new file mode 100644 index 00000000..7a011977 --- /dev/null +++ b/docs/superpowers/specs/2026-08-11-mobile-oa-start-approval-design.md @@ -0,0 +1,238 @@ +# 移动端「发起审批」设计 + +> 日期:2026-08-11 +> 工程:`mobile-h5`(微信小程序)+ 独立 OA 表单 H5 +> 对齐参考:`web-admin` 发起审批(`views/oa-approval/start` + `OaStartFormDialog` + `OaFlowPreview`) +> 相关:`docs/superpowers/specs/2026-08-10-mobile-h5-vant-ui-design.md`、`docs/miniprogram-ui-spec-sanqiang.md` + +--- + +## 1. 背景与目标 + +### 1.1 现状 + +- `mobile-h5`:登录与首页已完成;首页「功能菜单」目前为空(未接移动端菜单权限)。 +- `web-admin`:发起审批已上线——卡片展示已发布流程 → 弹窗上半 form-create 动态表单、下半审批流预览 → 暂存草稿 / 提交。 +- Web 表单使用 `@form-create/element-ui` + 大量自研组件/套件;移动端需用 `@form-create/vant` 渲染**同一套** `formSchemaJson`。 + +### 1.2 目标 + +1. 在微信小程序中提供「发起审批」:模板列表(原生)+ 填写页(H5,经 web-view)。 +2. **凡 Web 可发起的已发布模板,移动端均可完整填写**(基础控件、自研组件、自研套件全覆盖)。 +3. **不按流程单独开发界面**:一个 H5 填写页根据 `appId` 拉取 JSON 动态渲染。 +4. 阶段一先做「厨房水槽」真机验证,暴露 web-view + form-create/vant + 全 type 注册问题。 + +### 1.3 非目标(本设计范围外) + +- 待办审批、已办、抄送、审批详情办理(可后续独立设计)。 +- 改造 Web 设计器;移动端只做运行时渲染与交互。 +- 在小程序原生运行时内直接挂载 `@form-create/vant`(已评估为高风险,不作为主路径)。 + +--- + +## 2. 已确认决策 + +| 决策点 | 结论 | +|--------|------| +| 发布目标 | 微信小程序(`mobile-h5`) | +| 表单承载 | 独立部署 H5 + 小程序整页 `web-view` | +| 列表 vs 填写 | **A1**:模板列表用小程序原生;仅填写页进 H5 | +| 表单能力 | **全量对齐 Web**(基础 + 自研组件 + 套件) | +| 多流程 UI | **一套 H5 页 + JSON 渲染**,不为每个流程单独做页 | +| 阶段一验证 | 首页硬编码测试菜单 → web-view → H5 水槽页(手工 kitchen-sink rule) | +| 品牌色 | 三墙 `#0a9f6d` 等;禁止混用 Web `#10b981` | + +--- + +## 3. 架构 + +``` +┌─ mobile-h5(微信小程序)────────────────────────────┐ +│ 首页功能菜单 ← 「移动端菜单」+ 角色授权(联调阶段) │ +│ │ │ +│ ▼ │ +│ 模板列表页(原生) │ +│ · GET templates + groups │ +│ · 卡片 / 分组(对齐 Web 发起审批列表思路) │ +│ · 「发起」→ 打开 web-view 页 │ +│ │ │ +│ ▼ │ +│ 整页 web-view │ +│ src = {H5_ORIGIN}/oa-start/?appId=&token=… │ +│ (阶段一水槽:/oa-form-sink/) │ +└──────────────────────────┼───────────────────────────┘ + ▼ +┌─ 独立 H5(建议目录 mobile-oa-h5)─────────────────────┐ +│ Vue3 + Vant4 + @form-create/vant │ +│ 注册:基础控件映射 + 全部自研 type(与 Web type 名一致)│ +│ 上:动态表单 ← formSchemaJson │ +│ 下:审批流预览 ← flow-preview │ +│ 底:取消 / 暂存草稿 / 提交 │ +│ 结束:postMessage + navigateBack → 小程序 │ +└──────────────────────────────────────────────────────┘ +``` + +### 3.1 为何用 web-view 而不是小程序内直挂 form-create + +- 官方 `@form-create/vant` 面向浏览器 H5 + Vant,**不是** uni-app / 微信小程序一等公民。 +- 同类 OA + form-create + uni-app 实践普遍采用「Vant H5 + web-view 嵌入」。 +- 微信小程序中 `web-view` **强制全屏**,故填写相关 UI(表单、审批流、底栏)全部放在 H5,避免原生与 web-view 叠层。 + +### 3.2 JSON 驱动(回答「是否每个流程一个界面」) + +**否。** 与 Web `OaStartFormDialog` 相同: + +1. 设计器产出 `formSchemaJson.rule` / `option`(存库)。 +2. 发起时 `GET templates/{appId}` 取 schema + 流程树。 +3. 同一 H5 页 `` 渲染。 +4. 请假 / 报销 / 加班等仅 `rule` 不同;前提是 H5 已注册所有用到的 `type`。 + +--- + +## 4. 页面与工程划分 + +| 端 | 路径 / 工程 | 职责 | +|----|-------------|------| +| 小程序 | 首页 `MenuGrid` | 正式「发起审批」菜单;阶段一可硬编码「表单水槽测试」 | +| 小程序 | `/pages/oa/start/index` | 已发布模板卡片列表 | +| 小程序 | `/pages/oa/start/webview`(或 `/pages/oa/form-sink/index`) | 整页 `web-view` 容器 | +| H5 | `/oa-form-sink` | 厨房水槽:手工 rule 覆盖全部 type | +| H5 | `/oa-start` | 正式填写:真实模板 + 审批流 + 草稿/提交 | + +H5 建议独立目录(如 `mobile-oa-h5/`),Vite 构建并部署到已配置的小程序**业务域名** HTTPS 路径;与 HBuilderX 小程序工程解耦。 + +--- + +## 5. 阶段一:厨房水槽 Spike + +### 5.1 目标 + +真机验证:web-view 内 `@form-create/vant` + 全量自研 type 注册能否稳定渲染与交互。 + +### 5.2 入口 + +- 首页「功能菜单」本地注入测试项:`表单水槽测试` → `/pages/oa/form-sink/index`。 +- 不依赖后台菜单接口(首页当前 `menus=[]`)。 + +### 5.3 H5 水槽页 + +- 手工 `kitchen-sink-rule`:覆盖全部基础控件 + 自研组件 + 自研套件。 +- 底栏:校验、打印/展示 `formData`(本阶段可不接真实发起 API)。 +- 审批流区:可静态占位,避免干扰表单验证。 + +### 5.4 成功 / 失败标准 + +**成功**:开发者工具 + 真机可打开;各 type 可交互;校验与取值正常;无白屏。 + +**失败**:记录问题清单后仍不可用 → 复盘部署/域名/JSBridge;不回退到「小程序内直挂 form-create」作为主方案(该路径已否决)。 + +### 5.5 阶段一明确不做 + +- 菜单管理正式注册与角色联调。 +- 模板列表、草稿箱、真实提交。 +- 线上模板 schema 联调(阶段二)。 + +--- + +## 6. 阶段二:正式发起审批 + +### 6.1 小程序模板列表 + +对齐 Web `oa-approval/start` 思路: + +- 数据:`fetchOaTemplates` + `fetchOaGroupList`(或等价接口)。 +- UI:分组卡片、图标、名称、描述、「发起」;搜索/分组 Tab 可按排期对齐。 +- 点击发起:跳转 web-view 页,URL 带 `appId`、登录态(token 等)。 + +### 6.2 H5 正式填写页(对齐 `OaStartFormDialog`) + +1. 入参:`appId` 必填;可选 `draftId`。 +2. 拉模板详情 → 预处理 rule(ensure*、默认值、Kit 联动,行为对齐 Web 运行时)。 +3. 下半:`flow-preview`;条件未齐显示 pending;`initiator_select` 支持选人。 +4. 暂存 / 提交:复用 drafts / instances API。 +5. 成功或取消:`postMessage` + `navigateBack`;小程序 `@message` 收结果(注意微信端 message 多在后退/销毁时送达)。 + +### 6.3 菜单与权限 + +1. Web「菜单管理 → 移动端菜单」下注册「发起审批」,`path` 指向小程序列表页。 +2. 角色授权后首页展示。 +3. 提供或约定「当前用户移动端菜单」接口,替换首页空菜单。 + +### 6.4 API + +- 优先复用 `/web/admin/oa-approval/*` + 现有 JWT;确认小程序登录角色的菜单/数据权限足够。 +- 若权限模型不适配,再增加 `/mini/oa-approval/*`,契约与 Web 运行时对齐。 + +--- + +## 7. 自研组件与套件(全量) + +`type` 名称与 Web 注册保持一致。H5 侧用 Vant/移动交互重实现,不能直接复用 Element Plus 组件。 + +**组件类(含但不限于):** + +- 上传、金额、人员、所属人、部门、所属部门、岗位、收款账户、关联审批等。 + +**套件类(含但不限于):** + +- 请假、加班、转正、离职、差旅/行程等。 + +**运行时:** + +- 默认值、时长/日期自动计算、手改标记与恢复、节假日等与 Web 一致的联动逻辑。 + +### 7.1 移植顺序(建议) + +1. 上传、金额、人员/部门/岗位、所属人/所属部门 +2. 收款账户、关联审批 +3. 请假 / 加班 / 转正 / 离职套件 +4. 差旅 / 行程套件 +5. 运行时细节对齐与真实模板回归 + +阶段一水槽 rule 应预先包含上述全部 type,用于尽早暴露缺口。 + +--- + +## 8. 风险与对策 + +| 风险 | 对策 | +|------|------| +| web-view 全屏、无法叠原生控件 | 填写页 UI 全部在 H5 | +| 业务域名未配置 | H5 部署到已备案 HTTPS 业务域名 | +| postMessage 非实时 | 提交/取消后主动返回,触发小程序收消息 | +| Token 安全 | 短时参数或桥接;避免长期明文落日志 | +| 套件行为与 Web 不一致 | 水槽 + 同模板双端对照清单 | +| 首页菜单长期为空 | 阶段二必须打通移动端菜单接口 | + +--- + +## 9. 实施顺序 + +| 序号 | 内容 | +|------|------| +| P0 | 独立 H5 工程骨架 + Vant + `@form-create/vant` | +| P1 | 水槽页 + 全 type 注册(可先 mock 未完成的自研控件) | +| P2 | 小程序:测试菜单 + 整页 web-view 打开水槽;真机验收 | +| P3 | 按序完成自研组件/套件真实实现 | +| P4 | H5 `/oa-start`:模板 API + flow-preview + 草稿/提交 | +| P5 | 小程序原生模板列表 + 菜单注册 + 首页菜单联调 | +| P6 | 已发布模板全量回归(移动端可完整发起) | + +--- + +## 10. 验收标准 + +1. 阶段一:水槽页在微信真机 web-view 中可完整操作厨房水槽 rule。 +2. 阶段二:已发布模板均可在移动端发起;表单字段与 Web 同模板一致可填;审批流预览与手选审批人可用;草稿与提交成功。 +3. 首页通过「移动端菜单」授权可见「发起审批」。 +4. 不为每个流程单独维护一套填写 Vue 页面。 + +--- + +## 11. 参考路径(Web) + +- 列表:`web-admin/src/views/oa-approval/start/index.vue` +- 弹窗:`web-admin/src/components/oa-approval/OaStartFormDialog.vue` +- 审批流:`web-admin/src/components/oa-approval/OaFlowPreview.vue` +- API:`web-admin/src/api/oaApproval.ts` +- 组件注册:`web-admin/src/main.ts` + `src/utils/oa-form-create-*.ts`