tboss-oa-prd.md 49 KB

TBOSS OA 模块 — 产品需求文档

版本:v1.0 | 日期:2026-06-04 | 状态:待评审


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 工作台(Home)

工作台是登录后的默认首页,内容按角色权限动态变化。权限判定依据 OaUserPermission,优先级 Admin > Finance > Approver > Employee,高优先级角色叠加低优先级角色的基础区块。

所有角色共有

区块 说明
轮播图 顶部 Banner 轮播(3s 自动切换),数据来源 OA 本地 SysBanner 表。管理员可在后台维护。点击有链接则跳转,无链接则全屏预览
功能金刚区 4 列宫格,分三个区域。【发起】第一行:事前申请/费用报销/用车申请/加班申请。管理员额外显示:发布公告。【记录】第二行:申请记录/报销记录/加班记录/用车记录,第三行:外勤日志/公司公告。【报表】第四行:事前申请报表/费用报销报表/加班报表/用车报表,第五行:外勤日志报表。每个报表点击直接进入对应报表页

员工版

在共有基础上增加快捷看板,两张数据卡片仅展示本人数据:

卡片 内容 点击跳转 数据来源
本月累计报销 本月本人已付款报销总额(¥) 报销记录列表 .NET 预计算:SUM(Expense.TotalAmount WHERE ApplicantId=本人 AND PaymentStatus=paid)
本月已提单据 本月本人提交的全部单据数(笔) 申请记录列表 .NET 预计算:COUNT(所有业务表 WHERE ApplicantId=本人 AND 本月)

数据缓存 5 分钟,下拉强制刷新。

经理/老板版

在员工版基础上叠加两个区块:

待审批卡片:金刚区下方醒目的红色角标卡片,展示本人待审批单据数量和最新摘要。数据来源 .NET → ERP 审批引擎。点击跳转消息列表(筛选审批待办)。

快捷看板升级:三张卡片的数据范围从"本人"升级为本部门汇总:

卡片 内容 点击跳转 数据来源
本月累计报销 本部门已付款报销总额(¥) 报销记录列表(部门视图) .NET 预计算:SUM(Expense.TotalAmount WHERE DeptId=本部门 AND PaymentStatus=paid)
本月已提单据 本部门全部单据数(笔) 申请记录列表(部门视图) .NET 预计算:COUNT(所有业务表 WHERE DeptId=本部门 AND 本月)
部门在途单据 本部门审批中的单据数(笔) 申请记录列表(部门视图,筛选审批中) .NET → ERP 审批引擎:COUNT(pending WHERE DeptId=本部门)

如果用户同时拥有经理和员工权限,显示经理版(高优先级叠加)。

财务版

在员工版基础上,将快捷看板替换为财务看盘,三张大数字卡片展示全公司数据:

卡片 内容 数据来源
本月已支付总额 全公司本月 PaymentStatus=paid 的报销总额(¥) .NET 预计算:SUM(Expense.TotalAmount WHERE PaymentStatus=paid AND 本月)
待付款总额 全公司当前已通过但未付款的报销总额(¥) .NET 预计算:SUM(Expense.TotalAmount WHERE Status=approved AND PaymentStatus=unpaid)
本周异常退回 本周财务退回修改的报销单数量(笔) .NET 预计算:COUNT(Expense WHERE 本周被退回)

数据缓存 5 分钟,下拉强制刷新。财务看盘替代快捷看板,财务不展示个人快捷看板。

管理员版

在员工版基础上叠加:金刚区发起区域额外显示"发布公告"入口。快捷看板展示全公司数据(与财务版相同,三张大数字卡片:本月已支付总额 / 待付款总额 / 本周异常退回)。数据来源 .NET 全公司聚合查询,缓存 5 分钟。


3.3 事前申请(Expense Application)

功能 优先级 说明
新建申请 P0 多费用类型(可同时勾选差旅+办公等)。关联项目(.NET → ERP ProjectService)→ 加载科目(.NET → ERP SubjectService)→ 查预算余额。预估明细行(数量×单价),附件上传
预算查看 P0 选完项目+科目后实时展示可用余额(BudgetService)。余额不足时金额标红并触发超支审批链。ERP 无预算数据时跳过校验,不影响提交
草稿暂存 P0 草稿可多次编辑后提交
提交审批 P0 校验必填项+预算 → 提交至 ERP 审批引擎
列表筛选 P0 全部/草稿/审批中/已通过/已拒绝/已撤回
详情查看 P0 状态横幅 + 费用明细 + 附件 + 审批时间线
撤回申请 P1 pending 状态可撤回(任何审批阶段均可撤,ERP 最终裁决)
删除草稿 P1 draft 状态可删除(仅本人),删除后不可恢复

3.4 费用报销(Expense Reimbursement)

功能 优先级 说明
新建报销 P0 两种方式:①导入事前申请(项目/科目/成本中心自动带入,填每张导入金额);②直接新建(手动选项目→科目→查预算,与事前申请相同的链式操作)。均支持外币明细(自动汇率折算)、发票影像上传。成本中心可空(ERP 无数据时隐藏)
导入事前申请 P0 从已通过且尚有额度的申请多选导入,每条填导入金额。导入后自动回填项目/科目,额度实时校验,超申请金额不可提交。未导入时手动选择项目+科目触发预算查询
列表筛选 P0 全部/草稿/审批中/已通过/已拒绝/已撤回(与事前申请一致)
详情查看 P0 状态横幅 + 费用明细 + 审批时间线 + 附件预览
撤回申请 P1 pending 状态可撤回(任何审批阶段均可撤,ERP 最终裁决)
删除草稿 P1 draft 状态可删除(仅本人)
草稿/提交 P0 支持存为草稿后继续编辑,提交时校验必填项+预算,提交至 ERP 审批引擎
财务核销 P0 发票合规三字查验(验真/税号/类目)→ 录入电汇流水号+记账凭证号 → 归档
连续核销 P1 归档后跳转下一笔待付款
退回修改 P1 退给员工重填 或 退给经理重审

3.5 加班申请(Overtime)

功能 优先级 说明
新建申请 P0 加班类型(工作日/休息日/节假日)、补偿方式(转调休/加班费/混合)、开始/结束时间、原因
净工时自动计算 P0 扣除午休(12:00-13:00)和晚餐(18:00-18:30)盲区
混合模式 P1 调休比例滑块(10%-90%,步长10%),实时显示分配文案
列表筛选 P0 全部/草稿/审批中/已通过/已拒绝/已撤回
详情查看 P0 状态横幅 + 加班信息 + 审批时间线
撤回申请 P1 pending 状态可撤回(任何审批阶段均可撤,ERP 最终裁决)
删除草稿 P1 draft 状态可删除(仅本人)

3.6 用车申请(Vehicle)

功能 优先级 说明
新建申请 P0 车牌号选择、始发地/目的地(支持地图选点)、出车/还车时间、同行人(通讯录多选)
排期冲突检测 P0 选好车牌+时间后异步校验是否存在时段重叠冲突
列表筛选 P0 全部/草稿/审批中/已通过/已拒绝/已撤回/已还车
详情查看 P0 状态横幅 + 行程信息 + 审批时间线 + 地图标记
撤回申请 P1 pending 状态可撤回(任何审批阶段均可撤,ERP 最终裁决)
删除草稿 P1 draft 状态可删除(仅本人)
还车登记 P0 approved 状态可登记还车:实还时间、出车前/还车后里程表读数、路桥停车费
车辆池管理 P1 管理员维护车辆信息(车牌/类型/品牌/座位/驾驶员/状态)

3.7 外勤日志(Outing Log)

功能 优先级 说明
新建日志 P0 GPS 自动定位(只读,不可手动修改)、客户名(自动联想 ERP 客户池)、工作总结、后续计划
现场拍照 P0 强制调用相机(不可选相册),照片带防伪水印(服务器授时+经纬度),最少 1 张最多 9 张
主管点评 P0 经理在详情页底部星级评分 + 文字点评,气泡样式展示
列表筛选 P0 全部/草稿/已完成
详情查看 P0 定位地图 + 工作摘要 + 照片墙 + 点评历史
新点评标记 P1 列表页橙色"新点评"标记(对比 LastViewedTime)
客户动态创建 P2 输入新客户名后提交时自动在 ERP 创建

3.8 公告管理(Announcement)

功能 优先级 说明
公告列表 P0 置顶优先 → 未过期按发布时间倒序 → 已过期置灰;类型筛选;不支持搜索
公告详情 P0 红头文件样式、HTML/Markdown 正文、附件下载;停留 ≥2s 自动标记已读
发布公告 P0 富文本编辑、置顶开关、有效期、接收范围(全员/部门树/指定用户)、预览
触达审计 P1 管理员查看已读/未读员工列表
DING 催办 P1 管理员在公告详情页查看已读/未读名单,对未读员工一键推送高优先级通知

3.9 数据报表(Reports)

报表入口、按角色数据范围、详细图表说明见 §3.11。此处仅列出优先级。

功能 优先级 说明
事前申请明细报表 P1 含数值卡片 + 趋势图,按角色控制数据范围
费用报销明细报表 P1 同上
加班明细报表 P1 同上
用车明细报表 P1 同上
外勤日志明细报表 P1 同上
数据导出 P2 财务角色可导出 Excel

3.10 权限管理(Admin)

功能 优先级 说明
用户搜索 P0 支持按姓名或工号模糊搜索,输入过程中自动联想匹配
权限配置 P0 快捷套餐 + 单点加减;无角色用户默认等同"员工"
变更审计 P1 权限变更历史时间线
自保护 P0 管理员无法取消自己的 admin 角色;至少保留一名管理员

3.11 报表入口与权限

入口:唯一入口为工作台金刚区报表区域,点击任一报表直接进入对应独立页。五个报表各自独立路由、独立加载数据。页面内顶部为筛选条件,下方为数值卡片 + 趋势图。

角色数据范围

同一报表页,不同角色看到的数据范围不同:

角色 数据范围 展示形式 可导出
员工 仅本人 数值卡片 + 个人趋势图
经理/老板 本部门 数值卡片 + 部门横向对比柱状图 + 明细列表
财务 全公司 数值卡片 + 全公司趋势图 + 明细列表 ✅ Excel
管理员 全公司 与财务相同

数据来源:所有报表数据均来自 OA 本地业务表(事前申请/费用报销/加班/用车/外勤日志主表及明细表)。.NET 服务端按角色权限(本人/本部门/全公司)和时间范围聚合查询后返回。审批状态相关统计(如"待审批笔数")通过 .NET → ERP 实时查询补充。数值卡片和趋势图共用同一数据源,仅展示维度不同。

性能策略:预置时间段(本月/本季/本年)数据由 .NET 预计算,缓存 5 分钟。自定义时间段实时查询。数值卡片数据同时受时间筛选和角色数据范围双重约束,无数据时显示 0 或 ¥0.00,仅做展示不可点击。

各报表详细规格

报表 数值卡片 专属筛选 员工图表 经理图表 财务/管理员图表
事前申请明细 ①累计申请总额 ②当月笔数 ③已通过笔数 ④已通过金额 状态(全部/已通过/已拒绝/已撤回) 个人近 12 月申请金额 vs 已通过金额双折线 本部门横向对比柱状图(每人两根柱:申请/已通过) + 底部明细列表 全公司趋势图(同员工) + 底部明细列表
费用报销明细 ①累计核销总额 ②当月笔数 ③待审批笔数 ④待付款笔数 状态 + 付款状态 个人近 12 月报销金额 vs 审批通过金额双折线 本部门横向对比柱状图(每人两根柱:报销/通过) + 底部明细列表 全公司趋势图 + 底部明细列表
加班明细 ①当月净工时 ②当月次数 ③累计调休小时 ④加班费次数 加班类型(工作日/休息日/节假日) 个人近 12 月加班工时柱状图,按类型分色堆叠 本部门横向对比柱状图(每人汇总工时) + 底部明细列表 全公司趋势图 + 底部明细列表
用车明细 ①当月次数 ②累计里程 ③路桥停车费 ④未还车数 车辆 + 用途 个人近 12 月用车次数折线 本部门横向对比柱状图(每人次数/费用) + 底部明细列表 全公司趋势图(次数 vs 费用双轴) + 底部明细列表
外勤日志明细 ①当月拜访次数 ②拜访客户数(去重)③平均评分 ④未点评数 客户名模糊搜索 个人近 12 月拜访次数 vs 评分双轴折线 本部门横向对比柱状图(每人次数/评分) + 底部明细列表 全公司趋势图 + 底部明细列表

数值卡片说明:所有卡片数据受时间筛选(本月/本季/本年)和角色数据范围(本人/本部门/全公司)双重约束。无数据时显示 0 或 ¥0.00。卡片仅做展示,不可点击。

经理版交互增强:点击柱状图上代表某员工的柱子 → 下方列表联动过滤该员工本月单据 → 可穿透跳转对应详情页。

各角色工作台看板卡片与报表的关系:看板卡片(§3.2)展示的是关键汇总数字,点击卡片跳转到的是对应单据列表页;金刚区报表入口(本小节)展示的是完整的趋势图表分析页。两者互补:看板做决策提醒,报表做深度分析。

3.12 关键业务规则澄清

# 规则 说明
审批链配置 审批链在 ERP 端维护,OA 不存储不配置。OA 检测到超预算时,通过 ApprovalService.SubmitAsync(tags: ["budget_exceeded"]) 告知 ERP,由 ERP 审批引擎决定是否插入特批审批节点
审批数据来源 审批状态、审批时间线、待办列表均通过 .NET → ERP 实时查询,OA 本地不存储。列表页和详情页每次打开均实时请求,保证数据始终最新
多 ERP 路由 宿主 App 登录时已确定用户所属 ERP 实例,OA 通过 .NET 服务端上下文获取,无需额外路由逻辑。一人跨多 ERP 场景由宿主 App 切换账套时重新初始化
附件存储 统一上传至云端对象存储(OSS),Attachment.FileUrl 存绝对 URL。访问通过 CDN 加速。上传限制:图片 ≤10MB、PDF ≤20MB。附件存储不设自动清理机制
无发票场景 单笔费用 ≤200 元且类别为办公费/交通卡充值等小额零星支出时,允许 InvoiceType=none。无发票费用在财务核销时三项合规检查自动通过,财务仅审核费用合理性
申请过期处理 ValidUntil 到期后,定时 Job 自动释放冻结预算(调 BudgetService.Release),UsageStatus 标记为 fully_used(不可再被报销引用)。通知申请人"申请已过期,预算已释放"
报表数据权限 个人报表:仅本人可见。部门报表(经理):按人汇总展示 + 可展开逐笔明细。全公司报表(财务/管理员):展示全公司所有明细。数据范围由角色权限控制,详见 §3.11
审批撤回窗口 ApprovalStatus=pending 即可撤回(不限制当前审批级别)。已审批通过的节点历史保留,流程终止。ERP 不支持撤回时,OA 按钮仍展示,调 ERP 后被拒则弹错误提示
预算、项目、科目(概念与关系) 三个概念构成两级核算体系。项目是企业内按目标划分的独立核算单元(如"华东市场拓展""ERP 系统升级")。科目是费用类别在财务口径下的分类(如"差旅费""招待费")。预算挂在项目×科目的交叉点上——同一个科目在不同项目下预算不同。操作链:员工填事前申请时选项目 → 系统加载该项目下有预算的科目列表 → 选定科目后实时查询该项目该科目的可用余额。三个字段均通过 .NET 适配器从 ERP 获取,ERP 无数据时对应下拉为空,后续预算校验自动跳过,不影响提交
成本中心 核算维度,报销表单可选字段。OA 通过 .NET → ERP CostCenterService 拉取下拉列表,员工选择费用归属的核算单元。未选中或 ERP 无数据时允许跳过,不影响提交。值存入 Expense.CostCenterId,供财务后续核算
外币/汇率 报销明细行默认币种 CNY。员工选择外币(如 USD)后,OA 调 .NET → ERP ExchangeRateService 获取当日汇率,自动填入 ExchangeRate。服务端计算 BaseAmount = TotalAmount × ExchangeRate,预算校验和报表均以本币(CNY)为准。ERP 无汇率数据时仅支持 CNY,外币选项隐藏
事前申请状态 审批状态(ApprovalStatus)draft 草稿→可编辑/提交/删除;pending 审批中→可撤回;approved 已通过→可被报销引用;rejected 已拒绝→可重新编辑提交;withdrawn 已撤回→仅查看。使用状态(UsageStatus,仅 approved 后生效)unused 未被报销引用;partially_used 部分金额已报销;fully_used 全部金额已报销,不可再被引用。draft/pending/rejected/withdrawn 状态下 UsageStatus 无意义
费用报销状态 同审批流程(draftpendingapproved/rejected/withdrawn)。付款状态(PaymentStatus):仅 approved 后生效,unpaid 待付款→财务核销后变为 paid 已付款。两个状态独立但有序:必须先审批通过,才进入付款环节
加班申请状态 同事前申请,仅审批状态(draftpendingapproved/rejected/withdrawn),无二级状态
用车申请状态 审批状态同其他单据,额外一个独有终态:returned 已还车。完整流转:draftpendingapprovedreturned(还车登记完成,车辆恢复空闲)。rejected/withdrawn 同理
外勤日志状态 不走审批流,draft 草稿→completed 已提交。提交即完成,主管可在详情页点评
公告状态 不走审批流,draft 草稿(仅创建者和管理员可见)→published 已发布(全员可见,触发触达记录写入)
列表筛选 使用顶部 Tabs 选项卡按状态筛选,按时间倒序排列,暂不支持全文搜索。Tabs 下方增加筛选栏(日期范围 + 业务专属维度)。各单据 Tabs:事前/加班 全部/草稿/审批中/已通过/已拒绝/已撤回;报销 全部/草稿/审批中/已通过/待付款/已付款/已拒绝/已撤回;用车额外含已还车;外勤日志全部/草稿/已完成。公告不按状态筛——员工侧 Tabs 为公告类型(全部/通知公告/人事制度/放假活动),仅展示已发布公告;管理员侧在类型 Tabs 基础上,右上角多一个"我的草稿"入口,点开仅展示自己创建的草稿。

筛选栏明细
事前申请:日期范围 + 费用类型(差旅/招待/办公/会议)+ 紧急程度(普通/紧急/特急)
费用报销:日期范围
加班申请:日期范围 + 加班类型(工作日/休息日/节假日)
用车申请:日期范围 + 用车目的(客户接待/商务出行/公务)
外勤日志:日期范围
公告:无额外筛选(PRD 明确不做搜索)
经理列表范围 审批类单据列表页(事前/报销/加班/用车)顶部状态 Tab 上方增加两个 TDChip 切换:我的发起(默认,展示本人提交的单据)和 下属审批(展示本部门下属提交的单据)。切换时列表刷新,下属审批 模式下卡片额外显示申请人姓名和部门。处于 pending 状态的下属卡片左滑→[一键同意](绿色按钮),无需进入详情页即可就地审批通过,调 POST /api/oa/approval/action
财务列表操作 费用报销列表页,财务角色默认查看全公司数据。列表页不提供快捷付款操作——财务核销必须进入详情页完成三字查验(验真/税号/类目)并录入电汇流水号和记账凭证号后方可归档。[待付款] Tab 中的卡片点击进入详情页操作
预算冻结异常 提交时调 ERP BudgetService.Freeze() 可能因 ERP 超时或预算版本冲突而失败。失败时 OA 提示"预算扣减失败,请稍后重试",不创建审批实例,用户可重新提交
草稿生命周期 存草稿:表单页点击「存为草稿」→ 写入数据库(Status=draft)→ 返回列表页并默认激活"草稿"Tab。找草稿:列表页切换到「草稿」Tab 即可查看所有草稿。继续编辑:点击草稿卡片 → 打开表单页,自动回填已保存数据 → 可继续编辑后再次存草稿或提交。草稿仅创建者本人可见,不可被审批人查看。草稿无过期时间,可长期保存
并发编辑 草稿仅创建者可见和编辑,不存在多人并发问题。驳回重新提交时采用乐观锁(WHERE Version=原值),冲突时提示"单据已被修改,请刷新后重试"
设备兼容性 仅支持竖屏手机。平板可运行但不做布局优化。折叠屏展开态默认按手机竖屏布局居中显示
多语言 V1 支持简体中文、繁体中文、英文。所有 UI 文案通过 Flutter 国际化(AppLocalizations)管理。默认跟随系统语言,用户可在个人中心手动切换(入口:/profile → 语言设置 → 选择语言 → 立即生效)

4. 业务流程图

4.1 工作台角色路由

flowchart TD
    A[用户打开 App] --> B[.NET 加载 OaUserPermission]
    B --> C{权限判定}
    C -->|有 oa.admin.*| D[管理员版工作台]
    C -->|有 oa.expense.mark_paid| E[财务版工作台]
    C -->|有 oa.*.approve 或 view_dept| F[经理版工作台]
    C -->|其他| G[员工版工作台]

    D --> D1[轮播图 + 金刚区 + 发布公告入口 + 全公司财务看盘]
    E --> E1[轮播图 + 金刚区 + 全公司财务看盘]
    F --> F1[轮播图 + 金刚区 + 待审批卡片 + 部门快捷看板]
    G --> G1[轮播图 + 金刚区 + 个人快捷看板]

    D1 --> H[用户点击金刚区入口进入对应功能]
    E1 --> H
    F1 --> H
    G1 --> H

4.2 费用报销全流程

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[金额标红警告]
    I --> K[调 ERP BudgetService 冻结预算, tags: budget_exceeded]
    H -->|校验失败| J[ScrollTo 报错字段]
    J --> E
    H -->|校验通过| K
    K --> 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{财务核销}
    X --> Y[查验: 发票验真+税号一致+类目合规]
    Y --> Z{三项全勾?}
    Z -->|否| X
    Z -->|是| AA[录入电汇流水号+记账凭证号]
    AA --> AB[PaymentStatus=paid, 归档 + 连续核销]

    T --> AC[.NET 通知: 已拒绝]
    AC --> AD[员工重新编辑发起]
    AD --> A

4.3 事前申请全流程

flowchart TD
    A[员工发起] --> B[填写申请]
    B --> C[选择费用类型: 多选, 如差旅+办公]
    C --> D[选择项目 → 加载科目 → 查预算余额]
    D --> E[填预估明细行: 数量×单价, 支持多行]
    E --> F[上传支撑材料: 报价单/合同等, 最多9张]
    F --> G{存草稿 还是 提交?}
    G -->|存草稿| H[草稿保存]
    H --> A
    G -->|提交审批| I[校验必填项 + 调 ERP BudgetService 查预算]
    I -->|超预算| J[金额标红警告]
    J --> L[调 ERP BudgetService 冻结预算, tags: budget_exceeded]
    I -->|校验失败| K[ScrollTo 报错字段]
    K --> E
    I -->|校验通过| L
    L --> M[.NET → ERP 创建审批实例]
    M --> N[OA 存 ApprovalInstanceId, Status=pending]
    N --> O[.NET 消息推送审批人]

    O --> P[经理审批]
    P --> Q{审批动作}
    Q -->|同意| R{是否最后一级?}
    R -->|是| S[Status=approved, ERP 预算冻结转扣减]
    R -->|否| T[流转下一级]
    T --> O
    Q -->|拒绝| U[Status=rejected]

    N -.->|员工随时撤回| V[调 ERP 撤回 → 释放冻结预算]
    V --> W[Status=withdrawn, 审批终止]

    S --> X[.NET 通知申请人]
    X --> Y[UsageStatus=unused, 等待报销引用]
    U --> Z[.NET 通知: 已拒绝]
    Z --> AA[员工重新编辑发起]
    AA --> A

4.4 加班申请全流程

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.5 外勤日志全流程

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.6 用车申请全流程

flowchart TD
    A[员工发起] --> B[选择车牌号: OA 本地 SysVehicle 车池]
    B --> C[填写用车事由 + 始发地/目的地]
    C --> D[地图选点: MethodChannel 唤醒原生地图, 回填经纬度]
    D --> E[选择出车/还车时间]
    E --> F[添加同行人: MethodChannel 通讯录多选]
    F --> G{排期冲突检测}
    G -->|冲突| H[红色警告: 该时段车辆已被预订, 提交按钮锁死]
    G -->|无冲突| I{存草稿 还是 提交?}
    H --> B
    I -->|存草稿| J[草稿保存]
    J --> A
    I -->|提交审批| K[校验必填项]
    K -->|校验失败| L[ScrollTo 报错字段]
    L --> C
    K -->|校验通过| M[.NET → ERP 创建审批实例]
    M --> N[OA 存 ApprovalInstanceId, Status=pending]
    N --> O[.NET 消息推送审批人]

    O --> P[经理审批]
    P --> Q{审批动作}
    Q -->|同意| R{是否最后一级?}
    R -->|是| S[Status=approved, 车辆状态更新为使用中]
    R -->|否| T[流转下一级]
    T --> O
    Q -->|拒绝| U[Status=rejected]

    N -.->|员工随时撤回| V[调 ERP 撤回]
    V --> W[Status=withdrawn, 审批终止]

    S --> X[.NET 通知申请人]
    X --> Y[用车中, 等待还车登记]
    Y --> Z[员工点击确认还车]
    Z --> AA[填写: 实还时间 + 出车前里程 + 还车后里程 + 费用备注]
    AA --> AB{里程校验: 还车里程 >= 出车里程?}
    AB -->|否| AC[红色提示, 提交按钮置灰]
    AC --> AA
    AB -->|是| AD[确认提交]
    AD --> AE[Status=returned, 车辆恢复空闲, 单据归档]
    U --> AF[.NET 通知: 已拒绝]
    AF --> AG[员工重新编辑发起]
    AG --> A

4.7 公告发布全流程

flowchart TD
    A[管理员进入公告发布页] --> B[填写标题 + 选择分类: 通知/制度/活动]
    B --> C[富文本编辑正文: 加粗/斜体/列表/图片/链接/字号]
    C --> D[上传附件: 最多5个, PDF/图片/Word/Excel, 单文件<=20MB]
    D --> E[设置: 置顶开关 + 有效期可选]
    E --> F[选择接收范围]
    F --> G{范围类型}
    G -->|全员| H[PrivateLevel=0, 无需指定目标]
    G -->|按部门| I[部门树多选, 实时统计覆盖人数]
    G -->|按用户| J[员工搜索多选, 实时统计覆盖人数]
    H --> K{操作}
    I --> K
    J --> K
    K -->|存草稿| L[Status=draft, 仅创建者和管理员可见]
    L --> M[后续可编辑后发布]
    K -->|预览| N[TDDialog 全屏模拟详情页展示效果]
    N --> K
    K -->|发布| O[确认弹窗: 确认向 N 名员工发布? 发布后不可撤回]
    O -->|确认| P[Status=published, 异步写入 AnnouncementReadLog]
    P --> Q[.NET 消息推送范围内员工]

    P --> R[员工查看公告]
    R --> S[停留 >= 2秒 → 自动标记已读]
    S --> T[AnnouncementReadLog.IsRead=1, 列表红点消失]

    P -.->|管理员后续操作| U[查看触达统计: 已读/未读名单]
    U --> V[DING 一键催办未读员工: 强推 Push]

4.8 审批流对接时序

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: 推送: "您的报销申请已通过"

    Note over M,S: 拒绝流程
    M->>S: POST 审批动作(reject, instanceId, opinion)
    S->>ERP: 执行审批(reject, instanceId, opinion)
    ERP-->>S: { success }
    S-->>M: 拒绝成功
    ERP->>P: 触发审批结果通知
    P->>E: 推送: "您的报销申请已被拒绝"

4.9 角色权限配置流程

flowchart TD
    A[管理员进入权限管理页] --> B[搜索员工: 姓名/工号]
    B --> C[点击员工卡片]
    C --> D[右侧滑出权限编辑抽屉]
    D --> E[展示当前权限状态]

    E --> F{选择操作}
    F -->|快捷套餐| G[点击套餐按钮: 员工/审批人/财务/管理员]
    F -->|手动勾选| H[逐项勾选/取消权限点]

    G --> J{套餐覆盖当前权限}
    H --> 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

4.10 报表使用流程

flowchart TD
    A[用户进入工作台] --> B[点击金刚区报表入口]
    B --> C{选择报表}
    C -->|事前申请报表| D1[进入报表页]
    C -->|费用报销报表| D2[进入报表页]
    C -->|加班报表| D3[进入报表页]
    C -->|用车报表| D4[进入报表页]
    C -->|外勤日志报表| D5[进入报表页]

    D1 --> E[.NET 根据角色加载数据范围]
    D2 --> E
    D3 --> E
    D4 --> E
    D5 --> E

    E --> F[页面渲染: 数值卡片 + 趋势图]
    F --> G{用户操作}
    G -->|切换时间| H[选择本月/本季/本年 或自定义起止日期]
    G -->|切换筛选| I[选择专属筛选条件: 状态/类型/车辆/客户等]
    H --> J[图表 300ms 刷新]
    I --> J
    J --> F

    F --> K{角色判断}
    K -->|经理| L[点击柱状图员工柱子 → 下方列表联动过滤 → 可穿透跳转详情页]
    K -->|财务/管理员| M[查看底部明细列表 + 导出 Excel]
    K -->|员工| 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 .NET CustomerService,外勤日志输入时联想查询,提交时关联 ERP 客户 ID
预算 ERP → OA .NET BudgetService,余额查询/冻结/扣减/释放,ERP 无预算时返回空→OA 隐藏预算区块
项目 ERP → OA .NET ProjectService,事前申请表单级联下拉
科目 ERP → OA .NET SubjectService,依赖项目选定后加载
成本中心 ERP → OA .NET CostCenterService,报销表单可选字段,ERP 无数据时隐藏
汇率 ERP → OA .NET ExchangeRateService,默认 CNY,选外币后自动填写当日汇率
审批发起 OA → ERP .NET 服务端调用 ERP 审批 API
审批状态查询 OA → ERP 同上
审批动作 OA → ERP 同上
消息推送 ERP → 用户 .NET 服务端消息模块在审批事件后触发推送
原生能力 App → OA MethodChannel:相机、相册、通讯录、地图、GPS 定位

5.4 性能考量

场景 策略 预期体验
列表页加载 OA 本地业务数据 + .NET → ERP 实时查询审批状态 首次 1-2 秒(内网 ERP 延迟低)
详情页打开 实时调用 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 隐藏对应功能区块
定时 Job 调度 申请过期自动释放预算 预算无法自动释放,需人工处理
.NET 服务端消息模块 推送通知 站内消息仍可见(轮询),Push 通知不可用
MethodChannel 相机/相册/通讯录/GPS/地图选点 对应功能不可用,按钮置灰+提示
SQL Server OA 业务数据持久化 全模块不可用

假设

  • 宿主 App 已完成用户登录认证,OA 启动时能从宿主获取 Token 和 ERP 用户 ID
  • ERP 审批引擎支持基础审批动作(同意/拒绝),转交和高级形态(会签/或签)暂不支持
  • 每套 ERP 的审批 API 签名虽不同,但功能语义一致(都有创建实例/查询状态/执行动作)
  • 预算、汇率等数据在 ERP 端已维护;费用标准 V1 不涉及 | 后续版本再接入

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 适配器实现)
预算科目 财务核算科目(如差旅费、招待费),预算挂在项目×科目的交叉点上
成本中心 费用归属的核算单元,报销时可选填,ERP 无数据时隐藏
外币折算 报销明细选择外币后自动从 ERP 获取汇率,折算为本币(CNY)进行预算校验和报表统计
拼单导入 报销时从多张已通过的事前申请导入金额,合并为一张报销单提交
排期冲突 用车申请选定车牌+时间后检测是否与已批准的申请存在时段重叠
触达率 公告发布后已读人数占应达总人数的比例