tboss-oa-api.md 22 KB

TBOSS OA 模块 — API 接口文档

版本:v1.0 | 日期:2026-06-03 | Base URL:https://{host}/api


1. 通用规范

1.1 请求头

Content-Type: application/json
Authorization: Bearer {token}    ← 由宿主 App 注入
X-User-Id: {erpUserId}           ← 当前登录用户 ERP ID

1.2 统一响应格式

{
  "code": 0,
  "message": "success",
  "data": { ... },
  "timestamp": 1717401600
}

1.3 分页响应

{
  "code": 0,
  "data": {
    "items": [ ... ],
    "total": 128,
    "page": 1,
    "pageSize": 20
  }
}

1.4 错误码

code 含义 处理方式
0 成功
400 参数校验失败 Toast 提示具体字段错误
401 未授权 / Token 过期 触发宿主重新登录
403 无 OA 操作权限 Toast "无此操作权限"
404 资源不存在 TDEmpty 或 Toast
409 并发冲突 (CONCURRENCY_CONFLICT / APPROVAL_CONFLICT) TDDialog 提示刷新
422 业务校验失败 展示具体错误信息
500 服务器内部错误 Toast "服务器繁忙,请稍后重试"
504 ERP 审批接口超时 Toast "审批服务暂不可用,请稍后重试"

1.5 枚举值

所有状态/类型字段使用英文标识字符串,前端负责国际化映射。完整枚举取值见 tboss-oa-database.md 第 6 节。


2. OA 权限 API

2.1 获取权限点列表

GET /api/oa/permissions

响应

{
  "code": 0,
  "data": {
    "permissions": [
      {
        "id": 1,
        "code": "oa.expense.apply",
        "name": "发起报销",
        "module": "expense",
        "sortOrder": 1
      },
      {
        "id": 2,
        "code": "oa.expense.view_own",
        "name": "查看自己的报销单",
        "module": "expense",
        "sortOrder": 2
      }
    ]
  }
}

2.2 获取用户权限

GET /api/oa/user-permissions?userId={erpUserId}

响应

{
  "code": 0,
  "data": {
    "userId": 1001,
    "permissions": ["oa.expense.apply", "oa.expense.view_own", "oa.announcement.view"],
    "presetRoles": ["employee"]
  }
}

2.3 保存用户权限

PUT /api/oa/user-permissions

请求

{
  "userId": 1001,
  "permissionCodes": [
    "oa.expense.apply",
    "oa.expense.view_dept",
    "oa.expense.approve",
    "oa.outing_log.comment"
  ]
}

响应

{
  "code": 0,
  "message": "权限已更新"
}

错误: | code | 场景 | |------|------| | 403 | 无 oa.admin.permissions 权限 | | 422 | 试图移除自己的管理员权限 / 移除最后一名管理员 |

2.4 权限变更日志

GET /api/oa/permission-changelog?userId={erpUserId}&page=1&pageSize=20

响应

{
  "code": 0,
  "data": {
    "items": [
      {
        "id": 1,
        "targetUserId": 1001,
        "operatorId": 2001,
        "operatorName": "管理员王五",
        "changeType": "assign",
        "beforePermissions": ["oa.expense.apply", "oa.expense.view_own"],
        "afterPermissions": ["oa.expense.apply", "oa.expense.view_own", "oa.expense.approve"],
        "createTime": "2026-06-03T10:30:00"
      }
    ],
    "total": 5,
    "page": 1
  }
}

3. 业务单据 API

3.1 通用说明

{bizType} 取值:expense-apply | expense | overtime | vehicle

3.2 提交单据(新建 + 发起审批)

POST /api/oa/{bizType}/submit

事前申请

请求

{
  "id": null,
  "urgency": "normal",
  "expenseType": "travel",
  "purpose": "北京客户拜访差旅费预估",
  "projectId": 100,
  "budgetSubjectId": 5,
  "estimatedStartDate": "2026-06-10",
  "estimatedEndDate": "2026-06-12",
  "isOvernight": true,
  "transportType": "high_speed_rail",
  "isTaxIncluded": false,
  "referenceNo": "HT-2026-0089",
  "details": [
    {
      "expenseCategory": "transport",
      "quantity": 2,
      "unitPrice": 550.00,
      "unit": "张",
      "remark": "往返高铁票"
    },
    {
      "expenseCategory": "hotel",
      "quantity": 2,
      "unitPrice": 400.00,
      "unit": "晚",
      "remark": "住宿"
    }
  ],
  "attachments": [
    { "fileName": "出差审批截图.png", "fileUrl": "https://oss/...", "fileType": "image", "fileSize": 204800 }
  ]
}

响应

{
  "code": 0,
  "data": {
    "id": 12345,
    "applicationNo": "BXSQ-20260603-001",
    "approvalInstanceId": "inst_erp_a_009832",
    "approvalStatus": "pending"
  }
}

费用报销

请求

{
  "id": null,
  "sourceApplicationId": 12300,
  "purpose": "北京客户拜访差旅费报销",
  "projectId": 100,
  "budgetSubjectId": 5,
  "costCenterId": 10,
  "bankName": "中国工商银行",
  "accountName": "张三",
  "bankAccount": "6222021234567890123",
  "details": [
    {
      "expenseDate": "2026-06-10",
      "expenseType": "transport",
      "expenseDesc": "G123 北京南-上海虹桥",
      "amount": 523.58,
      "taxAmount": 26.42,
      "invoiceNo": "12345678",
      "invoiceCode": "011001900111",
      "invoiceType": "special",
      "taxRate": 0.0900
    }
  ],
  "attachments": [
    { "fileName": "高铁票.jpg", "fileUrl": "https://oss/...", "fileType": "image", "fileSize": 307200, "detailIndex": 0 }
  ]
}

响应:同事前申请结构。

加班申请

请求

{
  "id": null,
  "otType": "workday",
  "compensationType": "overtime_pay",
  "startTime": "2026-06-03T18:00:00",
  "endTime": "2026-06-03T22:00:00",
  "reason": "紧急上线支持,需加班完成部署"
}

响应

{
  "code": 0,
  "data": {
    "id": 12346,
    "applicationNo": "JB-20260603-001",
    "netOtHours": 3.5,
    "approvalInstanceId": "inst_erp_a_009833",
    "approvalStatus": "pending"
  }
}

用车申请

请求

{
  "id": null,
  "vehicleId": 3,
  "purpose": "business",
  "reason": "前往客户现场演示产品",
  "origin": "公司总部",
  "originLongitude": 121.473701,
  "originLatitude": 31.230416,
  "destination": "客户公司",
  "destLongitude": 121.510000,
  "destLatitude": 31.250000,
  "startTime": "2026-06-05T09:00:00",
  "endTime": "2026-06-05T17:00:00",
  "passengerCount": 3,
  "passengers": [
    { "userId": 1002, "passengerName": "李四" },
    { "userId": null, "passengerName": "客户代表" }
  ]
}

响应:同其他单据。

3.3 存草稿

PUT /api/oa/{bizType}/draft

请求体与提交相同,id 为已有草稿 ID(编辑已有草稿)或 null(新建草稿)。不触发审批。

响应

{
  "code": 0,
  "data": { "id": 12347 }
}

3.4 列表查询

GET /api/oa/expense-apply/list?status=pending&page=1&pageSize=20
GET /api/oa/expense/list?status=all&page=1
GET /api/oa/overtime/list?status=approved&page=1
GET /api/oa/vehicle/list?status=all&page=1

参数

参数 类型 必填 说明
status string all / draft / pending / approved / rejected / withdrawn / returned(仅 vehicle)
page int 默认 1
pageSize int 默认 20
scope string own(默认) / dept / all — 根据权限自动限定

响应(以报销列表为例):

{
  "code": 0,
  "data": {
    "items": [
      {
        "id": 100,
        "reportNo": "BX-20260603-001",
        "totalAmount": 1580.00,
        "purpose": "差旅费报销",
        "applicationDate": "2026-06-03",
        "approvalStatus": "pending",
        "paymentStatus": "unpaid",
        "applicantName": "张三",
        "deptName": "销售部",
        "createTime": "2026-06-03T10:00:00"
      }
    ],
    "total": 42,
    "page": 1,
    "pageSize": 20
  }
}

3.5 详情查询

GET /api/oa/expense-apply/detail/12345
GET /api/oa/expense/detail/100
GET /api/oa/overtime/detail/12346
GET /api/oa/vehicle/detail/200

响应(以报销详情为例):

{
  "code": 0,
  "data": {
    "id": 100,
    "reportNo": "BX-20260603-001",
    "sourceApplicationId": 12300,
    "sourceApplicationNo": "BXSQ-20260520-003",
    "applicantId": 1001,
    "applicantName": "张三",
    "deptId": 10,
    "deptName": "销售部",
    "applicationDate": "2026-06-03",
    "projectId": 100,
    "costCenterId": 10,
    "totalAmount": 1580.00,
    "purpose": "差旅费报销",
    "bankName": "中国工商银行",
    "accountName": "张三",
    "bankAccount": "6222****0123",
    "isInvoiceVerified": false,
    "isTaxIdMatched": false,
    "isCategoryCompliant": false,
    "bankTransferNo": null,
    "voucherNo": null,
    "approvalStatus": "approved",
    "paymentStatus": "unpaid",
    "approvalInstanceId": "inst_erp_a_009832",
    "previousInstanceIds": [],
    "details": [
      {
        "id": 500,
        "expenseDate": "2026-06-10",
        "expenseType": "transport",
        "expenseTypeName": "交通费",
        "expenseDesc": "G123 高铁票",
        "amount": 523.58,
        "taxAmount": 26.42,
        "totalAmount": 550.00,
        "invoiceNo": "12345678",
        "invoiceCode": "011001900111",
        "invoiceType": "special",
        "taxRate": 0.09,
        "sortOrder": 1
      }
    ],
    "attachments": [
      { "id": 10, "fileName": "高铁票.jpg", "fileUrl": "https://oss/...", "fileType": "image", "fileSize": 307200, "detailId": 500 }
    ],
    "createTime": "2026-06-03T10:00:00",
    "updateTime": "2026-06-03T15:30:00"
  }
}

3.6 删除单据

DELETE /api/oa/expense/100
DELETE /api/oa/{bizType}/{id}

约束:仅 draftrejected 状态可删除。软删除(IsDeleted=1)。

响应

{ "code": 0, "message": "已删除" }

错误: | code | 场景 | |------|------| | 422 | 非 draft/rejected 状态不可删除 |


4. 外勤日志 API

4.1 提交外勤日志

PUT /api/oa/outing-log/submit

请求

{
  "id": null,
  "customerId": 5001,
  "customerName": "北京科技有限公司",
  "checkInLongitude": 116.407526,
  "checkInLatitude": 39.904030,
  "checkInAddress": "北京市朝阳区建国路88号",
  "visitSummary": "与客户CTO进行了产品演示,讨论了定制化需求...",
  "nextPlan": "下周三前送出详细方案和报价",
  "attachments": [
    { "fileName": "现场_20260603_143021.jpg", "fileUrl": "https://oss/...", "fileType": "sign_in_photo", "fileSize": 2048000 }
  ]
}

响应

{
  "code": 0,
  "data": {
    "id": 300,
    "visitNo": "VST-20260603-001",
    "status": "completed"
  }
}

校验

  • GPS 定位不能为空
  • 至少 1 张现场照片
  • 客户名为空时自动创建 ERP 客户

4.2 标记已查看

PUT /api/oa/outing-log/300/view

无请求体。更新 LastViewedTime = NOW(),使列表页"新点评"红点消失。

4.3 主管点评

POST /api/oa/outing-log/300/comment

请求

{
  "ratingStars": 4,
  "commentText": "拜访记录详实,客户需求梳理清晰。建议补充技术方案的可行性分析。"
}

权限:需要 oa.outing_log.comment 权限。

响应

{
  "code": 0,
  "data": {
    "id": 400,
    "commenterId": 2001,
    "commenterName": "王经理",
    "ratingStars": 4,
    "commentText": "拜访记录详实,客户需求梳理清晰。建议补充技术方案的可行性分析。",
    "createTime": "2026-06-03T16:00:00"
  }
}

5. 审批代理 API

5.1 待审批列表

GET /api/oa/approval/pending?userId=2001&bizType=&page=1&pageSize=20

参数: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | userId | long | ✅ | 审批人 ERP 用户 ID | | bizType | string | 否 | 为空时返回所有类型 | | page | int | 否 | | | pageSize | int | 否 | |

响应

{
  "code": 0,
  "data": {
    "items": [
      {
        "bizType": "expense",
        "bizId": 100,
        "bizNo": "BX-20260603-001",
        "amount": 1580.00,
        "summary": "差旅费报销",
        "submitTime": "2026-06-03T10:00:00",
        "applicantId": 1001,
        "applicantName": "张三",
        "deptName": "销售部",
        "approvalLevel": 1
      },
      {
        "bizType": "overtime",
        "bizId": 12346,
        "bizNo": "JB-20260603-001",
        "amount": 3.5,
        "summary": "紧急上线支持",
        "submitTime": "2026-06-03T18:30:00",
        "applicantId": 1002,
        "applicantName": "李四",
        "deptName": "技术部",
        "approvalLevel": 2
      }
    ],
    "total": 8,
    "page": 1
  }
}

5.2 待审批数量

GET /api/oa/approval/pending-count?userId=2001

响应

{ "code": 0, "data": { "count": 8 } }

5.3 审批时间线

GET /api/oa/approval/timeline?bizType=expense&bizId=100

响应

{
  "code": 0,
  "data": {
    "bizType": "expense",
    "bizId": 100,
    "currentStatus": "pending",
    "currentApproverName": "王经理",
    "nodes": [
      {
        "level": 0,
        "action": "submit",
        "approverName": "张三",
        "opinion": null,
        "approvalTime": "2026-06-03T10:00:00",
        "isValid": true
      },
      {
        "level": 1,
        "action": "pending",
        "approverName": "王经理",
        "opinion": null,
        "approvalTime": null,
        "isValid": true
      }
    ]
  }
}

5.4 审批动作

POST /api/oa/approval/action

请求(同意)

{
  "instanceId": "inst_erp_a_009832",
  "action": "approve",
  "opinion": "同意报销"
}

请求(拒绝)

{
  "instanceId": "inst_erp_a_009832",
  "action": "reject",
  "opinion": "发票金额与申请金额不符,请核实后重新提交"
}

请求(转交)

{
  "instanceId": "inst_erp_a_009832",
  "action": "transfer",
  "transferToUserId": 2003,
  "opinion": "转交财务总监审批"
}

响应

{
  "code": 0,
  "message": "审批成功",
  "data": { "newStatus": "approved" }
}

校验

  • action=rejectopinion 必填且 ≥5 个汉字
  • action=transfertransferToUserId 必填

5.5 撤回申请

POST /api/oa/approval/withdraw

请求

{
  "bizType": "expense",
  "bizId": 100,
  "instanceId": "inst_erp_a_009832"
}

响应

{ "code": 0, "message": "已撤回" }

后端操作:.NET 服务端调 ERP 撤回 → OA 更新 ApprovalStatus='withdrawn',旧 ApprovalInstanceId 追加到 PreviousInstanceIds

5.6 我的审批历史

GET /api/oa/approval/my-history?userId=1001&page=1

响应

{
  "code": 0,
  "data": {
    "items": [
      {
        "bizType": "expense",
        "bizId": 100,
        "bizNo": "BX-20260603-001",
        "summary": "差旅费报销",
        "amount": 1580.00,
        "status": "approved",
        "submitTime": "2026-06-03T10:00:00",
        "timeline": "王经理已通过"
      }
    ],
    "total": 15,
    "page": 1
  }
}

5.7 下属单据列表(经理版)

GET /api/oa/approval/subordinates?approverId=2001&bizType=expense&status=pending&page=1

响应:结构与列表查询相同,额外返回申请人姓名/部门。


6. 公告 API

6.1 发布公告

POST /api/oa/announcement/publish

请求(新建发布)

{
  "id": null,
  "title": "关于2026年端午节放假安排的通知",
  "content": "<h2>放假时间</h2><p>6月19日(周五)至6月21日(周日)...</p>",
  "type": "activity",
  "isTop": false,
  "expiryDate": "2026-06-22T00:00:00",
  "privateLevel": 0,
  "targets": []
}

请求(按部门发布)

{
  "id": null,
  "title": "销售部Q2业绩考核通知",
  "content": "<p>...</p>",
  "type": "notice",
  "isTop": true,
  "privateLevel": 1,
  "targets": [
    { "targetType": "dept", "targetId": 10 }
  ]
}

响应

{
  "code": 0,
  "data": {
    "id": 50,
    "status": "published",
    "publishTime": "2026-06-03T14:00:00",
    "targetCount": 156
  }
}

后端操作:发布时异步初始化 AnnouncementReadLog(IsRead=0)。

6.2 标记已读

POST /api/oa/announcement/50/read

无请求体。停留 ≥2s 时调用。无权限要求。

6.3 DING 催办

POST /api/oa/announcement/50/ding

权限:需要 oa.announcement.manage 权限。

响应

{
  "code": 0,
  "data": { "urgedCount": 5 }
}

后端操作:查 AnnouncementReadLog WHERE IsRead=0 → 更新 IsUrged=1 → 调消息模块推送。

6.4 已读/未读统计

GET /api/oa/announcement/read-stats/50

响应

{
  "code": 0,
  "data": {
    "readCount": 45,
    "unreadCount": 5,
    "readUsers": [
      { "userId": 1001, "userName": "张三", "deptName": "销售部", "readTime": "2026-06-03T14:05:00" }
    ],
    "unreadUsers": [
      { "userId": 1005, "userName": "赵六", "deptName": "技术部" }
    ]
  }
}

7. 报表 API

7.1 通用格式

GET /api/oa/report/{type}?range=month&userId={erpUserId}&deptId={deptId}

参数: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | range | string | ✅ | month / quarter / year | | userId | long | 否 | 个人报表时传入;部门/全公司报表时不传 | | deptId | long | 否 | 部门报表时传入 |

type 取值expense-apply | expense | overtime | vehicle | outing-log

7.2 费用报销报表

GET /api/oa/report/expense?range=year&userId=1001

响应

{
  "code": 0,
  "data": {
    "cards": {
      "yearTotalPaid": 28500.00,
      "monthCount": 3,
      "pendingCount": 1,
      "approvedUnpaidCount": 2
    },
    "chart": {
      "labels": ["2025-07", "2025-08", "...", "2026-06"],
      "appliedAmounts": [1200, 3400, 0, 0, 5600, 2300, 4500, 1800, 2900, 0, 3800, 2000],
      "approvedAmounts": [1200, 3000, 0, 0, 5600, 2300, 4000, 1800, 2900, 0, 3800, 2000]
    }
  }
}

7.3 加班报表

GET /api/oa/report/overtime?range=year&deptId=10

经理版额外数据view_dept 权限):

{
  "cards": {
    "monthTotalHours": 42.5,
    "monthCount": 8,
    "compLeaveHours": 24.0,
    "overtimePayCount": 3
  },
  "chart": {
    "labels": ["2025-07", "...", "2026-06"],
    "workdayHours": [10, 8, 12, ...],
    "weekendHours": [5, 0, 8, ...],
    "holidayHours": [0, 0, 0, ...]
  },
  "memberBreakdown": [
    { "userId": 1001, "userName": "张三", "totalHours": 18.5 },
    { "userId": 1002, "userName": "李四", "totalHours": 24.0 }
  ]
}

7.4 导出 Excel

POST /api/oa/report/expense/export

权限:需要 oa.report.export 权限。

请求

{
  "range": "quarter",
  "deptId": 10,
  "projectId": 100
}

响应Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,二进制文件流。Flutter 收到后通过 MethodChannel 唤起系统分享面板。


8. ERP 集成 API(.NET 服务端转发)

8.1 预算查询

GET /api/oa/budget/balance?projectId=100&subjectId=5

响应

{ "code": 0, "data": { "hasBudget": true, "availableAmount": 150000.00, "frozenAmount": 20000.00 } }

ERP 无预算时返回 { "hasBudget": false },OA 前端隐藏预算区块。

8.2 项目/科目/成本中心

GET /api/oa/projects              # 项目列表
GET /api/oa/subjects?projectId=   # 某项目下的预算科目
GET /api/oa/cost-centers          # 成本中心列表

8.3 费用标准校验

POST /api/oa/standard/check

请求

{ "expenseType": "hotel", "cityLevel": "一线城市", "employeeLevel": "普通员工", "amount": 600 }

响应

{ "code": 0, "data": { "pass": false, "maxAmount": 500, "exceedAmount": 100 } }

8.4 汇率查询

GET /api/oa/exchange-rate?currencyCode=USD

响应

{ "code": 0, "data": { "currencyCode": "USD", "rate": 7.2456, "date": "2026-06-03" } }

9. 借款/备用金 API

9.1 提交借款

POST /api/oa/loan/submit

请求

{ "loanType": "travel_advance", "amount": 5000.00, "purpose": "北京出差备用金" }

响应:同其他业务单据,返回 loanId + loanNo + approvalInstanceId。

9.2 还款登记

POST /api/oa/loan/repay

请求

{ "loanId": 50, "repaymentType": "cash_return", "amount": 2000.00 }

9.3 查询未还借款

GET /api/oa/loan/outstanding?userId=1001

用于报销表单提交时自动匹配冲销。


10. 申请变更 API

10.1 发起变更

POST /api/oa/expense-apply/change

请求

{
  "applicationId": 12345,
  "changeType": "amount_increase",
  "changeReason": "需增加拜访城市,追加差旅预算",
  "afterDetails": [ ... ]
}

响应:返回 changeId + approvalInstanceId(补充审批实例 ID)。


11. 基础数据 API

8.1 车辆管理

GET    /api/oa/vehicles              # 列表
POST   /api/oa/vehicles              # 添加
PUT    /api/oa/vehicles/3            # 修改

GET 响应

{
  "code": 0,
  "data": {
    "vehicles": [
      {
        "id": 1,
        "licensePlate": "粤B12345",
        "vehicleType": "sedan",
        "brand": "丰田凯美瑞",
        "seats": 5,
        "driverName": "陈司机",
        "status": "idle",
        "isActive": true
      }
    ]
  }
}

8.2 轮播图

GET /api/oa/banners

响应

{
  "code": 0,
  "data": {
    "banners": [
      {
        "id": 1,
        "imageUrl": "https://oss/...",
        "title": "2026年Q2优秀员工表彰",
        "linkUrl": "tboss://oa/announcement/detail/50",
        "sortOrder": 1
      }
    ]
  }
}

9. 复用已有 API(参考)

以下 API 为 .NET 服务端已有,OA 模块直接调用。此处仅列接口签名,详细文档见原系统。

方法 URL 说明 关键参数
GET /api/user/{id} 用户信息 id: ERP 用户 ID
GET /api/user/search?q=&page= 用户搜索 q: 姓名/工号
GET /api/dept/tree 部门树
PUT /api/user/avatar 上传头像 multipart/form-data
GET /api/customer/search?q= 客户联想 q: 客户名称
GET /api/messages?page= 消息列表 page
GET /api/messages/unread-count 未读消息数
PUT /api/messages/:id/read 标记已读 id
POST /api/messages/read-all 全部已读
DELETE /api/messages/:id 删除消息 id
GET /api/dict/banks 银行列表
GET /api/dict/cost-categories 费用类别

文档版本:v1.0 | 日期:2026-06-03