feat(cost&wms): 新增成本模块与考勤优化功能

1. 新增成本相关业务模块:成本项目配置、成本单价历史、生产月报、生产指标明细、生产成本明细的CRUD接口与页面
2. 为生产月报实体增加列配置字段及数据库映射
3. 优化考勤查询接口,将get请求改为post并使用body传参
4. 考勤页面增加部门筛选、员工多选筛选和打卡记录展示功能
This commit is contained in:
2026-05-26 17:49:32 +08:00
parent b9da496f79
commit 454d8de6a2
19 changed files with 2522 additions and 9 deletions

View File

@@ -12,6 +12,14 @@
<el-button type="warning" plain icon="el-icon-download" @click="handleExport">导出</el-button>
</div>
<div class="dept-filter-section" v-if="departmentList.length > 0">
<el-radio-group v-model="selectedDept" @change="handleDeptChange">
<el-radio-button v-for="item in departmentList" :key="item.deptName" :label="item.deptName">
{{ item.deptName }}{{ item.count }}
</el-radio-button>
</el-radio-group>
</div>
<el-alert type="info" title="提示:双击单元格可查看考勤详情或调整考勤结果"></el-alert>
<div class="schedule-table-wrapper">
@@ -350,13 +358,25 @@
<el-table-column prop="endTime" label="结束时间" width="150" />
<el-table-column prop="outHours" label="时长(小时)" width="100" />
<el-table-column prop="outPlace" label="地点" />
<el-table-column prop="approvalStatus" label="状态" width="100">
<el-table-column prop="approvalStatus" label="状态" width="100">
<template slot-scope="scope">
<span :class="getApprovalStatusClass(scope.row.approvalStatus)">{{ getApprovalStatusText(scope.row.approvalStatus) }}</span>
</template>
</el-table-column>
</el-table>
<!-- 打卡记录不分页 -->
<el-divider content-position="left">打卡记录</el-divider>
<el-table v-loading="detailRecordsLoading" :data="detailRecordsList" border stripe size="small">
<el-table-column prop="ename" label="姓名" width="100" />
<el-table-column prop="deptname" label="部门" />
<el-table-column prop="checktime" label="打卡时间">
<template slot-scope="scope">
<span>{{ scope.row.checktime }}</span>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button v-if="!isEdit" type="primary" @click="handleEdit">编辑</el-button>
<el-button v-if="isEdit" @click="cancelEdit">取消</el-button>
@@ -365,7 +385,7 @@
</div>
</el-dialog>
<el-dialog title="考勤比对" :visible.sync="checkOpen" width="400px" append-to-body>
<el-dialog title="考勤比对" :visible.sync="checkOpen" width="700px" append-to-body>
<el-form ref="checkForm" :model="checkForm" :rules="checkRules" label-width="80px">
<el-form-item label="开始日期" prop="startDate">
<el-date-picker
@@ -383,6 +403,16 @@
placeholder="请选择结束日期">
</el-date-picker>
</el-form-item>
<el-form-item label="选择员工" prop="userIds">
<el-transfer
v-model="selectedUserIds"
:data="transferData"
:titles="['待选员工', '已选员工']"
filterable
filter-placeholder="请输入员工姓名">
<span slot-scope="{ option }">{{ option.label }}</span>
</el-transfer>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="checkLoading" type="primary" @click="submitCheck"> </el-button>
@@ -397,6 +427,8 @@ import { listAttendanceCheck, getAttendanceCheck, delAttendanceCheck, generateAt
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker";
import { listOutRequest } from "@/api/wms/outRequest";
import { listLeaveRequest } from "@/api/wms/leaveRequest";
import { listEmployeeInfo } from "@/api/wms/employeeInfo";
import { listRecords } from "@/api/wms/attendance";
import dayjs from "dayjs";
export default {
@@ -406,7 +438,7 @@ export default {
},
data() {
return {
loading: false,
loading: true,
checkLoading: false,
showSearch: true,
attendanceData: [],
@@ -461,11 +493,30 @@ export default {
detailOutList: [],
detailOutQuery: {
applicantName: ''
}
},
allEmployees: [],
departmentList: [],
selectedDept: '',
currentDeptEmployeeIds: '',
selectedUserIds: [],
detailRecordsLoading: false,
detailRecordsList: []
};
},
computed: {
transferData() {
return this.allEmployees.map(emp => ({
key: emp.infoId,
label: emp.name + '' + emp.dept + ''
}))
}
},
created() {
this.initDateRange();
this.getAllEmployees().then(() => {
this.initDateRange();
});
},
methods: {
initDateRange() {
@@ -487,6 +538,38 @@ export default {
this.getOutList()
},
getAllEmployees() {
return listEmployeeInfo({
pageNum: 1,
pageSize: 10000
}).then(res => {
this.allEmployees = res.rows || []
const deptMap = {}
this.allEmployees.forEach(emp => {
const deptName = emp.dept || '未分配部门'
if (!deptMap[deptName]) {
deptMap[deptName] = []
}
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
}
})
},
handleDeptChange(deptName) {
const dept = this.departmentList.find(d => d.deptName === deptName)
this.currentDeptEmployeeIds = dept ? dept.empIds : ''
this.getList()
},
formatDate(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
@@ -546,7 +629,11 @@ export default {
getList() {
this.loading = true
listAttendanceCheck(this.dateRangeParams).then(response => {
const params = {
...this.dateRangeParams,
userIds: this.currentDeptEmployeeIds.split(',')
}
listAttendanceCheck(params).then(response => {
this.attendanceData = this.transformData(response.rows || [])
this.loading = false
}).catch(() => {
@@ -616,6 +703,22 @@ export default {
})
},
getDetailRecords(ename, date) {
this.detailRecordsLoading = true
listRecords({
pageNum: 1,
pageSize: 100,
ename,
checktimeStart: date + ' 00:00:00',
checktimeEnd: date + ' 23:59:59'
}).then(response => {
this.detailRecordsList = response.rows || []
this.detailRecordsLoading = false
}).catch(() => {
this.detailRecordsLoading = false
})
},
transformData(rows) {
const dataMap = {}
rows.forEach(record => {
@@ -717,6 +820,7 @@ export default {
this.detailOutQuery.applicantName = row.employeeName
this.getDetailLeaveList()
this.getDetailOutList()
this.getDetailRecords(row.employeeName, date)
this.detailDialogVisible = true
}
},
@@ -737,11 +841,13 @@ export default {
startDate: this.dateRangeParams.startDate,
endDate: this.dateRangeParams.endDate
}
this.selectedUserIds = this.allEmployees.map(emp => emp.infoId)
},
cancelCheck() {
this.checkOpen = false
this.checkForm = { startDate: undefined, endDate: undefined }
this.selectedUserIds = []
this.$refs['checkForm'] && this.$refs['checkForm'].resetFields()
},
@@ -749,7 +855,11 @@ export default {
this.$refs["checkForm"].validate(valid => {
if (valid) {
this.checkLoading = true
generateAttendanceCheck(this.checkForm).then(response => {
const params = {
...this.checkForm,
employeeIds: this.selectedUserIds.join(',')
}
generateAttendanceCheck(params).then(response => {
this.$modal.msgSuccess("比对成功")
this.checkOpen = false
this.dateRangeParams.startDate = this.checkForm.startDate
@@ -1048,4 +1158,18 @@ export default {
.approval-default {
color: #606266;
}
.dept-filter-section {
margin-bottom: 20px;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.dept-filter-label {
font-size: 14px;
color: #606266;
margin-right: 10px;
white-space: nowrap;
}
</style>