# TBOSS OA 模块 — 产品思路

> 版本：v1.0 | 日期：2026-06-04 | 基于 PRD v1.0 | 状态：已确认

---

## 1. 模块定位

在已有 ERP App 内嵌入一个 OA 功能模块（Flutter），后端在现有 .NET Framework 4.8 服务端上新增 API。V1 实现 8 个核心模块：费用申请、费用报销、加班申请、用车申请、外勤日志、公告管理、数据报表、权限管理，加上工作台共 9 个功能页面组。

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

**不复建的已有能力**：用户与组织架构、审批引擎、消息通知推送、预算系统、项目主数据、成本中心、客户主数据、汇率——全部通过 .NET 适配器层从 ERP 复用。

**Why**：公司已有成熟 ERP 和多套审批 API，OA 是一个移动端业务前端，不是独立系统。

---

## 2. 系统架构

```
┌─────────────────────────────────────────────────────────────┐
│                 Flutter OA 模块                              │
│  统一的 REST API 调用（只调 .NET 服务端）                       │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│             .NET Framework 4.8 服务端（已有 + 新增）            │
│                                                              │
│  已有（复用）：                                               │
│  ├─ 用户/部门/客户数据 ── 来自多套 ERP 主数据                    │
│  ├─ 消息通知推送 ────── App Push + 站内消息                    │
│  ├─ 审批引擎适配 ────── 适配器层（每套 ERP 一个 Adapter）       │
│  ├─ 预算系统适配 ────── BudgetService（余额/冻结/扣减/释放）     │
│  ├─ 项目/科目/成本 ──── ProjectService/SubjectService/CostCenterService │
│  ├─ 汇率适配 ────────── ExchangeRateService                   │
│  └─ 客户适配 ────────── CustomerService                       │
│                                                              │
│  新增 OA 能力：                                               │
│  ├─ 权限管理 ── OA 独立权限点 + 快捷套餐                        │
│  ├─ 业务单据 ── 报销/事前/加班/用车/外勤 CRUD + 审批操作入口      │
│  ├─ 公告管理 ── 发布/浏览/已读追踪/DING 催办                    │
│  └─ 报表数据 ── 5 大明细报表聚合查询（按角色数据范围）            │
└─────────────────────────────────────────────────────────────┘
```

**Why**：

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

---

## 3. OA 独立权限模型

### 3.1 设计背景

**约束**：ERP 采用 ACL 模型，没有预设的"财务""采购""销售"角色。OA 端也需要审批单据。ERP 的权限和 OA 的权限是两套独立体系。

### 3.2 权限点清单

```
报销：
  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 / 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      管理（编辑/删除/置顶/DING）

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

管理：
  oa.admin.permissions        管理 OA 权限
  oa.admin.vehicles           管理车辆池
  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 审批引擎的审批链配置决定。

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

**Why**：OA 侧的角色本质上是功能可见性开关 + 数据范围边界，不是数据权限的最终裁判。

---

## 4. 审批对接方案

### 4.1 数据存储

OA 不存审批配置和记录。每张审批类业务主表（ExpenseApply / Expense / Overtime / Vehicle）新增两个字段：

```
ApprovalInstanceId     VARCHAR(50)     -- 当前有效的 ERP 审批实例 ID
PreviousInstanceIds    VARCHAR(MAX)    -- 历史实例 ID JSON 数组（驳回/撤回后追加）
```

列表页、详情页的审批状态均通过 .NET → ERP 实时查询，不本地缓存。

### 4.2 状态同步策略

**约束**：ERP 审批完成后没有回调 OA 的机制。OA 不缓存审批状态。

| 场景 | 策略 |
|------|------|
| 列表页 | 打开时实时调 .NET → ERP 查询每笔单据的审批状态，数据始终最新 |
| 详情页 | 打开时实时从 ERP 刷新 |
| 审批操作后 | 立即更新本地数据 |
| 消息通知 | 由 .NET 服务端消息模块在审批完成后从 ERP 侧触发推送 |

**Why**：V1 用户量小（百人级），ERP 内网直连延迟低，实时查询的性能代价可接受。去掉缓存简化了数据模型和同步逻辑。

### 4.3 ERP 集成适配器清单

所有外部数据通过 .NET 适配器模式获取。ERP 无某能力时 Adapter 返回空，OA 隐藏对应功能区块：

| 适配器 | 用途 | ERP 无能力时 |
|--------|------|------------|
| ApprovalService | 审批引擎（提交/查询/审批/撤回） | —（必须） |
| UserService | 用户信息（姓名/部门/岗位/头像） | —（必须） |
| DepartmentService | 组织架构树 | —（必须） |
| BudgetService | 预算余额/冻结/扣减/释放 | 隐藏预算区块 |
| ProjectService | 项目下拉 | 隐藏项目选择器 |
| SubjectService | 预算科目下拉 | 隐藏科目选择器 |
| CostCenterService | 成本中心下拉 | 隐藏成本中心字段 |
| ExchangeRateService | 汇率查询 | 仅支持 CNY |
| CustomerService | 客户搜索/创建 | 手动输入客户名 |

---

## 5. 功能模块与数据范围

| 模块 | 走审批 | 核心数据来源 |
|------|--------|------------|
| 费用申请 | ✅ ERP | OA 业务表 + ERP 审批实例 + ERP 预算 |
| 费用报销 | ✅ ERP | OA 业务表 + ERP 审批实例 + ERP 预算/汇率 |
| 加班申请 | ✅ ERP | OA 业务表 + ERP 审批实例 |
| 用车申请 | ✅ ERP | 车辆池 OA 自管（SysVehicle）；审批走 ERP |
| 外勤日志 | ❌ | OA 自闭环；客户名关联 ERP 客户 ID |
| 公告管理 | ❌ | OA 完全自闭环 |
| 数据报表 | ❌ | OA 业务表 + ERP 审批状态 |
| 权限管理 | ❌ | OA 独立权限表 |
| 工作台 | ❌ | OA 本地 + .NET 聚合查询 + ERP 审批引擎 |

---

## 6. 数据存储原则

**OA 自管**：业务单据（事前/报销/加班/用车/外勤/公告）、附件（Attachment 统一聚合）、权限（OaPermission）、车辆池（SysVehicle）、轮播图（SysBanner）、费用类别字典（SysCostCategory）。

**ERP 管理**：用户、部门、角色、客户、项目、预算科目、成本中心、审批链、审批记录、消息——全部通过适配器查询，OA 不持久化。

详细表结构见 `tboss-oa-database.md`。

---

## 7. 竞品对标

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

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

---

## 8. 待确认

| # | 事项 | 影响 |
|---|------|------|
| 1 | ERP 审批历史是按 instanceId 还是 bizType+bizId 查询？ | 决定是否要 PreviousInstanceIds |
| 2 | 各套 ERP 的具体 API 签名差异 | .NET 适配器层开发量 |
| 3 | ERP 客户表的主键类型和查询 API | 外勤日志客户关联的实现方式 |
