# 工作进度-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()`, **并删除 `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)因强依赖薪资配置,放到薪资配置确认后再做 - **每轮对话结尾记得生成本工作进度文档**