Files
AIOA/docs/engineering/mobile-schema-forms.md
T
2026-07-18 19:20:07 +08:00

65 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Flutter Schema 驱动表单卡片
## 目标
Flutter 页面不为每种 OA 表单重复编写固定控件。服务端返回版本化的 JSON Schema 和 UI Schema,客户端从受控组件目录中自动生成移动表单卡片。
```text
表单定义 API
├─ JSON Schema:字段、类型、必填、枚举和数据约束
└─ UI Schema:分组、顺序、标签、控件和移动端提示
Flutter Schema 解析
白名单控件渲染器
Riverpod 草稿状态与本地校验
用户确认卡片
后端再次校验并执行写操作
```
## 已实现控件
- `text`:单行文本
- `textArea`:多行文本
- `select`:受控枚举选择
- `dateTime`:日期和时间选择
未知字段或未知控件不能执行动态代码,只显示安全错误提示。后续控件必须通过客户端版本发布进入白名单,例如人员选择、部门选择、附件、金额、定位和明细表格。
## AI 边界
AI 可以根据自然语言生成表单字段建议值,但不能:
- 生成或执行 Dart、JavaScript 等客户端代码。
- 绕过 Schema 枚举和校验规则。
- 绕过用户确认直接提交。
- 自行增加后端未定义的字段。
- 修改隐藏的租户、申请人、审批人或权限字段。
客户端校验用于交互体验,Kotlin 后端仍必须重新执行权限、数据、状态、幂等和业务规则校验。
## 当前演示
工作台点击“发起请假”后,请假类型、开始时间、结束时间和原因均由 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 并清除本机凭据。