feat: 节假日配置、排班管理独立页面、考勤加班显示优化
- 新增 HolidayConfig 模型,支持法定节假日和调休工作日配置 - 加班费同步逻辑改用 HolidayConfig 判断日期类型 - 员工端考勤显示加班工时、费率和日期类型 - 周末/节假日出勤状态显示为"周末出勤"/"节假日出勤" - 新增 Employee.defaultShiftId 字段,支持长期排班(工作日班次) - 排班管理拆分为独立页面(班次管理+排班),考勤管理保留出勤相关功能 - 排班和每日出勤页面增加身份证号列 - 修复岗位和部门编辑失败问题(POST 改 PUT) - 新增 backfill 脚本:合同薪资回填、默认班次回填 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -257,7 +257,24 @@ router.get('/contract', portalAuth, async (req: any, res, next) => {
|
||||
if (!contract) {
|
||||
return res.json({ success: true, data: null })
|
||||
}
|
||||
res.json({ success: true, data: contract })
|
||||
// 补充员工工资结构(合同中 baseSalary/performanceSalary 为 0 时作为 fallback)
|
||||
const employee = await prisma.employee.findFirst({
|
||||
where: { id: req.employee.id },
|
||||
select: { monthlySalary: true, baseSalary: true, performanceSalary: true },
|
||||
})
|
||||
const empBase = employee?.baseSalary ? Number(decrypt(employee.baseSalary)) || 0 : 0
|
||||
const empPerf = employee?.performanceSalary ? Number(decrypt(employee.performanceSalary)) || 0 : 0
|
||||
const empMonthly = employee?.monthlySalary ? Number(decrypt(employee.monthlySalary)) || 0 : 0
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
...contract,
|
||||
// 合同中工资为 0 时用员工档案的工资补齐
|
||||
baseSalary: contract.baseSalary || empBase,
|
||||
performanceSalary: contract.performanceSalary || empPerf,
|
||||
monthlySalary: empMonthly,
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
@@ -730,7 +747,54 @@ router.get('/attendance', portalAuth, async (req: any, res, next) => {
|
||||
},
|
||||
orderBy: { date: 'asc' },
|
||||
})
|
||||
res.json({ success: true, data: { published: true, records, title: publish.title } })
|
||||
|
||||
// 查询节假日配置,判断每日日期类型和加班费率
|
||||
const holidays = await prisma.holidayConfig.findMany({
|
||||
where: { orgId: req.employee.orgId, date: { gte: startDate, lt: endDate } },
|
||||
})
|
||||
const holidayMap = new Map<string, string>() // dateStr -> type
|
||||
for (const h of holidays) {
|
||||
holidayMap.set(h.date.toISOString().slice(0, 10), h.type)
|
||||
}
|
||||
|
||||
// 获取加班费配置
|
||||
const otConfig = await prisma.overtimeConfig.findUnique({ where: { orgId: req.employee.orgId } })
|
||||
const rates = {
|
||||
weekday: otConfig?.weekdayRate ?? 1.5,
|
||||
weekend: otConfig?.weekendRate ?? 2.0,
|
||||
holiday: otConfig?.holidayRate ?? 3.0,
|
||||
}
|
||||
|
||||
// 为每条记录附加日期类型和加班费率
|
||||
const enrichedRecords = records.map(r => {
|
||||
const dateStr = r.date.toISOString().slice(0, 10)
|
||||
const day = new Date(dateStr + 'T00:00:00')
|
||||
const dayOfWeek = day.getDay()
|
||||
const holidayType = holidayMap.get(dateStr)
|
||||
|
||||
let dateType: 'weekday' | 'weekend' | 'holiday' = 'weekday'
|
||||
let overtimeRate = rates.weekday
|
||||
|
||||
if (holidayType === 'HOLIDAY') {
|
||||
dateType = 'holiday'
|
||||
overtimeRate = rates.holiday
|
||||
} else if (holidayType === 'WORKDAY') {
|
||||
dateType = 'weekday'
|
||||
overtimeRate = rates.weekday
|
||||
} else if (dayOfWeek === 0 || dayOfWeek === 6) {
|
||||
dateType = 'weekend'
|
||||
overtimeRate = rates.weekend
|
||||
}
|
||||
|
||||
return {
|
||||
...r,
|
||||
dateType,
|
||||
overtimeRate,
|
||||
hasOvertime: (r.overtimeHours || 0) > 0,
|
||||
}
|
||||
})
|
||||
|
||||
res.json({ success: true, data: { published: true, records: enrichedRecords, title: publish.title, overtimeRates: rates } })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user