2026-07-30-oa-confirmation-kit-design.md 14 KB

OA 表单设计 · 转正套件(Confirmation Kit)设计文档

日期: 2026-07-30
状态: 已实现(计划见 docs/superpowers/plans/2026-07-30-oa-confirmation-kit.md)
范围: web-admin 用户管理主数据补齐;审批设计器「套件」Tab 转正套件;发起/详情运行时默认与联动;backend 审批通过后回写发起人 sys_user
界面模式: 对齐请假套件与 FormCreate 控件库;视觉 Fresh Mint
前置:

  • docs/superpowers/specs/2026-07-30-oa-leave-kit-design.md(套件组装体模式)
  • docs/superpowers/specs/2026-07-30-oa-post-select-design.md(职位组件)
  • docs/superpowers/specs/2026-07-27-oa-dept-select-design.md(部门组件)
  • docs/superpowers/specs/2026-07-30-oa-owner-fields-design.md(发起人默认值模式可参考)

1. 背景与目标

在「2 表单设计」套件 Tab 增加 转正套件:一键插入转正申请常用字段;发起时自动带出申请人主数据;审批全部通过后将约定字段回写发起人用户主数据。

1.1 目标

  • sys_user 补齐 入职日期、试用期(月数);用户管理可编辑。
  • 套件 Tab 可拖入 转正套件(容器 + 基础/业务子字段)。
  • 发起时默认填入申请人:入职日期、试用期、姓名、邮箱、部门、手机号;职位不默认。
  • 转正日期可由「入职日期 + 试用期月数」自动建议,可改;手改后断开联动(同请假时长)。
  • 子字段可在设计器配置 显示/隐藏;隐藏字段仍可带默认值,通过后仍可回写。
  • 审批 全部通过 后回写发起人主数据(见 §2)。

1.2 非目标(首期)

  • 职位、岗位职级、转正日期回写用户表。
  • 转正通过后的合同、账号状态、人事档案等副作用。
  • 代他人发起并回写他人主数据。
  • 一体复合控件(单 type 包对象值)——否决,采用与请假相同的组装体方案。

2. 产品决策(已确认)

项 决策
实现方案 方案 1:套件容器 + 子字段拼装(非一体值对象)
容器类型 confirmationKit
回写时机 审批 全部通过 后再回写
回写对象 始终 发起人 的 sys_user
回写字段 入职日期、试用期月数、姓名、邮箱、部门、手机号
不回写 职位、岗位职级、转正日期(仅审批单)
试用期存储 整数月数(如 3),界面展示「3 个月」
转正日期 有入职日 + 试用期时自动建议,仍可改
转正日联动 未手改则随入职/试用期重算;手改后断开;可「恢复自动计算」
职位默认 不默认,发起人自选
职位选择 保持现有职位组件 多选
部门控件 现有「部门」组件,值 { id, name }
显示/隐藏 设计器按子字段配置;隐藏不展示、不前端必填
隐藏与回写 隐藏字段若有默认/提交值,通过后 仍回写(设计器弱提示)
回写空值 某字段为空则 跳过该列,不清空主数据
回写失败 校验失败 不回滚 审批通过状态,记日志/告警

3. 信息模型

3.1 心智模型

┌─ 转正套件(confirmationKit / 容器)────────────────────┐
│  套件属性:子字段显示/隐藏                               │
│                                                         │
│  · datePicker     → 入职日期        ← 默认申请人         │
│  · inputNumber    → 试用期(月)    ← 默认申请人         │
│  · datePicker     → 转正日期        ← 自动建议,可改     │
│  · post           → 职位            ← 不默认,多选       │
│  · input          → 岗位职级        ← 空                 │
│  · input          → 姓名            ← 默认申请人         │
│  · input          → 邮箱            ← 默认申请人         │
│  · dept           → 部门            ← 默认主部门         │
│  · input          → 手机号          ← 默认申请人         │
└─────────────────────────────────────────────────────────┘
  • 选中 套件容器:配置显示字段等套件属性;运行时/发起页 不 额外渲染套件边框或标题。
  • 选中 子字段:标题、必填、校验等与普通组件相同。

3.2 子字段约定

语义 key 建议 title type 必填默认 回写
hireDate 入职日期 datePicker(仅日期,YYYY-MM-DD) 是 ✓ → hire_date
probationMonths 试用期(月) inputNumber,整数 ≥0 是 ✓ → probation_months
confirmationDate 转正日期 datePicker(仅日期) 否 ✗
post 职位 post(现有,多选) 否 ✗
jobLevel 岗位职级 input 否 ✗
name 姓名 input 是 ✓ → nick_name
email 邮箱 input 否 ✓ → email
dept 部门 dept(现有,建议单选) 是 ✓ → dept_id ← id
phone 手机号 input 否 ✓ → phone_no

插入时子字段 field 生成唯一 ID(同表单可多套,自动去重后缀)。语义识别优先稳定标记(如 props._fc_kit_field: 'hireDate'),避免仅依赖 title。

3.3 Schema 结构(示意)

{
  "type": "confirmationKit",
  "props": {
    "visibleFields": {
      "hireDate": true,
      "probationMonths": true,
      "confirmationDate": true,
      "post": true,
      "jobLevel": true,
      "name": true,
      "email": true,
      "dept": true,
      "phone": true
    }
  },
  "children": [
    {
      "type": "datePicker",
      "field": "hireDate_xxxx",
      "title": "入职日期",
      "props": {
        "_fc_kit_field": "hireDate",
        "type": "date",
        "valueFormat": "YYYY-MM-DD"
      },
      "$required": true
    },
    {
      "type": "inputNumber",
      "field": "probationMonths_xxxx",
      "title": "试用期(月)",
      "props": { "_fc_kit_field": "probationMonths", "min": 0, "precision": 0 },
      "$required": true
    },
    {
      "type": "datePicker",
      "field": "confirmationDate_xxxx",
      "title": "转正日期",
      "props": {
        "_fc_kit_field": "confirmationDate",
        "type": "date",
        "valueFormat": "YYYY-MM-DD",
        "confirmationDateManual": false
      },
      "$required": false
    },
    {
      "type": "post",
      "field": "post_xxxx",
      "title": "职位",
      "props": { "_fc_kit_field": "post", "multiple": true }
    },
    {
      "type": "input",
      "field": "jobLevel_xxxx",
      "title": "岗位职级",
      "props": { "_fc_kit_field": "jobLevel" }
    },
    {
      "type": "input",
      "field": "name_xxxx",
      "title": "姓名",
      "props": { "_fc_kit_field": "name" },
      "$required": true
    },
    {
      "type": "input",
      "field": "email_xxxx",
      "title": "邮箱",
      "props": { "_fc_kit_field": "email" }
    },
    {
      "type": "dept",
      "field": "dept_xxxx",
      "title": "部门",
      "props": { "_fc_kit_field": "dept", "multiple": false },
      "$required": true
    },
    {
      "type": "input",
      "field": "phone_xxxx",
      "title": "手机号",
      "props": { "_fc_kit_field": "phone" }
    }
  ]
}

容器为布局类,不计可填字段数;visibleFields 与子字段 hidden 保持同步(实现时二选一为主、另一派生即可,文档以「隐藏不展示」为准)。

3.4 值格式

字段 格式
日期 YYYY-MM-DD
试用期 整数
部门 { id, name }(全路径名称优先)
职位 与现有 post 一致(多选为数组)
姓名/邮箱/手机号/职级 字符串

4. 用户主数据

4.1 sys_user 增补

列 类型 说明
hire_date DATE NULL 入职日期
probation_months INT NULL 试用期月数(≥0)

同步范围:

  • SQLAlchemy SysUser、CRUD _row_to_dict、Create/Update Body
  • 用户管理新增/编辑弹窗可编辑;查看详情展示
  • userInfo / _build_user_info_payload 带出 hireDate、probationMonths
  • docs/sql/ 增量脚本;字段一致性检查

既有已具备且用户管理可编辑:nick_name(姓名)、email、dept_id、phone_no。

4.2 列表展示

  • 编辑弹窗:必须可维护入职日期、试用期。
  • 列表列:可选窄列或仅详情展示(实现时最小为弹窗 + 详情即可)。

5. 运行时

5.1 发起默认值

仅对 空字段 写入(不覆盖用户已填):

语义 来源
hireDate userInfo.hireDate
probationMonths userInfo.probationMonths
confirmationDate 入职 + 试用期可算则写入建议值;否则空
post 不填
jobLevel 空
name 显示名 / nickName
email email
dept 主部门 { id, name }(全路径优先)
phone phoneNo
  • 隐藏字段:仍按上表写入默认到 formData(便于通过后回写)。
  • 详情 / 已发起单:只展示已存 form_data,不按当前查看者覆盖。
  • 设计器画布:不依赖设计者登录身份作为业务默认。

5.2 转正日期联动

  • 算法:confirmationDate = hireDate 按自然月加 probationMonths(实现时与前端/后端同一工具函数,可单测)。
  • confirmationDateManual === false:入职日或试用期变化时重算并写回转正日。
  • 用户手改转正日 → confirmationDateManual = true,断开联动。
  • 提供「恢复自动计算」:清手动标记并立即重算。

5.3 显示 / 隐藏

  • 隐藏:发起/详情不渲染;前端不校验必填。
  • 默认值仍可写入 formData。
  • 通过后:若该语义在回写名单且值非空,照常回写。
  • 设计器弱提示:「隐藏且属于回写字段时,审批通过仍可能更新用户主数据。」

5.4 提交校验(发起)

  • 仅校验 可见 且必填的子字段。
  • 隐藏字段不拦必填。
  • 发布白名单纳入 confirmationKit;套件子节点缺失 → 警告可发(对齐请假)。

6. 审批通过后回写

6.1 触发

实例状态变为 全部通过 时调用:

apply_confirmation_kit_user_sync(db, instance)

挂在现有「通过」后置点,避免散落多 API。

6.2 流程

实例 → 全部通过
  → 扫描 form schema 中 confirmationKit
  → 解析 children 语义标记 → 从 form_data 取值
  → 目标用户 = 发起人 user_id
  → 有值则更新对应列;空则跳过
  → 格式校验失败:记日志,不回滚通过状态

6.3 映射

语义 sys_user 列
hireDate hire_date
probationMonths probation_months
name nick_name
email email
dept dept_id(取 id)
phone phone_no

不写:post、jobLevel、confirmationDate。

6.4 幂等与安全

  • 有值才更新,避免空值清空。
  • 租户隔离:仅更新本租户发起人。
  • 不信任客户端另传「回写目标用户」。
  • 手机号/邮箱校验对齐用户管理规则。

7. 设计器

7.1 套件 Tab

  • 卡片标题:转正(与请假并列)。
  • 拖入插入容器 + 9 子字段。

7.2 容器属性

  • 「显示字段」九项勾选(默认全开),同步子字段 hidden / visibleFields。
  • 隐藏回写提示文案见 §5.3。

7.3 子字段属性

  • 与普通同类型控件一致(含职位多选、部门单选)。
  • 转正日期可暴露「恢复自动计算」相关说明(运行时按钮也可挂在字段旁,实现时与请假时长 UX 对齐)。

8. 建议文件落点

区域 路径(示意)
套件容器 web-admin/src/components/oa-approval/OaConfirmationKit.vue
DragRule web-admin/src/utils/oa-confirmation-kit-rule.ts
注册 现有 kit 注册入口旁增加转正
默认值 + 联动 web-admin/src/utils/oa-confirmation-kit-runtime.ts
自然月加 前后端共享算法(前端 TS + 后端 Python,行为一致)
用户管理 web-admin/src/views/system/user/index.vue + API 类型
模型 / SQL SysUser + docs/sql/ 增量
userInfo backend _build_user_info_payload
回写服务 backend/app/services/oa_confirmation_kit_sync.py + 通过态钩子

9. 验收标准

  1. 用户管理可维护入职日期、试用期(月);userInfo 可带出。
  2. 套件 Tab 可拖「转正」;可隐藏部分字段。
  3. 发起:主数据六项自动填;职位为空;转正日可按规则建议;手改后断开,可恢复自动。
  4. 通过前主数据不变;通过后六项回写发起人;空字段不清空库。
  5. 隐藏字段的默认值在通过后仍可回写。
  6. 部门值为 {id,name};职位为现有多选控件。
  7. 回写失败不撤销审批通过状态。

10. 开放实现细节(不阻塞产品)

  • 列表是否增加「入职日期」列:实现时最小范围可不加列。
  • 「恢复自动计算」是字段旁链接还是属性面板说明:对齐请假时长即可。
  • visibleFields 与子字段 hidden 以何者为 source of truth:实现选一并在 runtime 归一化。