日期: 2026-07-30
状态: 已实现(计划见 docs/superpowers/plans/2026-07-30-oa-leave-kit.md)
范围: web-admin 审批设计器「2 表单设计」套件 Tab + 发起/详情运行时;backend 时长重算与发布/提交校验
界面模式: 对齐 FormCreate 左侧控件库;视觉 Fresh Mint
Demo: docs/mockups/oa-form-kit-tab-demo.html
前置: docs/superpowers/specs/2026-07-14-oa-approval-dingtalk-design.md §4.5 / §4.6 / §5.4
客户希望在「2 表单设计」左侧「组件」旁增加 套件 Tab:将常用业务字段组合为一键插入的预制包。首个套件为 请假套件。
| 项 | 决策 |
|---|---|
| 左侧 UI | Tab:组件 → 套件 → 大纲;套件独立 Tab(不出现在「组件」里);双列小卡片 |
| 组成 | 4 个基础组件拼装;套件容器上配置工时属性 |
| 字段 | 请假类型、开始时间、结束时间、时长(h) |
| 类型选项 | 内置:事假、调休、病假、年假、产假、陪产假、婚假、例假、丧假、哺乳假;设计器可维护 |
| 计量单位 | 全部按小时 |
| 时间精度 | 开始/结束:年月日时分(YYYY-MM-DD HH:mm) |
| 工时模型 | 上午时段 + 下午时段;间隙(午休)自然不计 |
| 默认时段 | 上午 08:30–12:00,下午 13:00–17:30 |
| 配置位置 | 套件实例属性(每个审批应用各自配置) |
| 时长手改 | 默认可改;手改后不再随起止/工时自动重算;提供「恢复自动计算」 |
| 小数 | 保留 1 位小数 |
| 实现方案 | 方案 1:套件容器 + 展开/内嵌基础子字段(非一体 leaveKit 值对象) |
┌─ 请假套件(组装体 / 容器)─────────────────────┐
│ 套件属性:上午时段、下午时段 │
│ │
│ · 基础·下拉 → 请假类型 │
│ · 基础·日期时间 → 开始时间 │
│ · 基础·日期时间 → 结束时间 │
│ · 基础·数字 → 时长(h) │
└─────────────────────────────────────────────────┘
容器类型建议登记为 leaveKit(布局类,不计可填字段数),或复用 group 并带 _fc_kit: 'leave' 标记。推荐独立 leaveKit 便于发布校验与选中态属性面板。
{
"type": "leaveKit",
"props": {
"morningStart": "08:30",
"morningEnd": "12:00",
"afternoonStart": "13:00",
"afternoonEnd": "17:30"
},
"children": [
{
"type": "select",
"field": "leaveType",
"title": "请假类型",
"options": [
{ "label": "事假", "value": "事假" },
{ "label": "调休", "value": "调休" },
{ "label": "病假", "value": "病假" },
{ "label": "年假", "value": "年假" },
{ "label": "产假", "value": "产假" },
{ "label": "陪产假", "value": "陪产假" },
{ "label": "婚假", "value": "婚假" },
{ "label": "例假", "value": "例假" },
{ "label": "丧假", "value": "丧假" },
{ "label": "哺乳假", "value": "哺乳假" }
],
"$required": true
},
{
"type": "datePicker",
"field": "leaveStart",
"title": "开始时间",
"props": { "type": "datetime", "format": "YYYY-MM-DD HH:mm", "valueFormat": "YYYY-MM-DD HH:mm" },
"$required": true
},
{
"type": "datePicker",
"field": "leaveEnd",
"title": "结束时间",
"props": { "type": "datetime", "format": "YYYY-MM-DD HH:mm", "valueFormat": "YYYY-MM-DD HH:mm" },
"$required": true
},
{
"type": "inputNumber",
"field": "leaveDuration",
"title": "时长(h)",
"props": {
"precision": 1,
"min": 0,
"durationManual": false
},
"$required": true
}
]
}
说明:
field 插入时生成唯一 ID(同表单可插入多套请假套件,自动去重后缀)。props.kitRef 或父 leaveKit 关联,用于运行时读取工时配置。durationManual 存在时长字段 props;发起人手改后置 true。{
"leaveType": "事假",
"leaveStart": "2026-07-30 09:00",
"leaveEnd": "2026-07-30 15:00",
"leaveDuration": 5.5
}
| 字段 | JSON 值形态 |
|---|---|
| 请假类型 | string(选项 value) |
| 开始/结束 | string,YYYY-MM-DD HH:mm |
| 时长 | number,一位小数 |
工时时段与 durationManual 不作为业务展示主字段写入 form_data 的独立 key(配置在 schema);若运行时需回传手改状态,可在时长字段旁用约定 props 或并行隐藏字段,实现计划中二选一并保持双端一致。
对闭开或闭闭区间,实现统一为:将 [start, end] 与每一天的上午段、下午段求交集,累加分钟数,再 / 60,四舍五入到 1 位小数。
end <= start:时长视为无效(前端提示;后端拒绝或置 0 并报错)。0.0。示例(默认工时):
09:00,结束 15:00(同日)09:00–12:00(3h)+ 下午 13:00–15:00(2h)= 5.0h12:00–13:00 不计)| 状态 | 行为 |
|---|---|
durationManual = false |
起止或套件工时变化时自动重算并写回时长 |
durationManual = true |
不再自动重算;保留用户输入 |
| 「恢复自动计算」 | 清 durationManual,按当前起止与工时重算 |
number ≥ 0 且一位小数。eval;算法放在独立纯函数模块(可与 oa_formula 并列,如 oa_leave_hours.py + 前端 oa-leave-hours.ts)。FcDesigner.addMenu({ name: 'kit', title: '套件' })(或等价配置),保证顺序在「组件」相关菜单之后。addDragRule 注册请假套件;视觉与基础组件卡片一致。coming 占位,不注册拖拽或禁用。| 操作 | 行为 |
|---|---|
| 拖入/点击请假 | 插入 leaveKit + 4 子字段 |
| 选中容器 | 右侧:上午/下午四个时间;校验段内 start < end |
| 选中子字段 | 常规属性;类型字段可维护 options |
| 删除子字段 | 允许;套件不完整时发布 警告可发(不强制阻断) |
| 再拖一套 | 允许;field 自动唯一 |
子字段与普通字段相同:勾选「参与流程条件分支」后可在流程设计中引用(类型、时长等)。
leaveKit(或约定 group 标记)加入布局类白名单。select / datePicker / inputNumber(或项目现用等价 type)。HH:mm;上午/下午各自 start < end;下午起点 < 上午终点时仅 提示(不强制)。| 层 | 落点 |
|---|---|
| 设计器宿主 | web-admin/src/oa-fc-host/:菜单「套件」、拖拽规则、容器组件与属性 |
| 主应用注册 | 与金额/人员同类:setupOaLeaveKit + main.ts / oa-fc-host/main.ts |
| 算法前端 | web-admin/src/utils/oa-leave-hours.ts |
| 算法后端 | backend/app/services/oa_leave_hours.py;发起提交路径调用 |
| 发布白名单 | backend/app/services/oa_publish.py → LAYOUT_TYPES 增加 leaveKit |
| Demo | docs/mockups/oa-form-kit-tab-demo.html |
datePicker datetime 的 valueFormat 与后端解析严格对齐。