feat(wms/attendance): 新增考勤检查部门筛选功能,优化跨天排班逻辑与打卡记录批量查询

1. 前端新增部门筛选下拉框,支持按部门筛选员工并自动勾选,优化穿梭框数据映射逻辑
2. 后端实现跨天排班重叠检测机制,正向跨天夜班被反向跨天班覆盖时跳过下班打卡校验
3. 重构打卡记录查询为批量预取模式,通过单次SQL查询提升性能,支持按员工姓名集合和时间范围精确检索
4. 优化考勤检查记录构建逻辑,调整时段时间计算方式,完善全天缺勤状态判断规则
This commit is contained in:
2026-05-27 14:16:34 +08:00
parent e95e9adfcd
commit 405f388702
4 changed files with 203 additions and 65 deletions

View File

@@ -403,10 +403,20 @@
placeholder="请选择结束日期">
</el-date-picker>
</el-form-item>
<el-form-item label="选择部门" prop="dept">
<el-select v-model="checkDept" placeholder="请选择部门" @change="handleCheckDeptChange">
<el-option
v-for="item in departmentList"
:key="item.deptName"
:label="item.deptName + '' + item.count + '人)'"
:value="item.deptName"
/>
</el-select>
</el-form-item>
<el-form-item label="选择员工" prop="userIds">
<el-transfer
v-model="selectedUserIds"
:data="transferData"
:data="checkTransferData"
:titles="['待选员工', '已选员工']"
filterable
filter-placeholder="请输入员工姓名">
@@ -499,6 +509,7 @@ export default {
departmentList: [],
selectedDept: '',
currentDeptEmployeeIds: '',
checkDept: '',
selectedUserIds: [],
detailRecordsLoading: false,
@@ -508,9 +519,18 @@ export default {
computed: {
transferData() {
return this.allEmployees.map(emp => ({
key: emp.infoId,
key: String(emp.infoId),
label: emp.name + '' + emp.dept + ''
}))
},
checkTransferData() {
if (!this.checkDept) return this.transferData
return this.allEmployees
.filter(emp => (emp.dept || '未分配部门') === this.checkDept)
.map(emp => ({
key: String(emp.infoId),
label: emp.name + '' + emp.dept + ''
}))
}
},
created() {
@@ -548,15 +568,18 @@ export default {
this.allEmployees.forEach(emp => {
const deptName = emp.dept || '未分配部门'
if (!deptMap[deptName]) {
deptMap[deptName] = []
deptMap[deptName] = new Set()
}
deptMap[deptName].add(String(emp.infoId))
})
this.departmentList = Object.keys(deptMap).map(deptName => {
const ids = [...deptMap[deptName]]
return {
deptName,
count: ids.length,
empIds: ids.join(',')
}
deptMap[deptName].push(emp.infoId)
})
this.departmentList = Object.keys(deptMap).map(deptName => ({
deptName,
count: deptMap[deptName].length,
empIds: deptMap[deptName].join(',')
}))
if (this.departmentList.length > 0) {
this.selectedDept = this.departmentList[0].deptName
this.currentDeptEmployeeIds = this.departmentList[0].empIds
@@ -841,23 +864,35 @@ export default {
startDate: this.dateRangeParams.startDate,
endDate: this.dateRangeParams.endDate
}
this.selectedUserIds = []
this.checkDept = this.selectedDept || ''
if (this.checkDept) {
const dept = this.departmentList.find(d => d.deptName === this.checkDept)
this.selectedUserIds = dept ? dept.empIds.split(',') : []
} else {
this.selectedUserIds = []
}
},
cancelCheck() {
this.checkOpen = false
this.checkForm = { startDate: undefined, endDate: undefined }
this.selectedUserIds = []
this.checkDept = ''
this.$refs['checkForm'] && this.$refs['checkForm'].resetFields()
},
handleCheckDeptChange(deptName) {
const dept = this.departmentList.find(d => d.deptName === deptName)
this.selectedUserIds = dept ? dept.empIds.split(',') : []
},
submitCheck() {
this.$refs["checkForm"].validate(valid => {
if (valid) {
this.checkLoading = true
const params = {
...this.checkForm,
userIds: this.selectedUserIds.join(',')
userIds: this.selectedUserIds
}
generateAttendanceCheck(params).then(response => {
this.$modal.msgSuccess("比对成功")