# 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 约束): - `DeptId`、`ProjectId`、`BudgetSubjectId`、`CostCenterId` → 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 适配器的查询参数 |