|
@@ -0,0 +1,142 @@
|
|
|
|
|
+# 报销明细「发生时间」字段 — 设计文档
|
|
|
|
|
+
|
|
|
|
|
+> **日期**: 2026-08-17
|
|
|
|
|
+> **状态**: 已确认设计(待实现)
|
|
|
|
|
+> **仓库**: shanxia2.0(`backend/` + `web-admin/` + `bx-mobile/`)
|
|
|
|
|
+> **入口页**: `http://localhost:3006/#/bx/reimburse/apply`
|
|
|
|
|
+
|
|
|
|
|
+## 背景与问题
|
|
|
|
|
+
|
|
|
|
|
+报销申请「新增 / 编辑」弹窗的报销明细当前列为:序号、费用项目、金额、报销事由、操作。
|
|
|
|
|
+客户希望在「报销事由」后增加可选字段「发生时间」,可填可不填;精度为年月日。
|
|
|
|
|
+
|
|
|
|
|
+## 已确认决策
|
|
|
|
|
+
|
|
|
|
|
+| # | 决策 | 说明 |
|
|
|
|
|
+|---|------|------|
|
|
|
|
|
+| D1 | **独立字段** | 表 `bx_reimburse_detail` 新增可空 `occur_date`(DATE),不用拼进 `remark` |
|
|
|
|
|
+| D2 | **仅年月日** | API / 前端统一 `YYYY-MM-DD`;不做时分秒 |
|
|
|
|
|
+| D3 | **可选** | 不校验必填;空串 / null → 库 `NULL` |
|
|
|
|
|
+| D4 | **只读空值** | 始终展示该列/字段,空显示为 `—` |
|
|
|
|
|
+| D5 | **三端一致** | backend + web-admin + bx-mobile 同步读写与展示 |
|
|
|
|
|
+| D6 | **不做** | 列表筛选、导出、未来日期限制、主表列、列表卡片摘要 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 一、目标与范围
|
|
|
|
|
+
|
|
|
|
|
+### 目标
|
|
|
|
|
+
|
|
|
|
|
+每条报销明细可记录可选的费用发生日期,并在申请录入与各只读明细场景一致展示。
|
|
|
|
|
+
|
|
|
|
|
+### 范围内
|
|
|
|
|
+
|
|
|
|
|
+- 库表 / Model / Schema / API 写入与回读
|
|
|
|
|
+- Web:申请弹窗录入 + 查看弹窗;审批页与 view(mine/todo/all)明细表
|
|
|
|
|
+- Mobile:申请页录入;详情页与审批页明细展示
|
|
|
|
|
+
|
|
|
|
|
+### 范围外
|
|
|
|
|
+
|
|
|
|
|
+- 列表筛选 / 导出 / 打印
|
|
|
|
|
+- `ApprovalDetailPage`(当前未展示报销明细分列,不改)
|
|
|
|
|
+- 历史数据回填(存量保持 `NULL`)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 二、数据模型与 API
|
|
|
|
|
+
|
|
|
|
|
+### 2.1 表字段
|
|
|
|
|
+
|
|
|
|
|
+`bx_reimburse_detail` 新增:
|
|
|
|
|
+
|
|
|
|
|
+| 列名 | 类型 | 可空 | 位置 | 注释 |
|
|
|
|
|
+|------|------|------|------|------|
|
|
|
|
|
+| `occur_date` | `date` | YES | `amount` 之后、`tenant_no` 之前 | 费用发生日期 |
|
|
|
|
|
+
|
|
|
|
|
+存量行:`occur_date = NULL`。
|
|
|
|
|
+
|
|
|
|
|
+### 2.2 DDL 与快照
|
|
|
|
|
+
|
|
|
|
|
+- 迁移脚本:`backend/scripts/migrate_20260817_bx_reimburse_detail_occur_date.sql`
|
|
|
|
|
+- 同步更新:`docs/sql/shanxia2.0.sql` 中 `bx_reimburse_detail` 表定义
|
|
|
|
|
+
|
|
|
|
|
+### 2.3 Model / Schema
|
|
|
|
|
+
|
|
|
|
|
+- Model:`BxReimburseDetail.occur_date`(nullable Date)
|
|
|
|
|
+- `ReimburseDetailCreate.occur_date: Optional[str] = None`
|
|
|
|
|
+- `ReimburseDetailOut.occur_date: OptDateToStr = None`(序列化为 `YYYY-MM-DD` 或 null)
|
|
|
|
|
+- JSON 驼峰别名:`occurDate`
|
|
|
|
|
+
|
|
|
|
|
+### 2.4 写入链路
|
|
|
|
|
+
|
|
|
|
|
+1. `api/bx/reimburse.py` → `_build_details_data` 透传 `occur_date`
|
|
|
|
|
+2. `services/bx/reimburse.py` → `create_with_details` / `update_with_details` 写入明细
|
|
|
|
|
+3. 解析:空 → `NULL`;非空按与 `reimburse_date` 同类的日期解析(`YYYY-MM-DD`)
|
|
|
|
|
+4. 出参:`ReimburseDetailOut.model_validate` 自然带出(字段挂在 Model 上即可)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 三、前端交互
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 列 / 字段顺序
|
|
|
|
|
+
|
|
|
|
|
+费用项目 → 金额 → 报销事由 → **发生时间** →(操作列,仅编辑表)
|
|
|
|
|
+
|
|
|
|
|
+### 3.2 web-admin
|
|
|
|
|
+
|
|
|
|
|
+**录入** — `views/bx/reimburse/apply/index.vue`
|
|
|
|
|
+
|
|
|
|
|
+- 明细表新增「发生时间」列(无必填星号)
|
|
|
|
|
+- `el-date-picker`:`type="date"`,`value-format="YYYY-MM-DD"`,可清空
|
|
|
|
|
+- `DetailLine`、提交 payload、编辑回填增加 `occurDate`
|
|
|
|
|
+- 不做必填校验
|
|
|
|
|
+
|
|
|
|
|
+**只读**(始终显示列,空为 `—`)
|
|
|
|
|
+
|
|
|
|
|
+- 同页查看弹窗明细表
|
|
|
|
|
+- `views/bx/reimburse/approve/index.vue`
|
|
|
|
|
+- `views/bx/view/mine|todo|all/index.vue`
|
|
|
|
|
+
|
|
|
|
|
+### 3.3 bx-mobile
|
|
|
|
|
+
|
|
|
|
|
+**录入** — `ReimburseApplyPage.vue`:报销事由后增加发生时间日期选择(可清空);提交/回填带 `occurDate`。
|
|
|
|
|
+
|
|
|
|
|
+**只读**(始终显示,空为 `—`)
|
|
|
|
|
+
|
|
|
|
|
+- `ReimburseDetailPage.vue`
|
|
|
|
|
+- `ReimburseApprovePage.vue`
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 四、改动文件清单
|
|
|
|
|
+
|
|
|
|
|
+| 层 | 文件 |
|
|
|
|
|
+|----|------|
|
|
|
|
|
+| DB | `backend/scripts/migrate_20260817_bx_reimburse_detail_occur_date.sql` |
|
|
|
|
|
+| DB 快照 | `docs/sql/shanxia2.0.sql` |
|
|
|
|
|
+| Model | `backend/app/models/bx_models.py` |
|
|
|
|
|
+| Schema | `backend/app/schemas/bx/reimburse.py` |
|
|
|
|
|
+| API | `backend/app/api/bx/reimburse.py` |
|
|
|
|
|
+| Service | `backend/app/services/bx/reimburse.py` |
|
|
|
|
|
+| Web | `web-admin/src/views/bx/reimburse/apply/index.vue` |
|
|
|
|
|
+| Web | `web-admin/src/views/bx/reimburse/approve/index.vue` |
|
|
|
|
|
+| Web | `web-admin/src/views/bx/view/mine/index.vue` |
|
|
|
|
|
+| Web | `web-admin/src/views/bx/view/todo/index.vue` |
|
|
|
|
|
+| Web | `web-admin/src/views/bx/view/all/index.vue` |
|
|
|
|
|
+| Mobile | `bx-mobile/src/views/reimburse/ReimburseApplyPage.vue` |
|
|
|
|
|
+| Mobile | `bx-mobile/src/views/reimburse/ReimburseDetailPage.vue` |
|
|
|
|
|
+| Mobile | `bx-mobile/src/views/reimburse/ReimburseApprovePage.vue` |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 五、验收要点
|
|
|
|
|
+
|
|
|
|
|
+1. 新增/编辑:可填、可清空发生时间;不填可保存与提交。
|
|
|
|
|
+2. 各只读明细场景:有值显示 `YYYY-MM-DD`,无值显示 `—`。
|
|
|
|
|
+3. Web 与 bx-mobile 行为一致。
|
|
|
|
|
+4. 旧单据明细为空时展示 `—`,编辑其他字段不受影响。
|
|
|
|
|
+
|
|
|
|
|
+## 六、错误处理
|
|
|
|
|
+
|
|
|
|
|
+- 非法日期格式:后端解析失败时返回 400(与现有报销日期解析策略一致)。
|
|
|
|
|
+- 前端 date-picker 正常情况下只产出合法 `YYYY-MM-DD` 或空。
|