65 lines
4.6 KiB
Markdown
65 lines
4.6 KiB
Markdown
# 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 并清除本机凭据。
|