feat: complete leave approval MVP

This commit is contained in:
selfrelease
2026-07-18 19:20:07 +08:00
parent 2105fe3bac
commit 090a7e33ce
133 changed files with 7845 additions and 100 deletions
+24
View File
@@ -0,0 +1,24 @@
# 数据范围与工具权限
后端以 OA 数据库中的当前用户角色为授权事实来源,不信任 Flutter 传入的角色、租户或数据范围。
## 数据范围
- `OWN`:只能访问当前租户、当前用户自己的申请、附件、通知和 AI 查询上下文。
- `ASSIGNED`:只能访问 Flowable 明确分配给当前用户的审批任务。
系统暂不提供全租户申请列表,因此 `oa_admin``hr_reviewer` 也不能绕过流程任务查看任意员工申请。
## 角色与权限
普通员工 `employee` 获得本人请假、附件、通知和只读 AI 工具权限。
以下任一角色额外获得已分配审批任务的读取和处理权限:
- `department_manager`
- `oa_admin`
- `hr_reviewer`
`GET /api/v1/me` 返回服务端计算的 `permissions``dataScopes`,客户端可据此展示工具;应用服务仍会再次校验权限,客户端隐藏按钮不能替代服务端授权。
权限不足统一返回 HTTP 403 和错误码 `PERMISSION_DENIED`。对不属于当前用户的数据和任务继续返回 404,避免泄露资源是否存在。
+18
View File
@@ -44,3 +44,21 @@ AI 可以根据自然语言生成表单字段建议值,但不能:
## 当前演示
工作台点击“发起请假”后,请假类型、开始时间、结束时间和原因均由 Schema 渲染。点击“AI 自动填写”只更新草稿状态,点击“检查并确认”后才展示最终确认卡片。
客户端优先从受保护的 `/api/v1/form-definitions/leave-request` 加载最新定义,成功后写入本地缓存。网络或认证暂不可用时优先读取最近一次有效缓存;首次离线则使用随客户端发布并经过测试的安全内置定义。运行时可通过 `--dart-define=AIOA_API_BASE_URL=...``--dart-define=AIOA_ACCESS_TOKEN=...` 配置 API 与开发令牌。
未完成的表单值会在每次字段修改或应用 AI 建议后自动写入本机。再次进入页面时自动恢复并显示来源提示;损坏或不兼容的本地草稿会被隔离清除,避免阻断表单页面。用户可显式清除草稿,后续真实提交成功后也必须清除本地副本。
用户在确认卡片中确认后,客户端调用后端草稿创建 API。请求发出前会持久化请求体与 `Idempotency-Key`;断网或服务端暂时不可用时保留待重试记录,同一份表单再次提交会复用原幂等键,后端成功响应后才清除待重试记录和本地表单草稿。
附件内容不进入 PostgreSQL 或 Flowable 变量。后端为本人草稿创建 MinIO 短期预签名上传任务,客户端直传后通知后端完成;后端重新校验对象大小和 MIME 类型,再将元数据状态改为 `READY`。下载每次重新鉴权并生成短期 URL,上传、完成、下载和删除均写入审计记录。
请假提交成功后为部门主管生成站内待办通知;流程最终批准或驳回后为申请人生成结果通知。Flutter“待办”页包含通知列表和未读数量,点击未读通知后调用后端标记已读。推送仅作为后续提醒通道,权威通知内容与已读状态保存在 PostgreSQL。
主管在 Flutter 待办卡片中查看请假类型、时间与原因,并输入审批意见后批准或驳回。审批请求在本机持久化请求体和幂等键;弱网重试复用同一 `Idempotency-Key`,成功后从列表移除当前任务。
员工可从工作台进入“我的请假申请”,查看草稿和历史申请。草稿可以提交到 Flowable,待审批申请可以撤回;详情页展示权威状态和审批事件时间线。提交与撤回均持久化幂等键,弱网重试不会重复启动或取消流程。
自然语言草稿使用千问 `qwen-plus`Flutter 只调用受保护的 Kotlin API,Kotlin 记录模型名、提示长度和澄清项数量后调用 Python AI 服务,Python 才持有供应商密钥。模型输出必须通过字段白名单、请假类型枚举、ISO-8601 时区、时间范围和文本长度校验;建议只填入本地草稿,仍需用户确认并由 Kotlin 业务接口重新校验。
Flutter 使用 Keycloak Authorization Code + PKCE 登录。Access Token、Refresh Token 和 ID Token 保存在系统安全存储中,访问令牌在过期前自动刷新;统一 HTTP 客户端只向 Kotlin API Origin 注入 Bearer Token,不会把令牌发送给 MinIO 预签名地址或千问。退出时调用 OIDC End Session 并清除本机凭据。
+16 -8
View File
@@ -7,17 +7,18 @@
- [x] OpenAPI 基础契约
- [x] Kotlin 后端 Wrapper、测试和构建入口
- [x] Trace ID、统一异常和数据库基础迁移
- [ ] GitLab CI 格式检查、测试和构建流水线
- [x] GitLab CI 格式检查、测试和 Android 构建流水线
## M1:身份与组织
- [x] Keycloak Realm、移动客户端和开发测试身份
- [x] Flutter OIDC Authorization Code + PKCE、安全 Token 存储、刷新与退出
- [x] 当前用户 OA 数据查询
- [x] 租户、部门、人员、岗位、任职关系和角色基础模型
- [x] 统一鉴权、错误结构、Trace ID 和审计基础
- [x] Keycloak 与后端容器端到端验证
- [ ] 设备注册、撤销与远程注销
- [ ] 数据范围与工具权限
- [x] 设备注册、撤销与远程注销
- [x] 数据范围与工具权限
## M2:请假审批闭环
@@ -31,14 +32,21 @@
- [x] 按请假时长路由的主管与 OA 条件串行审批
- [x] 长期年假的 OA 与 HR 并行会签及任一驳回终止
- [x] Flutter 工程、四栏导航和 Schema 驱动请假表单卡片
- [ ] 后端表单定义 API、客户端远程加载与离线缓存
- 附件、通知、弱网恢复和幂等处理
- [x] 后端表单定义 API、客户端远程加载与离线缓存
- [x] 移动端未完成草稿自动保存、损坏隔离与弱网恢复
- [x] 移动端后端草稿创建与失败提交幂等重试
- [x] 请假附件元数据、MinIO 预签名上传、完成校验、下载与删除 API
- [x] Flutter 附件选择、上传进度、MinIO 直传与附件卡片
- [x] 站内通知、未读数、已读状态、审批待办与结果通知
- [x] Flutter 主管待办列表、批准驳回与幂等安全重试
- [x] Flutter 我的申请、提交、撤回、详情和流程时间线
- [x] APNs / FCM 推送(Firebase 配置存在时启用,缺失时降级站内通知)
## M3AI 最小闭环
- 自然语言生成请假草稿
- 查询本人流程进度
- 确认卡片、工具鉴权和 AI 审计
- [x] 千问自然语言生成受约束请假草稿建议
- [x] 查询本人流程进度
- [x] 确认卡片、Kotlin 代理鉴权和 AI 审计
## Definition of Done