This commit is contained in:
2026-07-03 16:56:47 +08:00
33 changed files with 1342 additions and 50 deletions

View File

@@ -56,3 +56,13 @@ export function syncRecords({ starttime, endtime }) {
}
})
}
// 导出考勤记录表
export function exportAttendanceReport(params) {
return request({
url: '/wms/attendanceRecords/exportReport',
method: 'post',
params: params,
responseType: 'blob'
})
}

View File

@@ -1,26 +1,26 @@
// lockValue: 锁值用于防止并发操作不同的lockValue对应不同的锁
// 1分步加工 2. 退火 3. 酸轧 4. 酸轧分条 4. 合卷
export const PROCESSES = [
{ name: '酸连轧工序', actionType: 11, api: 'pendingAction', lockValue: 3 },
{ name: '酸轧分条工序', actionType: 120, api: 'pendingAction', lockValue: 4 },
{ name: '酸轧合卷', actionType: 201, api: 'pendingAction', lockValue: 5 },
{ name: '镀锌合卷', actionType: 202, api: 'pendingAction', lockValue: 5 },
{ name: '脱脂合卷', actionType: 203, api: 'pendingAction', lockValue: 5 },
{ name: '拉矫平整合卷', actionType: 204, api: 'pendingAction', lockValue: 5 },
{ name: '双机架合卷', actionType: 205, api: 'pendingAction', lockValue: 5 },
{ name: '镀铬合卷', actionType: 206, api: 'pendingAction', lockValue: 5 },
{ name: '镀锌工序', actionType: 501, api: 'specialSplit', lockValue: 1 },
{ name: '脱脂工序', actionType: 502, api: 'specialSplit', lockValue: 1 },
{ name: '拉矫平整工序', actionType: 503, api: 'specialSplit', lockValue: 1 },
{ name: '双机架工序', actionType: 504, api: 'specialSplit', lockValue: 1 },
{ name: '镀铬工序', actionType: 505, api: 'specialSplit', lockValue: 1 },
{ name: '纵剪分条工序', actionType: 506, api: 'specialSplit', lockValue: 1 },
{ name: '酸轧修复工序', actionType: 520, api: 'specialSplit', lockValue: 1 },
{ name: '镀锌修复工序', actionType: 521, api: 'specialSplit', lockValue: 1 },
{ name: '脱脂修复工序', actionType: 522, api: 'specialSplit', lockValue: 1 },
{ name: '拉矫修复工序', actionType: 523, api: 'specialSplit', lockValue: 1 },
{ name: '双机架修复工序', actionType: 524, api: 'specialSplit', lockValue: 1 },
{ name: '镀铬修复工序', actionType: 525, api: 'specialSplit', lockValue: 1 },
{ name: '酸连轧工序', actionId: 11, api: 'pendingAction', lockValue: 3 },
{ name: '酸轧分条工序', actionId: 120, api: 'pendingAction', lockValue: 4 },
{ name: '酸轧合卷', actionId: 201, api: 'pendingAction', lockValue: 5 },
{ name: '镀锌合卷', actionId: 202, api: 'pendingAction', lockValue: 5 },
{ name: '脱脂合卷', actionId: 203, api: 'pendingAction', lockValue: 5 },
{ name: '拉矫平整合卷', actionId: 204, api: 'pendingAction', lockValue: 5 },
{ name: '双机架合卷', actionId: 205, api: 'pendingAction', lockValue: 5 },
{ name: '镀铬合卷', actionId: 206, api: 'pendingAction', lockValue: 5 },
{ name: '镀锌工序', actionId: 501, api: 'specialSplit', lockValue: 1 },
{ name: '脱脂工序', actionId: 502, api: 'specialSplit', lockValue: 1 },
{ name: '拉矫平整工序', actionId: 503, api: 'specialSplit', lockValue: 1 },
{ name: '双机架工序', actionId: 504, api: 'specialSplit', lockValue: 1 },
{ name: '镀铬工序', actionId: 505, api: 'specialSplit', lockValue: 1 },
{ name: '纵剪分条工序', actionId: 506, api: 'specialSplit', lockValue: 1 },
{ name: '酸轧修复工序', actionId: 520, api: 'specialSplit', lockValue: 1 },
{ name: '镀锌修复工序', actionId: 521, api: 'specialSplit', lockValue: 1 },
{ name: '脱脂修复工序', actionId: 522, api: 'specialSplit', lockValue: 1 },
{ name: '拉矫修复工序', actionId: 523, api: 'specialSplit', lockValue: 1 },
{ name: '双机架修复工序', actionId: 524, api: 'specialSplit', lockValue: 1 },
{ name: '镀铬修复工序', actionId: 525, api: 'specialSplit', lockValue: 1 },
]
export const PRODUCTION_LINES = [

View File

@@ -69,6 +69,7 @@
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="warning" icon="el-icon-upload" size="mini" @click="handleSync">同步</el-button>
<el-button type="success" icon="el-icon-download" size="mini" @click="handleExportReport">导出考勤表</el-button>
</el-form-item>
</el-form>
@@ -187,11 +188,42 @@
<el-button @click="syncDialogVisible = false">取消</el-button>
</div>
</el-dialog>
<!-- 导出考勤表对话框 -->
<el-dialog title="导出考勤记录表" :visible.sync="exportDialogVisible" width="480px" append-to-body>
<el-form ref="exportForm" :model="exportFormData" :rules="exportRules" label-width="90px">
<el-form-item label="考勤时间" prop="dateRange">
<el-date-picker
v-model="exportFormData.dateRange"
type="daterange"
range-separator="~"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
style="width: 100%">
</el-date-picker>
</el-form-item>
<el-form-item label="员工编号" prop="pin">
<el-input v-model="exportFormData.pin" placeholder="请输入员工编号(可选)" clearable />
</el-form-item>
<el-form-item label="姓名" prop="ename">
<el-input v-model="exportFormData.ename" placeholder="请输入姓名(可选)" clearable />
</el-form-item>
<el-form-item label="部门" prop="deptname">
<el-input v-model="exportFormData.deptname" placeholder="请输入部门(可选)" clearable />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="exportLoading" type="primary" @click="doExportReport">确定导出</el-button>
<el-button @click="exportDialogVisible = false">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listRecords, getRecords, delRecords, addRecords, updateRecords, syncRecords } from "@/api/wms/attendance";
import { listRecords, getRecords, delRecords, addRecords, updateRecords, syncRecords, exportAttendanceReport } from "@/api/wms/attendance";
export default {
name: "Records",
@@ -211,6 +243,41 @@ export default {
syncRules: {
syncMonth: [{ required: true, message: "请选择同步月份", trigger: "change" }]
},
// 导出弹窗
exportDialogVisible: false,
// 导出loading
exportLoading: false,
// 导出表单
exportFormData: {
dateRange: [],
pin: "",
ename: "",
deptname: ""
},
// 导出表单校验
exportRules: {
dateRange: [{ required: true, message: "请选择考勤时间范围", trigger: "change" }]
},
// 日期选择器快捷选项
pickerOptions: {
shortcuts: [{
text: '本月',
onClick(picker) {
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), 1);
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
picker.$emit('pick', [start, end]);
}
}, {
text: '上月',
onClick(picker) {
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth() - 1, 1);
const end = new Date(now.getFullYear(), now.getMonth(), 0);
picker.$emit('pick', [start, end]);
}
}]
},
// 遮罩层
loading: true,
// 选中数组
@@ -391,6 +458,61 @@ export default {
this.download('wms/records/export', {
...this.queryParams
}, `records_${new Date().getTime()}.xlsx`)
},
/** 导出考勤记录表 */
handleExportReport() {
this.$modal.confirm(
'导出前请先确保已同步最新的考勤数据,是否继续导出?',
'提示',
{
confirmButtonText: '已同步,继续导出',
cancelButtonText: '去同步',
type: 'info'
}
).then(() => {
this.exportFormData.dateRange = [];
this.exportFormData.pin = "";
this.exportFormData.ename = "";
this.exportFormData.deptname = "";
this.exportDialogVisible = true;
this.$nextTick(() => {
this.$refs.exportForm && this.$refs.exportForm.clearValidate();
});
}).catch(action => {
if (action === 'cancel') {
this.handleSync();
}
});
},
/** 执行导出考勤记录表 */
doExportReport() {
this.$refs.exportForm.validate(valid => {
if (!valid) return;
const [startDate, endDate] = this.exportFormData.dateRange;
this.exportLoading = true;
exportAttendanceReport({
startTime: startDate,
endTime: endDate,
pin: this.exportFormData.pin || undefined,
ename: this.exportFormData.ename || undefined,
deptname: this.exportFormData.deptname || undefined
}).then(res => {
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `考勤记录表_${startDate}_${endDate}.xlsx`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
this.$modal.msgSuccess("导出成功");
this.exportLoading = false;
this.exportDialogVisible = false;
}).catch(() => {
this.exportLoading = false;
});
});
}
}
};

View File

@@ -205,9 +205,9 @@
<el-table-column type="selection" width="45" align="center" />
<el-table-column label="排产单号" prop="scheduleNo" min-width="140" show-overflow-tooltip />
<el-table-column label="生产日期" prop="prodDate" width="110" align="center" show-overflow-tooltip />
<el-table-column label="工序类型" prop="actionType" width="100" align="center" show-overflow-tooltip>
<el-table-column label="工序类型" prop="actionId" width="100" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ getActionTypeName(scope.row.actionType) }}
{{ getActionIdName(scope.row.actionId) }}
</template>
</el-table-column>
<el-table-column label="排产状态" prop="scheduleStatus" width="90" align="center">
@@ -317,8 +317,8 @@
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="工序类型">
<el-select v-model="editForm.actionType" placeholder="请选择工序类型" clearable filterable style="width:100%">
<el-option v-for="p in processOptions" :key="p.actionType" :label="p.name" :value="p.actionType" />
<el-select v-model="editForm.actionId" placeholder="请选择工序类型" clearable filterable style="width:100%">
<el-option v-for="p in processOptions" :key="p.actionId" :label="p.name" :value="p.actionId" />
</el-select>
</el-form-item>
</el-col>
@@ -528,8 +528,8 @@
</el-col>
<el-col :span="12">
<el-form-item label="工序类型">
<el-select v-model="mergeForm.actionType" placeholder="请选择工序类型" clearable filterable style="width:100%">
<el-option v-for="p in processOptions" :key="p.actionType" :label="p.name" :value="p.actionType" />
<el-select v-model="mergeForm.actionId" placeholder="请选择工序类型" clearable filterable style="width:100%">
<el-option v-for="p in processOptions" :key="p.actionId" :label="p.name" :value="p.actionId" />
</el-select>
</el-form-item>
</el-col>
@@ -687,7 +687,7 @@ export default {
mergeTemplateIndex: 0,
mergeSourceRows: [],
mergeForm: {
itemCount: 0, scheduleNo: '', actionType: '', customerName: '', spec: '', material: '',
itemCount: 0, scheduleNo: '', actionId: '', customerName: '', spec: '', material: '',
scheduleWeight: 0, productType: '', productItem: '', businessUser: '',
businessPhone: '', deliveryCycle: undefined, usePurpose: '',
thicknessTolerance: '', widthTolerance: '', surfaceQuality: '',
@@ -730,7 +730,7 @@ export default {
return {
scheduleId: undefined,
scheduleNo: '',
actionType: '',
actionId: '',
prodDate: '',
scheduleStatus: undefined,
totalPlanWeight: undefined,
@@ -891,9 +891,9 @@ export default {
handleEditScheduled(row) {
this.editForm = { ...this.getEmptyEditForm(), ...row }
// 确保 actionType 为数字类型以匹配下拉选项
if (this.editForm.actionType != null && typeof this.editForm.actionType !== 'number') {
this.editForm.actionType = Number(this.editForm.actionType)
// 确保 actionId 为数字类型以匹配下拉选项
if (this.editForm.actionId != null && typeof this.editForm.actionId !== 'number') {
this.editForm.actionId = Number(this.editForm.actionId)
}
// 确保 scheduleStatus 为数字类型以匹配下拉选项
if (this.editForm.scheduleStatus != null && typeof this.editForm.scheduleStatus !== 'number') {
@@ -977,7 +977,7 @@ export default {
this.mergeForm = {
itemCount: this.mergeSourceRows.length,
scheduleNo: row.scheduleNo || '',
actionType: row.actionType != null ? Number(row.actionType) : '',
actionId: row.actionId != null ? Number(row.actionId) : '',
customerName: row.customerName || '',
spec: row.spec || '',
material: row.material || '',
@@ -1033,9 +1033,9 @@ export default {
return total.toFixed(3)
},
getActionTypeName(actionType) {
const p = this.processOptions.find(item => String(item.actionType) === String(actionType))
return p ? p.name : (actionType || '')
getActionIdName(actionId) {
const p = this.processOptions.find(item => String(item.actionId) === String(actionId))
return p ? p.name : (actionId || '')
},
handleDetailClick(sch, detail) {