电子线束ERP - HR人事考勤模块详细功能介绍|C/S开发框架

考勤模块是 ERP 里最容易"看起来简单、做起来失控"的模块之一。一旦业务变成多班次接力、按拉线错峰吃饭、直接与间接人工口径不同,原来那套"读打卡表、算差值"的写法很快就会崩——每一处硬编码都会在下一个客户现场变成 Bug。
本文以电子线束行业的 HR 人事考勤模块为例,介绍基于 CSFrameworkV6 平台落地这类模块时的功能划分、关键实现思路、技术栈选型与外部设备接入方式,供做同类业务系统的开发者参考。
一、先定数据流,再谈功能
模块的功能清单很长,但骨架只有一条数据流。把它定清楚,后面的功能才有位置可放:
| 环节 | 职责 | 主要表 / 入口 |
|---|---|---|
| 采集 | 设备同步、Excel 导入、HR 补卡 | tb_AttendTime |
| 归档 | 匹配班次与节假日,逐日判定迟到/早退/缺卡 | tb_AttendArchive(HRCoreDAL_AttendComputing) |
| 报表 | 按归档逐日重算工时,汇总到人/部门 | HRCoreDAL_AttendReport |
| 薪资 | 异常与工时进入工资核算 | 考勤工资调整、薪资调整 |
关键决策是在原始打卡与薪资之间强制插入一层归档。好处有三个:计算结果可审计(每笔工资能追溯到具体日期、班次、卡)、口径可对比(改造前后跑同月归档逐字比对,等价性可证明)、数据可封账(薪资结完不再变动)。代价是要多写一个计算引擎,但这笔账值得。
二、功能清单
1. 人力资源
- 员工档案(含身份证阅读器录入)、员工合同、岗位调整记录、薪资调整记录
- 员工异动日志:调岗/辞职/自离/辞退/劝离/急辞/开除/停薪留职 8 类异动统一落日志表,记录异动前后部门、岗位、状态与生效日期
- 恢复在职:误操作可回退,同时补写异动日志,避免直接改库造成履历断档
- 考勤工资调整:按人按月调整考勤工资项
2. 考勤配置
- 考勤参数配置(14 项算法参数 + 特殊考勤日两个页签,同一 DAL)
- 班次管理、排班管理(部门/拉线/人员三级适用范围)、节假日管理
- 考勤设备管理(IP/MAC/端口/SDK 登录测试)、考勤设备绑定
3. 考勤处理
- 原始考勤记录、导入考勤数据、考勤计算(归档)、补卡管理、请假管理
4. 报表
- 个人考勤报表(含横向版)、部门考勤报表、原始考勤记录表
三、三个关键实现
1. 班次槽位解耦:把字面量换成语义
最初的实现里,取卡算法到处写着 "A1"、"B1"、"C1"——上午、下午、加班三个班次用字符串字面量判断。业务提出"要支持 A2/B2/C2 错峰班次"时,这套写法立刻变成灾难:十几处硬编码要同时改,漏一处就判错。
解法是把字面量抽象成槽位:班次编号首字母定槽位(A→上午、B→下午、C→加班、X→特殊),数字只表示错峰分组。槽位用只读计算属性从班次编号现算,因此不可能与字段不同步:
public static class AttendSlot
{
public const int ShangWu = 1; // 上午
public const int XiaWu = 2; // 下午
public const int JiaBan = 3; // 晚上加班
public const int TeShu = 9; // 特殊班
/// <summary>班次编号首字母定槽位,数字只表示错峰分组(A1/A2 同槽位)</summary>
public static int GetSlot(string shiftId)
{
if (string.IsNullOrWhiteSpace(shiftId)) return TeShu;
switch (shiftId.Trim().Substring(0, 1).ToUpper())
{
case "A": return ShangWu;
case "B": return XiaWu;
case "C": return JiaBan;
default: return TeShu;
}
}
}
另一个细节:"下一段班"不能用"槽位数值 + 1"去推,而应按排班单明细的 SortID 排序取 ±1。实测中存在一张单是 X1 + X2(首字母相同),按槽位推会取错,按排序取才对。
2. 适用范围解析收口到一个静态类
排班单原本只能按部门,后来扩到"部门 / 拉线 / 人员",优先级 人员 > 拉线 > 部门,命中即整单替换。麻烦的是,排班单在三个地方被消费:考勤计算(封账)、考勤报表、员工排班查询。三处各写一遍匹配逻辑,口径必然发散。
做法是抽出一个统一解析器,三处全部改调它:
public static class AttendScheduleScopeResolver
{
public const string ScopeDept = "部门";
public const string ScopeLine = "拉线";
public const string ScopeEmp = "人员";
public const string UnrestrictedFlag = "*";
/// <summary>按 人员 > 拉线 > 部门 优先级解析员工命中的排班单</summary>
public static List<string> FilterDocNos(List<ScheduleDoc> docs, Employee emp)
{
// 1) 人员级:InfoIDs 包含该员工工号
var byEmp = docs.Where(d => NormalizeScope(d.ScopeType) == ScopeEmp
&& MatchMultiValue(d.InfoIDs, emp.InfoID)).ToList();
if (byEmp.Any()) return byEmp.Select(d => d.DocNo).ToList();
// 2) 拉线级
var byLine = docs.Where(d => NormalizeScope(d.ScopeType) == ScopeLine
&& MatchMultiValue(d.LineNums, emp.LineNum)).ToList();
if (byLine.Any()) return byLine.Select(d => d.DocNo).ToList();
// 3) 部门级(ScopeType 为空/NULL 一律按部门,老数据零影响)
return docs.Where(d => NormalizeScope(d.ScopeType) == ScopeDept
&& d.CenterID == emp.DeptCode)
.Select(d => d.DocNo).ToList();
}
}
两个约束值得记下来:范围值留空表示"不限"(等价于部门级,保证老数据行为不变);多值匹配必须精确切分(按半角/全角逗号、分号切分后 Trim 再比),不能用 Contains 做子串匹配,否则部门码 / 拉线码互为子串时会误命中。
3. 参数走反射缓存,界面改完即生效
14 项考勤参数如果做成方法参数层层传递,调用链会立刻失控。这里的做法是把参数表反射成强类型对象,进程内单例缓存:
// 1) 参数表 tb_AttendOptions:ParamCode 必须等于 AttendOptions 模型的属性名
// 2) 首次访问时反射加载,按 ParamCode 赋值到对象属性
AttendOptions options = HRCoreDAL.GetAttendOptionsCache();
// 3) 使用处直接读强类型属性,编译期即可发现拼写错误
var window = options.ValidTimeRangeMinutes; // 打卡取值窗口半径
var grace = options.GracePeriodMinutes; // 宽松窗口
// 4) 界面保存后强制重载,立即生效(无需重启客户端)
HRCoreBLL.LoadAttendOptions();
这套机制的隐含契约是:ParamCode 必须与模型属性名完全一致,拼错不会报错、只会静默不生效。因此新增参数必须三处同步——表里插记录、模型加同名属性、使用处读属性。
四、平台技术栈
| 层次 | 选型 | 说明 |
|---|---|---|
| 开发语言 | C# | 全栈统一,客户端与服务端共用模型 |
| 运行时 | .NET 8(net8.0-windows) | 客户端 WinForms,服务端 API 同版本 |
| 界面框架 | WinForms + DevExpress 22.1.13 | Grid、编辑控件、打印与导出 |
| 数据访问 | EF Core 8.0.6 + SQL Server Provider | Database First,LINQ 查询,多账套切换 |
| 数据库 | SQL Server | 单库多账套,账套间数据隔离 |
| 报表 | FastReport 2023.1.8 | 个人/部门考勤报表、导出 Excel/PDF |
| 架构 | C/S(客户端 + 服务端 API) | 客户端自动升级、统一登录、在线授权 |
| 权限 | 模块 + 功能 + 数据权限 | 数据权限支持部门/角色/人员范围,敏感列按权限隐藏 |
| 审计 | 数据日志 + 业务日志 | 敏感字段变更留痕,异动有履历 |
为什么坚持 C/S:考勤机 SDK 是原生动态库(P/Invoke 调用),只有在客户端进程内才能稳定工作;车间与门卫室的网络环境普遍不稳,客户端本地缓存 + 断点重传比浏览器更可靠。而 DevExpress 的数据网格在处理"一天三班、一月三十天、上千人"的考勤明细时,分页与虚拟滚动是刚需。
五、考勤设备接入
1. 设备选型与两条通道
主用设备是海康威视人脸识别门禁考勤一体机,接入方式两条并行:
| 通道 | 实现 | 适用场景 |
|---|---|---|
| HCNetSDK | C# P/Invoke 封装(约两万行声明) | 设备登录、网络参数读取、考勤事件订阅与查询、员工与人脸照片下发 |
| ISAPI | HTTP + JSON(报文模型强类型化) | 人员分页查询、全量人员拉取、人脸照片设置/获取、事件按条件检索 |
两条通道各有取舍:SDK 功能全、性能好,但需要随程序分发原生 DLL(位数必须与进程一致);ISAPI 无依赖、易调试,但大批量分页拉取时要注意设备的返回缓冲与分页上限。
2. 封装分层
// 独立类库分层,界面层不碰 SDK 细节
// HikHelper 设备登录/登出/网络参数
// HikAttendHelper 考勤事件查询(支持多工号)
// HikEmployeeHelper 员工登记/查询/删除/全量分页拉取
// HikFaceHelper 人脸照片 设置/获取/删除/现场拍照
// CHCNetSDK.cs SDK P/Invoke 声明
// Class/ ISAPI 报文模型(强类型)
界面层只调用 HikHelper.LoginDevice()、HikAttendHelper.Query() 这类高层方法,设备型号差异、SDK 返回值判断、超时重试都收敛在类库内。这样换设备型号或补一个新接口,不会牵动业务窗体。
3. 兜底方案
对异地办公、外派驻厂或尚未布机的场景,模块支持导入钉钉考勤 Excel(按模板映射工号、时间、方向),导入前预览原始记录并给出异常行提示。导入数据与设备采集进入同一张原始打卡表,后续归档口径完全一致——业务上不会出现"两套考勤"。
六、实施与验证建议
- 先配参数再算数据:参数、班次、排班、节假日缺一不可,否则算出来的数字没有意义
- 用"逐字等价"做改造验收:重构取卡算法这类高风险改动,最可靠的方式是改造前后各跑一次同月归档,逐人逐日比对迟到/早退/有效类型,差异必须为零
- 数据级验证优先于界面验证:先比对 SQL 结果集,再点界面。界面"看起来对了"是假象,数字对了才算改完
- 新增字段先建表再发客户端:模型加了字段而库里没列,EF 查询会直接报"列名无效",整条考勤链路会挂
- 双轨运行至少两个月:新系统与手工台账并行,差异归零后再封账
七、小结
这个模块真正难的不是"连考勤机、读打卡"——那是两天的活。难的是把行业里那些默认成规的规矩(三段班接力、拉线错峰、直接/间接人工不同口径、请假与加班交叉)翻译成一套可配置、可回归、可解释的算法,并且在业务不断加需求时还能守住等价性。
实践下来有效的三条经验:把业务字面量抽象成语义(槽位)、把重复的匹配逻辑收口到一个解析器、把参数做成强类型缓存并在保存时强制重载。这三件事做完,后面加错峰班次、加按人员排班,都只是配置层的事,算法不用再动。

CSFramework成功案例-电子线束行业ERP-线联ERP|C/S开发框架
行业软件简称大全:ERP/MRP/MES/CRM/MIS/HIS/POS/HRP/SCM/OA-C/S开发框架
Winform C/S结构与Web B/S结构开发MES/ERP系统优缺点及区别|C/S开发框架
CSFramework成功案例-ERP系统-人事行政后勤招聘管理系统HR模块
行业软件简称大全:ERP/MRP/MES/CRM/MIS/HIS/POS/HRP/SCM/OA
C/S系统快速开发框架成功案例 - 医院资源规划系统(HRP)
ERP开发框架与ERP开发平台成功案例(C#.NET)
CSFrameworkV6开发框架打造塑木地板新材料行业ERP系统
C/S快速开发框架|旗舰版V5.1客户案例 | 染厂ERP系统|C/S开发框架
CSFrameworkV6旗舰版|成功案例|塑料板材行业ERP系统|C/S开发框架
CSFrameworkV6旗舰版|成功案例|纸箱行业ERP系统|C/S开发框架
喜鹊ERP | DevExpress 表格常用操作指南|表格组件自动分组|C/S开发框架
喜鹊ERP | FastReport.NET报表实施与开发操作指引|C/S开发框架
喜鹊ERP | 局域网服务器固定IP操作指南|C/S开发框架
喜鹊ERP用户操作手册|表格样式设置、表格常用操作|C/S开发框架
生产制造企业的业务流程(适用软件ERP/OMS/MES)|C/S开发框架
什么是C/S结构? | C/S框架核心组成部分 | C/S框架-WebService部署图 | C/S框架-权限管理 | C/S结构系统框架 - 5.1旗舰版介绍 | C/S结构系统框架 - 功能介绍 | C/S结构系统框架 - 产品列表 | C/S结构系统框架 - 应用展示(图) | 三层体系架构详解 | C/S架构轻量级快速开发框架 | C/S框架网客户案例 | WebApi快速开发框架 | C/S框架代码生成器 | 用户授权注册软件系统 | 版本自动升级软件 | 数据库底层应用框架 | CSFramework.CMS内容管理系统 |
在线客服
