241 lines
6.9 KiB
C++
241 lines
6.9 KiB
C++
#ifndef ATTENDANCE_SYSTEM_APP_HPP
|
||
#define ATTENDANCE_SYSTEM_APP_HPP
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
#include <map>
|
||
#include <ctime>
|
||
#include <memory>
|
||
#include <functional>
|
||
#include <algorithm>
|
||
#include <sstream>
|
||
#include <iomanip>
|
||
#include <stdexcept>
|
||
#include <cassert>
|
||
|
||
// ============================================================
|
||
// 常量与枚举
|
||
// ============================================================
|
||
|
||
/// 打卡类型
|
||
enum class CheckType {
|
||
Unknown,
|
||
ClockIn, // 上班打卡
|
||
ClockOut // 下班打卡
|
||
};
|
||
|
||
/// 异常标记
|
||
enum class AbnormalFlag {
|
||
None,
|
||
Late, // 迟到
|
||
EarlyLeave, // 早退
|
||
Absenteeism // 旷工
|
||
};
|
||
|
||
/// 报表输出格式
|
||
enum class ReportFormat {
|
||
Excel,
|
||
PDF
|
||
};
|
||
|
||
/// 预警发送状态
|
||
enum class AlertStatus {
|
||
Pending,
|
||
Sent,
|
||
Failed,
|
||
Read
|
||
};
|
||
|
||
/// 角色类型(RBAC)
|
||
enum class RoleType {
|
||
Employee,
|
||
DeptManager,
|
||
HRAdmin,
|
||
SystemAdmin
|
||
};
|
||
|
||
// ============================================================
|
||
// 数据结构定义
|
||
// ============================================================
|
||
|
||
/// 员工信息
|
||
struct Employee {
|
||
std::string employeeId;
|
||
std::string name;
|
||
std::string department;
|
||
std::string position;
|
||
std::string shiftId;
|
||
std::string phone;
|
||
RoleType role{RoleType::Employee};
|
||
|
||
// 脱敏手机号显示(后4位明文)
|
||
std::string maskedPhone() const {
|
||
if (phone.length() != 11) return "***";
|
||
return "*******" + phone.substr(7);
|
||
}
|
||
};
|
||
|
||
/// 排班规则
|
||
struct ShiftRule {
|
||
std::string shiftId;
|
||
std::string shiftName;
|
||
int startHour{9}; // 上班小时
|
||
int startMin{0}; // 上班分钟
|
||
int endHour{18}; // 下班小时
|
||
int endMin{0}; // 下班分钟
|
||
int flexWindow{30}; // 弹性时间窗口(分钟)
|
||
int graceLate{15}; // 迟到宽限分钟
|
||
|
||
/// 获取上班时间(分钟偏移量)
|
||
int workStartMinutes() const { return startHour * 60 + startMin; }
|
||
|
||
/// 获取下班时间(分钟偏移量)
|
||
int workEndMinutes() const { return endHour * 60 + endMin; }
|
||
};
|
||
|
||
/// 打卡流水记录
|
||
struct CheckInRecord {
|
||
std::string recordId;
|
||
std::string employeeId;
|
||
std::time_t timestamp{0};
|
||
CheckType type{CheckType::Unknown};
|
||
std::string deviceId;
|
||
std::string latitude;
|
||
std::string longitude;
|
||
bool verified{false};
|
||
};
|
||
|
||
/// 考勤核算结果(按天)
|
||
struct DailyAttendance {
|
||
std::string dateStr;
|
||
std::string employeeId;
|
||
int expectedMinutes{0}; // 应出勤分钟
|
||
int actualMinutes{0}; // 实际出勤分钟
|
||
int overtimeMinutes{0}; // 加班分钟
|
||
int leaveDeduction{0}; // 调休抵扣分钟
|
||
AbnormalFlag abnormal{AbnormalFlag::None};
|
||
|
||
/// 有效出勤率(%)
|
||
double attendanceRate() const {
|
||
if (expectedMinutes == 0) return 100.0;
|
||
return 100.0 * actualMinutes / expectedMinutes;
|
||
}
|
||
|
||
/// 是否异常
|
||
bool hasAbnormal() const { return abnormal != AbnormalFlag::None; }
|
||
|
||
std::string abnormalStr() const {
|
||
switch (abnormal) {
|
||
case AbnormalFlag::Late: return "迟到";
|
||
case AbnormalFlag::EarlyLeave: return "早退";
|
||
case AbnormalFlag::Absenteeism: return "旷工";
|
||
default: return "正常";
|
||
}
|
||
}
|
||
};
|
||
|
||
/// 异常预警日志
|
||
struct AlertLog {
|
||
std::string alertId;
|
||
std::string employeeId;
|
||
AbnormalFlag type{AbnormalFlag::None};
|
||
std::time_t occurTime{0};
|
||
std::string channel; // 通知渠道:站内信/短信/企业微信
|
||
AlertStatus status{AlertStatus::Pending};
|
||
int retryCount{0};
|
||
};
|
||
|
||
/// 报表任务
|
||
struct ReportTask {
|
||
std::string taskId;
|
||
std::string requester;
|
||
std::string deptId;
|
||
std::string dateRangeBegin;
|
||
std::string dateRangeEnd;
|
||
ReportFormat format{ReportFormat::Excel};
|
||
std::string status{"Pending"}; // Pending / Running / Done / Failed
|
||
std::string downloadUrl;
|
||
std::time_t createTime{0};
|
||
};
|
||
|
||
/// 权限配置(RBAC)
|
||
struct Permission {
|
||
std::string resource; // 资源路径,如 "/api/v1/reports"
|
||
std::string action; // 操作:READ / WRITE / DELETE
|
||
};
|
||
|
||
// ============================================================
|
||
// 业务逻辑类
|
||
// ============================================================
|
||
|
||
class AttendanceService {
|
||
public:
|
||
AttendanceService();
|
||
|
||
// ---- 员工管理 ----
|
||
void addEmployee(const Employee& emp);
|
||
const Employee* findEmployee(const std::string& id) const;
|
||
std::vector<Employee> getEmployeesByDept(const std::string& dept) const;
|
||
|
||
// ---- 排班管理 ----
|
||
void addShiftRule(const ShiftRule& rule);
|
||
const ShiftRule* findShift(const std::string& shiftId) const;
|
||
|
||
// ---- 打卡处理 ----
|
||
CheckInRecord processCheckIn(const std::string& employeeId,
|
||
CheckType type,
|
||
const std::string& deviceId,
|
||
std::time_t timestamp);
|
||
|
||
std::vector<CheckInRecord> getRecords(const std::string& employeeId) const;
|
||
|
||
// ---- 考勤核算 ----
|
||
DailyAttendance calculateDaily(const std::string& employeeId,
|
||
const std::string& dateStr);
|
||
|
||
std::vector<DailyAttendance> generateReport(const std::string& deptId,
|
||
const std::string& dateBegin,
|
||
const std::string& dateEnd);
|
||
|
||
// ---- 异常预警 ----
|
||
AlertLog createAlert(const std::string& employeeId, AbnormalFlag type);
|
||
std::vector<AlertLog> getAlerts(const std::string& employeeId) const;
|
||
|
||
// ---- 报表任务 ----
|
||
ReportTask createReportTask(const std::string& requester,
|
||
const std::string& deptId,
|
||
const std::string& dateBegin,
|
||
const std::string& dateEnd,
|
||
ReportFormat fmt);
|
||
void completeTask(const std::string& taskId, const std::string& url);
|
||
|
||
// ---- 工具 ----
|
||
static std::string timeToString(std::time_t t);
|
||
static std::string currentDateStr();
|
||
static std::time_t parseDate(const std::string& dateStr);
|
||
|
||
private:
|
||
std::map<std::string, Employee> employees_;
|
||
std::map<std::string, ShiftRule> shifts_;
|
||
std::vector<CheckInRecord> records_;
|
||
std::vector<AlertLog> alerts_;
|
||
std::vector<ReportTask> tasks_;
|
||
int idCounter_{0};
|
||
|
||
std::string nextId();
|
||
int minutesFromMidnight(std::time_t t) const;
|
||
bool isSameDate(std::time_t t, const std::string& dateStr) const;
|
||
};
|
||
|
||
// ============================================================
|
||
// 工具函数声明
|
||
// ============================================================
|
||
|
||
/// 脱敏工具:将敏感字符串中间部分替换为 '*'
|
||
std::string maskSensitive(const std::string& input, size_t visibleHead = 2, size_t visibleTail = 2);
|
||
|
||
/// 格式化输出一行分隔线
|
||
void printSeparator(char ch = '=', size_t count = 60);
|
||
|
||
#endif // ATTENDANCE_SYSTEM_APP_HPP
|