pages/oa/start|drafts|pending|done|mine|cc|webview、OaDetail、oa-badge、oa/print、路由 /oa-detail 均存在)。730cc99^..HEAD):730cc99 菜单 → 2dac9d6 API → cf4994e webview → 387e824 卡片 → 6b0fb7b 草稿 → 47d7a14/d827f55/76dab57 详情 → 29560b7 已办/我发起/抄送 → d528776 待办办理 → ecdf73f 撤销重开 → 06b1468 抄送增强 → 915253e 角标 → cbef681 打印。./scripts/update-graph.sh backend 已执行;真机/微信内全链路仍需人工 QA(见文末「剩余人工 QA」)。For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 在小程序落地草稿箱 / 待办 / 已办 / 我发起的 / 抄送我的五中心:原生列表 + H5 详情办理(对齐 Web 业务,UI 对齐既有 mobile-h5 / mobile-oa-h5)。
Architecture: 列表在 mobile-h5;表单与办理在 mobile-oa-h5 新增 /oa-detail(mode=view|approve);草稿编辑继续 /oa-start?draftId=。API 复用 /web/admin/oa-approval/* + JWT。菜单种子挂「移动端菜单」根下。
Tech Stack: uni-app 微信小程序、web-view、Vue3、Vant4、@form-create/vant、FastAPI(菜单 SQL)
Spec: docs/superpowers/specs/2026-08-12-mobile-oa-task-centers-design.md
原则(强制): 功能语义对齐 web-admin OA 对应页与 instances/detail.vue;UI 对齐 mobile-h5(如 pages/demo/list、pages/oa/start)与 mobile-oa-h5(OaStart.vue、footer、picker),禁止照搬 Element 桌面布局。
已完成(勿重复): 五菜单 PNG → mobile-h5/static/menu-icons/oa-*.png;van-icon / menu-icon-colors.js / backend/app/api/mini_menu.py path→icon 映射。
Out of scope: 时间范围/分组/流程状态等已剔除筛选;Web 设计器改造;小程序内直挂 form-create。
| 路径 | 职责 |
|---|---|
docs/sql/mobile_menu_oa_task_centers.sql |
五菜单种子(OA002–OA006) |
mobile-h5/utils/oa-api.js |
drafts / tasks / mark-read / counts |
mobile-h5/utils/oa-h5.js |
buildOaDetailUrl;扩展 start 预填若需要 |
mobile-h5/utils/oa-badge.js |
拉草稿/待办/抄送角标(可新建) |
mobile-h5/pages.json |
注册五列表 + 通用 webview(或扩 start/webview) |
mobile-h5/pages/oa/drafts/index.vue |
草稿箱 |
mobile-h5/pages/oa/pending/index.vue |
待办 |
mobile-h5/pages/oa/done/index.vue |
已办 |
mobile-h5/pages/oa/mine/index.vue |
我发起的 |
mobile-h5/pages/oa/cc/index.vue |
抄送我的 |
mobile-h5/pages/oa/webview/index.vue |
通用 web-view(start + detail)或 扩展 start/webview.vue |
mobile-h5/components/OaTaskCard.vue |
任务/草稿卡片(移动端样式,非 BizListCard 业务 mock) |
mobile-oa-h5/src/api/oa.js |
instance detail + task actions + withdraw + cc read |
mobile-oa-h5/src/views/OaDetail.vue |
详情只读 / 办理 |
mobile-oa-h5/src/oa/components/OaProgressTimeline.vue |
审批进度(对齐 Web progress;可基于现有 Flow 组件) |
mobile-oa-h5/src/oa/components/OaActionSheet*.vue |
意见 / 加签 / 转交弹层(Vant Dialog/Popup) |
mobile-oa-h5/src/router.js |
/oa-detail |
mobile-oa-h5/src/oa/print/(可选) |
PDF 打印移植 |
Web 只读对照:
web-admin/src/views/oa-approval/{drafts,pending,done,mine,cc}/index.vueweb-admin/src/views/oa-approval/instances/detail.vueweb-admin/src/api/oaApproval.tsweb-admin/src/utils/oa-approval-print.ts(打印)首页宫格(授权菜单)
→ 五列表之一(原生)
→ 草稿编辑 → webview → /oa-start?draftId=
→ 待办办理 → webview → /oa-detail?mode=approve&instanceId=&taskId=
→ 已办/抄送/我发起查看 → /oa-detail?mode=view&instanceId=
→ postMessage → navigateBack → 列表 onShow 刷新 + 角标
Files:
Create: docs/sql/mobile_menu_oa_task_centers.sql
[ ] Step 1: 按 mobile_menu_oa_start.sql 写五条幂等 INSERT
完整内容:
-- 小程序 OA 五中心菜单种子(挂在「移动端菜单」根下)
-- 前置:docs/sql/mobile_menu_oa_start.sql(发起审批 OA001)可已执行
-- 角色授权请在 Web「角色管理」勾选本菜单。
SET @mini_root = (
SELECT id FROM sys_menu
WHERE del_flag = 0 AND parent_id = '0' AND menu_name LIKE '%移动端%'
LIMIT 1
);
-- 草稿箱
INSERT INTO sys_menu (
id, menu_name, parent_id, menu_type, path, component, perms,
is_frame, visible, status, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
'MINI000000000000000000000000OA002',
'草稿箱',
@mini_root,
'C',
'/pages/oa/drafts/index',
NULL,
'mini:oa:drafts',
1,
'1',
'1',
'zkxw',
20,
'小程序草稿箱',
'admin',
'',
NOW(),
NULL,
NOW(),
0
FROM DUAL
WHERE @mini_root IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM sys_menu WHERE id = 'MINI000000000000000000000000OA002' AND del_flag = 0
);
-- 待办中心
INSERT INTO sys_menu (
id, menu_name, parent_id, menu_type, path, component, perms,
is_frame, visible, status, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
'MINI000000000000000000000000OA003',
'待办中心',
@mini_root,
'C',
'/pages/oa/pending/index',
NULL,
'mini:oa:pending',
1,
'1',
'1',
'zkxw',
30,
'小程序待办中心',
'admin',
'',
NOW(),
NULL,
NOW(),
0
FROM DUAL
WHERE @mini_root IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM sys_menu WHERE id = 'MINI000000000000000000000000OA003' AND del_flag = 0
);
-- 已办中心
INSERT INTO sys_menu (
id, menu_name, parent_id, menu_type, path, component, perms,
is_frame, visible, status, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
'MINI000000000000000000000000OA004',
'已办中心',
@mini_root,
'C',
'/pages/oa/done/index',
NULL,
'mini:oa:done',
1,
'1',
'1',
'zkxw',
40,
'小程序已办中心',
'admin',
'',
NOW(),
NULL,
NOW(),
0
FROM DUAL
WHERE @mini_root IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM sys_menu WHERE id = 'MINI000000000000000000000000OA004' AND del_flag = 0
);
-- 我发起的
INSERT INTO sys_menu (
id, menu_name, parent_id, menu_type, path, component, perms,
is_frame, visible, status, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
'MINI000000000000000000000000OA005',
'我发起的',
@mini_root,
'C',
'/pages/oa/mine/index',
NULL,
'mini:oa:mine',
1,
'1',
'1',
'zkxw',
50,
'小程序我发起的',
'admin',
'',
NOW(),
NULL,
NOW(),
0
FROM DUAL
WHERE @mini_root IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM sys_menu WHERE id = 'MINI000000000000000000000000OA005' AND del_flag = 0
);
-- 抄送我的
INSERT INTO sys_menu (
id, menu_name, parent_id, menu_type, path, component, perms,
is_frame, visible, status, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
'MINI000000000000000000000000OA006',
'抄送我的',
@mini_root,
'C',
'/pages/oa/cc/index',
NULL,
'mini:oa:cc',
1,
'1',
'1',
'zkxw',
60,
'小程序抄送我的',
'admin',
'',
NOW(),
NULL,
NOW(),
0
FROM DUAL
WHERE @mini_root IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM sys_menu WHERE id = 'MINI000000000000000000000000OA006' AND del_flag = 0
);
GET /mini/menus 应含 5 条 pathExpected: list 中出现 /pages/oa/drafts|pending|done|mine|cc/index,icon 分别为 oa-drafts|oa-pending|oa-done|oa-mine|oa-cc。
git add docs/sql/mobile_menu_oa_task_centers.sql
git commit -m "$(cat <<'EOF'
feat(oa): add mobile menu seeds for five OA task centers
EOF
)"
Files:
mobile-h5/utils/oa-api.jsModify: mobile-oa-h5/src/api/oa.js
[ ] Step 1: 在 mobile-h5/utils/oa-api.js 追加(保留现有 templates 方法;按项目 request.js 支持的 get/post/del 写法实现)
对齐 web-admin/src/api/oaApproval.ts:
// drafts
export function fetchOaInstanceDraftList(params) { /* GET /web/admin/oa-approval/drafts */ }
export function fetchOaInstanceDraftCount() { /* GET .../drafts/count */ }
export function fetchDeleteOaInstanceDraft(id) { /* DELETE .../drafts/{id} */ }
export function fetchBatchDeleteOaInstanceDrafts(ids) { /* POST .../drafts/batch-delete { ids } */ }
export function fetchSubmitOaInstanceDraft(id, data) { /* POST .../drafts/{id}/submit */ }
// tasks
export function fetchOaTasks(kind, params) {
// kind: pending|done|mine|cc
// GET .../tasks/{kind} query: page,pageSize,appName,initiatorName,readStatus(cc)
}
export function fetchOaPendingTaskCount() { /* GET .../tasks/pending/count */ }
export function fetchOaCcUnreadCount() { /* GET .../tasks/cc/unread-count */ }
export function fetchMarkOaCcTaskRead(taskId) { /* POST .../tasks/{id}/read */ }
export function fetchBatchMarkOaCcTasksRead(ids) { /* POST .../tasks/cc/read-batch { ids } */ }
实现时复用文件内已有 get / authHeader;若 request.js 无 del/post,按同目录其它 utils 写法调用。每个函数必须带 Authorization: Bearer。
mobile-oa-h5/src/api/oa.js 追加export function fetchOaInstanceDetail(id) {
return get(`/web/admin/oa-approval/instances/${encodeURIComponent(id)}`)
}
export function fetchApproveOaTask(taskId, comment) {
return post(`/web/admin/oa-approval/tasks/${encodeURIComponent(taskId)}/approve`, { comment })
}
export function fetchRejectOaTask(taskId, comment) {
return post(`/web/admin/oa-approval/tasks/${encodeURIComponent(taskId)}/reject`, { comment })
}
export function fetchReturnOaTask(taskId, comment) {
return post(`/web/admin/oa-approval/tasks/${encodeURIComponent(taskId)}/return`, { comment })
}
export function fetchAddSignOaTask(taskId, data) {
// data: { userIds: string[], comment?: string }
return post(`/web/admin/oa-approval/tasks/${encodeURIComponent(taskId)}/add-sign`, data)
}
export function fetchTransferOaTask(taskId, data) {
// data: { targetUserId: string, comment?: string }
return post(`/web/admin/oa-approval/tasks/${encodeURIComponent(taskId)}/transfer`, data)
}
export function fetchWithdrawOaInstance(instanceId) {
return post(`/web/admin/oa-approval/instances/${encodeURIComponent(instanceId)}/withdraw`, {})
}
export function fetchMarkOaCcTaskRead(taskId) {
return post(`/web/admin/oa-approval/tasks/${encodeURIComponent(taskId)}/read`, {})
}
[ ] Step 3: 本地用已登录 token 在浏览器/控制台或临时页面各打一条 drafts list / tasks pending 验证 200
[ ] Step 4: Commit
git add mobile-h5/utils/oa-api.js mobile-oa-h5/src/api/oa.js
git commit -m "$(cat <<'EOF'
feat(oa): extend mobile OA APIs for drafts, tasks, and detail actions
EOF
)"
buildOaDetailUrl(S0)Files:
mobile-h5/utils/oa-h5.jsmobile-h5/pages/oa/webview/index.vue(推荐新建通用页)或 扩展 pages/oa/start/webview.vueModify: mobile-h5/pages.json
[ ] Step 1: 在 oa-h5.js 增加
/** 审批详情 / 办理页 */
export function buildOaDetailUrl({ instanceId, taskId, mode } = {}) {
const token = getToken()
const params = {}
if (instanceId) params.instanceId = instanceId
if (taskId) params.taskId = taskId
if (mode) params.mode = mode // view | approve
if (token) params.token = token
return withQuery('/oa-detail', params)
}
const DETAIL_TITLE_KEY = 'oa_detail_nav_title'
export function stashOaDetailTitle(name) { /* 同 stashOaStartTitle 模式 */ }
export function takeOaDetailTitle() { /* 同 takeOaStartTitle */ }
onLoad(query):
forceReloginquery.draftId 或(query.appId 且无 instanceId)→ buildOaStartUrlquery.instanceId → buildOaDetailUrl({ instanceId, taskId, mode })takeOaDetailTitle() / takeOaStartTitle()CLOSE_ACTIONS 扩展:oa-detail-close、oa-detail-done、oa-detail-withdraw、oa-detail-restart 等;H5 iframe message 与小程序 @message 行为对齐现有 start webviewpages.json 注册五列表空壳路径 + webview(标题用中文业务名)示例条目:
{
"path": "pages/oa/drafts/index",
"style": {
"navigationBarTitleText": "草稿箱",
"navigationBarBackgroundColor": "#ecfdf5",
"navigationBarTextStyle": "black"
}
}
同样注册 pending/done/mine/cc;webview 标题默认「审批详情」。
[ ] Step 4: 真机/开发者工具打开任意 webview URL 带 token,确认能加载 H5(detail 可先 404,本 Task 只要求 start 路径不回归)
[ ] Step 5: Commit
git add mobile-h5/utils/oa-h5.js mobile-h5/pages.json mobile-h5/pages/oa/webview/
git commit -m "$(cat <<'EOF'
feat(oa): add shared OA webview and detail URL builder
EOF
)"
Files:
mobile-h5/components/OaTaskCard.vuemobile-h5/styles/components/oa-task-list.scss(若项目按组件拆 scss)Reference UI: mobile-h5/pages/demo/list.vue、pages/oa/start/index.vue、styles/tokens.scss
[ ] Step 1: 实现 OaTaskCard
Props 建议:
{
title: String, // 流程名
statusText: String,
statusTone: String, // warn|success|danger|info
metaLines: Array, // [{ label, value }]
unread: Boolean, // 抄送红点
actions: Array // [{ key, label, primary?, danger? }]
}
Emits: action with { key, ... };整卡点击可 emit open。
样式:三墙 Token;卡片圆角/间距对齐 start 列表与 demo list;不要复制 Web 表格列。
utils/oa-list.js(可选)提供:page/pageSize/loading/finished、loadMore、onPullDownRefresh 重置。若不想抽 mixin,五页内复制最小分页逻辑亦可(YAGNI:先两页共用后再抽)。
git add mobile-h5/components/OaTaskCard.vue mobile-h5/styles/components/oa-task-list.scss
git commit -m "$(cat <<'EOF'
feat(oa): add mobile OA task card for center lists
EOF
)"
Files:
mobile-h5/pages/oa/drafts/index.vuemobile-h5/pages.json(若 Task3 已注册可跳过)功能清单(规格 §2.1): 列表、分页、流程名筛选、编辑、列表提交、单删、批量删、角标(角标可先调 count API,宫格角标 UI 放 Task 11)。
结构参考 pages/demo/list.vue:顶区搜索(仅关键词)+ 列表 + 多选模式批量删。
关键方法:
async loadList(reset) {
// fetchOaInstanceDraftList({ keyword, page, pageSize })
}
openEdit(row) {
stashOaStartTitle(row.appName || row.title)
uni.navigateTo({
url: `/pages/oa/webview/index?draftId=${row.id}&appId=${row.appId || ''}`
// 若仍用 start/webview:`/pages/oa/start/webview?draftId=...`
})
}
async submitRow(row) {
// uni.showModal 确认 → fetchSubmitOaInstanceDraft(row.id) → 刷新
// 失败:可改为 openEdit 让用户改表单(对齐 Web)
}
async deleteRow(row) { /* confirm → fetchDeleteOaInstanceDraft */ }
async batchDelete() { /* selected ids → fetchBatchDeleteOaInstanceDrafts */ }
[ ] Step 2: onShow 刷新列表
[ ] Step 3: 手工验收
git add mobile-h5/pages/oa/drafts/
git commit -m "$(cat <<'EOF'
feat(oa): add mobile draft box list with edit submit delete
EOF
)"
/oa-detail 只读(S2)Files:
mobile-oa-h5/src/views/OaDetail.vuemobile-oa-h5/src/oa/components/OaProgressTimeline.vue(或复用/改造现有 flow 展示)mobile-oa-h5/src/router.jsReference: OaStart.vue(schema-prep、form-create disabled)、Web detail.vue(progress 字段)
[ ] Step 1: 注册路由
import OaDetail from './views/OaDetail.vue'
// ...
{ path: '/oa-detail', component: OaDetail }
OaDetail.vue 最小只读captureTokenFromUrl(与 main/OaStart 一致)instanceId、mode(默认 view)、taskIdfetchOaInstanceDetail → formSchemaJson + formData → schema-prep → <form-create-mobile disabled>progress 时间线statusText)mode=view 且非发起人特殊操作时仅「关闭」→ postMessage / wx.miniProgram.navigateBack,action=oa-detail-closeUI:padding、底栏按钮类名对齐 OaStart / oa-form.css / footer demo。
http://127.0.0.1:5178/oa-h5/oa-detail?instanceId=真实ID&token=...&mode=view
Expected: 表单只读可见、进度可见、关闭可返回。
git add mobile-oa-h5/src/views/OaDetail.vue mobile-oa-h5/src/oa/components/OaProgressTimeline.vue mobile-oa-h5/src/router.js
git commit -m "$(cat <<'EOF'
feat(oa): add mobile OA detail page in read-only mode
EOF
)"
Files:
mobile-h5/pages/oa/done/index.vuemobile-h5/pages/oa/mine/index.vue(本 Task 仅查看;打印/复制/撤销后续 Task)Create: mobile-h5/pages/oa/cc/index.vue(本 Task:列表+打开已读+进详情;阅读筛选/批量可本 Task 一并做或见 Task 10)
[ ] Step 1: 已办页
筛选:appName、initiatorName(搜索框 + 可选第二条件,移动端可用一行双字段或展开筛选,不要 Web 日期/状态)。
fetchOaTasks('done', …) → 卡片 → stashOaDetailTitle → navigate webview instanceId&mode=view。
筛选仅 appName。fetchOaTasks('mine', …) → view。
打开前或打开时:fetchMarkOaCcTaskRead(taskId)(task 行上的抄送任务 id,字段名对齐 Web row.id)。
再进 mode=view。H5 详情可再兜底 mark-read。
[ ] Step 4: 验收三页均可进只读详情并返回刷新
[ ] Step 5: Commit
git add mobile-h5/pages/oa/done/ mobile-h5/pages/oa/mine/ mobile-h5/pages/oa/cc/
git commit -m "$(cat <<'EOF'
feat(oa): add done mine cc lists opening read-only OA detail
EOF
)"
Files:
mobile-h5/pages/oa/pending/index.vuemobile-oa-h5/src/views/OaDetail.vueOaPersonSelect 或 Vant Popup + 已有选人)对照 Web detail.vue: myPendingTask、canApprove、allowReturn、allowAddSign、转交排除规则。
筛选:流程名、申请人。进入:mode=approve&instanceId=&taskId=(taskId 用行上待办任务 id)。
mode=approve 且存在当前用户 pending task)| 按钮 | API |
|---|---|
| 同意 | fetchApproveOaTask(taskId, comment?) |
| 拒绝 | fetchRejectOaTask |
| 打回 | 意见必填 → fetchReturnOaTask |
| 加签 | 选多人 → fetchAddSignOaTask({ userIds, comment }) |
| 转交 | 选一人(排除本人与本节点已有待办)→ fetchTransferOaTask({ targetUserId, comment }) |
成功后 toast + postMessage({ source:'zkxw-oa-h5', action:'oa-detail-done' }) + navigateBack。
意见输入用 Vant Dialog/Popup,样式对齐 mobile-oa-h5,不要 Element MessageBox。
[ ] Step 3: 五条办理主路径各测至少一次(可用测试租户)
[ ] Step 4: Commit
git add mobile-h5/pages/oa/pending/ mobile-oa-h5/src/views/OaDetail.vue mobile-oa-h5/src/oa/components/
git commit -m "$(cat <<'EOF'
feat(oa): add pending list and approve reject return add-sign transfer
EOF
)"
Files:
mobile-h5/pages/oa/mine/index.vuemobile-oa-h5/src/views/OaDetail.vuemobile-oa-h5/src/views/OaStart.vue(接收预填)Modify: mobile-h5/utils/oa-h5.js(可选 storage 传 fromInstance 预填)
[ ] Step 1: 详情撤销
条件:当前用户是发起人且实例 running(与 Web canWithdraw 一致)。
fetchWithdrawOaInstance → done 回列表。
条件:发起人且 status ∈ returned|cancelled|rejected。
实现择一(优先与 Web 一致):
postMessage action=oa-detail-restart + appId + 小程序再开 start webview,并用 uni.setStorageSync('oa_restart_prefills', { formData, … })router.replace({ path:'/oa-start', query:{ appId, fromInstanceId } }),OaStart 拉实例详情回填选定一种写清,并在 OaStart 实现回填;提交成功后勿留下旧 instanceId。
[ ] Step 3: 列表行也提供「复制并重新发起」入口(终态时)
[ ] Step 4: 验收撤销与复制提交新单
[ ] Step 5: Commit
git add mobile-h5/pages/oa/mine/ mobile-oa-h5/src/views/OaDetail.vue mobile-oa-h5/src/views/OaStart.vue mobile-h5/utils/oa-h5.js
git commit -m "$(cat <<'EOF'
feat(oa): support withdraw and copy-restart on mobile mine flows
EOF
)"
Files:
Modify: mobile-h5/pages/oa/cc/index.vue
[ ] Step 1: 阅读状态筛选 — readStatus: unread|read|all(默认 unread,对齐 Web)
[ ] Step 2: 未读红点样式 — OaTaskCard unread
[ ] Step 3: 单条已读 — 不打开详情也可 mark
[ ] Step 4: 批量已读 — 多选 + fetchBatchMarkOaCcTasksRead
[ ] Step 5: 验收后 Commit
git add mobile-h5/pages/oa/cc/
git commit -m "$(cat <<'EOF'
feat(oa): add cc read filters batch mark and unread styles
EOF
)"
Files:
mobile-h5/utils/oa-badge.jsModify: mobile-h5/components/MenuGrid.vue 和/或 pages/index/index.vue
[ ] Step 1: refreshOaMenuBadges
并行请求:
fetchOaInstanceDraftCountfetchOaPendingTaskCountfetchOaCcUnreadCount返回 map:path → count(/pages/oa/drafts/index 等)。展示:>99 显示 99+。
onShow 刷新MenuGrid 在 title 旁或图标右上角显示数字(样式轻量,对齐三墙,勿过重)。
[ ] **Step 3: 从 webview 返回后各列表 onShow 也可触发首页角标(通过 storage 事件或全局简单 bus;最小做法:仅首页 onShow 刷新即可)
[ ] Step 4: Commit
git add mobile-h5/utils/oa-badge.js mobile-h5/components/MenuGrid.vue mobile-h5/pages/index/index.vue
git commit -m "$(cat <<'EOF'
feat(oa): show draft pending cc badges on mobile home menu
EOF
)"
Files:
web-admin/src/utils/oa-approval-print.tsmobile-oa-h5/src/oa/print/exportOaApprovalPdf.js(或等价)Modify: OaDetail.vue + mine/cc 列表入口
[ ] Step 1: 在 H5 内实现 PDF 生成(优先 jspdf/html2canvas 等与 Web 同类方案;以 Web 工具函数逻辑为准)
[ ] Step 2: 详情与列表「打印」按钮:生成后尝试下载 / 新开预览;微信内若失败,showToast 明确文案(规格允许兜底,不阻塞其它功能)
[ ] **Step 3: 真机验收;记录限制到 docs/superpowers/specs/ 旁注或本 plan 底部「打印验收笔记」
[ ] Step 4: Commit
git add mobile-oa-h5/src/oa/print/ mobile-oa-h5/src/views/OaDetail.vue mobile-h5/pages/oa/mine/ mobile-h5/pages/oa/cc/
git commit -m "$(cat <<'EOF'
feat(oa): add mobile approval PDF print for mine and cc
EOF
)"
pages/oa/start/* 仍在;真机全链路见下方人工 QAmini_menu.py(本计划默认已改完),执行 ./scripts/update-graph.sh backend| 规格项 | Task |
|---|---|
| 菜单 SQL OA002–006 + 图标映射 | Task 1(图标已完成) |
| 功能对齐 Web / UI 对齐移动端 | 全文原则 + Task 4–8 |
| 草稿 1/2/3/6/7/8/9/10 | Task 5 + Task 11 |
| 待办办理五动作 + 角标 | Task 8 + 11 |
| 已办只读 | Task 6–7 |
| 我发起撤销/复制/打印 | Task 9 + 12 |
| 抄送阅读/批量/打印/角标 | Task 7/10/11/12 |
/oa-detail |
Task 6 + 8 + 9 |
| S0–S7 顺序 | Task 1→12 |
实现时每完成一个 Task 再开下一个;打印(Task 12)可与角标并行,但不得阻塞 Task 5–10 合并。
mobile-oa-h5 用可打印 HTML + window.print()(无 jspdf/html2canvas 依赖);字段/流程组装对齐 Web oa-approval-print.ts(关联审批嵌套块简化为「已关联 N 条」)。autoPrint=1;详情底栏次要「打印」按钮(紧挨关闭)。showToast:「微信内暂不支持系统打印,请用手机浏览器打开或到电脑端导出」。不阻塞其它功能。