tboss-oa-product-strategy.md 13 KB

TBOSS OA 模块 — 产品思路

版本:v1.0 | 日期:2026-06-03 | 状态:已确认


1. 模块定位

在已有 ERP App 内嵌入一个 OA 功能模块(Flutter),后端在现有 .NET Framework 4.8 服务端上新增 API。

OA 只负责:业务表单的录入与展示、公告管理、报表展示、OA 独立权限控制。

不复建的已有能力:用户与组织架构、审批引擎、消息通知推送、客户主数据——均复用 ERP/.NET 服务端。

Why:公司已有成熟 ERP 和多套审批 API,消息通知也在 .NET 服务端上跑着。OA 是一个移动端业务前端,不是独立系统。


2. 系统架构

┌─────────────────────────────────────────────────────────────┐
│                 Flutter OA 模块                              │
│  统一的 REST API 调用(只调 .NET 服务端)                       │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│             .NET Framework 4.8 服务端(已有 + 新增)            │
│                                                              │
│  已有(复用):                                               │
│  ├─ 用户/部门/客户数据 ── 来自多套 ERP 主数据                    │
│  ├─ 消息通知推送 ────── App Push + 站内消息                    │
│  └─ 审批操作代理 ────── 适配器层(每套 ERP 一个 Adapter)       │
│                                                              │
│  新增 OA 能力:                                               │
│  ├─ 权限管理 ── OA 独立权限点 + 快捷套餐                        │
│  ├─ 业务单据 ── 报销/事前/加班/用车/外勤 CRUD + 审批操作入口      │
│  ├─ 公告管理 ── 发布/浏览/已读追踪/DING 催办                    │
│  └─ 报表数据 ── 5 大明细报表聚合查询                           │
└─────────────────────────────────────────────────────────────┘

Why

  • Flutter 只调 .NET 服务端:多 ERP 适配、消息推送、状态刷新全部下沉到服务端,移动端不感知复杂度
  • 无 ERP 回调:ERP 审批完成后不会主动通知 OA。状态同步策略为"列表页缓存秒开 + 后台静默刷新 + 详情页实时校准"
  • 消息通知复用:审批通过/拒绝后的通知由 .NET 服务端已有消息模块直接从 ERP 侧触发推送,OA 不负责

3. OA 独立权限模型

3.1 设计背景

约束

  • ERP 采用 ACL 模型:按单据/模块给每个用户赋予增删改查权限,没有预设的"财务""采购""销售"角色
  • OA 端也需要审批单据(事前申请、报销单、用车申请、加班申请)
  • ERP 的权限和 OA 的权限是两套独立体系

讨论过程:是否保留 4 角色?→ "审批人"和"财务"在 OA 端如何定义?→ 结论:角色是权限的快捷套餐,底层是 ACL。

3.2 权限点清单(~20 个)

报销:
  oa.expense.apply            发起报销
  oa.expense.view_own         查看自己的报销单
  oa.expense.view_dept        查看本部门报销单
  oa.expense.view_all         查看全公司报销单
  oa.expense.approve          执行审批操作(显示审批按钮)
  oa.expense.mark_paid        标记已付款(财务核销)

事前申请:
  oa.expense_apply.apply
  oa.expense_apply.view_own / view_dept / view_all / approve

加班:
  oa.overtime.apply / view_own / view_dept / view_all / approve

用车:
  oa.vehicle.apply / view_own / view_dept / view_all / approve

外勤日志:
  oa.outing_log.create        写日志
  oa.outing_log.view_own / view_dept / view_all
  oa.outing_log.comment       点评打分

公告:
  oa.announcement.view        浏览公告
  oa.announcement.publish     发布公告
  oa.announcement.manage      管理(编辑/删除/置顶)

报表:
  oa.report.view_own / view_dept / view_all
  oa.report.export            导出 Excel

管理:
  oa.admin.permissions        管理 OA 权限
  oa.admin.vehicles           管理车辆池
  oa.admin.customers          管理客户池
  oa.admin.banners            管理工作台轮播图

3.3 快捷套餐

套餐 包含 适用
员工 apply + view_own + create + announcement.view 默认
审批人 员工 + approve + view_dept + outing_log.comment 部门主管
财务 view_all + expense.mark_paid + report.view_all + report.export 核销人员
管理员 全部权限 IT/HR 管理员

3.4 "审批人"和"财务"的定义

审批人角色 ≠ 可以审批所有单据。 OA 端只是:

  • 解锁审批操作栏 UI(同意/拒绝/转交按钮)
  • 解锁部门级数据范围(列表页"下属审批"标签、部门报表)
  • 解锁外勤日志点评功能

具体谁能审批哪个单据,由 ERP 审批引擎的审批链配置决定,OA 只是把操作入口和审批结果展示出来。

财务角色同理:解锁发票合规核销区 + 打款归档按钮 + 全公司数据 + 导出。不参与正常审批流。

Why:ERP 已经有完整的审批引擎和审批链配置,OA 侧的角色本质上是功能可见性开关 + 数据范围边界,不是数据权限的最终裁判。


4. 审批对接方案

4.1 OA 不存审批配置和记录

审批链配置、审批记录、审批流转全部由 ERP 审批引擎管理。

Why:审批引擎是 ERP 核心能力,OA 是消费者而非替代者。OA 存一份审批数据会造成双写和一致性难题。

4.2 业务表新增字段

每张需要审批的业务主表(ExpenseApplication / Expense / Overtime / Vehicle):

ApprovalInstanceId     VARCHAR(50)     -- 当前有效的 ERP 审批实例 ID
ApprovalStatus         VARCHAR(20)     -- OA 本地缓存状态(列表页秒开用)
PreviousInstanceIds    VARCHAR(MAX)    -- 历史实例 ID JSON 数组
                                       -- 驳回重新发起时追加旧 ID

Why 3 个字段

  • ApprovalInstanceId 是必须的,关联 ERP 审批实例
  • ApprovalStatus 是性能缓存:列表页 20 条单据如果每条都跨系统查 ERP 会卡。缓存状态下拉刷新时校准
  • PreviousInstanceIds 用于追溯驳回重新提交前的审批历史。如果 ERP 能按 bizType+bizId 直接查全部审批历史则不需要此字段(待确认)

4.3 状态同步策略

约束:ERP 审批完成后没有回调 OA 的机制。

场景 策略
列表页 展示本地缓存 ApprovalStatus(秒开);后台静默批量刷新
详情页 打开时实时从 ERP 刷新校准
下拉刷新 强制穿透缓存
审批操作后 立即写缓存 + 异步校准
消息通知 由 .NET 服务端消息模块在审批完成后从 ERP 侧触发推送

Why:没有回调的情况下,列表页每次全量跨系统查询太慢,缓存 + 按需刷新是代价最低的平衡方案。

4.4 多 ERP 适配

公司有多套 ERP 系统,审批 API 接口签名不一致。适配工作全部在 .NET 服务端完成:

.NET 服务端
  ┌──────────────────────────┐
  │  OA ApprovalService      │  ← 统一接口(Flutter 调的)
  ├──────────────────────────┤
  │  ErpAAdapter             │  ← 翻译 ERP-A 的 API 格式
  │  ErpBAdapter             │  ← 翻译 ERP-B 的 API 格式
  │  ErpCAdapter             │  ← 翻译 ERP-C 的 API 格式
  └──────────────────────────┘

每套 ERP 需要提供的能力:

OA 需要的 ERP 审批 API 提供
提交单据进入审批流 发起审批
获取单据当前审批状态 查询实例状态
获取审批时间线 查询流程节点历史
获取某人的待审批列表 查询待办
执行审批(同意/拒绝/转交) 审批动作接口

Why:Flutter 端只需要统一的 REST API,多 ERP 的差异由服务端适配器模式隔离,后续新增 ERP 只需增加一个 Adapter。


5. 功能模块与数据范围

5.1 模块总览

模块 走审批 核心数据来源
事前申请 ✅ ERP OA 业务表 + ERP 审批实例
费用报销 ✅ ERP OA 业务表 + ERP 审批实例
加班申请 ✅ ERP OA 业务表 + ERP 审批实例
用车申请 ✅ ERP 车辆池 OA 自管;审批走 ERP
外勤日志 OA 自闭环;客户名关联 ERP 客户 ID
公告 OA 完全自闭环
报表 OA 业务表 + ERP 审批状态

5.2 数据所有权

OA 独立维护:
  ├─ 所有业务单据及明细(报销/事前/加班/用车/外勤/公告)
  ├─ 附件(支撑材料/发票影像/外勤照片/公告附件)
  ├─ 外勤点评
  ├─ 车辆池(ERP 不管公车)
  ├─ 公告触达审计(已读/未读/DING)
  ├─ OA 权限数据
  └─ 轮播图配置

从 ERP 查询(不持久化):
  ├─ 用户信息(姓名/部门/岗位/头像)
  ├─ 组织架构树
  ├─ 客户数据
  ├─ 审批流程数据(状态/时间线/待办)
  └─ 项目/预算科目/成本中心

6. 数据库表变更

6.1 删除(不再由 OA 管理)

原因
SysUser ERP 管理用户
SysRole / SysUserRole 改为 OA 权限模型
SysRoleChangeLog 改为 OaPermissionChangeLog
SysDepartment ERP 管理组织架构
SysCostCenter / SysProject / SysBudgetSubject ERP 管理,通过 .NET 适配器查询
SysCustomer / SysCustomerContact ERP 管理客户,通过 .NET 适配器查询
SysBank .NET 服务端字典
ApprovalChain / ApprovalRecord ERP 审批引擎管理
Message .NET 服务端消息模块管理
SysProjectBudget / ExpenseStandard ERP 管理,通过 BudgetService / StandardService 适配器

6.2 新增

OaPermission         -- 权限点字典
OaUserPermission     -- 用户-权限关联(基于 ERP UserId)
OaPermissionChangeLog -- 权限变更审计
ExpenseApplicationMapping -- 申请↔报销多对多
ExpenseApplicationChange -- 申请变更/追加记录
Loan / LoanRepayment  -- 借款/备用金及还款

6.3 业务表变更

所有审批类主表(ExpenseApplication / Expense / Overtime / Vehicle)新增:

  • ApprovalInstanceId VARCHAR(50)
  • ApprovalStatus VARCHAR(20)
  • PreviousInstanceIds VARCHAR(MAX)

引用 ERP 数据的字段改为存储 ERP ID(非 FK 约束):

  • DeptIdProjectIdBudgetSubjectIdCostCenterId → ERP 对应实体 ID
  • OutingLog.CustomerId → ERP 客户 ID

6.4 保留不变

OA 自管的核心表保持原有结构:

  • 业务主表:ExpenseApplication, Expense, Overtime, Vehicle, OutingLog, Announcement
  • 业务子表:ExpenseAppDetail, ExpenseDetail, VehiclePassenger
  • 附件表:Attachment(统一聚合,BizType 区分)
  • 借款表:Loan, LoanRepayment
  • 申请↔报销关联:ExpenseApplicationMapping(多对多)
  • 申请变更:ExpenseApplicationChange
  • 互动/审计表:OutingLogComment, AnnouncementReadLog, AnnouncementTarget
  • 基础表:SysVehicle, SysBanner

7. 竞品对标

维度 钉钉/企微 蓝凌/泛微 TBOSS OA
部署方式 SaaS 私有化/SaaS 嵌入 ERP App,非独立产品
审批引擎 自带 自带 复用 ERP,适配器隔离多套差异
用户体系 独立维护 独立/AD 同步 映射 ERP 用户,零重复维护
预算控制 提醒级 冻结级 取决于 ERP 预算能力
角色模型 链式主管 岗位/相对角色 权限点 ACL + 快捷套餐
移动端深度 功能全但不可定制 偏 PC 原生嵌入(相机/通讯录/地图/GPS)
事前→报销 关联控件 一键转换+预算冻结 一键导入+三级追踪+分批报销
审批形态 基础 会签/或签/加签 取决于 ERP 审批引擎

已有竞争力:预算冻结+三级使用追踪、外勤防伪(GPS只读+水印)、公告触达审计+DING催办、复合角色+工作台动态变体。

差距(部分取决于 ERP 能力):会签/或签审批形态、OCR 发票识别、离线审批。


8. 待确认

# 事项 影响
1 ERP 审批历史是按 instanceId 还是 bizType+bizId 查询? 决定是否要 PreviousInstanceIds
2 各套 ERP 的具体 API 签名差异 .NET 服务端适配器层开发量(审批+预算+项目+科目+成本+标准+客户+汇率)
3 ERP 客户表的主键类型和查询 API 外勤日志客户关联的实现方式
4 ERP 费用标准表结构 StandardService 适配器的查询参数