feat(base): 添加工单执行和调试备份功能

- 在orderInfo API中新增工单查询、生产开始、完工提报、数量更新等接口
- 在processSnapshot API中新增调试备份的创建、查询、设为默认、应用等功能接口
- 新增backup.vue页面实现调试备份的完整管理界面
- 新增execution.vue页面实现工单执行流程的管理界面
- 添加工单执行状态管理和数量更新功能
- 实现备份参数查看和应用功能
- 集成权限控制和数据验证机制
master
zangch@mesnac.com 1 week ago
parent 09fee5f073
commit 5258a78178

@ -61,3 +61,54 @@ export function replaceProductionLine(data) {
data: data
})
}
// 根据工单编号查询工单
export function getOrderInfoByCode(orderCode) {
return request({
url: '/base/orderInfo/byCode/' + orderCode,
method: 'get'
})
}
// 开始生产
export function startProduction(orderCode, operator) {
return request({
url: '/base/orderInfo/startProduction',
method: 'post',
params: { orderCode, operator }
})
}
// 完工提报
export function completeProduction(orderCode, completeQty, defectQty) {
return request({
url: '/base/orderInfo/completeProduction',
method: 'post',
params: { orderCode, completeQty, defectQty }
})
}
// 更新完工数量
export function updateQuantity(orderCode, completeQty, defectQty) {
return request({
url: '/base/orderInfo/updateQuantity',
method: 'post',
params: { orderCode, completeQty, defectQty }
})
}
// 获取正在执行的工单列表
export function getRunningOrders() {
return request({
url: '/base/orderInfo/running',
method: 'get'
})
}
// 获取指定设备正在执行的工单
export function getRunningOrderByDevice(deviceCode) {
return request({
url: '/base/orderInfo/running/' + deviceCode,
method: 'get'
})
}

@ -59,3 +59,46 @@ export function compareSnapshots(snapshotId1, snapshotId2) {
params: { snapshotId1, snapshotId2 }
})
}
// 创建调试备份
export function createBackup(data) {
return request({
url: '/base/processSnapshot/createBackup',
method: 'post',
params: data
})
}
// 查询调试备份列表
export function getBackupList(query) {
return request({
url: '/base/processSnapshot/backupList',
method: 'get',
params: query
})
}
// 获取默认备份
export function getDefaultBackup(query) {
return request({
url: '/base/processSnapshot/defaultBackup',
method: 'get',
params: query
})
}
// 设为默认备份
export function setDefaultBackup(snapshotId) {
return request({
url: '/base/processSnapshot/setDefault/' + snapshotId,
method: 'put'
})
}
// 应用备份(查看参数)
export function applyBackup(snapshotId) {
return request({
url: '/base/processSnapshot/applyBackup/' + snapshotId,
method: 'get'
})
}

@ -0,0 +1,311 @@
<template>
<div class="app-container">
<!-- 搜索表单 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" class="search-form">
<el-form-item label="设备编号" prop="deviceCode">
<el-input v-model="queryParams.deviceCode" placeholder="请输入设备编号" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="执行状态" prop="executionStatus">
<el-select v-model="queryParams.executionStatus" placeholder="请选择执行状态" clearable>
<el-option label="待执行" value="PENDING" />
<el-option label="运行中" value="RUNNING" />
<el-option label="已完成" value="COMPLETED" />
<el-option label="已暂停" value="PAUSED" />
</el-select>
</el-form-item>
<el-form-item>
<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-form-item>
</el-form>
<!-- 工单列表 -->
<el-table v-loading="loading" :data="orderList" border>
<el-table-column label="工单编号" prop="orderCode" width="150" />
<el-table-column label="物料名称" prop="materialName" show-overflow-tooltip />
<el-table-column label="计划数量" prop="orderAmount" width="100" align="center" />
<el-table-column label="完工数量" prop="actualCompleteQty" width="100" align="center">
<template slot-scope="scope">
<span>{{ scope.row.actualCompleteQty || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="不良数量" prop="actualDefectQty" width="100" align="center">
<template slot-scope="scope">
<span>{{ scope.row.actualDefectQty || 0 }}</span>
</template>
</el-table-column>
<el-table-column label="执行状态" prop="executionStatus" width="100" align="center">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.executionStatus)">
{{ getStatusText(scope.row.executionStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作员" prop="executionOperator" width="100" align="center" />
<el-table-column label="开始时间" prop="startTime" width="160" align="center" />
<el-table-column label="操作" width="280" fixed="right" align="center">
<template slot-scope="scope">
<el-button
v-if="!scope.row.executionStatus || scope.row.executionStatus === 'PENDING'"
size="mini"
type="primary"
@click="handleStart(scope.row)"
v-hasPermi="['base:orderInfo:start']"
>开始生产</el-button>
<el-button
v-if="scope.row.executionStatus === 'RUNNING'"
size="mini"
type="warning"
@click="handleUpdateQty(scope.row)"
v-hasPermi="['base:orderInfo:updateQty']"
>更新数量</el-button>
<el-button
v-if="scope.row.executionStatus === 'RUNNING'"
size="mini"
type="success"
@click="handleComplete(scope.row)"
v-hasPermi="['base:orderInfo:complete']"
>完工提报</el-button>
<el-button
size="mini"
type="info"
@click="handleDetail(scope.row)"
>详情</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 开始生产对话框 -->
<el-dialog title="开始生产" :visible.sync="startDialogVisible" width="400px" append-to-body>
<el-form :model="startForm" label-width="80px">
<el-form-item label="工单编号">
<el-input v-model="startForm.orderCode" disabled />
</el-form-item>
<el-form-item label="物料名称">
<el-input v-model="startForm.materialName" disabled />
</el-form-item>
<el-form-item label="操作员">
<el-input v-model="startForm.operator" placeholder="请输入操作员" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="startDialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmStart"> </el-button>
</div>
</el-dialog>
<!-- 更新数量对话框 -->
<el-dialog title="更新完工数量" :visible.sync="updateQtyDialogVisible" width="400px" append-to-body>
<el-form :model="updateForm" label-width="80px">
<el-form-item label="工单编号">
<el-input v-model="updateForm.orderCode" disabled />
</el-form-item>
<el-form-item label="计划数量">
<el-input v-model="updateForm.planQty" disabled />
</el-form-item>
<el-form-item label="完工数量">
<el-input-number v-model="updateForm.completeQty" :min="0" style="width: 100%" />
</el-form-item>
<el-form-item label="不良数量">
<el-input-number v-model="updateForm.defectQty" :min="0" style="width: 100%" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="updateQtyDialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmUpdateQty"> </el-button>
</div>
</el-dialog>
<!-- 完工提报对话框 -->
<el-dialog title="完工提报" :visible.sync="completeDialogVisible" width="400px" append-to-body>
<el-form :model="completeForm" label-width="80px">
<el-form-item label="工单编号">
<el-input v-model="completeForm.orderCode" disabled />
</el-form-item>
<el-form-item label="计划数量">
<el-input v-model="completeForm.planQty" disabled />
</el-form-item>
<el-form-item label="完工数量">
<el-input-number v-model="completeForm.completeQty" :min="0" style="width: 100%" />
</el-form-item>
<el-form-item label="不良数量">
<el-input-number v-model="completeForm.defectQty" :min="0" style="width: 100%" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="completeDialogVisible = false"> </el-button>
<el-button type="success" @click="confirmComplete"></el-button>
</div>
</el-dialog>
<!-- 工单详情对话框 -->
<el-dialog title="工单详情" :visible.sync="detailDialogVisible" width="600px" append-to-body>
<el-descriptions :column="2" border>
<el-descriptions-item label="工单编号">{{ detailOrder.orderCode }}</el-descriptions-item>
<el-descriptions-item label="物料编码">{{ detailOrder.materialCode }}</el-descriptions-item>
<el-descriptions-item label="物料名称" :span="2">{{ detailOrder.materialName }}</el-descriptions-item>
<el-descriptions-item label="计划数量">{{ detailOrder.orderAmount }}</el-descriptions-item>
<el-descriptions-item label="执行状态">
<el-tag :type="getStatusType(detailOrder.executionStatus)">
{{ getStatusText(detailOrder.executionStatus) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="完工数量">{{ detailOrder.actualCompleteQty || 0 }}</el-descriptions-item>
<el-descriptions-item label="不良数量">{{ detailOrder.actualDefectQty || 0 }}</el-descriptions-item>
<el-descriptions-item label="操作员">{{ detailOrder.executionOperator || '-' }}</el-descriptions-item>
<el-descriptions-item label="设备编号">{{ detailOrder.deviceCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="开始时间">{{ detailOrder.startTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="完工时间">{{ detailOrder.finishTime || '-' }}</el-descriptions-item>
</el-descriptions>
<div slot="footer" class="dialog-footer">
<el-button @click="detailDialogVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listOrderInfo, startProduction, completeProduction, updateQuantity } from "@/api/base/orderInfo";
export default {
name: "OrderExecution",
data() {
return {
loading: false,
total: 0,
orderList: [],
queryParams: {
pageNum: 1,
pageSize: 10,
deviceCode: null,
executionStatus: null
},
startDialogVisible: false,
updateQtyDialogVisible: false,
completeDialogVisible: false,
detailDialogVisible: false,
startForm: {
orderCode: '',
materialName: '',
operator: ''
},
updateForm: {
orderCode: '',
planQty: 0,
completeQty: 0,
defectQty: 0
},
completeForm: {
orderCode: '',
planQty: 0,
completeQty: 0,
defectQty: 0
},
detailOrder: {}
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listOrderInfo(this.queryParams).then(response => {
this.orderList = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
getStatusType(status) {
const map = { 'RUNNING': 'warning', 'COMPLETED': 'success', 'PAUSED': 'info', 'PENDING': '' };
return map[status] || '';
},
getStatusText(status) {
const map = { 'RUNNING': '运行中', 'COMPLETED': '已完成', 'PAUSED': '已暂停', 'PENDING': '待执行' };
return map[status] || '待执行';
},
handleStart(row) {
this.startForm = {
orderCode: row.orderCode,
materialName: row.materialName,
operator: this.$store.state.user.name || ''
};
this.startDialogVisible = true;
},
confirmStart() {
if (!this.startForm.operator) {
this.$modal.msgWarning("请输入操作员");
return;
}
startProduction(this.startForm.orderCode, this.startForm.operator).then(response => {
this.$modal.msgSuccess("开始生产成功");
this.startDialogVisible = false;
this.getList();
});
},
handleUpdateQty(row) {
this.updateForm = {
orderCode: row.orderCode,
planQty: row.orderAmount,
completeQty: row.actualCompleteQty || 0,
defectQty: row.actualDefectQty || 0
};
this.updateQtyDialogVisible = true;
},
confirmUpdateQty() {
updateQuantity(this.updateForm.orderCode, this.updateForm.completeQty, this.updateForm.defectQty).then(response => {
this.$modal.msgSuccess("更新数量成功");
this.updateQtyDialogVisible = false;
this.getList();
});
},
handleComplete(row) {
this.completeForm = {
orderCode: row.orderCode,
planQty: row.orderAmount,
completeQty: row.actualCompleteQty || 0,
defectQty: row.actualDefectQty || 0
};
this.completeDialogVisible = true;
},
confirmComplete() {
this.$modal.confirm('确认完工提报?完工后工单状态将变为已完成').then(() => {
completeProduction(this.completeForm.orderCode, this.completeForm.completeQty, this.completeForm.defectQty).then(response => {
this.$modal.msgSuccess("完工提报成功");
this.completeDialogVisible = false;
this.getList();
});
});
},
handleDetail(row) {
this.detailOrder = row;
this.detailDialogVisible = true;
}
}
};
</script>
<style scoped>
.search-form {
margin-bottom: 15px;
}
</style>

@ -0,0 +1,213 @@
<template>
<div class="app-container">
<el-card>
<!-- 搜索表单 -->
<el-form :inline="true" :model="queryParams" ref="queryForm" size="small">
<el-form-item label="模具编号" prop="moldCode">
<el-input v-model="queryParams.moldCode" placeholder="请输入模具编号" clearable />
</el-form-item>
<el-form-item label="机台编号" prop="deviceCode">
<el-input v-model="queryParams.deviceCode" placeholder="请输入机台编号" clearable />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="queryParams.productCode" placeholder="请输入产品编号" clearable />
</el-form-item>
<el-form-item>
<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="success" icon="el-icon-plus" size="mini" @click="handleCreate" v-hasPermi="['base:processSnapshot:createBackup']"></el-button>
</el-form-item>
</el-form>
<!-- 备份列表 -->
<el-table v-loading="loading" :data="backupList" border stripe>
<el-table-column label="备份名称" prop="backupName" min-width="150" />
<el-table-column label="模具" prop="moldCode" width="100" align="center" />
<el-table-column label="机台" prop="deviceCode" width="100" align="center" />
<el-table-column label="产品" prop="productCode" width="100" align="center" />
<el-table-column label="默认" width="80" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.isDefault === '1'" type="success" size="small"></el-tag>
<el-tag v-else type="info" size="small"></el-tag>
</template>
</el-table-column>
<el-table-column label="操作员" prop="createBy" width="100" align="center" />
<el-table-column label="备份时间" prop="snapshotTime" width="160" align="center" />
<el-table-column label="操作" width="260" fixed="right" align="center">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"></el-button>
<el-button size="mini" type="text" icon="el-icon-check" @click="handleApply(scope.row)"></el-button>
<el-button
v-if="scope.row.isDefault !== '1'"
size="mini"
type="text"
icon="el-icon-star-off"
@click="handleSetDefault(scope.row)"
v-hasPermi="['base:processSnapshot:setDefault']"
>设为默认</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['base:processSnapshot:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 创建备份对话框 -->
<el-dialog title="创建调试备份" :visible.sync="createDialogVisible" width="500px" append-to-body>
<el-form :model="createForm" :rules="createRules" ref="createForm" label-width="100px">
<el-form-item label="备份名称" prop="backupName">
<el-input v-model="createForm.backupName" placeholder="请输入备份名称" />
</el-form-item>
<el-form-item label="模具编号" prop="moldCode">
<el-input v-model="createForm.moldCode" placeholder="请输入模具编号" />
</el-form-item>
<el-form-item label="机台编号" prop="deviceCode">
<el-input v-model="createForm.deviceCode" placeholder="请输入机台编号" />
</el-form-item>
<el-form-item label="产品编号" prop="productCode">
<el-input v-model="createForm.productCode" placeholder="请输入产品编号" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="createDialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmCreate"> </el-button>
</div>
</el-dialog>
<!-- 查看参数对话框 -->
<el-dialog title="备份参数详情" :visible.sync="viewDialogVisible" width="800px" append-to-body>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="备份名称">{{ currentSnapshot.backupName }}</el-descriptions-item>
<el-descriptions-item label="模具">{{ currentSnapshot.moldCode }}</el-descriptions-item>
<el-descriptions-item label="机台">{{ currentSnapshot.deviceCode }}</el-descriptions-item>
<el-descriptions-item label="产品">{{ currentSnapshot.productCode }}</el-descriptions-item>
<el-descriptions-item label="操作员">{{ currentSnapshot.createBy }}</el-descriptions-item>
<el-descriptions-item label="备份时间">{{ currentSnapshot.snapshotTime }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">参数列表</el-divider>
<el-table :data="paramList" stripe max-height="400" size="small">
<el-table-column label="参数编码" prop="paramCode" width="120" />
<el-table-column label="参数名称" prop="paramName" min-width="150" />
<el-table-column label="参数值" prop="paramValue" width="120" align="right" />
<el-table-column label="采集时间" prop="collectTime" width="160" align="center" />
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="viewDialogVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getBackupList, createBackup, applyBackup, setDefaultBackup, delProcessSnapshot } from "@/api/base/processSnapshot";
export default {
name: "DebugBackup",
data() {
return {
loading: false,
queryParams: {
moldCode: null,
deviceCode: null,
productCode: null
},
backupList: [],
createDialogVisible: false,
viewDialogVisible: false,
createForm: {
backupName: '',
moldCode: '',
deviceCode: '',
productCode: ''
},
createRules: {
backupName: [{ required: true, message: '请输入备份名称', trigger: 'blur' }],
deviceCode: [{ required: true, message: '请输入机台编号', trigger: 'blur' }]
},
currentSnapshot: {},
paramList: []
};
},
created() {
this.handleQuery();
},
methods: {
handleQuery() {
this.loading = true;
getBackupList(this.queryParams).then(response => {
this.backupList = response.data || [];
this.loading = false;
}).catch(() => {
this.loading = false;
});
},
resetQuery() {
this.resetForm("queryForm");
this.queryParams = { moldCode: null, deviceCode: null, productCode: null };
this.handleQuery();
},
handleCreate() {
this.createForm = { backupName: '', moldCode: '', deviceCode: '', productCode: '' };
this.createDialogVisible = true;
},
confirmCreate() {
this.$refs.createForm.validate(valid => {
if (valid) {
createBackup(this.createForm).then(response => {
this.$modal.msgSuccess("备份创建成功");
this.createDialogVisible = false;
this.handleQuery();
});
}
});
},
handleView(row) {
this.currentSnapshot = row;
applyBackup(row.snapshotId).then(response => {
this.paramList = response.data ? response.data.paramList || [] : [];
this.viewDialogVisible = true;
});
},
handleApply(row) {
this.$modal.confirm('确认应用此备份?系统将显示备份时的参数值,请参考调整设备参数。').then(() => {
applyBackup(row.snapshotId).then(response => {
this.currentSnapshot = row;
this.paramList = response.data ? response.data.paramList || [] : [];
this.viewDialogVisible = true;
this.$modal.msgSuccess("参数已加载,请参考调整设备参数");
});
});
},
handleSetDefault(row) {
this.$modal.confirm('确认将此备份设为默认?同类型备份只能有一个默认。').then(() => {
setDefaultBackup(row.snapshotId).then(response => {
this.$modal.msgSuccess("设置成功");
this.handleQuery();
});
});
},
handleDelete(row) {
this.$modal.confirm('确认删除此备份?删除后不可恢复。').then(() => {
delProcessSnapshot(row.snapshotId).then(response => {
this.$modal.msgSuccess("删除成功");
this.handleQuery();
});
});
}
}
};
</script>
<style scoped>
.el-divider {
margin: 20px 0 15px 0;
}
</style>
Loading…
Cancel
Save