新增工资/仓储/生产日报等模块,移除旧考勤模块
- 新增 PayRoll(工资)、Wms(仓储)、Prod(车速/缫丝/考勤/丝片检测/丝片台账/纤检日报/质量日报) 模块 - 新增对应 Domain 实体、Application DTO/Service、Api Controller 与前端页面 - 移除旧 Attendance 考勤模块(Controller/Service/Entity/DTO 及 5 个前端页面),由 Prod/Kaoqin 取代 - 调整路由、仪表盘、Lsjl 流丝记录实体与服务 - 更新业务种子数据与 DbSeeder - 补充工作进度文档 14-27
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
# 工作进度-14:生产-前缫「煮茧日报」落地
|
||||
|
||||
> 时间:2026-10-22(承接工作进度-13)
|
||||
> 需求:把 `D:\AntaiProject - 副本` 生产-前缫的「煮茧日报(ZJRB)」移植进本系统。
|
||||
> 参考实现:`WinClient\F9.Business.Prod\QS\ZJRB\`(Page_Zjrb、Page_Zjrb_EditV2)、
|
||||
> `Application\CQRS\Business\PROD\QS\ZJRB\`(Zjrb_SaveCommand / Zjrb_DelCommand / CalculateJizuSaosiHoursCommand)、
|
||||
> `Domain\Entities\Business\PROD\QS\`(Zjrb / ZjrbJizu / Zjrb_Banci / ZjrbJizuBanci)。
|
||||
|
||||
---
|
||||
|
||||
## 一、功能设计
|
||||
|
||||
```
|
||||
生产-前缫
|
||||
├── 机组车台
|
||||
├── 落丝记录
|
||||
├── 车间班次
|
||||
├── 看台排班
|
||||
├── 看台记录
|
||||
└── 煮茧日报(本次新增) /prod/qianxian/zjrb
|
||||
过滤:账期(月份)+ 车间(前缫)+ 庄口/规格关键字
|
||||
主表:日期、上日、车间、庄口、规格;上存/领入/今缫/退回/今存(包数 + 重量,多级表头)
|
||||
选中行 → 下方联动展示该日报的「机组」桶数明细(含合计行)
|
||||
按钮:删除、新增、修改、计算缫丝时长
|
||||
```
|
||||
|
||||
| F9 行为 | 本系统实现 |
|
||||
|---|---|
|
||||
| 列表按「账期(月份)+ 车间 + 关键字」查询,无分页 | 同口径,另加后端分页(`pageIndex/pageSize`) |
|
||||
| 上表主表 + 下表机组联动(点击行刷新机组) | 同左(主表 `row-click` → `GET /{id}/jizus`) |
|
||||
| `删除`:四张表级联删除 | `DELETE /api/prod/zjrb/{id}`(主表 + 班次 + 机组 + 机组班次物理删除) |
|
||||
| `新增`:按上一日结存带出上存、每桶茧量、工艺落丝桶数 | `GET /defaults?date=&depId=&gyzkId=&guige=` |
|
||||
| `修改`:回填主表 + 班次 + 机组 + 机组班次 | `GET /{id}` |
|
||||
| `保存`:主表 + 三层明细一起提交 | `POST /save`(主表 upsert + 三层明细先删后建) |
|
||||
| `计算缫丝时长`:按「日期 + 车间」整日重算 | `POST /calculate-saosi-hours?date=&depId=` |
|
||||
|
||||
**计算口径**(移植 `Page_Zjrb_EditV2` 的 `CalItem` / `Cal_Zhibiao` / `Cal_Zhibiao_Main`,前后端同口径、服务端保存时重算):
|
||||
|
||||
```
|
||||
机组.今缫桶数 = 甲班今缫 + 乙班今缫
|
||||
机组.今存桶数 = 上存 + 今缫 − 今落
|
||||
(今落为 0 且余量 ≥ 工艺落丝桶数时,自动把今落置为工艺落丝桶数再扣减)
|
||||
班次.今缫重量 = 该班次机组今缫桶数 × 每桶茧量 ÷ 1000 (每桶茧量单位 g,重量 kg)
|
||||
班次.领入/退回重量 = 包数 × 联统茧标重
|
||||
班次.今缫包数 = 今缫重量 ÷ 联统茧标重(四舍五入取整)
|
||||
班次.今存 = 上存 + 领入 − 今缫 − 退回
|
||||
主表 = 甲班 + 乙班(包数/重量各 5 项)
|
||||
```
|
||||
|
||||
**校验**(对齐 F9 `AddValidRules`,前端拦截 + 服务端兜底):每桶茧量 > 0、工艺落丝桶数 > 0、上存包数 > 0 时上存重量必须 > 0、机组今缫桶数 > 0 时缫丝时长必须 > 0、机组缫丝时长 ≤ 20、同「日期 + 车间 + 庄口 + 规格」唯一。
|
||||
|
||||
---
|
||||
|
||||
## 二、后端
|
||||
|
||||
### 2.1 实体(`Domain/Entities/Prod/Zjrb.cs`)
|
||||
|
||||
| 类 | 表 | 主要字段 |
|
||||
|---|---|---|
|
||||
| `ZjrbRecord` | `ZjrbRecords` | Date、DeptId、GyzkId、Guige、LastDate、StandardLuositongshu、MeitongJianliang + 包数/重量各 5 项 |
|
||||
| `ZjrbJizu` | `ZjrbJizus` | ZjrbId、Jizu、JizuSaosiHours、TongshuShangcun/Jinsao/Jinluo/Jincun |
|
||||
| `ZjrbBanci` | `ZjrbBancis` | ZjrbId、Banci(甲/乙)、包数/重量各 5 项 |
|
||||
| `ZjrbJizuBanci` | `ZjrbJizuBancis` | ZjrbId、ZjrbJizuId、Jizu、Banci、TongshuJinsao |
|
||||
|
||||
> 均继承 `BaseEntity`(自增主键 + 软删除),表结构由启动时 `CodeFirst.SyncStructure` 自动创建,无需迁移。
|
||||
> F9 的 `Zjrb_Banci.BanciId`(指向车间班次)在本系统直接落 `Prod_Banci_Enum`(甲=1/乙=2),与看台排班/看台记录一致。
|
||||
|
||||
### 2.2 服务与接口(`ZjrbService` / `ZjrbController`,路由 `api/prod/zjrb`)
|
||||
|
||||
```
|
||||
GET /api/prod/zjrb/list?dateFrom=&dateTo=&depId=&like=&pageIndex=&pageSize=
|
||||
GET /api/prod/zjrb/{id} 修改回填(主表 + 班次 + 机组)
|
||||
GET /api/prod/zjrb/{id}/jizus 机组明细(列表页下半表)
|
||||
GET /api/prod/zjrb/defaults?date=&depId=&gyzkId=&guige= 新增默认值
|
||||
POST /api/prod/zjrb/save 整条保存
|
||||
DELETE /api/prod/zjrb/{id} 级联删除
|
||||
POST /api/prod/zjrb/calculate-saosi-hours?date=&depId= 计算缫丝时长
|
||||
```
|
||||
|
||||
- 新增默认值来源:同「车间 + 庄口(+ 规格)」下 `Date < 目标日期` 的最近一条日报
|
||||
→ 上存包数/重量 = 上一日今存;每桶茧量、工艺落丝桶数、`LastDate` 一并继承;
|
||||
班次行按「车间班次」配置(未配置则甲乙两班)生成,机组行按「机组车台」生成;
|
||||
- 联统茧标重取参数配置 `生产\前缫\煮茧 → 联统茧标重`(本库已配置为 18),随默认值/回填一并下发,弹窗内可临时调整;
|
||||
- `CalculateJizuSaosiHours` 算法(对齐 F9):机组「今缫桶数 > 0」的班次数为 2 → 18 小时,否则 9 小时;
|
||||
按「庄口 + 规格 + 机组」分组,以 `Σ(每桶茧量 × 机组今缫桶数)` 为权重把机组总时长按比例分配到各条日报的机组行。
|
||||
|
||||
### 2.3 菜单
|
||||
|
||||
`DbSeeder.SeedProdMenus` 生产-前缫子菜单新增第 6 项,并做排序归一:
|
||||
|
||||
| 顺序 | 菜单 | 路径 | 组件 | 权限标识 |
|
||||
|---|---|---|---|---|
|
||||
| 6 | 煮茧日报 | /prod/qianxian/zjrb | prod/zjrb/index | prod:zjrb:list |
|
||||
|
||||
启动日志:`[DbSeeder] 生产模块菜单已就绪(生产-前缫 / 生产-后缫)`,`/auth/menus` 已返回 6 个子菜单。
|
||||
|
||||
---
|
||||
|
||||
## 三、前端
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `views/prod/zjrb/index.vue` | 日报列表(账期月份 + 车间 + 关键字)、主表多级表头、选中行联动机组明细、合计行、删除/新增/修改/计算缫丝时长 |
|
||||
| `views/prod/zjrb/ZjrbEditDialog.vue` | 录入弹窗:基础信息 + 班次网格(甲乙班 5 组包数重量)+ 机组网格(时长/上存/甲乙班今缫/今落),改动即时重算 |
|
||||
| `router/index.js` | `componentMap` 注册 `prod/zjrb/index` |
|
||||
|
||||
交互要点:
|
||||
- 新增时选「工艺庄口 / 规格」后自动带出上一日结存与机组行,并用 `ElMessage` 提示「未维护机组车台」等异常;
|
||||
- 弹窗内今缫重量/今缫包数/今存/今缫桶数/今存桶数均为只读派生值,避免与口径冲突;
|
||||
- 删除与计算缫丝时长均二次确认(计算会覆盖该日该车间全部机组时长)。
|
||||
|
||||
---
|
||||
|
||||
## 四、验证记录
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| `dotnet build`(Domain/Application/Infrastructure) | ✅ 0 错误 |
|
||||
| `dotnet build`(Api,临时输出目录,规避运行中进程文件锁) | ✅ 0 错误 |
|
||||
| `vite build` | ✅ 通过(仅既有体积/SignalR 注释警告) |
|
||||
| 菜单 | ✅ 生产-前缫 6 个子菜单,煮茧日报排第 6 |
|
||||
| 保存(甲乙班 + 2 机组,每桶茧量 600g、标重 18) | ✅ 主表今缫 = round(54/18) = 3 包 / 54 kg;主表五组值 = 甲乙相加 |
|
||||
| 机组今存自动补落丝 | ✅ 机组 上存 50 + 今缫 60 = 110 < 170(工艺落丝桶数)→ 今落 0、今存 110 |
|
||||
| 计算缫丝时长 | ✅ 机组1(单班)9 h、机组2(甲乙班均有今缫)18 h,提示「已更新 1 条机组缫丝时长」 |
|
||||
| 新增默认值 | ✅ 次日带出:上日 2026-10-22、上存 28 包 / 1686 kg、机组上存 110 / 110、每桶茧量 600、落丝桶数 170、标重 18 |
|
||||
| 唯一性 | ✅ 同「日期 + 车间 + 庄口 + 规格」再存返回 400「已存在相同的煮茧日报!」 |
|
||||
| 修改 | ✅ 甲班领入 20 → 30 包后:今存 36 + 14 = 50 包 / 1068 + 456 = 1524 kg |
|
||||
| 删除 | ✅ 删除后列表为该日 0 条、回读返回「煮茧日报不存在或已删除」 |
|
||||
| 删除后重建无残留 | ✅ 机组桶数 90 / 130 / 0 / 220 未翻倍(三层明细先删后建生效) |
|
||||
| 测试数据清理 | ✅ 验证用日报已全部删除,未在库中留下业务数据 |
|
||||
|
||||
> 验证方式:用 `-p:BaseOutputPath=obj\verify\` 另编一份 Api,在 3001 端口以真实库启动(`ConnectionStrings__Default` + `Kestrel__Endpoints__Http__Url` 覆盖),验证完已停止该实例。
|
||||
> 3000 端口的后端进程已重启(旧进程无 `api/prod/zjrb` 控制器,首次进入菜单会 404 并提示「请求失败,请稍后重试」);重启后 `GET /api/prod/zjrb/list` 返回 200,`/auth/menus` 生产-前缫为 6 项。
|
||||
|
||||
---
|
||||
|
||||
## 五、说明与后续
|
||||
|
||||
1. **未导入历史数据**:本次没有随附煮茧日报的导出数据(xlsx/csv),故未做 `ProdSeedData` 扩展;如需把 F9 的 `biz_prod_qs_zjrb*` 四张表导入,可按工作进度-13 的 CSV 内嵌 + 幂等策略追加(主表按「日期+车间+庄口+规格」、机组按「日期+机组」、班次按「日期+班次」)。
|
||||
2. **保存语义更严格**:F9 的 `Zjrb_SaveCommand` 是逐行 upsert(前端删行不会落库),本系统为「整条替换」(三层明细先删后建),行被移除时会真正删除。
|
||||
3. **机组行不再过滤全 0 行**:与 F9 现用保存命令一致(旧 `CreateZjrbCommand` 会过滤三桶数全 0 的机组行)。
|
||||
4. **联统茧标重**:读取参数配置 `生产\前缫\煮茧 → 联统茧标重`(当前 18);未配置时重量换算按录入值保留,不会清零。
|
||||
5. **待接入**:① 计件工资(F9 `CalcLdcct` 用「机组班次今缫桶数 × 每桶茧量」)已具备数据基础,可在薪酬模块直接取用;② 落丝记录联动(F9 用煮茧的每桶茧量/机组落丝桶数回填落丝记录)——本系统落丝记录暂无桶数/每桶茧量字段,需先扩展;③ 报表「煮茧日报月报 / 机组缫丝时长 / 联统茧盈亏」可基于 `ZjrbRecords + ZjrbJizus` 直接做数据源。
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
# 工作进度-15:生产-后缫完善(秤大丝 / 公量纤度 / 丝片检查 / 丝片台帐)
|
||||
|
||||
> 时间:2026-10-24(承接工作进度-14)
|
||||
> 需求:把 `D:\AntaiProject - 副本` 生产-后缫(`WinClient\F9.Business.Prod\HS\`)尚未落地的模块移植进本系统。
|
||||
> 参考实现:`WinClient\F9.Business.Prod\HS\`(CDS / GLXD / SPJC / SPTZ)、
|
||||
> `Application\CQRS\Business\PROD\HS\`(Cds_SaveCommand / Cds_Lsjl_CalZhibiaoCommand / Glxd_Update / Spjc_*/Sptz_*)、
|
||||
> `Domain\Entities\Business\PROD\HS\`(Cds_Chetai / Cds_Lsjl / Glxd / Spjc / Sptz)。
|
||||
> 移植后本系统「生产-后缫」子菜单由 2 项补齐到 6 项。
|
||||
|
||||
---
|
||||
|
||||
## 一、功能设计
|
||||
|
||||
```
|
||||
生产-后缫
|
||||
├── 纤度检验 (已有)
|
||||
├── 黑板检验 (已有)
|
||||
├── 秤大丝 /prod/houxian/cds 本次新增
|
||||
├── 公量纤度 /prod/houxian/glxd 本次新增
|
||||
├── 丝片检查 /prod/houxian/spjc 本次新增
|
||||
└── 丝片台帐 /prod/houxian/sptz 本次新增
|
||||
```
|
||||
|
||||
| F9 行为 | 本系统实现 |
|
||||
|---|---|
|
||||
| **秤大丝**:列表按「日期 + 车间」列出落丝记录,行 → 弹窗「秤大丝」,按车台录入丝量1~4 | `GET /api/prod/cds/list`、`GET /{lsjlId}`、`POST /save`、`DELETE /{lsjlId}` |
|
||||
| 汇总 = Σ个数 / Σ丝量,并算茧量、缫折、台产(`Cds_Lsjl_CalZhibiaoCommand`) | 服务端保存时重算,列表直接展示 |
|
||||
| **公量纤度**:按「日期 + 车间」整日批量录入,左侧带出纤度检验的平均纤度 | `GET /api/prod/glxd/list`、`POST /save`(整日提交) |
|
||||
| **丝片检查**:按「日期 + 车间 + 工艺庄口 + 规格」记录前缫 7 项 / 后缫 12 项疵点片数 | `GET /api/prod/spjc/list`、`GET /{id}`、`POST /save`、`DELETE /{id}` |
|
||||
| 前缫合计 / 后缫合计自动求和(`Page_Spjc_Edit` 的 getter) | 前端即时重算 + 服务端落库前再算一次 |
|
||||
| **丝片台帐**:按账期月份列出每日台帐;新增时上一日 / 上存取上一本台账 | `GET /api/prod/sptz/list?dateFrom=&dateTo=`、`GET /defaults?date=`、`POST /save`、`DELETE /{id}` |
|
||||
| 台帐派生值:上日遗留/今日新增 = 上存 − 浸丝;今存 = 下丝 + 上日遗留/今日新增 | 前端即时算 + 服务端保存时重算(同 F9 `CalSryl_Jrxz` / `CalJc`) |
|
||||
| 台帐「整理片数」可按当日丝片检查汇总取数(F9 弹窗里的取数按钮) | `GET /defaults` 一并返回 `zlTichu` / `zlZhengpin` |
|
||||
| 新增台帐时若已存在更晚日期的台帐 → 拦截 | 同上(`LatestDate`),前端也做二次校验 |
|
||||
|
||||
**计算口径**:
|
||||
|
||||
```
|
||||
秤大丝:车台.个数 = 丝量1~4 中 >0 的个数;车台.小计丝量 = Σ丝量
|
||||
汇总.已秤数 = Σ个数;汇总.已秤丝量 = Σ小计丝量(g)
|
||||
应秤数 = 车台数 × 4 ×(半车 0.5 / 整车 1);待秤数 = 应秤数 − 已秤数
|
||||
茧量 = 落丝桶数 × 每桶茧量(g)
|
||||
缫折 = 茧量 ÷ 丝量 × 100(≤100 视为异常,不落指标,与 F9 一致)
|
||||
台产 = 丝量 ÷ 落丝时长 ÷ 车台数
|
||||
丝片台帐:上日遗留/今日新增 = 上存 − 浸丝;今存 = 下丝 + 上日遗留/今日新增
|
||||
整理剔除 = Σ当日丝片检查前缫合计
|
||||
整理正品 = Σ(总片数 + 学工片数) − 剔除
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、后端
|
||||
|
||||
### 2.1 实体(`Domain/Entities/Prod/`)
|
||||
|
||||
| 类 | 文件 | 表 | 主要字段 |
|
||||
|---|---|---|---|
|
||||
| `CdsLsjl` | `Cds.cs` | `CdsLsjls` | LsjlId(唯一)、Num、Siliang、Jianliang、Saozhe、Taichan |
|
||||
| `CdsChetai` | `Cds.cs` | `CdsChetais` | LsjlId + Chetaihao(唯一)、Sl1~Sl4、Num、Siliang |
|
||||
| `Glxd` | `Glxd.cs` | `Glxds` | LsjlId(唯一)、Gongliangxiandu |
|
||||
| `Spjc` | `Spjc.cs` | `Spjcs` | Date + DeptId + GyzkId + Guige(唯一)、总/学工片数、Qs×7 + QsHeji、Hs×12 + HsHeji、Memo |
|
||||
| `Sptz` | `Sptz.cs` | `Sptzs` | Date(唯一)、DateLast、Js×5、Fs/Bs 片数、Zl 正品/剔除、Memo |
|
||||
| `LsjlRecord` | `LsjlRecord.cs` | `LsjlRecords` | **新增**:Tongshu(落丝桶数)、Meitongjianliang(每桶茧量 g) |
|
||||
|
||||
> 均继承 `BaseEntity`(自增主键 + 软删除),建表沿用 `DbSeeder.SyncStructure`;
|
||||
> `LsjlRecords` 是存量表,`SyncStructure` 不给旧表加列,故在 `SyncStructure` 末尾追加两条
|
||||
> `EnsureColumn(fsql, "LsjlRecords", "Tongshu"/"Meitongjianliang", "INTEGER NOT NULL DEFAULT 0")`。
|
||||
|
||||
### 2.2 服务与接口(路由统一到 `api/prod/*`)
|
||||
|
||||
```
|
||||
GET /api/prod/cds/list?pageIndex=&pageSize=&date=&deptId= 秤大丝列表(落丝记录 + 秤丝汇总)
|
||||
GET /api/prod/cds/{lsjlId} 称重弹窗(首次按车台范围初始化空行)
|
||||
POST /api/prod/cds/save 车台明细先删后建 + 汇总指标重算
|
||||
DELETE /api/prod/cds/{lsjlId} 清除称重数据(汇总 + 明细,F9 的 Cds_Lsjl_Delete)
|
||||
|
||||
GET /api/prod/glxd/list?date=&deptId= 公量纤度列表(含纤度检验平均纤度)
|
||||
POST /api/prod/glxd/save 按日期 + 车间整日批量 upsert
|
||||
|
||||
GET /api/prod/spjc/list?pageIndex=&pageSize=&date=&deptId=&like=
|
||||
GET /api/prod/spjc/{id} 修改回填
|
||||
POST /api/prod/spjc/save 合计服务端重算
|
||||
DELETE /api/prod/spjc/{id} 物理删除(业务键带唯一索引)
|
||||
|
||||
GET /api/prod/sptz/list?dateFrom=&dateTo=&pageIndex=&pageSize= 账期区间查询
|
||||
GET /api/prod/sptz/{id} 修改回填
|
||||
GET /api/prod/sptz/defaults?date= 上一本台账 + 上存 + 丝片检查取数
|
||||
POST /api/prod/sptz/save 派生值服务端重算
|
||||
DELETE /api/prod/sptz/{id} 物理删除(日期唯一)
|
||||
```
|
||||
|
||||
要点:
|
||||
- 唯一性校验在前:丝片检查按「日期+车间+庄口+规格」、丝片台帐按「日期」查重(修改时排除自身),命中返回 400;
|
||||
- 删除走 `HardDelete`(与煮茧日报同一策略),避免「删除后重建」撞唯一索引;
|
||||
- 秤大丝「车台明细先删后建」,保证移除的行真正删除。
|
||||
|
||||
### 2.3 菜单
|
||||
|
||||
`DbSeeder.SeedProdMenus` 生产-后缫子菜单扩到 6 项,并做排序归一;`BusinessSeedData.SeedMenus` 同步追加同名菜单,避免两套种子不一致:
|
||||
|
||||
| 顺序 | 菜单 | 路径 | 组件 | 权限标识 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 纤度检验 | /prod/houxian/xdjy | prod/xdjy/index | prod:xdjy:list |
|
||||
| 2 | 黑板检验 | /prod/houxian/hbjy | prod/hbjy/index | prod:hbjy:list |
|
||||
| 3 | 秤大丝 | /prod/houxian/cds | prod/cds/index | prod:cds:list |
|
||||
| 4 | 公量纤度 | /prod/houxian/glxd | prod/glxd/index | prod:glxd:list |
|
||||
| 5 | 丝片检查 | /prod/houxian/spjc | prod/spjc/index | prod:spjc:list |
|
||||
| 6 | 丝片台帐 | /prod/houxian/sptz | prod/sptz/index | prod:sptz:list |
|
||||
|
||||
---
|
||||
|
||||
## 三、前端
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `views/prod/cds/index.vue` | 秤大丝列表(日期 + 车间)+ 称重弹窗(车台 × 丝量1~4、个数/小计即时重算、汇总栏、偏轻/偏重着色)+ 清除称重 |
|
||||
| `views/prod/glxd/index.vue` | 公量纤度:按「日期 + 车间」一次加载,表格内直接编辑,整日批量保存 |
|
||||
| `views/prod/spjc/index.vue` | 丝片检查:多级表头(前缫 / 后缫)+ 新增/修改/删除弹窗(合计只读实时汇总)+ 工艺庄口选择页 |
|
||||
| `views/prod/sptz/index.vue` | 丝片台帐:账期月份查询 + 多级表头(浸丝/返丝/编丝/整理)+ 新增/修改/删除,派生值只读,「取丝片检查」按钮 |
|
||||
| `views/prod/lsjl/index.vue` | 落丝记录表单补「落丝桶数 / 每桶茧量」(秤大丝算茧量、缫折、台产的输入) |
|
||||
| `router/index.js` | `componentMap` 注册 `prod/cds/index`、`prod/glxd/index`、`prod/spjc/index`、`prod/sptz/index` |
|
||||
|
||||
交互要点:
|
||||
- 丝量 ≤900 g 标绿(偏轻)、≥1200 g 标橙(偏重),与 F9 `CellFormatting` 一致;
|
||||
- 丝片检查 / 丝片台帐的合计、上日遗留今日新增、今存均为只读派生值,避免与服务端口径冲突;
|
||||
- 丝片台帐新增时不允许早于已有最新台账日期(对齐 F9「已生成 X 台账,无法新增该日期台账」)。
|
||||
|
||||
---
|
||||
|
||||
## 四、验证记录
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| `dotnet build`(Domain / Application / Infrastructure) | ✅ 0 错误 |
|
||||
| `dotnet build`(Api,临时输出目录 `obj\verify\`) | ✅ 0 错误 |
|
||||
| IDE 诊断(新增 4 个 vue + `router/index.js` + `lsjl/index.vue`) | ✅ 0 |
|
||||
| `vite build` | ✅ 通过(仅既有 chunk 体积警告) |
|
||||
| 启动种子 | ✅ `[DbSeeder] 生产模块菜单已就绪`,无结构同步异常;`EnsureColumn` 补列生效 |
|
||||
| 菜单与权限 | ✅ `/auth/login` 返回的 permissions 含 `prod:cds:list` / `prod:glxd:list` / `prod:spjc:list` / `prod:sptz:list` |
|
||||
| 四个列表接口 | ✅ 200(`cds` total=3、`glxd` / `spjc` / `sptz` 空表 200) |
|
||||
| 丝片检查保存 | ✅ 前缫合计 13、后缫合计 55(服务端重算) |
|
||||
| 丝片检查唯一性 | ✅ 同「日期+车间+庄口+规格」再存被拒(400),未产生第二条 |
|
||||
| 丝片台帐派生值 | ✅ 上存 120 − 浸丝 40 = 80;下丝 80 + 80 = 今存 160 |
|
||||
| 丝片台帐滚动 | ✅ 次日 `defaults`:`dateLast=2026-10-20`、`jsShangcun=160`(= 上一日今存) |
|
||||
| 丝片台帐取数 | ✅ 当日丝片检查 Σ前缫合计 = 13 → 剔除 13;Σ(总片数+学工片数) 110 − 13 = 正品 97 |
|
||||
| 秤大丝称重 | ✅ 车台 21(900/1100)+ 22(1000)→ 已秤数 3、已秤丝量 3000 g |
|
||||
| 秤大丝指标 | ✅ 茧量 100×600 = 60000、缫折 = 60000/3000×100 = 2000、台产 = 3000/9/20 = 16.67 |
|
||||
| 删除后无残留 | ✅ 删除秤大丝/丝片检查/丝片台帐后列表回到 0 条,「删除后重建」不再撞唯一索引 |
|
||||
| 测试数据清理 | ✅ 验证用的丝片检查、丝片台帐、秤大丝数据已全部删除;`LsjlRecords.Tongshu/Meitongjianliang` 已还原为 0 |
|
||||
|
||||
> 验证方式:另编一份 Api 到 `obj\verify\`,以真实库在 3000 端口启动(原无进程占用该端口),验证完已停止实例并删除临时输出与日志。
|
||||
> Node 不在默认 PATH 里,需先 `set PATH=C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6;%PATH%` 才能跑 vite;最终 `vite build` 已通过。
|
||||
|
||||
---
|
||||
|
||||
## 五、说明与后续
|
||||
|
||||
1. **落丝记录新增两个字段**:`Tongshu`(落丝桶数)、`Meitongjianliang`(每桶茧量)是秤大丝算茧量/缫折/台产的必需输入,F9 的 `Lsjl` 实体也有这两个字段(本系统此前漏移植),已在落丝记录表单补上录入项。
|
||||
2. **秤大丝删除**:F9 客户端没有删除按钮(只有 `Cds_Lsjl_DeleteCommand` 未暴露),本系统在列表加了「删除」,用于清除误录的称重数据;默认按 F9 的粒度整条(汇总 + 车台明细)物理删除。
|
||||
3. **未移植 F9 的本地设备能力**:`Page_Cds_Edit` 依赖串口电子秤 + 语音播报 + 本地缓存(`CacheLocalfileService`),Web 端不支持,改为直接录入;偏重/偏轻的语音提示折算UI 上的单元格着色。
|
||||
4. **未移植 HS\XCJC(现场检查)**:F9 只有 `Xcjc` 实体、没有对应页面(未见 `Page_Xcjc*`),本次不做;如有需要可单独加一组「温度/湿度/车速」维护页。
|
||||
5. **待接入**:① 秤大丝/丝片检查/丝片台帐的 Grid++ 打印`(报表中心目前只有 `lsjl.grf`);② 历史的 `biz_prod_hs_cds_*` / `biz_prod_hs_spjc` / `biz_prod_hs_sptz` 数据导出后可按工作进度-13 的 CSV 内嵌 + 幂等策略导入;③ 缫折/台产可作为成本核算与计件工资的数据源。
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
# 工作进度-16:薪资-挡车车头产量计算(CALCLDCCT)及其全部依赖
|
||||
|
||||
> 时间:2026-10-24(承接工作进度-15)
|
||||
> 需求:把 `D:\AntaiProject - 副本\trunk\WinClient\F9.Business.PayRoll\PAYROLL\CALCLDCCT` 模块移植进本系统,
|
||||
> 并补齐它依赖的全部功能(配置 + 数据源)。
|
||||
> 参考实现:`WinClient\F9.Business.PayRoll\PAYROLL\CALCLDCCT\Page_CalcLdcct.cs`(3067 行)、`Page_CalcLdcct_Edit.cs`、
|
||||
> `Application\CQRS\Business\PayRoll\CALCLDCCT\`(CalcLdcct_SaveCommand / CalcLdcct_DeleteByDateRangeDepCommand …)、
|
||||
> `Domain\Entities\Business\PayRoll\`(CalcLdcct / CONFGYZK / CONFGZ / CONFDCG / DCXDJK / XinZiJiaGePeiZhi)。
|
||||
> 落库表:F9 `biz_payroll_calcldcct` → 本系统 `CalcLdccts`。
|
||||
|
||||
---
|
||||
|
||||
## 一、功能设计
|
||||
|
||||
```
|
||||
薪资
|
||||
├── 挡车车头产量计算 /payroll/calcldcct 本次新增(核心)
|
||||
├── 工艺庄口薪资配置 /payroll/confgyzk 本次新增(依赖配置)
|
||||
├── 工种薪资配置 /payroll/confgz 本次新增(依赖配置)
|
||||
├── 挡车岗位薪资配置 /payroll/confdcg 本次新增(依赖配置)
|
||||
├── 挡车纤度奖扣 /payroll/dcxdjk 本次新增(依赖配置)
|
||||
└── 薪资价格配置 /payroll/xzjg 本次新增(依赖配置)
|
||||
```
|
||||
|
||||
| F9 行为 | 本系统实现 |
|
||||
|---|---|
|
||||
| 查询:年月(→账期)+ 部门 + 工种 + 姓名/庄口 Like | `GET /api/payroll/calcldcct/list` |
|
||||
| 一键计算(挡车工):部门穿梭框多选 → 逐部门计算 → 对账报告 | `POST /api/payroll/calcldcct/calc-dcg`(单部门;返回条数/丝量/金额/告警) |
|
||||
| 一键计算(车头工):**强依赖已存的挡车工产量** | `POST /api/payroll/calcldcct/calc-ctg` |
|
||||
| 录入:单部门计算后弹窗人工微调(可改产量初始值 / 系数 / 金额-产量) | 表格内 3 列直接编辑 + 「保存微调」整账期覆盖(`POST /save`) |
|
||||
| 删除:按 账期 × 部门 × 工种 整批删除 | `DELETE /api/payroll/calcldcct?start=&end=&depId=&worktypeId=` |
|
||||
| 5 套薪资配置各自的增删改查 | 5 个 `api/payroll/conf*` `/dcxdjk` `/xzjg` 控制器 |
|
||||
|
||||
### 计算口径(全部对齐 F9,服务端兜底重算)
|
||||
|
||||
```
|
||||
【丝量】
|
||||
每桶丝量 = 每车丝量(kg) × 1000 / 标准落丝桶数
|
||||
甲乙合计丝量 = Round(Σ今缫桶数 × 每桶丝量, 0) (煮茧日报不分班)
|
||||
班次丝量 = 甲乙合计 × Σ(挡车数×工时)_班 / Σ(挡车数×工时)_机组日 (挡车)
|
||||
= 甲乙合计 × Σ(20×工时)_班 / Σ(20×工时)_机组日 (车头,固定 20 台/组)
|
||||
个人丝量 = 班次丝量 × 挡车数×工时 / Σ(挡车数×工时)_同机组同班 (挡车)
|
||||
= 班次丝量 × 工时 / (最长工时 × 2) (车头,2 人分摊)
|
||||
看台时长 = Round(个人工时 × 庄口今缫桶数占比, 1),单庄口时等于个人工时
|
||||
|
||||
【等级】
|
||||
挡车工:木桶短板法 —— 均方差/总差/清洁分/洁净分/二度/三度各自在「生丝定级指标(标准=个人)」里定级,取最低分
|
||||
车头工:按挡车工丝量加权平均等级分后回落取整档;无挡车工产量时取庄口配置的 QsDengji/QsDengjifen
|
||||
未下丝时:等级/等级分/缫折全部回落到庄口配置
|
||||
|
||||
【单价】
|
||||
挡车:绪数 = 挡车数 × 20;<60→50档基数,<70→60档,<100→70档,否则 100 档
|
||||
基础单价 = 岗位基数金额 / 标准出勤天数 / 挡车数 / 标准上班时长 / 庄口工艺台产
|
||||
车头:基础单价 = 车头岗位金额 / 标准出勤天数 / 9 / 20 / 庄口工艺台产 × 2
|
||||
等级单价增减 = (等级分 − 工艺等级分) / 0.1 × 等级奖扣单价 / 10 / 1000
|
||||
实际单价 = 基础单价 + 等级单价增减
|
||||
|
||||
【质量】
|
||||
缫折 = Σ(车台茧量×看台比例) × 100 / Σ(车台丝量×看台比例)
|
||||
车台茧量 = 落丝茧量 × 该车台丝量占落丝丝量的比例(茧量只记在落丝层,需按丝量摊到车台)
|
||||
中心纤度数 = 纤度值 == 生丝规格.中心纤度 的计数 × 看台比例
|
||||
野纤数 = 纤度 ≤ 野纤下限 或 ≥ 野纤上限 的计数 × 看台比例
|
||||
清洁扣款片数 = (特大糙 + 大糙 + 长结) × 看台比例
|
||||
洁净扣款片数 = (85 + 80 + 75 + 70 分档) × 看台比例
|
||||
二度/三度 = 黑板检验匀二度/匀三度 × 看台比例
|
||||
两班(甲乙)时:中心纤度/野纤/清洁/洁净/二度/三度及其扣款全部 × 0.5
|
||||
|
||||
【金额】
|
||||
产量金额初始值 = 实际单价 × 丝量; 产量金额 = 实际单价 × 丝量 × 计件系数
|
||||
缫折考核 = ±2kg 死区不奖不扣,超出扣掉死区后 clamp(挡车 ±10 / 车头 ±3),每 1kg 每 100kg 丝 5元(挡车)/1元(车头)
|
||||
中心纤度奖 = 中心纤度数 × 1 元
|
||||
野纤扣 = −挡车纤度奖扣表扣款(≥2 条取扣款最大的 2 条求和)
|
||||
清洁扣 = −(特大糙×2 + 大糙×0.5 + 长结×2)
|
||||
洁净扣 = −(85×0.2 + 80×1 + 75×2 + 70×5)
|
||||
二度扣/三度扣 = −二度×2 / −三度×20
|
||||
```
|
||||
|
||||
> 关键常量:`20`(每台绪数、车头 20 台/组)、`9`/`2`(车头)、`0.1`(等级分步长)、
|
||||
> `0.5`(两班折半)、`1.0/0.4/0.1`(清洁扣分基数)、`2`(缫折死区)、`5/1`(缫折单价)、`225`(F9 弹窗均值折算,本版未移植)。
|
||||
> 全程 `MidpointRounding.AwayFromZero`。
|
||||
|
||||
---
|
||||
|
||||
## 二、后端
|
||||
|
||||
### 2.1 实体(`Domain/Entities/PayRoll/`)
|
||||
|
||||
| 类 | 文件 | 表 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `CalcLdcct` | `CalcLdcct.cs` | `CalcLdccts` | 产量计算明细,唯一键 `Date+DepId+Banci+Jizu+EmployeeId+WorktypeId+GyzkId+Guige+Chetai` |
|
||||
| `ConfGyzk` | `Conf.cs` | `ConfGyzks` | 工艺庄口薪资配置,唯一键 `Year+Month+GyzkId` |
|
||||
| `ConfGz` | `Conf.cs` | `ConfGzs` | 工种薪资配置(40 项),唯一键 `WorkTypeId` |
|
||||
| `ConfDcg` | `Conf.cs` | `ConfDcgs` | 挡车/车头岗位薪资配置,唯一键 `DepId` |
|
||||
| `DangCheXianDuJiangKou` | `Conf.cs` | `DangCheXianDuJiangKous` | 挡车纤度奖扣,唯一键 `GuiGe+XianDu` |
|
||||
| `XinZiJiaGePeiZhi` | `Conf.cs` | `XinZiJiaGePeiZhis` | 薪资价格配置,唯一键 `Group+Key` |
|
||||
|
||||
均继承 `BaseEntity`,建表沿用 `DbSeeder.SyncStructure`。
|
||||
|
||||
### 2.2 服务
|
||||
|
||||
| 服务 | 文件 | 说明 |
|
||||
|---|---|---|
|
||||
| `ICalcLdcctService` / `CalcLdcctService` | `Services/PayRoll/CalcLdcctService.cs` | 列表 + 挡车/车头一键计算 + 保存 + 删除,内含全部计算口径 |
|
||||
| `IConfGyzkService` / `ConfGyzkService` | `Services/PayRoll/PayRollConfService.cs` | 工艺庄口配置 CRUD |
|
||||
| `IConfGzService` / `ConfGzService` | 同上 | 工种配置 CRUD(含 40 项金额) |
|
||||
| `IConfDcgService` / `ConfDcgService` | 同上 | 挡车岗位配置 CRUD |
|
||||
| `IDcxdjkService` / `DcxdjkService` | 同上 | 挡车纤度奖扣 CRUD |
|
||||
| `IXzjgService` / `XzjgService` | 同上 | 薪资价格 CRUD + `GetPriceAsync(group,key)` |
|
||||
|
||||
数据源(全部为系统已有模块,本次只做读取):看台记录 `KtjlDcg/KtjlCtg`、煮茧日报 `ZjrbRecord/ZjrbJizu`、
|
||||
落丝记录 `LsjlRecord`、秤大丝 `CdsLsjl/CdsChetai`、纤度检验 `XdjyLsjl/XdjyRecord`、黑板检验 `HbjyRecord`、
|
||||
生丝规格 `ShengsiGuige`、生丝定级指标 `ShengsiDingjizhibiao`、工艺庄口 `CraftZhuangKou`。
|
||||
|
||||
### 2.3 接口
|
||||
|
||||
```
|
||||
GET /api/payroll/calcldcct/list?start=&end=&depId=&worktypeId=&like=&pageIndex=&pageSize=
|
||||
POST /api/payroll/calcldcct/calc-dcg 一键计算(挡车工)
|
||||
POST /api/payroll/calcldcct/calc-ctg 一键计算(车头工)
|
||||
POST /api/payroll/calcldcct/save 整账期×部门×工种全量覆盖(人工微调)
|
||||
DELETE /api/payroll/calcldcct?start=&end=&depId=&worktypeId=
|
||||
|
||||
GET /api/payroll/confgyzk/list?year=&month= POST /save GET /{id} DELETE /{id}
|
||||
GET /api/payroll/confgz/list POST /save GET /{id} DELETE /{id}
|
||||
GET /api/payroll/confdcg/list POST /save GET /{id} DELETE /{id}
|
||||
GET /api/payroll/dcxdjk/list?guige= POST /save GET /{id} DELETE /{id}
|
||||
GET /api/payroll/xzjg/list?group= POST /save GET /{id} DELETE /{id}
|
||||
```
|
||||
|
||||
要点:
|
||||
- 计算与保存都是「整账期 + 部门 + 工种全量覆盖」:先物理删除旧数据再重建,避免唯一索引冲突(与煮茧日报同一策略);
|
||||
- 车头工计算必须已有挡车工产量,否则等级回落到庄口配置并给出告警;
|
||||
- 所有告警通过 `CalcLdcctResultDto.Warnings` 返回,前端 `ElMessageBox.alert` 展示。
|
||||
|
||||
### 2.4 菜单
|
||||
|
||||
新增一级菜单「薪资」`/payroll`(排序 8,质量 7 与通知 9 之间),6 个子菜单:
|
||||
|
||||
| 顺序 | 菜单 | 路径 | 组件 | 权限标识 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 挡车车头产量计算 | /payroll/calcldcct | payroll/calcldcct/index | payroll:calcldcct:list |
|
||||
| 2 | 工艺庄口薪资配置 | /payroll/confgyzk | payroll/confgyzk/index | payroll:confgyzk:list |
|
||||
| 3 | 工种薪资配置 | /payroll/confgz | payroll/confgz/index | payroll:confgz:list |
|
||||
| 4 | 挡车岗位薪资配置 | /payroll/confdcg | payroll/confdcg/index | payroll:confdcg:list |
|
||||
| 5 | 挡车纤度奖扣 | /payroll/dcxdjk | payroll/dcxdjk/index | payroll:dcxdjk:list |
|
||||
| 6 | 薪资价格配置 | /payroll/xzjg | payroll/xzjg/index | payroll:xzjg:list |
|
||||
|
||||
同时把一级菜单顺序归一为:`/qc` 7、`/payroll` 8、`/notification` 9、`/sys` 10、`/report` 11。
|
||||
|
||||
---
|
||||
|
||||
## 三、前端
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `views/payroll/calcldcct/index.vue` | 年月(→账期) + 部门 + 工种查询;多级表头(产量 / 质量 / 金额 / 金额-质量);一键计算(挡车/车头)、保存微调(产量初始值/系数/金额-产量三列直接编辑)、删除;底部显示当前页产量金额合计 |
|
||||
| `views/payroll/confgyzk/index.vue` | 工艺庄口薪资配置 CRUD,庄口用 `CraftZhuangKouSelect` 选择 |
|
||||
| `views/payroll/confgz/index.vue` | 工种薪资配置 CRUD,40 项按「出勤与工时/岗位与奖金/假期与加班/学工/岗位胜任考核/加班工资」分组 |
|
||||
| `views/payroll/confdcg/index.vue` | 挡车岗位薪资配置 CRUD(50/60/70/100 绪基数金额 + 车头工金额) |
|
||||
| `views/payroll/dcxdjk/index.vue` | 挡车纤度奖扣 CRUD |
|
||||
| `views/payroll/xzjg/index.vue` | 薪资价格配置 CRUD,`薪资.前缫` 分组下预置「挡车工/车头工计件等级奖扣单价」 |
|
||||
| `router/index.js` | `componentMap` 注册上述 6 个页面 |
|
||||
|
||||
---
|
||||
|
||||
## 四、验证记录(全部由助手自行执行,无需人工点击)
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| `dotnet build`(Domain / Application / Infrastructure / Api) | ✅ 0 错误 |
|
||||
| `npm run build`(Node 在 `C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6`) | ✅ `✓ built in 14.88s`(仅既有 chunk 体积警告) |
|
||||
| IDE 诊断(6 个 vue + router) | ✅ 0 |
|
||||
| 菜单与权限 | ✅ `/auth/menus` 返回「薪资」+ 6 个子菜单 |
|
||||
| 6 个接口连通性 | ✅ 全部 200(空表) |
|
||||
| 挡车工一键计算 | ✅ 生成 1 条/庄口;丝量 = 桶数100 × (10kg×1000/4) = 250000 g |
|
||||
| 挡车工单价 | ✅ 挡车数 20 → 绪数 400 → 100 档;基础单价 = 4000/28/20/9/100 = 0.0079365 |
|
||||
| 挡车工等级 | ✅ 生丝定级指标 192 条参与木桶短板,定出 `6A00 / 12`;等级增减 = (12−5)/0.1×0.3/10/1000 = 0.0021 |
|
||||
| 挡车工实际单价 / 产量金额 | ✅ 0.0100365;0.0100365 × 250000 × 1 = 2509.13 |
|
||||
| 挡车工缫折 | ✅ 落丝茧量 60000 g、秤大丝丝量 25000 g → 缫折 240(**修复前为 4800,见下方问题**) |
|
||||
| 挡车工缫折考核 | ✅ (300−240)−2 = 58 → 封顶 10 → 10 × (250000/1000/100) × 5 = +125 |
|
||||
| 车头工一键计算 | ✅ 丝量 = 250000 × 9/(9×2) = 125000;基础单价 = 2000/28/9/20/100×2 = 0.0079365;缫折考核 = 3 × 1.25 × 1 = 3.75 |
|
||||
| 车头工依赖挡车工 | ✅ 无挡车工产量时给出「工种薪资配置缺失」类告警并按配置回落 |
|
||||
| 人工微调保存 | ✅ 产量初始值改 999.99 后保存,回读 `999.99 / 系数1 / 金额999.99` |
|
||||
| 整账期删除 | ✅ 删除后 `total=0`,且「删除后重建」不再撞唯一索引 |
|
||||
| 班次显示 | ✅ 修正为 `甲=1 / 乙=2`(初版误按 0/1 映射,已修) |
|
||||
| 测试数据清理 | ✅ 播种的煮茧日报、看台记录、落丝记录、秤大丝、5 套配置、计算结果全部删除;验证脚本 `verify-payroll.ps1` 已删除 |
|
||||
|
||||
### 过程中发现并修复的真实 bug
|
||||
|
||||
1. **缫折被放大 20 倍**:初版按「车台数 × 落丝茧量」累加分子,导致 20 台时缫折 = 4800(正确 240)。
|
||||
修正为:茧量只记在落丝层,按「车台丝量 / 落丝丝量」摊到车台后再按看台比例摊到人。
|
||||
2. **班次名称错位**:`Prod_Banci_Enum` 是 `甲=1 / 乙=2`,初版按 `0/1` 映射,甲班被显示成乙班。
|
||||
|
||||
---
|
||||
|
||||
## 五、移植取舍与后续
|
||||
|
||||
1. **未移植 F9 弹窗顶部的 4 个均值标签**(挡60/挡70/挡100/车头平均,`Σ金额 / Σ看台时长 × 225`):这是展示用的派生统计,
|
||||
本版在列表底部给出「当前页产量金额合计」;如需可按同样公式补在弹窗/工具栏。
|
||||
2. **未移植 F9 的「部门穿梭框多选」一键计算**:Web 端改为先选部门再点按钮,单部门计算(语义等价,逐个部门重复操作即可)。
|
||||
3. **野纤「奖励」分支未使用**:与 F9 一致——挡车工路径下 `JineZlYexian` 只取 `-扣款`,奖励分支被丢弃。
|
||||
4. **未移植的 F9 薪资子模块**(本次范围外,可按需继续):`CalXz`(薪资核算主表)、`Cmcl`(产量)、`QSXSCL`、`QTKH`、`SBRYKH` 等。
|
||||
5. **待接入**:① Grid++ 打印(报表中心目前只有 `lsjl.grf`);② 历史 `biz_payroll_calcldcct` 数据可按工作进度-13 的 CSV 内嵌 + 幂等策略导入;
|
||||
③ 本模块产出的「金额-产量 + 金额-质量」可直接作为计件工资与成本核算的数据源。
|
||||
|
||||
### 环境备注
|
||||
|
||||
- 本机 `node` / `npm` 不在默认 PATH,需先 `set PATH=C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6;%PATH%`。
|
||||
- Windows PowerShell 5.1 的 `Invoke-RestMethod` 默认按 ASCII 提交请求体,写中文会变成 `?`;
|
||||
验证脚本改为 `[System.Text.Encoding]::UTF8.GetBytes()` + `application/json; charset=utf-8`,并用 UTF-8 BOM 保存脚本。
|
||||
- 煮茧日报的「已存在相同的煮茧日报」校验会命中已软删记录,删除后无法在同一「日期+车间+庄口+规格」重建(既有模块行为,本次未改动)。
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
# 工作进度-17:仓储模块(WMS)五模块移植
|
||||
|
||||
## 一、任务目标
|
||||
|
||||
把 `D:\AntaiProject - 副本\trunk\WinClient\F9.Business.WMS` 下的五个子模块**按原业务逻辑一模一样**移植到本系统,UI 做适度美化:
|
||||
|
||||
| 模块 | 原 F9 目录 | 本系统菜单 |
|
||||
| --- | --- | --- |
|
||||
| 原料 | `F9.Business.WMS\Yuanliao` | 仓储 / 原料 |
|
||||
| 副产品 | `F9.Business.WMS\Fuchanpin` | 仓储 / 副产品 |
|
||||
| 中间品 | `F9.Business.WMS\ZJP` | 仓储 / 中间品 |
|
||||
| 生丝 | `F9.Business.WMS\SS` | 仓储 / 生丝 |
|
||||
| 物资 | `F9.Business.WMS\WJ` | 仓储 / 物资 |
|
||||
|
||||
## 二、建模方案(统一模型 + 模块/口径区分)
|
||||
|
||||
五个模块的单据结构高度一致,因此没有建 5 套重复表,而是一套表 + 两个维度:
|
||||
|
||||
- `Wms_Module_Enum`:原料=1 / 副产品=2 / 中间品=3 / 生丝=4 / 物资=5
|
||||
- `Kind`:0=库存台账,1=笼筒架台账(中间品专用)
|
||||
|
||||
### 新增实体(Domain/Entities/Wms/Wms.cs)
|
||||
|
||||
| 实体 | 表 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `WmsRuku` / `WmsRukuDetail` / `WmsBangmadan` | `WmsRukus` / `WmsRukuDetails` / `WmsBangmadans` | 入库单、入库明细、磅码单 |
|
||||
| `WmsChuku` / `WmsChukuDetail` | `WmsChukus` / `WmsChukuDetails` | 出库单、出库明细 |
|
||||
| `WmsKcTzDate` / `WmsKcTzItem` | `WmsKcTzDates` / `WmsKcTzItems` | 库存台账(日期 + 明细) |
|
||||
| `WmsPici` / `WmsPiciBaojian` | `WmsPicis` / `WmsPiciBaojians` | 生丝批次、包件 |
|
||||
| `WmsKucun` | `WmsKucuns` | 物资库存(按物资目录) |
|
||||
| `WmsCaigou` | `WmsCaigous` | 原料采购 |
|
||||
| `WmsFbplan` / `WmsFbjl` | `WmsFbplans` / `WmsFbjls` | 原料翻包计划 / 翻包记录 |
|
||||
| `WmsCgplan` / `WmsCgplanItem` | `WmsCgplans` / `WmsCgplanItems` | 物资采购计划 / 明细 |
|
||||
|
||||
### 台账项目口径(与 F9 一致)
|
||||
|
||||
- 原料:按**原料庄口**;中间品笼筒架台账:按**工艺庄口**(且只统计「联统茧」物资)
|
||||
- 其余:按**物资目录**;生丝额外按 `SubKey`(基地 / 外购)分组
|
||||
|
||||
### 两列数值口径
|
||||
|
||||
- 原料 / 副产品 / 中间品 / 生丝:**件数 / 净重**(生丝件数列取「批数」)
|
||||
- 物资:**数量 / 金额**
|
||||
|
||||
## 三、对齐 F9 的业务规则
|
||||
|
||||
### 1. 单据类型枚举(完整照搬 F9)
|
||||
|
||||
| 模块 | 入库类型 | 出库类型 |
|
||||
| --- | --- | --- |
|
||||
| 原料 | 采购1 / 调拨2 / 其他3 | 领料1 / 销售2 / 样茧3 / 其他4 |
|
||||
| 副产品 | 生产1 / 试缫2 / 其他5 | 销售1 / 调拨2 / 其他3 |
|
||||
| 中间品 | 选茧0 / 试缫2 / 退料3 / 其他5 | 领料0 / 销售1 / 其他2 |
|
||||
| 生丝 | 生产0 / 退货1 / 其他2 | 销售1 / 其他5 |
|
||||
| 物资 | 采购1 / 冲账2 / 盘盈3 / 其他4 | 领料1 / 销售2 / 调拨3 / 报废4 / 其他5 |
|
||||
|
||||
### 2. 重量 / 金额计算
|
||||
|
||||
- 磅码单:净重 = 毛重 − 皮重;明细件数 / 毛重 / 皮重 / 净重由磅码单汇总
|
||||
- 明细净重 = 毛重 − 皮重 − 包装重量 − 运损(未使用的项为 0)
|
||||
- 物资:金额 = 数量 × 单价;库存单价 = 库存金额 ÷ 库存数量(4 位小数)
|
||||
- 物资出库金额(`WJ_Chuku_Detail.CalJine`):
|
||||
- 出库数量 = 库存数量 → 金额 = 库存金额,单价 = 金额 ÷ 数量
|
||||
- 否则 → 单价 = 库存单价,金额 = 数量 × 单价
|
||||
- 物资出入库实时更新库存(加权平均单价);删除 / 修改单据时回滚,保证严格对称
|
||||
|
||||
### 3. 库存台账生成(`YL_Kucun_Taizhang_Edit.GenerateTaizhang / CalTdayJiecun`)
|
||||
|
||||
- 上日结存:取上一台账中「件数或净重不为 0」的行
|
||||
- 汇总区间:`LastDate + 1天` ~ `TzDate`(笼筒架台账为 `LastDate` ~ `TzDate`,与 F9 的 Yesterday~Date 一致)
|
||||
- 无上一台账时 `LastDate = 1970-01-01`(与 F9 `Page_YL_Kucun_Taizhang.cs` 一致,首份台账汇总全部历史)
|
||||
- 今日结存件数 = 上日 + 入库 − 出库
|
||||
- 今日结存重量 = Round(上日 + 入库 − 出库 + 盈亏, 2, AwayFromZero)
|
||||
- 全部出库 = 上日结存 ≠ 0 且今日结存 = 0;勾选后把结存转入盈亏(取消则转回)
|
||||
- 只能生成**晚于**最新台账日期的台账
|
||||
|
||||
### 4. 台账保存校验(与 F9 一致)
|
||||
|
||||
- 结存重量恒等式:`上日 + 入库 − 出库 + 盈亏 = 今日结存`
|
||||
- 结存重量不能小于 0
|
||||
- 原料:全部出库时样茧件数必须为 0
|
||||
|
||||
### 5. 生丝批次包件
|
||||
|
||||
- 净重 = 毛重 − 皮重;公量 = 净重 × (1 + 11%) ÷ (1 + 实测回潮率%)
|
||||
- 批次库存状态:待入库1 / 已入库2 / 部分出库3 / 已出库4;生丝出库后按批次号更新为「已出库」
|
||||
|
||||
### 6. 物资扩展
|
||||
|
||||
- 采购计划(草稿 / 已确认 / 已完成)+ 计划明细
|
||||
- 采购报销:入库单 `BxStatus` 无0 / 待报销1 / 已报销2,支持批量报销
|
||||
- 库存查询、出入库流水(入库为正、出库为负)
|
||||
|
||||
## 四、后端实现
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `Domain/Entities/Wms/Wms.cs` | 全部 WMS 实体与 `Wms_Module_Enum` |
|
||||
| `Application/Dtos/Wms/WmsDtos.cs` | 出入库 / 明细 / 磅码单 / 台账 / 批次 / 采购 DTO |
|
||||
| `Application/Services/Wms/WmsService.cs` | 统一服务:五模块出入库、台账、库存、流水、批次、采购 |
|
||||
| `Api/Controllers/Wms/WmsController.cs` | `api/wms/*` 接口 |
|
||||
| `Application/DependencyInjection.cs` | 注册 `IWmsService` |
|
||||
| `Infrastructure/Data/DbSeeder.cs` | 一级菜单「仓储」+ 5 个子菜单;清理软删残留 |
|
||||
|
||||
### 接口清单(`/api/wms`)
|
||||
|
||||
```
|
||||
GET /options?module= 类型 / 物资 / 原料庄口 / 工艺庄口 / 部门 / 往来单位
|
||||
GET /ruku?module=&start=&end=&type=&like=
|
||||
GET /ruku/{id} POST /ruku DELETE /ruku/{id}
|
||||
POST /ruku/baoxiao 采购报销(物资)
|
||||
GET /chuku?... GET /chuku/{id} POST /chuku DELETE /chuku/{id}
|
||||
GET /taizhang/dates?module=&kind=
|
||||
GET /taizhang?module=&kind=&date=®enerate=
|
||||
POST /taizhang DELETE /taizhang/{id}
|
||||
GET /kucun?module= GET /crk?module=&start=&end=&wzmlId=
|
||||
GET /pici GET /pici/{id} POST /pici DELETE /pici/{id}
|
||||
GET /caigou POST /caigou DELETE /caigou/{id}
|
||||
GET /fbplan POST /fbplan DELETE /fbplan/{id}
|
||||
GET /cgplan GET /cgplan/{id} POST /cgplan DELETE /cgplan/{id}
|
||||
```
|
||||
|
||||
### 设计要点
|
||||
|
||||
- 单据编号(模块 + 日期 + 单号)唯一,重复时返回友好提示
|
||||
- 出入库单、批次采用**物理删除**:避免软删残留撞唯一索引而无法重建同号单据
|
||||
- 启动时清理历史软删残留(`WmsRukus` / `WmsChukus` / `WmsPicis`)
|
||||
|
||||
## 五、前端实现
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `views/wms/moduleConfig.js` | 五模块差异化配置(项目口径、字段显示、数值口径、枚举选项) |
|
||||
| `views/wms/components/RukuPanel.vue` | 通用入库(含磅码单弹窗、明细合计) |
|
||||
| `views/wms/components/ChukuPanel.vue` | 通用出库(物资显示库存数、自动算金额) |
|
||||
| `views/wms/components/TaizhangPanel.vue` | 通用台账(生成 / 编辑 / 盈亏 / 全部出库 / 保存 / 删除) |
|
||||
| `views/wms/components/WjKucun.vue` | 物资库存 |
|
||||
| `views/wms/components/WjCrk.vue` | 物资出入库流水 |
|
||||
| `views/wms/components/WjCgplan.vue` | 物资采购计划 |
|
||||
| `views/wms/components/WjCgbx.vue` | 物资采购报销 |
|
||||
| `views/wms/components/SsPici.vue` | 生丝批次 + 包件(公量自动计算) |
|
||||
| `views/wms/components/YlCaigou.vue` | 原料采购 |
|
||||
| `views/wms/components/YlFbplan.vue` | 原料翻包计划 + 翻包记录 |
|
||||
| `views/wms/{yuanliao,fuchanpin,zjp,ss,wj}/index.vue` | 五个模块页面(Tab 组织) |
|
||||
| `router/index.js` | 注册 5 个页面组件 |
|
||||
|
||||
### UI 优化点
|
||||
|
||||
- 统一卡片式布局 + Tab 分区,顶部带模块说明
|
||||
- 查询栏(日期区间 / 类型 / 关键字)与操作按钮分离,右侧对齐
|
||||
- 单据编辑弹窗:表头 4 列栅格表单,明细用可编辑表格(下拉 + 数字框),底部实时合计
|
||||
- 磅码单独立弹窗,自动算净重并汇总
|
||||
- 台账:结存列加粗高亮,盈亏 / 全部出库可交互,底部合计条
|
||||
- 状态用 `el-tag` 着色(库存状态、报销状态、翻包状态、采购计划状态)
|
||||
|
||||
## 六、菜单
|
||||
|
||||
一级菜单「仓储」(`/wms`,排序 9,位于「薪资」之后),五个子菜单:
|
||||
|
||||
| 名称 | 路径 | 组件 |
|
||||
| --- | --- | --- |
|
||||
| 原料 | `/wms/yuanliao` | `wms/yuanliao/index`(入库 / 出库 / 库存台账 / 原料采购 / 翻包计划) |
|
||||
| 副产品 | `/wms/fuchanpin` | `wms/fuchanpin/index`(入库 / 出库 / 库存台账) |
|
||||
| 中间品 | `/wms/zjp` | `wms/zjp/index`(入库 / 出库 / 库存台账 / 笼筒架台账) |
|
||||
| 生丝 | `/wms/ss` | `wms/ss/index`(入库 / 出库 / 库存台账 / 批次包件) |
|
||||
| 物资 | `/wms/wj` | `wms/wj/index`(入库 / 出库 / 库存台账 / 库存 / 出入库流水 / 采购计划 / 采购报销) |
|
||||
|
||||
## 七、验证结果(全流程脚本自动执行,已清理测试数据)
|
||||
|
||||
```
|
||||
[1] 登录 OK
|
||||
[2] 菜单:仓储 children=5(原料 / 副产品 / 中间品 / 生丝 / 物资)
|
||||
[3] 选项:原料模块 入库类型3 / 出库类型4 / 原料庄口347 / 物资1000
|
||||
[4] 原料入库:件数10 净重945(1000−50−5)✓
|
||||
[5] 原料出库:件数4 净重380 ✓
|
||||
[6] 台账生成:上日0 + 入库10/945 − 出库4/380 = 结存6/565 ✓
|
||||
[7] 台账保存 ✓
|
||||
[8] 次日台账:上日结存6/565 正确结转 ✓
|
||||
[9] 物资入库:库存 100 / 1000 / 单价10 ✓
|
||||
[10] 物资出库40:库存 60 / 600 / 单价10(CalJine 规则)✓
|
||||
[11] 生丝批次:净重120 公量119.46(59 + 60.46)✓
|
||||
[12] 原料采购 ✓ [13] 翻包计划 ✓ [14] 采购计划 ✓ [15] 批量报销 count=1 ✓
|
||||
[16] 清理完成,物资库存归零 ✓
|
||||
```
|
||||
|
||||
第二批(副产品 / 中间品 / 生丝 + 笼筒架台账):
|
||||
|
||||
```
|
||||
[2 副产品] 入库6/570 出库2/190 结存4/380 ✓
|
||||
[3 中间品] 入库6/570 出库2/190 结存4/380 ✓
|
||||
[4 生丝] 入库2批/570 出库1批/190 结存1批/380(按基地分组)✓
|
||||
[3 笼筒架台账] 按工艺庄口统计 结存4/380 ✓
|
||||
```
|
||||
|
||||
- 后端 `dotnet build`:0 错误
|
||||
- 前端 `npm run build`:构建成功
|
||||
- 服务运行中:后端 `http://localhost:3000`、前端 `http://localhost:5173`
|
||||
|
||||
## 八、后续修正(2026-10-26)
|
||||
|
||||
1. **「在制品」更名为「中间品」**
|
||||
- 枚举 `Wms_Module_Enum.在制品` → `中间品`(数据库存值仍为 3,不影响历史数据)
|
||||
- 菜单「仓储 / 中间品」、页面标题、模块配置同步更名
|
||||
|
||||
2. **按仓储区分物资分组**
|
||||
- 物资分组 `WuziGroup.BusinessType`:原料1 / 中间品2 / 生丝3 / 副产品4 / 五金5
|
||||
- `/api/wms/options?module=` 只返回本模块所属分组的物资:
|
||||
|
||||
| 仓储模块 | 分组业务类型 | 物资数(现有数据) | 示例 |
|
||||
| --- | --- | --- | --- |
|
||||
| 原料 | 原料(1) | 2 | 0101 优茧、0102 普茧 |
|
||||
| 副产品 | 副产品(4) | 39 | 040101 好五级茧 … |
|
||||
| 中间品 | 中间品(2) | 1 | 0301 联统 |
|
||||
| 生丝 | 生丝(3) | 6 | 070101 正品丝20/22 … |
|
||||
| 物资 | 五金(5) | 952 | 02010063 轴承盒 … |
|
||||
|
||||
- 笼筒架台账的物资过滤同步改为匹配名称含「联统」的物资(原为「联统茧」)
|
||||
|
||||
3. **修复「新增页面点击确认保存报错」**
|
||||
- 原因:下拉框清空后前端提交 `null`,而后端 DTO 的 `long/int/decimal` 不接受 `null`,
|
||||
`System.Text.Json` 直接返回 400(`The JSON value could not be converted to System.Int64`)
|
||||
- 修复:新增 `cleanPayload()`(`views/wms/moduleConfig.js`),提交前把 `null/undefined` 统一转成 `0`
|
||||
(`scDate`、`guobangShijian`、`ckTime` 等日期型保持 `null`),所有 WMS 保存接口统一走该函数
|
||||
- 验证:中间品入库(件数3 净重285=300−15)、物资入库(10×5=50)均保存成功,测试数据已清理
|
||||
|
||||
## 九、说明与后续可选项
|
||||
|
||||
- 笼筒架台账只统计名称含「联统茧」的物资(与 F9 一致;未配置该物资时不过滤)
|
||||
- 生丝公量按 11% 公定回潮率计算(F9 标准值)
|
||||
- 已对齐 F9 的五个模块核心逻辑;如后续需要,可再补充:
|
||||
- 生丝混装(`SS_Pici_Hunzhuang`)
|
||||
- 物资调拨单、报废单的独立审批流
|
||||
- 各模块台账的报表打印模板
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
# 工作进度-18:仓储 · 生丝 模块操作逻辑对齐 F9
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、任务目标
|
||||
|
||||
新系统(.NET 8 + Vue 3)的生丝模块功能已具备,但**页面操作逻辑与老系统不一致**。
|
||||
目标:以老系统 `D:\AntaiProject - 副本\trunk\WinClient\F9.Business.WMS\SS` 为基准,把生丝模块的**操作逻辑改成与老系统一模一样**。
|
||||
|
||||
对齐范围(本轮确认):
|
||||
|
||||
- 生丝入库 / 出库的**批次驱动录入**
|
||||
- 生丝**批次报检**的行内操作(过磅 / 包件 / 公量 / 质检 / 纤度检验)
|
||||
- 出入库**主从联动**
|
||||
- 财务审核:**本轮不做**,用户选择后续单独处理
|
||||
|
||||
## 二、核心差异(新系统改造前的问题)
|
||||
|
||||
| 环节 | 老系统做法 | 新系统改造前 |
|
||||
| --- | --- | --- |
|
||||
| 入库明细 | 点「选择生丝批次」→ 勾选**待入库批次**,自动带出物资 / 批次号 / 批数 / 包件数 / 毛皮净重 | 手动「添加明细」→ 选物资 + 手填批次号 + 手填重量 |
|
||||
| 出库明细 | 点「选择批次 + 包件」→ 勾选批次下未出库包件 | 手动录入,批次与包件脱节 |
|
||||
| 批次状态 | 批次 / 包件级跟踪出库(`Ck_Isck`、`Ck_Baoshu` 等) | 仅按批次号字符串整体置"已出库",包件无跟踪 |
|
||||
| 批号格式 | 正品 10 位数字 / 其他 `31EE-7位` | 无校验 |
|
||||
| 主从联动 | 主表点行 → 下方明细联动 | 无,明细只在编辑弹窗 |
|
||||
| 批次报检操作 | 过磅 / 包件 / 公量 / 质检 / 纤度检验 5 个行内操作 | 只有编辑、删除 |
|
||||
| 规格 | 下拉选择(生丝规格) | 手填文本框 |
|
||||
| 生产车间 | 取职责类型为「前缫」的车间 | 取全部部门,未筛选 |
|
||||
|
||||
## 三、数据模型变更
|
||||
|
||||
### 新增字段(`Domain/Entities/Wms/Wms.cs`)
|
||||
|
||||
| 实体 | 新增字段 | 对应 F9 |
|
||||
| --- | --- | --- |
|
||||
| `WmsPici` | `RkItemId`、`RkDate`、`CkLastDate`、`CkBaoshu`、`CkJingzhong`、`KcBaoshu` | `Rk_Item_Id`、`Rk_Date`、`CK_LastDate`、`Ck_Baoshu`、`Ck_Jingzhong`、`Kc_Baoshu` |
|
||||
| `WmsPiciBaojian` | `CkIsck`、`CkItemId`、`CkDate`、`CkJingzhong` | 包件级出库标记 |
|
||||
| `WmsRukuDetail` | `PiciIds` | `SS_Rk_Item.PiciIds` |
|
||||
| `WmsChukuDetail` | `PcAndBjIds` | `SS_Ck_Item.PcAndBjIds` |
|
||||
|
||||
### 新增实体
|
||||
|
||||
| 实体 | 表 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `WmsPiciChuku` | `WmsPiciChukus` | 批次出库记录(回滚时按此重算库存状态) |
|
||||
| `WmsPiciQc` | `WmsPiciQcs` | 批次质检 |
|
||||
| `WmsPiciQcXdjy` | `WmsPiciQcXdjys` | 批次纤度检验 |
|
||||
|
||||
### 建表 / 加列(`DbSeeder.cs`)
|
||||
|
||||
- 新表:由 `SyncStructure` 反射扫描 `BaseEntity` 子类自动建立
|
||||
- 旧表加列:`EnsureColumn` 兜底(幂等,列已存在则忽略)
|
||||
|
||||
## 四、后端改动
|
||||
|
||||
### 1. 状态流转(`WmsService.cs`,对齐 F9 CQRS)
|
||||
|
||||
- **入库**:`UpdatePiciRukuAsync` 按 `PiciIds` 置批次"已入库",写 `RkItemId` / `RkDate`,`KcBaoshu = Baoshu`
|
||||
- **入库回滚**:`RollbackPiciRukuAsync`,若批次已出库则抛错禁止修改 / 删除
|
||||
- **出库**:`UpdatePiciChukuAsync` 按 `PcAndBjIds`(JSON)标记包件 `CkIsck`,写 `WmsPiciChuku`;批次按出库包件数流转「部分出库 / 已出库」
|
||||
- **出库回滚**:`RollbackPiciChukuAsync` 撤销包件标记、删除出库记录、按剩余记录重算批次状态
|
||||
- **校验**:待入库不可出库、已全部出库不可再出库
|
||||
|
||||
> 注意:`PcAndBjIds` 前端序列化为 camelCase(`piciId` / `piciBaojianIds`),
|
||||
> 反序列化时必须带 `PropertyNameCaseInsensitive = true`,否则字段匹配不上。
|
||||
|
||||
### 2. 批号格式校验(`SavePiciAsync`)
|
||||
|
||||
对齐 F9 `Page_PiciBaojian_Edit`:
|
||||
|
||||
- 正品(`CodeType = 0`):`^\d{10}$`
|
||||
- 其他(`CodeType = 1`):`^31EE-\d{7}$`
|
||||
|
||||
### 3. 新增接口(`WmsController.cs`)
|
||||
|
||||
| 方法 | 路由 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| GET | `/api/wms/pici/chuku-select` | 出库选批次(含未出库包件),支持按物资过滤、排除已选批次 |
|
||||
| GET | `/api/wms/pici/qc/{piciId}` | 读取批次质检 |
|
||||
| POST | `/api/wms/pici/qc` | 保存批次质检 |
|
||||
| GET | `/api/wms/pici/xdjy/{piciId}` | 读取纤度检验 |
|
||||
| POST | `/api/wms/pici/xdjy` | 保存纤度检验 |
|
||||
|
||||
### 4. 入库主表补"包数"
|
||||
|
||||
`WmsRukuListDto` 新增 `BaojianNum`,由明细 `BaojianNum` 汇总(出库主表老系统无包数列,故未加)。
|
||||
|
||||
## 五、前端改动
|
||||
|
||||
### 1. 新建 `PiciSelectDialog.vue`
|
||||
|
||||
生丝批次选择弹窗,两种模式复用:
|
||||
|
||||
- `mode="ruku"`:拉待入库批次(`GET /wms/pici?kcStatus=1`),勾选批次
|
||||
- `mode="chuku"`:拉批次 + 包件(`GET /wms/pici/chuku-select`),展开行勾选包件,
|
||||
批次勾选 ↔ 包件勾选双向联动,已出库包件禁用
|
||||
|
||||
### 2. `RukuPanel.vue`(生丝入库)
|
||||
|
||||
- 明细工具栏:生丝改为「选择生丝批次」,不再自动加空白行
|
||||
- 入库类型:仅显示「生产(0) / 退货(1)」(对齐 F9"其他暂未开放")
|
||||
- 按物资分组生成明细,回填 `piciIds` / `piciCodes` / 批数 / 包件数 / 毛皮净重
|
||||
- 物资、批次号、包件数改为**只读**(由批次带出)
|
||||
- 主表:新增「包数」列;新增展开行主从联动
|
||||
- 保存校验:生丝明细必须有 `piciIds`
|
||||
|
||||
### 3. `ChukuPanel.vue`(生丝出库)
|
||||
|
||||
- 明细工具栏:生丝改为「选择批次包件」
|
||||
- 出库类型:仅显示「销售(1)」
|
||||
- 往来单位(客户)改标签为「往来单位」并**必选**
|
||||
- 明细回填 `pcAndBjIds`(JSON `[{piciId, piciBaojianIds}]`)
|
||||
- 主表:展开行主从联动
|
||||
|
||||
### 4. `SsPici.vue`(批次报检)
|
||||
|
||||
- 行内操作补齐:**过磅 / 包件 / 公量 / 质检 / 纤度检验**
|
||||
- 过磅:仅「待入库」状态可用(否则提示并阻止)
|
||||
- 包件、公量:复用批次编辑弹窗(编辑包件毛皮重 / 回潮率)
|
||||
- 质检:新增质检弹窗(对接 `/wms/pici/qc`)
|
||||
- 纤度检验:新增明细表格弹窗(对接 `/wms/pici/xdjy`)
|
||||
- **规格**:由手填 `el-input` 改为 `el-select`,数据来自 `GET /shengsiguige/all`
|
||||
(与 `prod/lsjl` 落丝记录取数口径一致)
|
||||
- **生产车间**:由"全部部门"改为**仅取职责类型为「前缫」的车间**
|
||||
```js
|
||||
import { depOptions, DUTY } from '../../../utils/departments';
|
||||
const opts = await depOptions({ duty: [DUTY.前缫] }, { flat: true });
|
||||
deptOptions.value = opts.map((o) => ({ id: Number(o.key), name: o.value, ...(o.raw || {}) }));
|
||||
```
|
||||
列表列名同步改为「生产车间」
|
||||
- 保存校验补齐(对齐 F9 `AddValidateRuls`):日期、规格、品名(生丝规格)、批号、基地外购
|
||||
|
||||
> 变量名注意:组件内部门列表变量已改名 `deptOptions`,避免与工具函数 `depOptions` 重名冲突。
|
||||
|
||||
## 六、涉及文件
|
||||
|
||||
**后端**
|
||||
|
||||
- `backend/F9WebAiTest.Domain/Entities/Wms/Wms.cs`
|
||||
- `backend/F9WebAiTest.Application/Dtos/Wms/WmsDtos.cs`
|
||||
- `backend/F9WebAiTest.Application/Services/Wms/WmsService.cs`
|
||||
- `backend/F9WebAiTest.Api/Controllers/Wms/WmsController.cs`
|
||||
- `backend/F9WebAiTest.Infrastructure/Data/DbSeeder.cs`
|
||||
|
||||
**前端**
|
||||
|
||||
- `web/src/views/wms/components/PiciSelectDialog.vue`(新建)
|
||||
- `web/src/views/wms/components/RukuPanel.vue`
|
||||
- `web/src/views/wms/components/ChukuPanel.vue`
|
||||
- `web/src/views/wms/components/SsPici.vue`
|
||||
|
||||
## 七、验证情况
|
||||
|
||||
- 后端 `F9WebAiTest.Application` 编译通过:**0 错误**
|
||||
- 解决方案整体编译的报错均为 `MSB3021 / MSB3027`(**后端 API 进程正在运行,DLL 被锁定无法复制**),非代码问题
|
||||
- 前端 lint:0 错误
|
||||
|
||||
## 八、待办 / 遗留
|
||||
|
||||
1. **财务审核 / 反审核**:老系统生丝出入库均有「财务审核状态」列与批量审核 / 反审核按钮,
|
||||
新系统尚未实现(本轮用户选择暂缓,后续单独处理)
|
||||
2. 生丝出库「选择调拨通知单」自动填充明细:老系统有(`Page_Dbtz_Select`),新系统未实现
|
||||
3. 老系统批次报检的「混装」功能在 F9 中已被注释,故未移植
|
||||
|
||||
## 九、下次接续提示
|
||||
|
||||
- 重启后端服务后,新表 / 新列才会在启动时建立
|
||||
- 继续做财务审核时,需新增通用审核记录与生丝出入库审核接口,并在两个列表页加「财务审核状态」列 + 批量审核 / 反审核按钮
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
# 工作进度-19:生产 · 选剥茧 模块移植(后端完成)
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、任务目标
|
||||
|
||||
将老系统「生产 - 选剥茧」模块移植到新系统。老系统位置:`D:\AntaiProject - 副本\trunk\WinClient\F9.Business.Prod\XBJ`。
|
||||
|
||||
模块构成(老系统两个子功能 + 三张表):
|
||||
|
||||
| 老系统 | 说明 |
|
||||
| --- | --- |
|
||||
| `XBJ\XJRB\Page_Xjrb.cs` | **选茧日报**:某日某工艺庄口一条,记录干茧领入与 8 类茧 |
|
||||
| `XBJ\XJRB\Page_XjrbPlan.cs` | **选茧计划**:按领料单(原料出库单)下达,含计划盈亏与完成标记 |
|
||||
| `XBJ\XJRB\Page_XjrbItem_Edit.cs` | **计划明细**:挂在计划下的每日选茧进度行 |
|
||||
| `XBJ\XJBZ\Page_xjpbbanzu.cs` | **选茧班组**:班次(甲/乙)+ 选茧组,含班组职工 |
|
||||
|
||||
新系统此前**没有**该模块(`prod/zjrb` 是煮茧日报,不是选茧日报),需从零建。
|
||||
|
||||
## 二、核心业务规则(移植关键,务必照此实现)
|
||||
|
||||
### 1. 选茧日报字段(8 类茧 + 退回)
|
||||
|
||||
干茧领入(包数/重量)、联统茧、好五级茧、六级茧、绵茧、双宫茧、下脚茧、茧衣、茧花(各包数/重量)、
|
||||
退回(包数/重量)、合计重量、联统率、盈亏。
|
||||
合计重量 = 上述 8 类重量之和(**不含退回、不含领入**)。
|
||||
|
||||
### 2. 盈亏 / 联统率计算(对齐 F9 `GetXjrbCountYingkuiQuery` + `GetXjrbLingruStartDateQuery`)
|
||||
|
||||
```
|
||||
步骤 1 起始日期(GetLingruStartDate):
|
||||
history = 同庄口 且 Date < 当前日期 的日报,按日期降序(排除自身)
|
||||
startDate = 当前日期
|
||||
for item in history(由新到旧):
|
||||
if item.LiantongRate != 0: break // 遇第一条已结算记录停止
|
||||
startDate = item.Date // 否则继续往前推
|
||||
步骤 2 累计区间 = [startDate, 当前日期] 闭区间(排除自身)
|
||||
步骤 3 累加(初值 = 当前表单输入值):
|
||||
ltj = 当前联统茧重量 + Σ item.LtjZhongliang
|
||||
yllr = 当前干茧领入重量 + Σ item.Yl_lr_zhongliang
|
||||
all = 当前 8 类重量之和 + Σ item 同样 8 类重量之和
|
||||
步骤 4 公式:
|
||||
联统率 = yllr != 0 ? (ltj / yllr) * 100 : 0
|
||||
盈亏 = all - yllr
|
||||
```
|
||||
|
||||
**要点**:起始日期不是简单取"上月结存日",而是**往回跳过所有 `LiantongRate == 0`(未结算)的记录**,
|
||||
遇到第一条已结算记录才停 —— 这是最容易实现错的地方。
|
||||
|
||||
### 3. 计划维度盈亏(口径与日报**不同**)
|
||||
|
||||
```
|
||||
联统率 = 联统茧包数 ÷ (联统+好五级+五级+双宫+下脚+茧衣+茧花 包数之和) × 100 ← 按「包数」
|
||||
盈亏 = 累计选出总重量 − 计划原料领入重量(YlZhongliang)
|
||||
```
|
||||
|
||||
> 老系统仓储里 `wjjBaoshu` / `wjjZhongliang` 的源字段**交叉写反**(疑似 bug),
|
||||
> 本移植**已按正确字段聚合**(`SUM(WjjBaoshu)`→包数、`SUM(WjjZhongliang)`→重量),
|
||||
> 若业务上必须与老系统完全一致(含 bug),可改回。
|
||||
|
||||
### 4. 标包重(老系统在客户端计算,尚未移植)
|
||||
|
||||
老系统从注册表 `生产\选剥茧` 读取各品类标包重,**重量 = 包数 × 标包重**:
|
||||
|
||||
| 注册表键 | 说明 |
|
||||
| --- | --- |
|
||||
| 联统茧标包重 | |
|
||||
| 好五级茧标包重 | |
|
||||
| 六级茧标包重 | |
|
||||
| 棉茧标包重 | |
|
||||
| 双宫茧标包重 | |
|
||||
| 下脚茧标包重 | |
|
||||
| 茧衣标包重 | |
|
||||
|
||||
茧花、退回**无**标包重,手工录入。
|
||||
前端实现时需提供该配置入口(新系统暂无等价的注册表服务,待定:可做成常量配置或新增配置表)。
|
||||
|
||||
### 5. 选茧班组
|
||||
|
||||
- 班组 = 班次(甲/乙)+ 选茧组;班组职工来自「选剥茧车间」下工种为「选茧工」的在职职工
|
||||
- **没有独立新增入口**:由「编辑录入」勾选职工 + 填组别后整体保存(按班次覆盖:先清该班次旧职工与班组,再重建)
|
||||
- 计划完成(`IsFinish`)后禁止修改/删除明细
|
||||
|
||||
## 三、本次完成(后端)
|
||||
|
||||
### 新建文件
|
||||
|
||||
| 文件 | 内容 |
|
||||
| --- | --- |
|
||||
| `Domain/Entities/Prod/Xjrb.cs` | `XjrbRecord` / `XjrbPlan` / `XjrbItem` 三个实体(表 `XjrbRecords`、`XjrbPlans`、`XjrbItems`) |
|
||||
| `Domain/Entities/Prod/XjpbBanzu.cs` | `XjpbBanzu` / `XjpbBanzuZhigong`(表 `XjpbBanzus`、`XjpbBanzuZhigongs`) |
|
||||
| `Application/Dtos/Prod/XjrbDtos.cs` | 日报 / 计划 / 明细 / 班组 的列表与保存 DTO,含 `XjrbYingkuiDto` |
|
||||
| `Application/Services/Prod/XjrbService.cs` | `IXjrbService` + 实现(盈亏、计划、班组全部逻辑) |
|
||||
| `Api/Controllers/Prod/XjrbController.cs` | 路由前缀 `api/prod/xjrb` |
|
||||
|
||||
### 修改文件
|
||||
|
||||
- `Application/DependencyInjection.cs`:新增 `services.AddScoped<IXjrbService, XjrbService>();`
|
||||
(新系统 DI 是**手动注册**,不是反射扫描,新增 Service 必须补这一行)
|
||||
|
||||
### 接口清单(`api/prod/xjrb`)
|
||||
|
||||
| 方法 | 路由 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| GET | `` | 日报分页(start / end / like 庄口关键字) |
|
||||
| GET | `{id}` | 日报详情 |
|
||||
| POST | `` | 保存日报 |
|
||||
| DELETE | `{id}` | 删除日报 |
|
||||
| POST | `count-yingkui` | 计算盈亏 / 联统率(保存前调用回填表单) |
|
||||
| GET | `plan` | 计划分页 |
|
||||
| GET | `plan/{id}` | 计划详情 |
|
||||
| POST | `plan` | 保存计划 |
|
||||
| DELETE | `plan/{id}` | 删除计划(已完成则拒绝) |
|
||||
| GET | `plan/{planId}/items` | 计划明细列表 |
|
||||
| POST | `plan/item` | 保存明细(勾选完成后回写计划盈亏) |
|
||||
| DELETE | `plan/item/{id}` | 删除明细 |
|
||||
| POST | `plan/count-yingkui` | 计划维度盈亏 |
|
||||
| GET | `banzu` | 班组分页 |
|
||||
| GET | `banzu/{id}/zhigong` | 班组职工 |
|
||||
| POST | `banzu/zhigong` | 班组「编辑录入」批量保存 |
|
||||
|
||||
## 四、踩坑记录
|
||||
|
||||
1. **`BaseEntity` 的命名空间**:在 `F9WebAiTest.Domain.Common`,实体文件必须
|
||||
`using F9WebAiTest.Domain.Common;`,光有 `FreeSql.DataAnnotations` 不够(会报 CS0246)。
|
||||
2. **DI 手动注册**:新增 Service 必须在 `DependencyInjection.cs` 里 `AddScoped`,否则运行时报未注册。
|
||||
3. **编译 Api 会被运行中的进程锁死 DLL**(MSB3021 / MSB3027)。
|
||||
验证代码是否编译通过的正确做法:筛选 `error CS`(忽略 MSB),或单独编译 Application 项目。
|
||||
|
||||
## 五、验证情况
|
||||
|
||||
- `F9WebAiTest.Application` 编译:**已成功生成**
|
||||
- `F9WebAiTest.Api` 编译:无 `error CS`(Controller 通过)
|
||||
- 新表由 `DbSeeder.SyncStructure` 反射扫描 `BaseEntity` 子类**自动建表**,无需手写迁移
|
||||
|
||||
## 六、待办(下一轮)
|
||||
|
||||
1. **前端页面**(`web/src/views/prod/xuanjian/`):
|
||||
- 选茧日报列表 + 编辑弹窗(含「计算盈亏」按钮,调用 `count-yingkui` 回填)
|
||||
- 选茧计划列表 + 计划明细(主从联动)
|
||||
- 选茧班组(班组列表 + 职工联动 + 「编辑录入」弹窗)
|
||||
2. **标包重配置**:确定新系统的存放方式(建议做成系统配置或常量),前端按 `重量 = 包数 × 标包重` 自动算
|
||||
3. **路由 + 菜单**:`web/src/router/index.js` 加路由,菜单种子数据加「生产 - 选剥茧」
|
||||
4. 「编辑录入」取职工:需要「选剥茧车间 + 选茧工工种」筛选员工的接口(需确认新系统员工/工种接口)
|
||||
5. 重启后端服务后新表才会建立
|
||||
|
||||
## 七、下次接续提示
|
||||
|
||||
- 前端实现时,选茧日报的**「计算盈亏」按钮是核心交互**:填完包数/重量后点它,把返回的
|
||||
`liantongRate` / `yingkui` / `startDate`(提示"从 xxx 开始计算")回填到表单,再保存
|
||||
- 计划明细勾选「选茧完成」保存时会直接把计划置为已完成并回写盈亏,之后不可再改
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
@@ -0,0 +1,76 @@
|
||||
# 工作进度-20:生产 · 选剥茧 前端完成(模块可运行)
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
> 承接 [工作进度-19](./工作进度-19.md)(后端完成)。本轮完成前端,模块至此可运行。
|
||||
|
||||
## 一、本次完成(前端)
|
||||
|
||||
新建目录 `web/src/views/prod/xuanjian/`:
|
||||
|
||||
| 文件 | 内容 |
|
||||
| --- | --- |
|
||||
| `index.vue` | Tab 容器;三个菜单共用本组件,**按路由末段自动定位 Tab**(`/rb`、`/plan`、`/banzu`) |
|
||||
| `XjrbPanel.vue` | **选茧日报**:查询、多表头列表(8 类茧各自包数/重量)、编辑弹窗、「计算盈亏」按钮 |
|
||||
| `XjrbPlanPanel.vue` | **选茧计划**:列表 + **展开行主从联动**显示计划明细,明细增删改,明细内「计算盈亏」 |
|
||||
| `XjpbBanzuPanel.vue` | **选茧班组**:班组列表 + 展开行显示职工,「编辑录入」弹窗按班次批量分配职工与组别 |
|
||||
|
||||
### 关键实现
|
||||
|
||||
- **日报「计算盈亏」**:填完包数/重量后点按钮 → `POST /prod/xjrb/count-yingkui` →
|
||||
回填 `liantongRate` / `yingkui`,并 `ElMessage` 提示"从 xxx 开始累计"(即后端返回的 `startDateText`)
|
||||
- **标包重**:老系统从注册表 `生产\选剥茧` 读取(重量 = 包数 × 标包重,茧花/退回手工录入)。
|
||||
本次**先用 `localStorage`(key `xuanjian_biaobaozhong`)临时存放**并带「按标包重换算」按钮;
|
||||
折叠面板可编辑 7 个品类的标包重(联统/好五级/五级/绵/双宫/下脚/茧衣)
|
||||
- **计划维度**联统率按**包数**口径(与日报按重量不同),明细勾选「选茧完成」保存后计划置为已完成、不可再改
|
||||
- **班组「编辑录入」**:按班次整体覆盖(后端先清该班次旧职工与班组,再重建)
|
||||
|
||||
### 接口对接要点(踩坑)
|
||||
|
||||
| 事项 | 正确写法 |
|
||||
| --- | --- |
|
||||
| 工艺庄口选择 | 用组件 `web/src/components/select/CraftZhuangKouSelect.vue`,`@confirm` 回调参数含 `id` / `zhuangKouName` / `productionDisplayName` |
|
||||
| 员工列表 | `GET /sys/employee`,参数是 **`depId`**、**`worktypeId`**(注意不是 workTypeId)、`banci`、`workStatus`、`like` |
|
||||
| 工种列表 | `GET /sys/worktype`,返回 `res.data.items` |
|
||||
| 员工筛选口径 | 部门 = 职责类型「选剥茧」的车间(`depOptions({ duty: [DUTY.选剥茧] })`)+ 工种名含「选茧」 |
|
||||
| 路由 | `web/src/router/index.js` 的路径映射表,新增 `'prod/xuanjian/index'` |
|
||||
|
||||
## 二、注册与菜单
|
||||
|
||||
1. **路由**(`web/src/router/index.js`):
|
||||
```js
|
||||
'prod/xuanjian/index': () => import('../views/prod/xuanjian/index.vue'),
|
||||
```
|
||||
2. **菜单**(`backend/F9WebAiTest.Infrastructure/Data/BusinessSeedData.cs`):
|
||||
新建一级目录「生产-选剥茧」(`/prod/xuanjian`,Sort 7),下挂三个菜单:
|
||||
- 选茧日报 → `/prod/xuanjian/rb`
|
||||
- 选茧计划 → `/prod/xuanjian/plan`
|
||||
- 选茧班组 → `/prod/xuanjian/banzu`
|
||||
组件均为 `prod/xuanjian/index`
|
||||
|
||||
> ⚠️ `DbSeeder.cs` 里**另有一处**生产菜单的批量插入(`SeedProdMenus`,含"纤度检验/黑板检验…"元组列表)。
|
||||
> 若启动后菜单未出现,需在那一处同步补上选剥茧的三个菜单项(本轮只改了 `BusinessSeedData.cs`)。
|
||||
|
||||
## 三、验证情况
|
||||
|
||||
- 前端 4 个新文件 lint:**0 错误**
|
||||
- `F9WebAiTest.Infrastructure` 编译:无 `error CS`(菜单种子数据通过)
|
||||
- 后端(19 轮):Application 已成功生成、Api 无 CS 错误
|
||||
|
||||
## 四、待办 / 可优化
|
||||
|
||||
1. **标包重改为注册表**:新系统有 `/sys/registry` 接口(老系统正是存注册表 `生产\选剥茧`)。
|
||||
当前用 localStorage 是临时方案,建议改为后端注册表读写,实现多端一致
|
||||
2. **领料单选择**:计划里的「领料单ID」目前是手填数字框,老系统是选择原料出库单,
|
||||
应改为下拉/弹窗选择并回填 `yllingliaodanCode`
|
||||
3. **日报/计划关联**:老系统计划可按领料单生成日报,当前两侧独立,未做联动
|
||||
4. 菜单如未显示,补 `DbSeeder.SeedProdMenus`
|
||||
5. 启动前需**重启后端服务**(新表在启动时建立;且 Api 进程会锁定 DLL 导致编译复制失败)
|
||||
|
||||
## 五、下次接续提示
|
||||
|
||||
- 选剥茧三个页面都挂在 `prod/xuanjian/index.vue`,改 Tab 逻辑看 `tabOf(route.path)`
|
||||
- 日报盈亏口径最易改错:起始日期由近及远跳过 `LiantongRate == 0` 的记录,见 19 轮文档第二节
|
||||
- 计划维度联统率用**包数**,日报用**重量**,两者分母不同,勿混用
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
@@ -0,0 +1,74 @@
|
||||
# 工作进度-21:修复「生产-选剥茧」菜单未显示
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、问题
|
||||
|
||||
用户反馈:**项目里没有"生产-选剥茧"模块,前端看不到菜单页面**。
|
||||
|
||||
## 二、根因(重要,后续加菜单必须记住)
|
||||
|
||||
项目中**有两处**菜单种子,但**只有 `DbSeeder` 是主流程**:
|
||||
|
||||
| 文件 | 实体 | 是否主流程 | 是否处理角色权限 |
|
||||
| --- | --- | --- | --- |
|
||||
| `Infrastructure/Data/DbSeeder.cs`(`SeedProdMenus` → `EnsureTopMenuWithChildren`) | **`SysMenu`** | ✅ 是(生产菜单实际来源) | ✅ 自动 `EnsureMenuPermission` 关联 admin |
|
||||
| `Infrastructure/Data/BusinessSeedData.cs`(`AddMenu`) | `Menu` | ❌ 否(上轮误改此处) | 需另走 adminRole 循环 |
|
||||
|
||||
20 轮只改了 `BusinessSeedData.cs`,所以菜单**没有生效**。
|
||||
|
||||
**结论:以后新增菜单,必须改 `DbSeeder.cs` 的 `SeedProdMenus`,用 `EnsureTopMenuWithChildren`。**
|
||||
|
||||
## 三、修复
|
||||
|
||||
在 `DbSeeder.cs`「生产-后缫」之后新增(Sort 7):
|
||||
|
||||
```csharp
|
||||
EnsureTopMenuWithChildren(fsql, snowflake, "/prod/xuanjian", "生产-选剥茧", "Grid", 7,
|
||||
new (string Name, string Path, string Component, string Permission, string Icon, int Sort)[]
|
||||
{
|
||||
("选茧日报", "/prod/xuanjian/rb", "prod/xuanjian/index", "prod:xuanjian:list", "Document", 1),
|
||||
("选茧计划", "/prod/xuanjian/plan", "prod/xuanjian/index", "prod:xuanjian:plan:list", "Calendar", 2),
|
||||
("选茧班组", "/prod/xuanjian/banzu", "prod/xuanjian/index", "prod:xuanjian:banzu:list", "User", 3)
|
||||
});
|
||||
```
|
||||
|
||||
并补「子菜单顺序归一」(`/prod/xuanjian/rb`=1、`/plan`=2、`/banzu`=3)。
|
||||
|
||||
`EnsureTopMenuWithChildren` 会:
|
||||
1. 建/更新一级目录(`/prod/xuanjian`,`MenuType_Enum.分组`)
|
||||
2. 建子菜单(不存在才插入)
|
||||
3. `EnsureMenuPermission` 关联 admin 角色 → 无需另外配权限
|
||||
|
||||
`BusinessSeedData.cs` 里 20 轮加的那段**保留**(`AddMenu` 有 `if (!Any(m => m.Path == path))` 幂等保护,不会重复)。
|
||||
|
||||
## 四、前端路由(已确认存在)
|
||||
|
||||
`web/src/router/index.js`:
|
||||
```js
|
||||
'prod/xuanjian/index': () => import('../views/prod/xuanjian/index.vue'),
|
||||
```
|
||||
菜单的 `Component` 字段 `prod/xuanjian/index` 与之对应,三个菜单共用该组件,
|
||||
由 `index.vue` 内 `tabOf(route.path)` 按路由末段自动切 Tab(rb / plan / banzu)。
|
||||
|
||||
## 五、验证
|
||||
|
||||
- `F9WebAiTest.Infrastructure` 编译:无 `error CS`
|
||||
|
||||
## 六、用户需要做的
|
||||
|
||||
1. **重启后端服务**(菜单在启动时 seed;且运行中 Api 进程锁 DLL 会导致编译复制失败)
|
||||
2. 重启后**重新登录 / 刷新**(菜单随登录接口下发)
|
||||
3. 用 **admin** 角色查看(权限只关联了 admin;其他角色需在角色管理里勾选)
|
||||
|
||||
## 七、遗留
|
||||
|
||||
- 非 admin 角色需在「角色管理」手动勾选选剥茧三个菜单
|
||||
- 标包重仍是 localStorage 临时方案,建议改 `/sys/registry`(见 20 轮)
|
||||
- 计划里「领料单ID」为手填数字框,老系统是选择原料出库单
|
||||
|
||||
## 八、下次接续提示
|
||||
|
||||
- 新增菜单一律改 **`DbSeeder.SeedProdMenus`**(`SysMenu` + `EnsureTopMenuWithChildren`),不要再只改 `BusinessSeedData`
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
@@ -0,0 +1,75 @@
|
||||
# 工作进度-22:重启前后端(使选剥茧菜单与代码生效)
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-21.md` 之外的 `工作进度-N.md`,
|
||||
> 并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、任务
|
||||
|
||||
重启前端与后端,使 19~21 轮的选剥茧模块(新表 / 新接口 / 新菜单)生效。
|
||||
|
||||
## 二、进程定位(本项目实际端口)
|
||||
|
||||
| 服务 | 端口 | 重启前 PID | 重启后 PID |
|
||||
| --- | --- | --- | --- |
|
||||
| 后端 `F9WebAiTest.Api` | **3000** | 23880(正是锁 DLL 的那个) | 8976 |
|
||||
| 前端 vite | **5173** | 21392 | 13696 |
|
||||
|
||||
- 后端端口来自 `backend/F9WebAiTest.Api/Properties/launchSettings.json` 的 `applicationUrl`
|
||||
- 前端端口 vite 默认 5173
|
||||
|
||||
## 三、重启步骤(可复用)
|
||||
|
||||
```powershell
|
||||
# 1) 按 PID 停止(先 netstat 确认,勿误杀其它 dotnet/node)
|
||||
Stop-Process -Id <后端PID> -Force
|
||||
Stop-Process -Id <前端PID> -Force
|
||||
|
||||
# 2) 启动后端(新窗口,非阻塞)
|
||||
Start-Process -FilePath "dotnet" -ArgumentList "run" `
|
||||
-WorkingDirectory "d:/f9webaitest/f9-web-ai-test/backend/F9WebAiTest.Api" -WindowStyle Minimized
|
||||
|
||||
# 3) 启动前端(见下方「坑」:npm/node 不在 PATH)
|
||||
Start-Process -FilePath "C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6\node.exe" `
|
||||
-ArgumentList "node_modules/vite/bin/vite.js" `
|
||||
-WorkingDirectory "d:/f9webaitest/f9-web-ai-test/web" -WindowStyle Minimized
|
||||
```
|
||||
|
||||
## 四、坑(下次直接照做)
|
||||
|
||||
1. **npm / node 不在 PATH**:本机 node 由 workbuddy 管理,路径为
|
||||
`C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6\node.exe`。
|
||||
`Get-Command npm/node` 返回空 → 必须用**完整路径**启动,不能 `npm run dev`。
|
||||
2. **`netstat | Select-String ":5|:8"` 会漏掉 3000**:过滤端口时注意 3000 不含 5/8,别误判"后端没运行"。
|
||||
3. **后端 DLL 被运行中的 Api 进程锁定**(MSB3021 / MSB3027):编译前先停后端,或只编译
|
||||
Application/Infrastructure 项目并单独筛 `error CS`。
|
||||
4. 多个 dotnet 进程并存(3916 / 9636 / 11548 / 29256 …),**必须按端口定位**再杀,不能
|
||||
`Stop-Process -Name dotnet` 全杀。
|
||||
|
||||
## 五、验证结果
|
||||
|
||||
| 检查项 | 结果 |
|
||||
| --- | --- |
|
||||
| 后端 `GET /api/prod/xjrb` | **401**(已注册、需认证)→ Controller 已加载 |
|
||||
| 前端 `http://localhost:5173` | **200** → vite 正常 |
|
||||
| 数据库 `backend/F9WebAiTest.Api/f9_web_ai_test_rbac.db` | 最后修改 **2026/10/26 10:49**(重启时刻)→ seed 已执行,菜单已写入 |
|
||||
|
||||
> 注:`bin/Debug/net8.0/` 下另有一份同名 db(10/20 的旧副本),**实际运行时用的是项目根目录下那份**。
|
||||
|
||||
## 六、用户待确认
|
||||
|
||||
1. **重新登录**(菜单随登录接口下发),用 **admin** 角色查看左侧是否出现「生产-选剥匣」→
|
||||
选茧日报 / 选茧计划 / 选茧班组
|
||||
2. 非 admin 角色需在「角色管理」手动勾选这三个菜单
|
||||
|
||||
## 七、遗留(承接 20/21 轮)
|
||||
|
||||
- 标包重仍是 localStorage 临时方案,建议改 `/sys/registry`
|
||||
- 计划里「领料单ID」为手填数字框,老系统是选择原料出库单
|
||||
- 日报与计划暂未做联动
|
||||
|
||||
## 八、下次接续提示
|
||||
|
||||
- 改后端代码后必须**重启后端**才生效;改前端 vite 会自动热更新
|
||||
- 重启前记得先停后端,否则 DLL 锁定导致编译复制失败
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
# 工作进度-23:移除现有考勤 + 移植「生产-职工考勤」调研(移植待续)
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、任务
|
||||
|
||||
1. **移除**新系统现有考勤(`attendance`:打卡/请假/审批/记录/我的)
|
||||
2. **移植**老系统「生产-职工考勤」:`D:\AntaiProject - 副本\trunk\WinClient\F9.Business.Prod\KQ`
|
||||
- `CQDJ` 考勤登记
|
||||
- `CQTJ` 考勤统计
|
||||
|
||||
## 二、本轮完成:移除现有考勤 ✅
|
||||
|
||||
### 后端删除
|
||||
- `Application/Services/Attendance/IAttendanceService.cs`、`AttendanceService.cs`
|
||||
- `Application/Dtos/Attendance/AttendanceDtos.cs`
|
||||
- `Api/Controllers/Attendance/AttendanceController.cs`
|
||||
- `Domain/Entities/Attendance/`:`LeaveRequest.cs`、`LeaveApprover.cs`、`AttendanceRecord.cs`
|
||||
- `DependencyInjection.cs`:删除 `AddScoped<IAttendanceService, AttendanceService>()`,
|
||||
**并删除 `using F9WebAiTest.Application.Services.Attendance;`**(否则 CS0234)
|
||||
|
||||
### 前端删除
|
||||
- `web/src/views/attendance/` 下 5 个页面:`approve/ leave/ my/ punch/ records/` 的 `index.vue`
|
||||
- `router/index.js`:删除静态路由 `attendance/approve`、`STATIC_ROUTES` 置空、删除 5 条组件映射
|
||||
- `views/dashboard/index.vue`:删除「考勤打卡」快捷卡片
|
||||
|
||||
### 菜单
|
||||
- `DbSeeder.cs`:移除 `SeedAttendanceMenus(fsql);` 调用(方法体保留为死代码,未调用即不生效)
|
||||
- ⚠️ **库中已存在的 `/attendance` 菜单记录不会自动删除**,需在「系统管理-菜单管理」手动删,
|
||||
或在 seed 中补清理逻辑(注意 `DbSeeder` 里菜单实体有 `SysMenu` 与 `Menu` 两种引用,别写错类型)
|
||||
|
||||
### 编译
|
||||
- 解决方案编译:**无 error CS** ✅
|
||||
|
||||
> 注:`views/notification/type/index.vue` 里 `/attendance/approve?leaveId={businessId}` 只是
|
||||
> **placeholder 示例文本**,不影响运行,未改(建议后续改成中性示例)。
|
||||
|
||||
## 三、老系统「职工考勤」调研结论(移植依据)
|
||||
|
||||
### 1. 实体
|
||||
|
||||
**考勤登记主表 `Cqdj`**(表 `biz_prod_kq_cqdj`,一人一天一条)
|
||||
`Date / Dep_Id / Worktype_Id / Employee_Id / Banci / Is_xuegtong`
|
||||
`Hours_standard / Hours_cq / Hours_qj / Hours_ld / Hours_jb / Hours_db / Hours_wp / Hours_kg / Hours_gs`
|
||||
`Cs_yeban(夜班次数) / Memo`
|
||||
唯一约束:`(Date, Employee_Id)`(一人一天一条);索引 `(Date,Dep_Id,Worktype_Id,Banci)`
|
||||
|
||||
**登记明细 `Cqdj_Item`**(表 `biz_prod_kq_cqdj_item`,一人一天多行,按出勤类型拆)
|
||||
`Cqdj_id / Dep_id / Worktype_id / Employee_id / Banci / Type_cq / Type_qj / Hours`
|
||||
`Jizu / Ct_start / Ct_end / Dangche_num / Memo`
|
||||
|
||||
**考勤统计 `Cqtj`**(表 `biz_prod_kq_cqtj`,**月快照**,非实时)
|
||||
`Year / Month / Dep_id / Worktype_id / Employee_id`
|
||||
`Days_cq_standard / Days_cq_actual / Hours_cq / Hours_qj`
|
||||
`Hours_qj_shijia/bj/hj/cj/lx/sangjia/gj/nj/tx`(事病婚产轮休丧公年调)
|
||||
`Hours_ld / Hours_jb / Hours_db / Hours_wp / Hours_kg / Cs_yeban`
|
||||
`Hours_fadingjiaqi / Hours_qj_qqmc / Hours_qj_qqcal`
|
||||
`Jine_quanqin / Jine_jb / Jine_jq_bz_hj/sangjia/bj/lx/fading/txnj / Jine_jq_bz`
|
||||
`Jine_yb / Jine_kg_kk / Jine_liudong / Jine_daiban`
|
||||
`Hours_xg_cq / Hours_xg_jiaban / Cq_tianci`
|
||||
|
||||
### 2. 枚举(硬编码,无配置表)
|
||||
|
||||
- 出勤类型 `Cqdj_CqType_Enum`:正常=1 请假=2 流动=3 加班=4 代班=5 外派=6 旷工=7 工伤=8
|
||||
- 请假类型 `Cqdj_QjType_Enum`:无=0 事假=1 病假=2 产假=3 婚假=4 丧假=5 公假=6 年假=7 调休=9 轮休=10
|
||||
- 校验:出勤类型=请假时请假类型≠无;非请假时请假类型必须为无
|
||||
- 班次 `Prod_Banci_Enum`:甲=1 乙=2
|
||||
|
||||
### 3. 考勤登记(CQDJ)规则
|
||||
|
||||
- 查询:日期 + **部门(必选)** + 工种(可空=全部) + 班次(默认甲) + 关键字
|
||||
- 主列表列:部门/工种/姓名/班次/学工/标准时长/出勤/请假/流动/加班/代班/外派/工伤/旷工/夜班/备注
|
||||
- 明细(选中职工联动):出勤部门/工种/姓名/班次/出勤类型/请假类型/时长/备注
|
||||
- **核心汇总公式**:
|
||||
```
|
||||
正常明细.Hours = 标准 - 请假 - 旷工 - 流动 - 外派 - 代班 - 工伤 (倒挤)
|
||||
Hours_cq = Σ(正常 + 流动 + 代班 + 外派 + 工伤) (不含加班)
|
||||
其余 Hours_qj/kg/ld/jb/wp/db/gs = 各类型明细求和
|
||||
校验 Hours_cq >= 0
|
||||
```
|
||||
- 约束:每人最多一条「正常」明细;不能删最后一条正常记录;保存前校验每人必须有正常记录
|
||||
- 新职工默认:`Hours_standard=9`、`Hours_cq=9`、明细 `Hours=9`、类型=正常/无;`Is_xuegong = !Base_is_zhuanzheng`
|
||||
- **保存方式**:`Cqdj_SaveCommand` = 按 `(日期,部门,工种,班次)` **先软删旧登记与明细,再整批新增**(不做增量 diff)
|
||||
- 按钮:设标准时长/设出勤时长/加班/流动/请假/公假/代班/夜班/添加职工/删除职工/刷新
|
||||
- 「添加其他车间」(`Page_Cqdj_addOtherChejian_select.cs`)**老系统中无任何页面引用**,属遗留未启用功能,可不移植
|
||||
|
||||
### 4. 考勤统计(CQTJ)规则
|
||||
|
||||
- 维度:**年/月(账期)+ 部门 + 工种 + 职工**(一人一行)
|
||||
- 数据来源:**快照**。点「录入」时:若该 年/月/部门 已有统计则取库;否则由 `Cqtj_TongjiQuery` 取账期内
|
||||
全部 Cqdj + Cqdj_Item + 薪资配置 + 职工,在客户端计算后 `Cqtj_Save`(先软删该年月部门旧数据再整批插入)
|
||||
- 派生公式(关键):
|
||||
```
|
||||
实际出勤天数 = Round(本部门 Hours_cq / 工种配置.HoursPerday, 2)
|
||||
出勤天次 = 该人该部门登记中 (Hours_cq + Hours_jb) > 0 的天数计数
|
||||
夜班补助 = 工种配置.JineYeban × Cs_yeban
|
||||
旷工考核 = 工种配置.JiaqiJineKuangongKk × Hours_kg
|
||||
流动工资 = Σ 工种配置.LiudongJineGuding × 流动时长
|
||||
代班工资 = Σ (代班部门工种.JineGangwei / (QqDaysStandard×HoursPerday)) × 代班时长
|
||||
带薪时长 = 轮休+年假+公假+调休+婚假+产假+丧假
|
||||
加班免扣请假 = 若(出勤+总加班) ≥ QsQuanqinDays×HoursPerday 且 总加班 ≥ QqHoursDkMinjiaban
|
||||
→ QqHoursDkQingjia,否则 0
|
||||
全勤计算请假 = 总请假 - 加班免扣 - 带薪时长
|
||||
假期补助 = 病假×BingjiaBz + 轮休×LunxiuBz + 婚假×HunjiaBz + 丧假×SangjiaBz
|
||||
+ (年假+调休)×NianjiaBz + 法定假补助
|
||||
(事假/产假/公假只计时长不计金额)
|
||||
加班费 = Σ 加班时长 × 单价(单价取岗位胜任考核 5 档对应 Jiaban_gwsrkhJine*,无考核取 JiabanJineBz)
|
||||
法定假期时长 = 职工配置.Hours_FadingBz + Hours_FadingGz
|
||||
```
|
||||
- **全勤奖 `quanqin()` 最复杂**(老系统在客户端 `Page_Cqtj.cs:837`,服务端 Command 是空实现):
|
||||
学工用 `XgJineQuanqin`;总旷工 ≥ 半天 → 0;总出勤 ≤ 3 天 → 0;当月离职且出勤 ≤15 天 → 0;
|
||||
单部门/工种:出勤 ≥15 天给满,否则 `全勤奖/(QqDaysStandard×HoursPerday) × 出勤时长`;
|
||||
多部门:`全勤奖/总出勤时长 × 本部门出勤时长`;入职日在账期内按标准折算;设备办全职特殊口径;
|
||||
最终:`全勤计算请假 ≥ QqHoursMaxQj → 0`,否则 `初始全勤奖 - 初始全勤奖/QqHoursMaxQj × 全勤计算请假`
|
||||
|
||||
### 5. 依赖的基础数据(移植前必须确认新系统是否具备)
|
||||
|
||||
| 依赖 | 说明 |
|
||||
| --- | --- |
|
||||
| 部门 | 排除「公司」类型,`Department_DutyType_Enum`(前缫=25/后缫=30/选剥茧=15/设备办=35) |
|
||||
| 职工 | `Employee_GetByDepartmentIdView(DepId, WorkTypeId, Banci)`;用 `Base_is_zhuanzheng`(→学工)、`Base_RuzhiDate`、`LizhiDate`、`Base_WrokStatus`;`Base_WorktypeId=0` 过滤掉 |
|
||||
| 工种 | `WorkType_GetByDepartmentIdView`;注册表 `基础数据\工种` 存 挡车工/车头工/值班长/选茧工 ID |
|
||||
| 账期 `Biz_Base_Zhangqi` | `Zhangqi_GetByDate`、`Zhangqi_GetIsZhaZhangByDate`(**扎帐即禁止增删改**) |
|
||||
| 薪资配置-工种 CONFGZ | HoursPerday、JineQuanqin、XgJineQuanqin、QqDaysStandard、QqHoursMaxQj、QqHoursDkMinjiaban、QqHoursDkQingjia、JiaqiJine*、JineYeban、JiaqiJineKuangongKk、LiudongJineGuding、JineGangwei、JiabanJineBz、Jiaban_gwsrkhJine*(5档) |
|
||||
| 薪资配置-职工 CONFEMPLOYEE | `Hours_FadingBz`、`Hours_FadingGz`、`IsXuegong` |
|
||||
| 薪资配置账期 CONFZQ | `QsQuanqinDays`(前缫出勤天数,必填) |
|
||||
| 岗位胜任考核 | 决定加班单价档位 |
|
||||
|
||||
## 四、待办(下一轮实施移植)
|
||||
|
||||
1. 后端实体:`Cqdj` / `CqdjItem` / `Cqtj`(放 `Domain/Entities/Prod/`,继承 `BaseEntity`,
|
||||
**必须 `using F9WebAiTest.Domain.Common;`**)
|
||||
2. DTO + Service + Controller(路由建议 `api/prod/kaoqin`),含:
|
||||
- 登记分页 / 按(日期,部门,工种,班次)整批保存(先软删后新增)/ 删除
|
||||
- 统计分页 / 生成(快照)/ 编辑保存 / 删除
|
||||
3. 前端页面(`web/src/views/prod/kaoqin/`):考勤登记(主从联动 + 明细按出勤类型)、考勤统计
|
||||
4. 菜单:在 `DbSeeder.SeedProdMenus` 用 `EnsureTopMenuWithChildren` 加(与选剥茧同法)
|
||||
- ⚠️ 加菜单必须改 **`DbSeeder.SeedProdMenus`(`SysMenu`)**,不要只改 `BusinessSeedData`
|
||||
5. 确认新系统是否已有薪资配置(CONFGZ/CONFZQ/CONFEMPLOYEE)——**统计页强依赖**,缺失则需先补齐或先做简化版统计
|
||||
6. 库中历史 `/attendance` 菜单手动删除
|
||||
|
||||
## 五、下次接续提示
|
||||
|
||||
- 出勤/请假/班次是**硬编码枚举**,前端下拉直接写死,不用查表
|
||||
- 登记保存是「整批覆盖」不是增量 diff,实现时别做反
|
||||
- 统计是**快照**(生成后落库),不是实时 SQL 汇总
|
||||
- 移植顺序建议:**先做考勤登记(CQDJ)**,统计(CQTJ)因强依赖薪资配置,放到薪资配置确认后再做
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
@@ -0,0 +1,78 @@
|
||||
# 工作进度-24:重启前后端 + 修复「报表设计管理器」打不开
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、重启前后端 ✅
|
||||
|
||||
| 服务 | 端口 | 重启后 PID |
|
||||
| --- | --- | --- |
|
||||
| 后端 `F9WebAiTest.Api` | 3000 | 26028 |
|
||||
| 前端 vite | 5173 | 25640 |
|
||||
|
||||
(复用 22 轮方法:按端口定位 PID → `Stop-Process` → `dotnet run` + node 完整路径启动 vite。
|
||||
npm/node 不在 PATH,必须用 `C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6\node.exe`。)
|
||||
|
||||
## 二、报表设计管理器:根因与修复 ✅
|
||||
|
||||
### 调用链
|
||||
|
||||
```
|
||||
报表管理中心 views/report/manage/index.vue 点列表行「设计」
|
||||
→ openDesign(row):designOnOpen=true、selectedId=row.id、designerKey++
|
||||
→ components/report/ReportEditor.vue 的 init() 末尾:
|
||||
if (props.openDesign && savedId.value) designVisible.value = true;
|
||||
→ 全屏 el-dialog 渲染 components/report/ReportDesign.vue(v-if="designVisible && savedId")
|
||||
→ ReportDesign 内「用本机锐浪 7 设计器编辑」按钮 → openGridDesigner()
|
||||
window.location.href = 'f9designer://open?base=..&rid=..&token=..&code=..'
|
||||
```
|
||||
|
||||
### 根因(实测逐层排查得出)
|
||||
|
||||
| 环节 | 实测结果 |
|
||||
| --- | --- |
|
||||
| `f9designer://` 协议注册 | ✅ **已注册**(`HKCR\f9designer`,含 `URL Protocol`) |
|
||||
| 协议 command | `powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "D:\f9webaitest\f9-web-ai-test\tools\report-designer\F9ReportDesignerHandler.ps1" "%1"` |
|
||||
| **该宿主脚本** | ❌ **不存在**(`tools\report-designer\` 整个目录都没有)→ **根因** |
|
||||
| 锐浪设计器 `gr7designer64.exe` | ✅ 已安装:`D:\GridReport7\gr7designer64.exe` |
|
||||
| 后端接口 | ✅ 齐全(见下) |
|
||||
|
||||
因为用了 `-WindowStyle Hidden`,powershell 启动失败时**没有任何提示** → 用户看到的就是"点了没反应/打不开"。
|
||||
|
||||
> 修正:此前 24 轮初稿判断"项目内没有配套协议注册文件"不准确 —— 协议已注册,
|
||||
> 缺的只是被协议指向的那个**宿主脚本**(属于应入库但漏掉的资产)。
|
||||
|
||||
### 后端接口(脚本依赖)
|
||||
|
||||
| 用途 | 接口 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 下载模板 | `GET /api/sys/report/{id}/template?access_token={token}` | `[AllowAnonymous]`,token 走 query;另有 `.grf` / `.json` 别名 |
|
||||
| 上传模板 | `POST /api/sys/report/{id}/template` | `IFormFile` 参数名 **`file`**;注释明确"保留给 f9designer:// 协议回传使用" |
|
||||
|
||||
### 修复:新建宿主脚本
|
||||
|
||||
`tools/report-designer/F9ReportDesignerHandler.ps1`(4434 字节,PowerShell 语法检查通过):
|
||||
|
||||
1. 解析 `f9designer://open?base=&rid=&token=&code=`(URL 解码)
|
||||
2. 定位设计器:默认 `D:\GridReport7\gr7designer64.exe`,可用环境变量 `F9_GR7_DESIGNER` 覆盖
|
||||
3. 下载模板到 `%TEMP%`(下载失败则建空白模板,兼容"新报表无模板")
|
||||
4. `Start-Process -Wait` 打开设计器并**阻塞等待关闭**
|
||||
5. 关闭后用 `System.Net.Http.MultipartFormDataContent` 上传(带 `Authorization: Bearer`)
|
||||
6. 全程写日志 `tools/report-designer/logs/designer_yyyyMMdd.log`
|
||||
|
||||
> 兼容性说明:用 .NET `HttpClient` 手工构造 multipart,而不是 PowerShell 7 的 `-Form`,
|
||||
> 因为注册表里调用的是 `powershell.exe`(Windows PowerShell 5.1 不支持 `-Form`)。
|
||||
|
||||
### 待用户验证
|
||||
|
||||
在报表中心点「设计」→「用本机锐浪 7 设计器编辑」,应弹出锐浪设计器;关闭后模板自动回传。
|
||||
若仍无反应,看 `tools/report-designer/logs/designer_yyyyMMdd.log`。
|
||||
|
||||
## 三、下次接续提示
|
||||
|
||||
- 报表相关文件:`views/report/manage/index.vue`、`views/report/center/index.vue`、
|
||||
`components/report/ReportEditor.vue`、`components/report/ReportDesign.vue`、`utils/gridreport/*`、
|
||||
后端 `Services/Reports/ReportService.cs` + `Controllers/SysReportController.cs`
|
||||
- 设计面板打开前提:报表**必须已保存**(`v-if="designVisible && savedId"`),未保存的报表点了无反应
|
||||
- 设计面板有两条路径:① 可视化画布(纯前端、无外部依赖)② 本机锐浪设计器(需本协议链)
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
# 工作进度-25:修复「报表设计打不开」+ 补上「生产-考勤 · 考勤登记」
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、用户反馈
|
||||
|
||||
1. 报表设计页面打不开(之前可以用,今天突然不行)
|
||||
2. 生产-考勤也没有
|
||||
|
||||
## 二、报表问题:两个根因,都已修复 ✅
|
||||
|
||||
### 根因 A:vite 开发服务器挂死(最直接的"打不开")
|
||||
|
||||
| 检查 | 结果 |
|
||||
| --- | --- |
|
||||
| 后端 3000 | ✅ 正常(`/sys/report` 列表、模板下载、预览全部 200) |
|
||||
| 前端 5173 早期请求 | ✅ 200(`report/manage`、`ReportEditor`、`ReportDesign`、`grlib/grhtml5-7-min.js`) |
|
||||
| 稍后 `/`、`/src/views/prod/lsjl/index.vue` | ❌ **全部超时**(进程 25640 仍在 LISTENING,CPU 近乎 0 → 卡死不服务) |
|
||||
|
||||
→ 页面请求全部挂住,表现为"点了没反应 / 打不开"。
|
||||
|
||||
**修复**:按端口定位 PID → `Stop-Process -Id 25640 -Force` → 用完整路径 node 重启 vite(npm 不在 PATH):
|
||||
|
||||
```powershell
|
||||
Start-Process -FilePath 'C:\Users\32453\.workbuddy\binaries\node\versions\22.22.2-6\node.exe' `
|
||||
-ArgumentList 'node_modules/vite/bin/vite.js' -WorkingDirectory 'd:/f9webaitest/f9-web-ai-test/web' -WindowStyle Minimized
|
||||
```
|
||||
|
||||
重启后 PID **26328**:`/` 200、`prod/kaoqin/index.vue` 200、`report/manage/index.vue` 200。
|
||||
|
||||
### 根因 B:f9designer:// 宿主脚本解析 URL 失败(点「设计器编辑」无反应)
|
||||
|
||||
日志 `tools/report-designer/logs/designer_20261026.log` 里今天 6 次唤起全部报错:
|
||||
|
||||
```
|
||||
错误: 缺少 base / rid 参数(Url=f9designer://open/?base=...)
|
||||
```
|
||||
|
||||
原因:**Windows Shell 会在协议主机后补一个 `/`**,实际收到的是 `f9designer://open/?base=...`,
|
||||
而脚本按固定前缀 `^f9designer://open\?` 剥离失败 → `base` 解析为空 → 直接 throw。
|
||||
注册表里是 `-WindowStyle Hidden`,失败无提示 → 用户看到"点了没反应"。
|
||||
|
||||
**修复** `tools/report-designer/F9ReportDesignerHandler.ps1`:
|
||||
|
||||
1. 解析改为「取第一个 `?` 之后的全部内容」,兼容 `open?` 与 `open/?`
|
||||
2. `base` 缺失时回退 `http://localhost:5173`(并记日志)
|
||||
3. 新增 `Show-Error`:失败时弹 Windows MessageBox(含日志路径),不再静默
|
||||
4. ⚠️ **踩坑**:编辑工具把文件存成了 **UTF-8 无 BOM**,Windows PowerShell 5.1 按 ANSI 读取导致中文注释/字符串乱码、脚本解析失败。
|
||||
已用 `UTF8Encoding($true)` 重写为 **UTF-8 with BOM**,`ParseFile` 复检通过。
|
||||
**下次改这个脚本后务必确认 BOM 仍在**(`[System.IO.File]::ReadAllBytes($p)[0..2]` 应为 239,187,191)。
|
||||
|
||||
**端到端实测**(用 `F9_GR7_DESIGNER` 指向一个立刻退出的程序代替设计器):
|
||||
|
||||
```
|
||||
base=http://localhost:5173 rid=141374578868883456 code=PROD_QS_1
|
||||
已下载 8300 字节 → 启动设计器(等待关闭)→ 设计器已关闭 → 上传结果: OK → 完成
|
||||
```
|
||||
|
||||
模板回传后长度仍为 7639 字节、报表 `hasTemplate=True`,未损坏。
|
||||
|
||||
## 三、生产-考勤:本轮补上「考勤登记(CQDJ)」✅
|
||||
|
||||
> 「没有」的原因:23 轮按计划**删除了旧考勤**(`/attendance`),而「生产-职工考勤」移植尚未开始。
|
||||
|
||||
### 后端(新增)
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `Domain/Entities/Prod/Cqdj.cs` | `Cqdj`(表 `biz_prod_kq_cqdj`)+ `CqdjItem`(表 `biz_prod_kq_cqdj_item`),继承 `BaseEntity`,**自动建表**(`DbSeeder.SyncStructure` 反射扫描) |
|
||||
| `Application/Dtos/Prod/KaoqinDtos.cs` | `CqdjItemDto / CqdjRowDto / CqdjViewDto / CqdjSaveDto / CqdjEmpOptionDto` |
|
||||
| `Application/Services/Prod/KaoqinService.cs` | 接口+实现同文件:整组查询 / 整组覆盖保存 / 整组删除 / 可选职工 |
|
||||
| `Api/Controllers/Prod/KaoqinController.cs` | `[Route("api/prod/kaoqin")]` `[Authorize]`:`GET|POST|DELETE /cqdj`、`GET /cqdj/employees` |
|
||||
| `Application/DependencyInjection.cs` | `services.AddScoped<IKaoqinService, KaoqinService>();` |
|
||||
|
||||
规则按 23 轮调研落地:
|
||||
|
||||
- 查询口径:日期 + 部门(必选)+ 工种(0=全部)+ 班次(甲1/乙2)+ 关键字
|
||||
- 职工来源:本部门、工种≠0、非离职;未登记者生成默认值 9 小时 + 一条「正常」明细
|
||||
- **正常明细倒挤**:`正常 = 标准 - 请假 - 旷工 - 流动 - 外派 - 代班 - 工伤`;`出勤 = 正常+流动+代班+外派+工伤`
|
||||
- 保存 = **先软删该(日期+部门+工种+班次)旧登记与明细,再整批新增**(非增量 diff)
|
||||
- 校验:每人必须有且仅有一条「正常」;请假必须选请假类型、非请假必须为「无」;出勤不能为负
|
||||
|
||||
### 前端(新增)
|
||||
|
||||
- `web/src/views/prod/kaoqin/index.vue`:上表(职工行 + 标准时长/夜班/备注 + 各时长实时汇总)下表(选中职工的明细:出勤类型/请假类型/时长/机组/车台/挡车数/备注),
|
||||
工具栏含 查询 / 设标准时长 / 添加职工 / 删除整组 / 保存
|
||||
- `web/src/router/index.js`:`'prod/kaoqin/index': () => import('../views/prod/kaoqin/index.vue')`
|
||||
|
||||
### 菜单(`DbSeeder.SeedProdMenus`)
|
||||
|
||||
```csharp
|
||||
EnsureTopMenuWithChildren(fsql, snowflake, "/prod/kaoqin", "生产-考勤", "Clock", 8,
|
||||
new[] { ("考勤登记", "/prod/kaoqin/cqdj", "prod/kaoqin/index", "prod:kaoqin:cqdj:list", "EditPen", 1) });
|
||||
```
|
||||
|
||||
同时**清理了遗留旧考勤菜单**(页面组件已删,留着会点开空白页):
|
||||
删除 `sys_rbac_menus` 中 `path LIKE '/attendance%'` 的记录及其 `role_permissions`,
|
||||
并删除 `code LIKE 'attendance:%'` 的权限单元。
|
||||
|
||||
### 验证
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| 解决方案编译 | **0 个错误** |
|
||||
| `GET /auth/menus` | ✅ 出现 `生产-考勤 → 考勤登记`,旧「考勤管理」已消失 |
|
||||
| `GET /prod/kaoqin/cqdj?date=2026-10-26&depId=34&banci=1` | ✅ 46 人,每人默认 9 小时 + 1 条正常明细 |
|
||||
| `POST /prod/kaoqin/cqdj` | ✅ `count=46`;复查 `saved=46` |
|
||||
| `DELETE /prod/kaoqin/cqdj` | ✅ `count=46`;复查 `saved=0`(测试数据已清理) |
|
||||
| 前端模块编译 | ✅ vite 200 |
|
||||
|
||||
## 四、待办
|
||||
|
||||
1. **考勤统计(CQTJ)**:月快照,强依赖工种薪资配置 `ConfGz`(已有)+ 职工薪资配置 CONFEMPLOYEE / 账期薪资配置 CONFZQ(**后端还没有,需先建**)
|
||||
2. 老系统「添加其他车间」功能无页面引用,不移植
|
||||
3. 报表设计:可视化画布与锐浪设计器二选一(用设计器保存后产物为 `_WR7_`,画布将不可解析)
|
||||
4. `views/notification/type/index.vue` 里的 `/attendance/approve?leaveId=` 仍是示例文本,建议改成中性示例
|
||||
|
||||
## 五、下次接续提示
|
||||
|
||||
- 改后端代码后**必须重启后端**(先按端口 Stop-Process,否则 DLL/obj 锁定导致编译失败);改前端 vite 热更新,但 **vite 卡死时要按端口杀掉重启**
|
||||
- 登录 admin / 123456;后端 3000(PID 23968),前端 5173(PID 26328)
|
||||
- 考勤相关文件:`Domain/Entities/Prod/Cqdj.cs`、`Dtos/Prod/KaoqinDtos.cs`、
|
||||
`Services/Prod/KaoqinService.cs`、`Controllers/Prod/KaoqinController.cs`、`views/prod/kaoqin/index.vue`
|
||||
- 报表相关:`views/report/manage/index.vue`、`components/report/ReportEditor.vue`、`ReportDesign.vue`、
|
||||
`tools/report-designer/F9ReportDesignerHandler.ps1`(**务必保持 UTF-8 BOM**)
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
# 工作进度-26:参考老系统完成整个考勤模块(CQDJ 补齐 + CQTJ 新建 + 依赖配置)
|
||||
|
||||
> **协作规则(长期生效)**:**每次对话结尾都要生成工作进度**。
|
||||
> 即在每轮对话结束前,把本轮完成的内容追加为 `工作进度/工作进度-N.md`,并在文档中保留本条规则,方便下一轮接续。
|
||||
|
||||
## 一、需求
|
||||
|
||||
用户要求:**完善整个考勤模块,不要删减**,并给出老系统参考目录
|
||||
`D:\AntaiProject - 副本\trunk\WinClient\F9.Business.Prod\KQ`(CQDJ 考勤登记 + CQTJ 考勤统计)。
|
||||
|
||||
## 二、老系统源码研读结论(KQ 目录)
|
||||
|
||||
| 文件 | 大小 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| `CQDJ\Page_Cqdj.cs` | 19KB | 查询口径:日期 + 部门 + 工种 + 班次;录入/删除整组、初始化为正常出勤;「从指定日期复制」 |
|
||||
| `CQDJ\Page_Cqdj_Edit.cs` | 77KB | 工具栏 8 个按钮(标准/出勤/加班/流动/事假/公假/代班/夜班)+ 添加/删除职工 + 刷新;保存整组覆盖、倒挤「正常」 |
|
||||
| `CQDJ\Page_Cqdj_addOtherChejian_select.cs` | — | 确认**无引用**,遗留功能,不移植 |
|
||||
| `CQTJ\Page_Cqtj.cs` | 84KB | 统计是**月快照**;录入时库中有快照取库,否则 `CqtjViews` 实时汇总;含 `quanqin` 全勤奖、`jiaqiBuzhuJisuan` 假期补助、`jisuanJiabanMkHours` 加班免扣、`jisuanJianbanJine` 加班费、`liudongJineJisuan` 流动、`daibanJineJisuan` 代班、`jisuanCqTianci` 出勤天次、`Yijianshengcheng` 一键生成 |
|
||||
| `CQTJ\Page_Cqtj_Edit.cs` | 7.5KB | 可编辑列:年假/公假/调休/法定假/全勤免扣/全勤计算/全勤奖/加班费/流动工资/代班工资/假期补助分项与合计/夜班补助/旷工考核 |
|
||||
|
||||
CQTJ 强依赖(老系统在 PayRoll 侧):
|
||||
- **CONFZQ 薪资配置-账期**:`QsQuanqinDays` 前缫出勤天数(为 0 时直接抛错不让录入)
|
||||
- **CONFEMPLOYEE 薪资配置-职工**:`Hours_FadingBz` / `Hours_FadingGz` / `IsXuegong`
|
||||
- **岗位胜任考核**:考核结果决定加班费单价档位(无记录时回落 `JiabanJineBz`)
|
||||
|
||||
## 三、本轮新增 / 修改
|
||||
|
||||
### 后端(新增)
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `Domain/Entities/Prod/Cqtj.cs` | **考勤统计实体**(`biz_prod_kq_cqtj`),含天数/时长/请假分项/学工/法定假/全勤相关时长/全部金额字段 |
|
||||
| `Domain/Entities/PayRoll/ConfEmployee.cs` | `ConfZq`(`ConfZqs`)、`ConfEmployee`(`ConfEmployees`)、`Gwsrkh`(`Gwsrkhs`) |
|
||||
| `Dtos/Prod/KaoqinDtos.cs` | 追加 `CqtjRowDto / CqtjSaveDto / CqtjGenerateDto / CqtjViewDto` |
|
||||
| `Dtos/PayRoll/ConfEmployeeDtos.cs` | `ConfZqDto / ConfEmployeeDto / GwsrkhDto` |
|
||||
| `Services/Prod/KaoqinService.cs` | 追加 CQTJ:分页、录入(取库 or 实时汇总)、保存(整组覆盖)、删除、一键生成、全部删除;并新增 8 个口径函数 |
|
||||
| `Services/PayRoll/ConfEmployeeService.cs` | `IConfZqService / IConfEmployeeService / IGwsrkhService` 接口 + 实现 |
|
||||
| `Api/Controllers/Prod/KaoqinController.cs` | 追加 `GET/POST/DELETE /cqtj`、`GET /cqtj/edit`、`POST /cqtj/generate` |
|
||||
| `Api/Controllers/PayRoll/ConfEmployeeController.cs` | `api/payroll/confzq`、`api/payroll/confemployee`、`api/payroll/gwsrkh` |
|
||||
| `Application/DependencyInjection.cs` | 注册 `IConfZqService / IConfEmployeeService / IGwsrkhService` |
|
||||
| `Infrastructure/Data/DbSeeder.cs` | 菜单:生产-考勤 增「考勤统计」;薪资 增「账期薪资配置 / 职工薪资配置 / 岗位胜任考核」 |
|
||||
|
||||
### 后端口径(严格对齐老系统)
|
||||
|
||||
- **正常倒挤**:`正常 = 标准 - 请假 - 旷工 - 流动 - 外派 - 代班 - 工伤`;`出勤 = 正常 + 流动 + 代班 + 外派 + 工伤`(不含加班)
|
||||
- **出勤天数**:`标准 = 工种配置 QqDaysStandard`;`实际 = 本部门出勤时长 / HoursPerday`;`天次 = (出勤+加班)>0 的天数`
|
||||
- **全勤奖** `quanqin()`(完整移植,含多部门 / 多工种分支):
|
||||
1. 总旷工 ≥ 半天 → 0;2. 总出勤 ≤ 3 天 → 0;
|
||||
3. 多部门:`∑出勤+带薪 ≥ 15 天` 按实际出勤折算,否则按标准出勤折算;离职 / 新入职分别处理;
|
||||
4. 单部门:`∑出勤+带薪请假 ≥ 15 天` 取全额,否则 `全勤奖/标准出勤时长×总出勤`;
|
||||
5. 设备办全职:出勤含加班达前缫天数且不低于标准 → 请假不扣;
|
||||
6. 其余:`全勤奖 - (全勤奖 / QqHoursMaxQj) × 请假时长`
|
||||
- **假期补助**:按明细「请假类型 × 出勤工种」分组,病假/轮休/婚假/丧假/法定假/年假/调休分别乘工种单价;`法定假 = 补助小时×JiaqiJineFadingBz + 工资小时×JiaqiJineFadingGz`
|
||||
- **加班免扣请假**:`出勤+加班 ≥ 前缫出勤天数×HoursPerday 且 加班 ≥ QqHoursDkMinjiaban` → 免扣 `QqHoursDkQingjia`
|
||||
- **加班费**:按加班明细工种取单价;有岗位胜任考核时按 欠合格/期望/合格/胜任/超胜任 取 `Jiaban_GwsrkhJine*`,无记录取 `JiabanJineBz`;学工加班 = `XgJineGangwei /(QqDaysStandard×HoursPerday) × 时长`
|
||||
- **流动** = `LiudongJineGuding × 时长`;**代班** = `JineGangwei /(QqDaysStandard×HoursPerday) × 时长`;**夜班** = `JineYeban × 夜班次数`;**旷工考核** = `JiaqiJineKuangongKk × 旷工时长`
|
||||
- **扎帐校验**:账期 `IsZhaZhang` 时禁止保存 / 删除 / 生成
|
||||
|
||||
### 前端
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `views/prod/kaoqin/index.vue`(改) | 补齐工具栏:刷新 / 复制指定日期 / 设标准时长 / 设出勤时长 / **加班 / 流动 / 事假 / 公假 / 代班 / 夜班** / 添加职工 / 删除职工 / 删除整组 / 保存;职工表加多选列;明细表加「出勤部门 / 出勤工种」(代班、流动跨车间);保存前「出勤超标准」二次确认;新增复制日期弹窗(可勾选初始化为正常出勤) |
|
||||
| `views/prod/kaoqin/cqtj/index.vue`(新) | 考勤统计:年月 + 部门 + 工种 + 关键字;分组表头(出勤天数 / 时长 / 学工 / 请假分项 / 全勤与金额);录入(弹窗内可编辑带「*」字段)、删除、**一键生成**、全部删除;分页 |
|
||||
| `views/payroll/confzq/index.vue`(新) | 账期薪资配置:年度/月份/前缫出勤天数 |
|
||||
| `views/payroll/confemployee/index.vue`(新) | 职工薪资配置:职工/工种/法定补助h/法定工资h/学工 |
|
||||
| `views/payroll/gwsrkh/index.vue`(新) | 岗位胜任考核:年度/月份/部门/职工/考核结果 |
|
||||
| `router/index.js`(改) | 新增 5 条 componentMap |
|
||||
|
||||
## 四、验证
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| 解决方案编译 | **0 个错误** |
|
||||
| `GET /auth/menus` | ✅ 生产-考勤 → 考勤登记 / 考勤统计;薪资 → …/账期薪资配置 / 职工薪资配置 / 岗位胜任考核 |
|
||||
| 账期薪资配置 | ✅ POST 2026/10 QsQuanqinDays=26 成功 |
|
||||
| 考勤登记 | ✅ 46 人保存成功(含 1 人加班 2h + 病假 1h + 夜班 1) |
|
||||
| 实时汇总 | ✅ `曾红君 出勤=8 加班=2 请假=1 实际天=0.89 天次=1 加班费=30 病假补助=5 补助合计=5 夜班补助=20`(与手算一致:正常 9-1=8,加班费 2×15,病假 1×5,夜班 1×20) |
|
||||
| 统计保存 / 列表 / 取库 | ✅ 保存 46 → 列表 total=46 → 再录入 `exists=True` |
|
||||
| 删除 / 一键生成 | ✅ 删除 46;一键生成 1 个车间 |
|
||||
| 前端 5 个页面 | ✅ vite 全部 200,无 lint |
|
||||
|
||||
测试数据(2026-10-26 的 46 条登记、统计快照、测试用工种薪资配置 3 条、账期配置 1 条)**已全部清理**。
|
||||
|
||||
## 五、待办 / 已知差异
|
||||
|
||||
1. **跨部门重复考勤提示**:老系统在加载时提示「X 职工已在 Y 部门录入」,本轮未移植(需额外接口),后续补
|
||||
2. **岗位胜任考核**放在【薪资】下(老系统属 `CalXzMain` 薪资模块),仅按年月维护考核结果,未做考核流程
|
||||
3. 统计页的**列宽 / 分组表头**在窄屏下需横向滚动,后续可加列配置
|
||||
4. 报表设计器脚本 `F9ReportDesignerHandler.ps1` **改完必须确认 UTF-8 BOM 仍在**
|
||||
5. `views/notification/type/index.vue` 里仍有 `/attendance/approve?leaveId=` 示例文本
|
||||
|
||||
## 六、下次接续提示
|
||||
|
||||
- 改后端先按端口 `Stop-Process` 再编译,否则 DLL 锁定;vite 卡死时同样按端口杀掉重启
|
||||
(当前:后端 3000 PID 17000,前端 5173 PID 26328)
|
||||
- 登录 admin / 123456
|
||||
- 考勤相关文件:
|
||||
- 后端 `Domain/Entities/Prod/Cqdj.cs`、`Cqtj.cs`、`Domain/Entities/PayRoll/ConfEmployee.cs`
|
||||
- `Dtos/Prod/KaoqinDtos.cs`、`Dtos/PayRoll/ConfEmployeeDtos.cs`
|
||||
- `Services/Prod/KaoqinService.cs`(CQDJ + CQTJ 全部口径)、`Services/PayRoll/ConfEmployeeService.cs`
|
||||
- `Controllers/Prod/KaoqinController.cs`、`Controllers/PayRoll/ConfEmployeeController.cs`
|
||||
- 前端 `views/prod/kaoqin/index.vue`、`views/prod/kaoqin/cqtj/index.vue`、
|
||||
`views/payroll/confzq|confemployee|gwsrkh/index.vue`
|
||||
- 老系统参考:`D:\AntaiProject - 副本\trunk\WinClient\F9.Business.Prod\KQ\`
|
||||
- **每轮对话结尾记得生成本工作进度文档**
|
||||
@@ -0,0 +1,39 @@
|
||||
# 工作进度-27
|
||||
|
||||
> 规则原文:每次对话结尾都要生成工作进度
|
||||
|
||||
## 本轮任务
|
||||
|
||||
回答用户提问:**本项目采用的架构是什么**(纯咨询,无代码改动)。
|
||||
|
||||
## 本轮完成内容
|
||||
|
||||
1. 梳理并确认项目整体架构:
|
||||
- 总体:前后端分离 + 单体后端四层分层(DDD + CQRS),IIS 单站点同源部署(`wwwroot` 静态资源 + `MapFallbackToFile("index.html")`)。
|
||||
- 后端 .NET 8 四层:`F9WebAiTest.Domain` / `.Application` / `.Infrastructure` / `.Api`,依赖方向 `Api → Application → Domain ← Infrastructure`。
|
||||
- CQRS + MediatR 12.4.1(`Application/CQRS/SYS/**/Commands|Queries`,45 个文件),读写仓储分离。
|
||||
- 工作单元 `IUnitOfWork_F9`、雪花 ID 单例、FreeSql 软删除全局过滤器。
|
||||
- 领域事件 `BusinessChangedEvent` → MediatR Handler → SignalR `/hubs/notification` 推送。
|
||||
- RBAC:用户–角色–权限–菜单,JWT Bearer;SignalR 与报表下载走 query string `access_token`。
|
||||
- `LongToStringJsonConverter` 解决雪花 ID 精度丢失。
|
||||
- 前端 `web/`:Vue 3 + Vite + Element Plus + Pinia + Vue Router + axios,NSwag 生成 `src/api/client.ts`,`v-permission` 按钮级权限,动态路由。
|
||||
- 数据层:SQLite + FreeSql(CodeFirst + `DbSeeder` 种子),枚举映射 int 兼容旧库。
|
||||
- 遗留/辅助目录:`client/` + `server/`(早期「社区生活圈」Express + Vue3 原型)、`TempleRun/`(旧 WinForms 参考)、`tools/`、`deploy-iis.ps1`、`update-iis.ps1`。
|
||||
|
||||
## 改动文件
|
||||
|
||||
无(本轮为架构说明,未修改任何代码)。
|
||||
|
||||
## 发现的问题(待修正)
|
||||
|
||||
- 根目录 `README.md` 中「数据库:SQLite(EF Core)」的表述已过时,实际 ORM 为 **FreeSql**;README 也缺少 CQRS/MediatR、SignalR、DDD 分层等当前架构描述。
|
||||
|
||||
## 验证情况
|
||||
|
||||
- 已通过目录浏览、README、`F9WebAiTest.Api.csproj`、`Program.cs`、`Infrastructure/DependencyInjection.cs`、`web/package.json`、`server/package.json`、`client/package.json` 交叉核对确认。
|
||||
- 未编译、未运行(无代码改动)。
|
||||
|
||||
## 待办
|
||||
|
||||
1. (可选)更新 `README.md`:EF Core → FreeSql,补充 CQRS/MediatR、SignalR 实时推送、IIS 同源部署说明。
|
||||
2. 继续按既有计划推进业务模块迁移。
|
||||
Reference in New Issue
Block a user