feat(eqp): add production line and inspect part query, enhance daily check statistics
1. 新增巡检记录BO和VO的产线、巡检部位字段 2. 关联设备部件表补充查询巡检部位和产线数据 3. 增加按产线过滤巡检记录的查询条件 4. 优化日巡检页面:替换日期选择器为时间段选择,新增负责人汇总统计、应检/实检差异统计和完成率指标
This commit is contained in:
@@ -65,6 +65,11 @@ public class EqpEquipmentInspectionRecordBo extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String photo;
|
private String photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产线
|
||||||
|
*/
|
||||||
|
private String productionLine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 巡检时间开始
|
* 巡检时间开始
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -84,5 +84,15 @@ public class EqpEquipmentInspectionRecordVo {
|
|||||||
*/
|
*/
|
||||||
private String checkStandard;
|
private String checkStandard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检部位
|
||||||
|
*/
|
||||||
|
private String inspectPart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产线
|
||||||
|
*/
|
||||||
|
private String productionLine;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class EqpEquipmentInspectionRecordServiceImpl implements IEqpEquipmentIns
|
|||||||
qw.eq(bo.getRunStatus() != null, "r.run_status", bo.getRunStatus());
|
qw.eq(bo.getRunStatus() != null, "r.run_status", bo.getRunStatus());
|
||||||
qw.eq(StringUtils.isNotBlank(bo.getInspector()), "r.inspector", bo.getInspector());
|
qw.eq(StringUtils.isNotBlank(bo.getInspector()), "r.inspector", bo.getInspector());
|
||||||
qw.eq(StringUtils.isNotBlank(bo.getAbnormalDesc()), "r.abnormal_desc", bo.getAbnormalDesc());
|
qw.eq(StringUtils.isNotBlank(bo.getAbnormalDesc()), "r.abnormal_desc", bo.getAbnormalDesc());
|
||||||
|
qw.eq(StringUtils.isNotBlank(bo.getProductionLine()), "p.production_line", bo.getProductionLine());
|
||||||
qw.ge(bo.getStartInspectTime() != null, "r.inspect_time", bo.getStartInspectTime());
|
qw.ge(bo.getStartInspectTime() != null, "r.inspect_time", bo.getStartInspectTime());
|
||||||
qw.le(bo.getEndInspectTime() != null, "r.inspect_time", bo.getEndInspectTime());
|
qw.le(bo.getEndInspectTime() != null, "r.inspect_time", bo.getEndInspectTime());
|
||||||
qw.eq("r.del_flag", 0);
|
qw.eq("r.del_flag", 0);
|
||||||
|
|||||||
@@ -33,9 +33,12 @@
|
|||||||
r.remark,
|
r.remark,
|
||||||
r.photo,
|
r.photo,
|
||||||
c.check_content AS checkContent,
|
c.check_content AS checkContent,
|
||||||
c.check_standard AS checkStandard
|
c.check_standard AS checkStandard,
|
||||||
|
p.inspect_part AS inspectPart,
|
||||||
|
p.production_line AS productionLine
|
||||||
FROM eqp_equipment_inspection_record r
|
FROM eqp_equipment_inspection_record r
|
||||||
LEFT JOIN eqp_equipment_checklist c ON r.check_id = c.check_id AND c.del_flag = '0'
|
LEFT JOIN eqp_equipment_checklist c ON r.check_id = c.check_id AND c.del_flag = '0'
|
||||||
|
LEFT JOIN eqp_equipment_part p ON c.part_id = p.part_id AND p.del_flag = '0'
|
||||||
${ew.customSqlSegment}
|
${ew.customSqlSegment}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
<div class="app-container" v-loading="loading">
|
<div class="app-container" v-loading="loading">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-form label-width="80px" inline>
|
<el-form label-width="80px" inline>
|
||||||
<el-form-item label="日期">
|
<el-form-item label="时间段">
|
||||||
<el-date-picker v-model="queryDate" type="date" value-format="yyyy-MM-dd"
|
<el-date-picker v-model="dateRange" type="daterange" value-format="yyyy-MM-dd"
|
||||||
placeholder="选择日期" @change="handleQuery" style="width: 200px;" />
|
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||||
|
@change="handleQuery" style="width: 260px;" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="产线">
|
<el-form-item label="产线">
|
||||||
<dict-select v-model="productionLine" dict-type="sys_lines" placeholder="请选择产线"
|
<dict-select v-model="productionLine" dict-type="sys_lines" placeholder="请选择产线"
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
<el-descriptions-item label="巡检部位数">{{ summary.partCount }}</el-descriptions-item>
|
<el-descriptions-item label="巡检部位数">{{ summary.partCount }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="巡检项数">{{ summary.checklistCount }}</el-descriptions-item>
|
<el-descriptions-item label="巡检项数">{{ summary.checklistCount }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="总巡检次数">{{ summary.totalCount }}</el-descriptions-item>
|
<el-descriptions-item label="总巡检次数">{{ summary.totalCount }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="理论应检次数">{{ summary.expectedTotal }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="通过">
|
<el-descriptions-item label="通过">
|
||||||
<el-tag type="success" size="small">{{ summary.passCount }}</el-tag>
|
<el-tag type="success" size="small">{{ summary.passCount }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@@ -27,8 +29,28 @@
|
|||||||
<el-tag type="danger" size="small">{{ summary.failCount }}</el-tag>
|
<el-tag type="danger" size="small">{{ summary.failCount }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="通过率">{{ summary.passRate }}</el-descriptions-item>
|
<el-descriptions-item label="通过率">{{ summary.passRate }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="检验完成率">{{ summary.completionRate }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
|
<!-- 负责人汇总 -->
|
||||||
|
<el-card class="section-card" v-if="personSummary.length" style="margin-bottom: 16px;">
|
||||||
|
<div slot="header"><i class="el-icon-user"></i> 按负责人汇总</div>
|
||||||
|
<el-table :data="personSummary" size="small" stripe border>
|
||||||
|
<el-table-column prop="responsiblePerson" label="负责人" />
|
||||||
|
<el-table-column prop="partCount" label="负责部位数" align="center" />
|
||||||
|
<el-table-column prop="checkCount" label="巡检项数" align="center" />
|
||||||
|
<el-table-column prop="totalInspections" label="实检次数" align="center" />
|
||||||
|
<el-table-column prop="expectedTotal" label="应检次数" align="center" />
|
||||||
|
<el-table-column prop="passCount" label="通过" align="center" />
|
||||||
|
<el-table-column prop="failCount" label="不通过" align="center" />
|
||||||
|
<el-table-column label="完成率" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-progress :percentage="scope.row.completionRate" :stroke-width="6" :show-text="true" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
<el-table :data="tableData" border stripe style="width: 100%" :cell-style="cellStyle"
|
<el-table :data="tableData" border stripe style="width: 100%" :cell-style="cellStyle"
|
||||||
@cell-mouse-enter="handleCellEnter" @cell-mouse-leave="handleCellLeave">
|
@cell-mouse-enter="handleCellEnter" @cell-mouse-leave="handleCellLeave">
|
||||||
<el-table-column label="巡检部位" align="center" prop="partName" width="140" />
|
<el-table-column label="巡检部位" align="center" prop="partName" width="140" />
|
||||||
@@ -65,13 +87,23 @@
|
|||||||
<span v-else class="result-none">-</span>
|
<span v-else class="result-none">-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="expectedCount" label="应检" width="55" align="center" />
|
||||||
|
<el-table-column prop="actualCount" label="实检" width="55" align="center" />
|
||||||
|
<el-table-column label="差异" width="55" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="scope.row.diff > 0" class="diff-over">+{{ scope.row.diff }}</span>
|
||||||
|
<span v-else-if="scope.row.diff < 0" class="diff-under">{{ scope.row.diff }}</span>
|
||||||
|
<span v-else class="diff-ok">0</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="passCount" label="通过" width="55" align="center" />
|
||||||
|
<el-table-column prop="failCount" label="不通过" width="60" align="center" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listEquipmentPart } from "@/api/mes/eqp/equipmentPart";
|
import { listEquipmentPart } from "@/api/mes/eqp/equipmentPart";
|
||||||
import { listEquipmentChecklist } from "@/api/mes/eqp/equipmentChecklist";
|
|
||||||
import { listEquipmentInspectionRecord } from "@/api/mes/eqp/equipmentInspectionRecord";
|
import { listEquipmentInspectionRecord } from "@/api/mes/eqp/equipmentInspectionRecord";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -80,14 +112,19 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
queryDate: this.getToday(),
|
dateRange: [this.getToday(), this.getToday()],
|
||||||
productionLine: '酸轧线',
|
productionLine: '酸轧线',
|
||||||
partList: [],
|
partList: [],
|
||||||
checklistList: [],
|
|
||||||
records: [],
|
records: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
checklistList() {
|
||||||
|
return this.partList.flatMap(p => (p.checklistList || []).map(cl => ({
|
||||||
|
...cl,
|
||||||
|
partName: cl.partName || p.inspectPart,
|
||||||
|
})));
|
||||||
|
},
|
||||||
tableData() {
|
tableData() {
|
||||||
const recordMap = {};
|
const recordMap = {};
|
||||||
this.records.forEach(r => {
|
this.records.forEach(r => {
|
||||||
@@ -99,6 +136,10 @@ export default {
|
|||||||
return this.checklistList.map(cl => {
|
return this.checklistList.map(cl => {
|
||||||
const dayRecords = recordMap[`${cl.checkId}_1`] || [];
|
const dayRecords = recordMap[`${cl.checkId}_1`] || [];
|
||||||
const nightRecords = recordMap[`${cl.checkId}_2`] || [];
|
const nightRecords = recordMap[`${cl.checkId}_2`] || [];
|
||||||
|
const expectedCount = this.daysInRange * 4;
|
||||||
|
const actualCount = dayRecords.length + nightRecords.length;
|
||||||
|
const passCount = [...dayRecords, ...nightRecords].filter(r => r.runStatus === 1).length;
|
||||||
|
const failCount = [...dayRecords, ...nightRecords].filter(r => r.runStatus === 2).length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
checkId: cl.checkId,
|
checkId: cl.checkId,
|
||||||
@@ -106,10 +147,17 @@ export default {
|
|||||||
checkContent: cl.checkContent,
|
checkContent: cl.checkContent,
|
||||||
dayRecords,
|
dayRecords,
|
||||||
nightRecords,
|
nightRecords,
|
||||||
|
expectedCount,
|
||||||
|
actualCount,
|
||||||
|
diff: actualCount - expectedCount,
|
||||||
|
passCount,
|
||||||
|
failCount,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
summary() {
|
summary() {
|
||||||
|
const days = this.daysInRange || 1;
|
||||||
|
const expectedTotal = this.checklistList.length * days * 4;
|
||||||
const totalCount = this.records.length;
|
const totalCount = this.records.length;
|
||||||
const passCount = this.records.filter(r => r.runStatus === 1).length;
|
const passCount = this.records.filter(r => r.runStatus === 1).length;
|
||||||
const failCount = this.records.filter(r => r.runStatus === 2).length;
|
const failCount = this.records.filter(r => r.runStatus === 2).length;
|
||||||
@@ -117,11 +165,52 @@ export default {
|
|||||||
partCount: this.partList.length,
|
partCount: this.partList.length,
|
||||||
checklistCount: this.checklistList.length,
|
checklistCount: this.checklistList.length,
|
||||||
totalCount,
|
totalCount,
|
||||||
|
expectedTotal,
|
||||||
passCount,
|
passCount,
|
||||||
failCount,
|
failCount,
|
||||||
passRate: totalCount > 0 ? (passCount / totalCount * 100).toFixed(1) + "%" : "0%",
|
passRate: totalCount > 0 ? (passCount / totalCount * 100).toFixed(1) + "%" : "0%",
|
||||||
|
completionRate: expectedTotal > 0 ? (totalCount / expectedTotal * 100).toFixed(1) + "%" : "0%",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
daysInRange() {
|
||||||
|
if (!this.dateRange || this.dateRange.length !== 2) return 1;
|
||||||
|
const start = new Date(this.dateRange[0]);
|
||||||
|
const end = new Date(this.dateRange[1]);
|
||||||
|
return Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1;
|
||||||
|
},
|
||||||
|
personSummary() {
|
||||||
|
const personMap = {};
|
||||||
|
this.partList.forEach(p => {
|
||||||
|
const person = p.responsiblePerson || '未指定';
|
||||||
|
if (!personMap[person]) {
|
||||||
|
personMap[person] = { responsiblePerson: person, partIds: new Set(), checkIds: new Set(), recordIds: new Set(), passIds: new Set(), failIds: new Set() };
|
||||||
|
}
|
||||||
|
personMap[person].partIds.add(p.partId);
|
||||||
|
(p.checklistList || []).forEach(cl => personMap[person].checkIds.add(cl.checkId));
|
||||||
|
});
|
||||||
|
this.records.forEach(r => {
|
||||||
|
for (const person of Object.values(personMap)) {
|
||||||
|
if (person.checkIds.has(r.checkId)) {
|
||||||
|
person.recordIds.add(r.recordId);
|
||||||
|
if (r.runStatus === 1) person.passIds.add(r.recordId);
|
||||||
|
if (r.runStatus === 2) person.failIds.add(r.recordId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Object.values(personMap).map(p => ({
|
||||||
|
responsiblePerson: p.responsiblePerson,
|
||||||
|
partCount: p.partIds.size,
|
||||||
|
checkCount: p.checkIds.size,
|
||||||
|
totalInspections: p.recordIds.size,
|
||||||
|
expectedTotal: p.checkIds.size * this.daysInRange * 4,
|
||||||
|
passCount: p.passIds.size,
|
||||||
|
failCount: p.failIds.size,
|
||||||
|
completionRate: p.checkIds.size * this.daysInRange * 4 > 0
|
||||||
|
? Math.round(p.recordIds.size / (p.checkIds.size * this.daysInRange * 4) * 100)
|
||||||
|
: 0,
|
||||||
|
}));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getToday() {
|
getToday() {
|
||||||
@@ -134,18 +223,22 @@ export default {
|
|||||||
handleCellEnter(row, column) {},
|
handleCellEnter(row, column) {},
|
||||||
handleCellLeave(row, column) {},
|
handleCellLeave(row, column) {},
|
||||||
async handleQuery() {
|
async handleQuery() {
|
||||||
if (!this.queryDate) return;
|
if (!this.dateRange || this.dateRange.length !== 2) return;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const partParams = {};
|
const partParams = {};
|
||||||
if (this.productionLine) partParams.productionLine = this.productionLine;
|
if (this.productionLine) partParams.productionLine = this.productionLine;
|
||||||
const [partRes, checklistRes, recordRes] = await Promise.all([
|
const recordParams = {
|
||||||
|
startInspectTime: this.dateRange[0] + ' 00:00:00',
|
||||||
|
endInspectTime: this.dateRange[1] + ' 23:59:59',
|
||||||
|
pageSize: 9999,
|
||||||
|
};
|
||||||
|
if (this.productionLine) recordParams.productionLine = this.productionLine;
|
||||||
|
const [partRes, recordRes] = await Promise.all([
|
||||||
listEquipmentPart(partParams),
|
listEquipmentPart(partParams),
|
||||||
listEquipmentChecklist(partParams),
|
listEquipmentInspectionRecord(recordParams),
|
||||||
listEquipmentInspectionRecord({ startTime: this.queryDate, endTime: this.queryDate, pageSize: 9999 }),
|
|
||||||
]);
|
]);
|
||||||
if (partRes.code === 200) this.partList = partRes.rows || [];
|
if (partRes.code === 200) this.partList = partRes.rows || [];
|
||||||
if (checklistRes.code === 200) this.checklistList = checklistRes.rows || [];
|
|
||||||
if (recordRes.code === 200) this.records = recordRes.rows || [];
|
if (recordRes.code === 200) this.records = recordRes.rows || [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("查询失败", e);
|
console.error("查询失败", e);
|
||||||
@@ -170,6 +263,14 @@ export default {
|
|||||||
.result-pass { color: #67c23a; }
|
.result-pass { color: #67c23a; }
|
||||||
.result-fail { color: #f56c6c; }
|
.result-fail { color: #f56c6c; }
|
||||||
.result-none { color: #c0c4cc; font-size: 16px; }
|
.result-none { color: #c0c4cc; font-size: 16px; }
|
||||||
|
|
||||||
|
.diff-over { color: #e6a23c; font-weight: bold; }
|
||||||
|
.diff-under { color: #f56c6c; font-weight: bold; }
|
||||||
|
.diff-ok { color: #67c23a; }
|
||||||
|
|
||||||
|
.section-card {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -16,6 +16,14 @@
|
|||||||
<el-input v-model="sharedQueryParams.lineSection" placeholder="请输入产线段" clearable
|
<el-input v-model="sharedQueryParams.lineSection" placeholder="请输入产线段" clearable
|
||||||
@keyup.enter.native="handleQuery" />
|
@keyup.enter.native="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="负责人" prop="responsiblePerson">
|
||||||
|
<el-input
|
||||||
|
v-model="sharedQueryParams.responsiblePerson"
|
||||||
|
placeholder="请输入负责人"
|
||||||
|
clearable
|
||||||
|
@keyup.enter.native="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handlePartQuery">搜索</el-button>
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handlePartQuery">搜索</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -132,6 +140,9 @@
|
|||||||
<el-form-item label="巡检部位" prop="inspectPart">
|
<el-form-item label="巡检部位" prop="inspectPart">
|
||||||
<el-input v-model="partForm.inspectPart" placeholder="请输入巡检部位" />
|
<el-input v-model="partForm.inspectPart" placeholder="请输入巡检部位" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="负责人" prop="responsiblePerson">
|
||||||
|
<el-input v-model="partForm.responsiblePerson" placeholder="请输入负责人" clearable />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="partForm.remark" placeholder="请输入备注" />
|
<el-input v-model="partForm.remark" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
Reference in New Issue
Block a user