TBOSS OA 模块 — 产品需求文档
版本:v1.0 | 日期:2026-06-03 | 状态:待评审 | 变更:精简 V1 范围(8 模块)
1. 产品背景
1.1 业务背景
公司已有成熟的 ERP 系统(多套部署实例),支撑企业日常运营。ERP 覆盖了用户管理、组织架构、客户主数据、审批引擎、消息通知等核心能力。现有 Android/iOS App 已嵌入 ERP 相关功能。
当前痛点:
- OA 流程依赖 PC 或线下:费用报销、事前申请、加班、用车等审批流程缺乏统一的移动端入口
- 外勤管理无数字化手段:业务员外出拜访缺少定位打卡和现场拍照核验机制
- 公告触达不可追踪:行政通知发布后无法确认哪些员工已读、哪些未读
- 数据孤岛:各业务单据分散在不同系统,缺少统一的个人/部门报表视图
1.2 产品目标
在已有 ERP App 内嵌入 OA 功能模块(Flutter 技术栈),为员工、审批人、财务人员、管理员提供移动端 OA 办公能力。
核心原则:不重复造轮子。ERP 已有的用户体系、审批引擎、消息推送、预算系统、项目主数据、成本中心通过适配器复用。V1 聚焦于 8 个核心模块的"填单→审批→查看"闭环。
1.3 市场定位
|
通用平台(钉钉/企微) |
专业 OA(蓝凌/泛微) |
TBOSS OA |
| 定位 |
独立 SaaS 平台 |
独立 OA 产品 |
ERP 移动端外挂 |
| 优势 |
生态丰富 |
管控深度 |
无缝嵌入已有系统 |
| 劣势 |
不可定制 |
移动端体验弱 |
依赖 ERP 能力边界 |
TBOSS OA 的核心差异化:不是独立产品,而是 ERP 的移动 OA 外挂——用户无需切换 App、无需维护两套账号、直接调用原生能力(相机/通讯录/地图/GPS)。
1.4 成功指标
| 指标 |
目标值 |
衡量方式 |
| 报销全流程耗时 |
从填单到付款到账 ≤3 个工作日 |
系统记录 CreateTime → PaymentStatus=paid 时间差 |
| 移动端 OA 覆盖率 |
80% 以上 OA 单据通过移动端发起 |
移动端提交量 / 总提交量 |
| 公告触达率 |
发布后 24h 内 ≥85% 员工已读 |
AnnouncementReadLog.IsRead=1 / 应达总人数 |
| 财务核销效率 |
单笔核销操作 ≤2 分钟 |
详情页打开 → 归档完成时间差 |
| 系统可用性 |
99.5%(月度) |
监控平台 |
1.5 明确不做的事(V1 边界)
以下功能有意识排除,避免范围蔓延:
| 不做 |
理由 |
| 审批链可视化配置 |
审批链在 ERP 端维护,OA 只消费 |
| 自定义表单模板 |
V1 固定表单字段 |
| 在线支付 / 银企直连 |
财务线下打款后录入流水号 |
| OA 端创建用户 / 部门 |
用户和组织架构由 ERP 管理 |
| 独立的消息推送通道 |
复用 .NET 服务端已有推送 |
| 电子签章 |
— |
| PC Web 端 |
V1 仅移动端(Flutter) |
2. 用户画像
2.1 普通员工(Employee)
| 属性 |
描述 |
| 身份 |
公司基层员工,归属某个部门 |
| 日常场景 |
出差前提交事前申请(可含多费用类型,关联项目+预算)→ 审批通过 → 回来提交费用报销(支持外币折算)→ 加班/用车/外勤日志 |
| 核心诉求 |
快速填单、拍发票、随时查看审批进度、草稿暂存 |
| 使用频率 |
每周 2-5 次 |
| 移动端偏好 |
表单简洁、支持拍照上传、操作反馈及时(撤回/编辑/查看状态) |
2.2 审批人 / 部门经理(Approver)
| 属性 |
描述 |
| 身份 |
部门主管/有审批职责的人员,通常直接管理 5-20 名下属 |
| 日常场景 |
收到审批待办通知 → 查看单据详情 + 风控参考 → 同意/拒绝;查看部门报表;在外勤日志下点评打分 |
| 核心诉求 |
快速了解单据全貌(申请人历史、预算消耗)、批量处理待办、移动端审批操作流畅 |
| 使用频率 |
每天 3-10 次 |
| 移动端偏好 |
待办红点醒目、卡片信息密度高、支持左滑快捷操作、拒绝时要求填写原因 |
2.3 财务人员(Finance)
| 属性 |
描述 |
| 身份 |
财务核销专员,负责发票合规查验和线下打款确认 |
| 日常场景 |
查看全公司已通过待付款的报销单 → 核验发票真伪/税号/类目合规 → 线下打款 → 录入电汇流水号和记账凭证号归档 |
| 核心诉求 |
发票影像清晰可查验、合规检查项不可跳过、连续核销不退回列表、数据可导出 |
| 使用频率 |
每天 5-20 笔核销 |
| 移动端偏好 |
发票大图预览、合规复选框联动锁定、凭证归档表单、导出 Excel |
2.4 系统管理员(Admin)
| 属性 |
描述 |
| 身份 |
IT 管理员 / HR 管理员 |
| 日常场景 |
为员工分配 OA 权限角色;发布/管理公司公告;DING 催办未读员工;查看公告触达率 |
| 核心诉求 |
权限配置灵活(套餐 + 单点调整)、公告富文本编辑、触达审计可视化 |
| 使用频率 |
每周 2-5 次 |
| 移动端偏好 |
搜索员工快捷、权限勾选直观、公告发布有预览 |
3. 核心功能列表
3.1 功能模块总览
模块 子功能 角色
─────────────────────────────────────────────────────
📋 事前申请 │ 表单/列表/详情 │ 全员
💰 费用报销 │ 表单/列表/详情/财务核销 │ 全员 + 财务
⏰ 加班申请 │ 表单/列表/详情 │ 全员
🚗 用车申请 │ 表单/列表/详情/还车登记 │ 全员
📍 外勤日志 │ 创建/列表/详情/点评 │ 业务员 + 经理
📢 公告管理 │ 列表/详情/发布/触达审计 │ 全员 + 管理员
📊 数据报表 │ 5 大明细报表 │ 全员(按角色范围)
🔧 权限管理 │ 用户权限配置 │ 管理员
🏠 工作台 │ 首页/消息/个人中心 │ 全员
3.2 事前申请(Expense Application)
| 功能 |
优先级 |
说明 |
| 新建申请 |
P0 |
多费用类型(可同时勾选差旅+办公等)。关联项目(.NET → ERP ProjectService)→ 加载科目(.NET → ERP SubjectService)→ 查预算余额。预估明细行(数量×单价),附件上传 |
| 预算查看 |
P0 |
选完项目+科目后实时展示可用余额(BudgetService)。余额不足时金额标红并触发超支审批链。ERP 无预算数据时跳过校验,不影响提交 |
| 草稿暂存 |
P0 |
草稿可多次编辑后提交 |
| 提交审批 |
P0 |
校验必填项+预算 → 提交至 ERP 审批引擎 |
| 列表筛选 |
P0 |
全部/草稿/审批中/已通过/已拒绝/已撤回 |
| 详情查看 |
P0 |
状态横幅 + 费用明细 + 附件 + 审批时间线 |
| 撤回申请 |
P1 |
pending 状态可撤回(任何审批阶段均可撤,ERP 最终裁决) |
3.3 费用报销(Expense Reimbursement)
| 功能 |
优先级 |
说明 |
| 新建报销 |
P0 |
两种方式:①导入事前申请(项目/科目/成本中心自动带入,填每张导入金额);②直接新建(手动选项目→科目→查预算,与事前申请相同的链式操作)。均支持外币明细(自动汇率折算)、发票影像上传。成本中心可空(ERP 无数据时隐藏) |
| 导入事前申请 |
P0 |
从已通过且尚有额度的申请多选导入,每条填导入金额。导入后自动回填项目/科目,额度实时校验,超申请金额不可提交。未导入时手动选择项目+科目触发预算查询 |
| 列表筛选 |
P0 |
全部/草稿/审批中/已通过/已拒绝/已撤回(与事前申请一致) |
| 详情查看 |
P0 |
状态横幅 + 费用明细 + 审批时间线 + 附件预览 |
| 撤回申请 |
P1 |
pending 状态可撤回(任何审批阶段均可撤,ERP 最终裁决) |
| 草稿/提交 |
P0 |
同事前申请 |
| 财务核销 |
P0 |
发票合规三字查验(验真/税号/类目)→ 录入电汇流水号+记账凭证号 → 归档 |
| 连续核销 |
P1 |
归档后跳转下一笔待付款 |
| 退回修改 |
P1 |
退给员工重填 或 退给经理重审 |
3.4 加班申请(Overtime)
| 功能 |
优先级 |
说明 |
| 新建申请 |
P0 |
加班类型(工作日/休息日/节假日)、补偿方式(转调休/加班费/混合)、开始/结束时间、原因 |
| 净工时自动计算 |
P0 |
扣除午休(12:00-13:00)和晚餐(18:00-18:30)盲区 |
| 混合模式 |
P1 |
调休比例滑块(10%-90%,步长10%),实时显示分配文案 |
| 列表/详情 |
P0 |
同其他单据 |
3.5 用车申请(Vehicle)
| 功能 |
优先级 |
说明 |
| 新建申请 |
P0 |
车牌号选择、始发地/目的地(支持地图选点)、出车/还车时间、同行人(通讯录多选) |
| 排期冲突检测 |
P0 |
选好车牌+时间后异步校验是否存在时段重叠冲突 |
| 还车登记 |
P0 |
approved 状态可登记还车:实还时间、出车前/还车后里程表读数、路桥停车费 |
| 车辆池管理 |
P1 |
管理员维护车辆信息(车牌/类型/品牌/座位/驾驶员/状态) |
3.6 外勤日志(Outing Log)
| 功能 |
优先级 |
说明 |
| 新建日志 |
P0 |
GPS 自动定位(只读,不可手动修改)、客户名(自动联想 ERP 客户池)、工作总结、后续计划 |
| 现场拍照 |
P0 |
强制调用相机(不可选相册),照片带防伪水印(服务器授时+经纬度),最少 1 张最多 4 张 |
| 主管点评 |
P0 |
经理在详情页底部星级评分 + 文字点评,气泡样式展示 |
| 新点评标记 |
P1 |
列表页橙色"新点评"标记(对比 LastViewedTime) |
| 客户动态创建 |
P2 |
输入新客户名后提交时自动在 ERP 创建 |
3.7 公告管理(Announcement)
| 功能 |
优先级 |
说明 |
| 公告列表 |
P0 |
置顶优先 → 未过期按发布时间倒序 → 已过期置灰;类型筛选;不支持搜索 |
| 公告详情 |
P0 |
红头文件样式、HTML/Markdown 正文、附件下载;停留 ≥2s 自动标记已读 |
| 发布公告 |
P0 |
富文本编辑、置顶开关、有效期、接收范围(全员/部门树/指定用户)、预览 |
| 触达审计 |
P1 |
管理员查看已读/未读员工列表 |
| DING 催办 |
P2 |
管理员对未读员工一键推送高优先级通知 |
3.8 数据报表(Reports)
| 功能 |
优先级 |
说明 |
| 事前申请明细报表 |
P1 |
申请金额 vs 已通过金额双折线图 |
| 费用报销明细报表 |
P1 |
报销金额趋势 + 待付款统计 |
| 加班明细报表 |
P1 |
加班工时柱状图(按类型分色堆叠) |
| 用车明细报表 |
P1 |
用车次数 vs 累计费用双轴图 |
| 外勤日志明细报表 |
P1 |
拜访次数 vs 平均评分趋势 |
| 数据导出 |
P2 |
财务角色可导出 Excel |
3.9 权限管理(Admin)
| 功能 |
优先级 |
说明 |
| 用户搜索 |
P0 |
姓名/工号模糊搜索(防抖 300ms) |
| 权限配置 |
P0 |
快捷套餐 + 单点加减;无角色用户默认等同"员工" |
| 变更审计 |
P1 |
权限变更历史时间线 |
| 自保护 |
P0 |
管理员无法取消自己的 admin 角色;至少保留一名管理员 |
3.12 关键业务规则澄清
| # |
规则 |
说明 |
| 审批链配置 |
审批链在 ERP 端维护,OA 不存储不配置。OA 检测到超标时,通过 ApprovalService.SubmitAsync(tags: ["standard_exceeded"]) 告知 ERP,由 ERP 审批引擎决定是否插入特批节点 |
|
| 多 ERP 路由 |
宿主 App 登录时已确定用户所属 ERP 实例,OA 通过 .NET 服务端上下文获取,无需额外路由逻辑。一人跨多 ERP 场景由宿主 App 切换账套时重新初始化 |
|
| 附件存储 |
统一上传至云端对象存储(OSS),Attachment.FileUrl 存绝对 URL。访问通过 CDN 加速。上传限制:图片 ≤10MB、PDF ≤20MB。过期单据附件保留 3 年后清理 |
|
| 无发票场景 |
单笔费用 ≤200 元且类别为办公费/交通卡充值等小额零星支出时,允许 InvoiceType=none。无发票费用在财务核销时三项合规检查自动通过,财务仅审核费用合理性 |
|
| 申请过期处理 |
ValidUntil 到期后,定时 Job 自动释放冻结预算(调 BudgetService.Release),UsageStatus 标记为 fully_used(不可再被报销引用)。通知申请人"申请已过期,预算已释放" |
|
| 报表数据权限 |
个人报表:仅本人可见具体金额。部门报表(经理):按人汇总展示("张三 ¥12,500"),不展示逐笔明细。全公司报表(财务):展示全公司所有明细 |
|
| 审批撤回窗口 |
ApprovalStatus=pending 即可撤回(不限制当前审批级别)。已审批通过的节点历史保留,流程终止。ERP 不支持撤回时,OA 按钮仍展示,调 ERP 后被拒则弹错误提示 |
|
| 预算、项目、科目(概念与关系) |
三个概念构成两级核算体系。项目是企业内按目标划分的独立核算单元(如"华东市场拓展""ERP 系统升级")。科目是费用类别在财务口径下的分类(如"差旅费""招待费")。预算挂在项目×科目的交叉点上——同一个科目在不同项目下预算不同。操作链:员工填事前申请时选项目 → 系统加载该项目下有预算的科目列表 → 选定科目后实时查询该项目该科目的可用余额。三个字段均通过 .NET 适配器从 ERP 获取,ERP 无数据时对应下拉为空,后续预算校验自动跳过,不影响提交 |
|
| 成本中心 |
核算维度,报销表单可选字段。OA 通过 .NET → ERP CostCenterService 拉取下拉列表,员工选择费用归属的核算单元。未选中或 ERP 无数据时允许跳过,不影响提交。值存入 Expense.CostCenterId,供财务后续核算 |
|
| 事前申请状态 |
审批状态(ApprovalStatus):draft 草稿→可编辑/提交/删除;pending 审批中→可撤回;approved 已通过→可被报销引用;rejected 已拒绝→可重新编辑提交;withdrawn 已撤回→仅查看。使用状态(UsageStatus,仅 approved 后生效):unused 未被报销引用;partially_used 部分金额已报销;fully_used 全部金额已报销,不可再被引用。draft/pending/rejected/withdrawn 状态下 UsageStatus 无意义 |
|
| 费用报销状态 |
同审批流程(draft→pending→approved/rejected/withdrawn)。付款状态(PaymentStatus):仅 approved 后生效,unpaid 待付款→财务核销后变为 paid 已付款。两个状态独立但有序:必须先审批通过,才进入付款环节 |
|
| 加班申请状态 |
同事前申请,仅审批状态(draft→pending→approved/rejected/withdrawn),无二级状态 |
|
| 外勤日志状态 |
不走审批流,draft 草稿→completed 已提交。提交即完成,主管可在详情页点评 |
|
| 公告状态 |
不走审批流,draft 草稿(仅创建者和管理员可见)→published 已发布(全员可见,触发触达记录写入) |
|
| 列表筛选 |
使用顶部 Tabs 选项卡按状态筛选,按时间倒序排列,暂不支持全文搜索。各单据 Tabs:审批类(事前/报销/加班)全部/草稿/审批中/已通过/已拒绝/已撤回;报销额外含待付款/已付款;用车额外含已还车;外勤日志全部/草稿/已完成。公告不按状态筛——员工侧 Tabs 为公告类型(全部/通知公告/人事制度/放假活动),仅展示已发布公告;管理员侧在类型 Tabs 基础上,右上角多一个"我的草稿"入口,点开仅展示自己创建的草稿 |
|
| 并发编辑 |
草稿仅创建者可见和编辑,不存在多人并发问题。驳回重新提交时采用乐观锁(WHERE Version=原值),冲突时提示"单据已被修改,请刷新后重试" |
|
| 设备兼容性 |
仅支持竖屏手机。平板可运行但不做布局优化。折叠屏展开态默认按手机竖屏布局居中显示 |
|
| 多语言 |
V1 支持简体中文、繁体中文、英文。所有 UI 文案通过 Flutter 国际化(AppLocalizations)管理,用户可在个人中心切换语言,默认跟随系统语言 |
|
4. 业务流程图
4.1 费用报销全流程
flowchart TD
A[员工发起] --> B{有事前申请?}
B -->|有| C[多选导入申请: 项目/科目自动带入, 填每张导入金额]
B -->|无| D[手工选择项目→科目→查预算, 填报销单]
C --> E[填发票明细: 币种/汇率/金额/发票号]
D --> E
E --> F{存草稿 还是 提交?}
F -->|存草稿| G[草稿保存]
G --> A
F -->|提交审批| H[校验必填项 + .NET 调 ERP BudgetService 预算]
H -->|超预算| I[金额标红警告, 触发特批审批链]
H -->|校验失败| J[ScrollTo 报错字段]
J --> E
H -->|校验通过| K[.NET → ERP 创建审批实例]
K --> L[OA 存 ApprovalInstanceId]
L --> M[.NET 消息推送审批人]
M --> N[经理审批]
N --> O{审批动作}
O -->|同意| P{是否最后一级?}
P -->|是| Q[Status=approved, ERP 预算扣减]
P -->|否| R[流转下一级]
R --> M
O -->|拒绝| S[Status=rejected]
L -.->|员工随时撤回| AA[调 ERP 撤回 → 释放冻结预算]
AA --> AB[Status=withdrawn, 审批终止]
Q --> U[.NET 通知申请人]
U --> V{财务核销}
V --> W[查验: 发票验真+税号一致+类目合规]
W --> X{三项全勾?}
X -->|否| V
X -->|是| Y[录入电汇流水号+记账凭证号]
Y --> Z[PaymentStatus=paid, 归档 + 连续核销]
S --> AA[.NET 通知: 已拒绝]
AA --> AB[员工重新编辑发起]
AB --> A
4.2 事前申请全流程
flowchart TD
A[员工发起] --> B[填写申请]
B --> C[选择费用类型: 多选, 如差旅+办公]
C --> D[选择项目 → 加载科目 → 查预算余额]
D --> E[填预估明细行: 数量×单价, 支持多行]
E --> F[上传支撑材料: 报价单/合同等, 最多6张]
F --> G{存草稿 还是 提交?}
G -->|存草稿| H[草稿保存]
H --> A
G -->|提交审批| I[校验必填项 + 调 ERP BudgetService 查预算]
I -->|超预算| J[金额标红警告, 触发特批审批链]
I -->|校验失败| K[ScrollTo 报错字段]
K --> E
I -->|校验通过| L[.NET → ERP 创建审批实例]
L --> M[OA 存 ApprovalInstanceId, Status=pending]
M --> N[.NET 消息推送审批人]
N --> O[经理审批]
O --> P{审批动作}
P -->|同意| Q{是否最后一级?}
Q -->|是| R[Status=approved, ERP 预算冻结转扣减]
Q -->|否| S[流转下一级]
S --> N
P -->|拒绝| T[Status=rejected]
M -.->|员工随时撤回| U[调 ERP 撤回 → 释放冻结预算]
U --> V[Status=withdrawn, 审批终止]
R --> W[.NET 通知申请人]
W --> X[UsageStatus=unused, 等待报销引用]
T --> Y[.NET 通知: 已拒绝]
Y --> Z[员工重新编辑发起]
Z --> A
4.3 加班申请全流程
flowchart TD
A[员工发起] --> B[选择加班类型: 工作日/休息日/节假日]
B --> C[选择补偿方式: 转调休/加班费/混合]
C --> D{混合模式?}
D -->|是| E[拖动比例滑块: 10%-90%, 步长10%]
D -->|否| F[填开始/结束时间]
E --> F
F --> G[系统自动计算净工时: 扣除午餐12-13点 + 晚餐18-18:30]
G --> H{净工时 > 0?}
H -->|否| I[净工时标红, 提交按钮置灰]
I --> F
H -->|是| J[填写加班原因]
J --> K{存草稿 还是 提交?}
K -->|存草稿| L[草稿保存]
L --> A
K -->|提交审批| M[校验必填项]
M -->|校验失败| N[ScrollTo 报错字段]
N --> J
M -->|校验通过| O[.NET → ERP 创建审批实例]
O --> P[OA 存 ApprovalInstanceId, Status=pending]
P --> Q[.NET 消息推送审批人]
Q --> R[经理审批]
R --> S{审批动作}
S -->|同意| T{是否最后一级?}
T -->|是| U[Status=approved]
T -->|否| V[流转下一级]
V --> Q
S -->|拒绝| W[Status=rejected]
P -.->|员工随时撤回| X[调 ERP 撤回]
X --> Y[Status=withdrawn, 审批终止]
U --> Z[.NET 通知申请人]
W --> AA[.NET 通知: 已拒绝]
AA --> AB[员工重新编辑发起]
AB --> A
4.4 外勤日志全流程
flowchart TD
A[业务员到达客户现场] --> B[打开 OA 创建外勤日志]
B --> C[GPS 自动定位, 地址只读]
C --> D{定位成功?}
D -->|失败| E[提交按钮置灰, 提示检查定位权限]
D -->|成功| F[输入/选择客户名称]
F --> G[填写工作总结 + 后续计划]
G --> H[强制拍照: 跳过相册, 直接唤起相机]
H --> I{至少 1 张照片?}
I -->|否| J[提交按钮置灰]
J --> H
I -->|是| K[照片自动添加水印: 授时+GPS]
K --> L{存草稿 还是 提交?}
L -->|存草稿| M[保存草稿]
L -->|提交| N[Status=completed, 写入数据库]
N --> O[经理在详情页查看]
O --> P[经理星级评分 + 文字点评]
P --> Q[点评数据写入 OutingLogComment]
Q --> R["列表页橙色新点评标记"]
R --> S["员工查看点评, 更新 LastViewedTime"]
S --> T[新点评标记消失]
4.5 审批流对接时序
sequenceDiagram
participant E as 员工(Flutter)
participant S as .NET 服务端
participant ERP as ERP 审批引擎
participant M as 经理(Flutter)
participant P as 消息推送
E->>S: POST 提交单据
S->>ERP: 创建审批实例(bizType, bizId, 表单数据)
ERP-->>S: { instanceId: "inst_001" }
S-->>E: { success, instanceId }
Note over E,S: OA 存 ApprovalInstanceId + Status=pending
ERP->>P: 触发审批待办通知
P->>M: 推送: "张三提交了报销申请, 待审批"
M->>S: GET 待审批列表
S->>ERP: 查询待办(approverId=M)
ERP-->>S: [{ bizType, bizId, 摘要 }]
S-->>M: 待办列表
M->>S: GET 单据详情 + 审批时间线
S->>ERP: 查询实例状态 + 流程节点历史
ERP-->>S: { status, timeline }
S-->>M: 详情 + 时间线
M->>S: POST 审批动作(approve, instanceId)
S->>ERP: 执行审批(agree, instanceId)
ERP-->>S: { success, newStatus }
S-->>M: 审批成功
ERP->>P: 触发审批结果通知
P->>E: 推送: "您的报销申请已通过"
4.6 角色权限配置流程
flowchart TD
A[管理员进入权限管理页] --> B[搜索员工: 姓名/工号]
B --> C[点击员工卡片]
C --> D[右侧滑出权限编辑抽屉]
D --> E[展示当前权限状态]
E --> F{选择操作}
F -->|快捷套餐| G[点击套餐按钮: 员工/审批人/财务/管理员]
F -->|手动勾选| H[逐项勾选/取消权限点]
F -->|启用/禁用| I[切换 IsActive 开关]
G --> J{套餐覆盖当前权限}
H --> J
I --> J
J --> K{点击保存?}
K -->|取消| L{有未保存修改?}
L -->|是| M[确认弹窗: 放弃修改?]
M -->|放弃| N[关闭抽屉]
M -->|继续编辑| D
L -->|否| N
K -->|确认保存| O{校验}
O -->|取消自己的admin| P[Toast: 无法移除自身管理员]
P --> D
O -->|移除最后admin| Q[后端拒绝: 至少保留一名管理员]
Q --> D
O -->|通过| R[写入 OaUserPermission + 审计日志]
R --> S[Toast: 权限已更新]
S --> N
5. 技术可行性分析
5.1 技术栈匹配
| 层 |
技术 |
成熟度 |
风险 |
| 移动端 |
Flutter 3.38.10 |
✅ 已验证 |
低 — 项目已有 Flutter 模块 |
| Android 宿主 |
Java/Kotlin |
✅ 已验证 |
低 — MethodChannel 互调已验证 |
| iOS 宿主 |
OC, Xcode 14.2 |
✅ 已验证 |
中 — Flutter 依赖需兼容 OC 宿主 |
| 后端 |
.NET Framework 4.8 |
✅ 已验证 |
低 — 已有服务端 |
| 数据库 |
SQL Server 2019+ |
✅ 已验证 |
低 |
5.2 关键风险与缓解
| 风险 |
影响 |
缓解措施 |
| 多 ERP 审批 API 签名不一致 |
适配器层开发量不确定 |
先对接一套 ERP,验证适配器模式后再扩展;Flutter 端不感知差异 |
| 无 ERP 回调机制 |
审批状态同步延迟 |
列表页缓存 + 后台静默刷新 + 详情页实时校准;用户体验可接受 |
| ERP 审批引擎能力边界未知 |
会签/或签等高级审批形态不可用 |
需求层面做最小假设(基础审批即可),高级形态作为后续增强 |
| iOS 编译兼容性 |
Flutter 3.38.10 依赖可能不兼容 Xcode 14.2 |
每次新增 Flutter 依赖后在 iOS 端编译验证 |
| 预算/项目/科目/成本中心依赖 ERP |
适配器开发量不确定 |
统一适配器模式,先对接一套 ERP 验证;ERP 无预算→返回空→OA 隐藏预算区块 |
5.3 与现有系统的集成点
| 集成点 |
方向 |
方式 |
| 用户信息 |
ERP → OA |
.NET 服务端查询 ERP 主数据,OA 通过 API 获取 |
| 组织架构 |
ERP → OA |
同上 |
| 客户数据 |
ERP → OA |
外勤日志输入时联想查询,提交时关联 ERP 客户 ID |
| 审批发起 |
OA → ERP |
.NET 服务端调用 ERP 审批 API |
| 审批状态查询 |
OA → ERP |
同上 |
| 审批动作 |
OA → ERP |
同上 |
| 消息推送 |
ERP → 用户 |
.NET 服务端消息模块在审批事件后触发推送 |
| 预算/项目/科目 |
ERP → OA |
.NET 适配器层统一查询(BudgetService/ProjectService/SubjectService) |
| 成本中心 |
ERP → OA |
.NET CostCenterService,可选字段,ERP 无数据时返回空列表→前端隐藏 |
| 汇率 |
ERP → OA |
.NET ExchangeRateService 查询,外币自动折算 |
| 原生能力 |
App → OA |
MethodChannel:相机、相册、通讯录、地图、GPS 定位 |
5.4 性能考量
| 场景 |
策略 |
预期体验 |
| 列表页加载 |
本地数据 + 后台静默更新审批状态 |
秒开,状态可能有短暂延迟 |
| 详情页打开 |
实时调用 ERP 刷新审批状态 |
200-500ms 延迟 |
| 附件上传 |
分片上传 + 缩略图预生成 |
图片 ≤10MB 3-5 秒 |
| 报表图表 |
后端预计算 + 5 分钟缓存 |
首次 1-2 秒,后续即时 |
| 多 ERP 查询 |
.NET 服务端并行调用 + 超时熔断 |
单 ERP 失败不影响其他 |
5.5 非功能需求
5.5.1 性能
| 指标 |
目标 |
测量方法 |
| 应用冷启动 |
≤3 秒 |
Flutter 引擎初始化到首页渲染完成 |
| 列表页首屏 |
≤1 秒(本地数据) |
本地缓存命中时 |
| 详情页加载 |
≤2 秒(含 ERP 状态刷新) |
打开→所有数据渲染完成 |
| 附件上传 |
图片 ≤5 秒(10MB) |
上传进度条完成 |
| API 响应(列表) |
P95 ≤500ms |
.NET 服务端处理时间 |
| API 响应(ERP 查询) |
P95 ≤3s(含 ERP 耗时) |
.NET → ERP → 返回 |
5.5.2 可用性
| 指标 |
目标 |
| 月度可用率 |
≥99.5%(允许月度故障 ≤3.6 小时) |
| 单 ERP 不可用时的降级 |
其他 ERP 用户不受影响;受影响用户看到明确错误提示(非白屏) |
| 数据持久性 |
已提交单据零丢失(SQL Server 主备) |
5.5.3 兼容性
| 平台 |
最低版本 |
| Android |
8.0 (API 26) |
| iOS |
14.0 |
| Flutter |
3.38.10(已锁定) |
| SQL Server |
2019+ |
5.5.4 安全
| 要求 |
说明 |
| 传输加密 |
全链路 HTTPS(客户端→服务端);内网 HTTP(服务端→ERP) |
| 身份认证 |
复用宿主 App Token;401 自动触发宿主重登录 |
| 数据隔离 |
列表查询按 OA 权限(view_own/view_dept/view_all)严格控制数据范围 |
| 敏感数据脱敏 |
银行账号列表页展示后 4 位(****0123),详情页完整展示 |
| 审计 |
权限变更全量记录 OaPermissionChangeLog;单据操作通过 CreateTime/UpdateTime 追溯 |
5.6 依赖与假设
| 依赖 |
说明 |
不可用时的降级 |
| 宿主 App Flutter 集成 |
Flutter Module 已嵌入 Android/iOS 宿主 |
OA 模块不可用 |
| ERP API 可用 |
审批/预算/项目/科目/成本/标准/汇率/客户接口 |
各 Adapter 返回空/不限,OA 隐藏对应功能区块 |
| .NET 服务端消息模块 |
推送通知 |
站内消息仍可见(轮询),Push 通知不可用 |
| MethodChannel |
相机/相册/通讯录/GPS/地图选点 |
对应功能不可用,按钮置灰+提示 |
| SQL Server |
OA 业务数据持久化 |
全模块不可用 |
假设:
- 宿主 App 已完成用户登录认证,OA 启动时能从宿主获取 Token 和 ERP 用户 ID
- ERP 审批引擎支持基础审批动作(同意/拒绝),转交和高级形态(会签/或签)暂不支持
- 每套 ERP 的审批 API 签名虽不同,但功能语义一致(都有创建实例/查询状态/执行动作)
- 费用标准、预算、汇率等数据在 ERP 端已维护
5.7 消息通知规范
| 事件 |
接收人 |
标题模板 |
点击跳转 |
| 单据提交审批 |
首级审批人 |
"{申请人}提交了{单据类型},待审批" |
对应详情页 + 审批操作栏 |
| 审批通过(非最后一级) |
下一级审批人 |
"{单据类型}待审批:{摘要}" |
对应详情页 + 审批操作栏 |
| 审批全部通过 |
申请人 |
"您的{单据类型}已全部通过审批" |
对应详情页 |
| 审批拒绝 |
申请人 |
"您的{单据类型}已被拒绝" |
对应详情页(展示拒绝理由) |
| 申请被撤回 |
当前审批人 |
"{申请人}撤回了{单据类型}" |
消息列表(单据已不可审批) |
| 公告发布 |
范围内全员 |
"【{公告类型}】{标题}" |
公告详情页 |
| DING 催办 |
未读员工 |
"【行政催办】{公告标题}" |
公告详情页(高优先级 Push) |
| 申请已过期 |
申请人 |
"您的{单据类型}{单号}已过期,预算已释放" |
对应详情页 |
通道优先级:审批类 → App Push + 站内消息。公告类 → 站内消息。DING 催办 → App Push(高优先级,无视免打扰)。
5.8 灰度发布策略
| 阶段 |
范围 |
时长 |
验证重点 |
| 内部试用 |
项目组 + 财务部(~20 人) |
1-2 周 |
功能完整性、流程闭环、严重 Bug |
| 部门试点 |
1-2 个部门(~100 人) |
2-4 周 |
真实场景覆盖、审批链适配、ERP 集成稳定性 |
| 全量发布 |
全公司 |
— |
性能、并发、用户反馈 |
灰度期间发现的严重问题回滚到上一版本,非严重问题记录后在全量发布前修复。
5.9 开发阶段建议
| 阶段 |
内容 |
周期估算 |
| Phase 1 |
事前申请(多类型+预算) + 费用报销(拼单导入+币种) + 加班 + 用车 + 外勤日志 + 公告 + 5 大报表 + 权限 + 工作台 + ERP 适配器(审批/预算/项目/科目/成本/汇率/客户) |
8 模块闭环 |
附录:术语表
| 术语 |
说明 |
| ERP |
企业资源计划系统,OA 模块的底层数据来源 |
| ACL |
访问控制列表,按用户逐个赋权 |
| 事前申请 |
费用发生前的预估申请,审批通过后可被报销单引用 |
| 审批实例 |
ERP 审批引擎中一次审批流程的运行实例 |
| 审批时间线 |
审批流程各节点的操作历史(谁在什么时间做了什么动作) |
| 净工时 |
扣除午休和晚餐休息盲区后的实际加班小时数 |
| 核销 |
财务确认发票合规、线下打款、凭证归档的完整闭环 |
| DING 催办 |
管理员对未读公告的员工推送高优先级通知 |
| 快捷套餐 |
预设的权限组合模板,一键赋予员工/审批人/财务/管理员权限 |
| ERP 适配器 |
.NET 服务端统一接口层,每套 ERP 一个实现,隔离差异 |
| 预算控制 |
事前申请/报销关联项目预算,超支自动警告(V1 通过 ERP 适配器实现) |