<template>
|
<view class="page">
|
<!-- 刀具选择区 -->
|
<view class="top-section-grid">
|
<view class="form-cell">
|
<label class="form-label">选择刀具编号:</label>
|
<select v-model="selectedToolNo" class="form-select">
|
<option v-for="tool in toolList" :key="tool.no" :value="tool.no">{{ tool.no }} | {{ tool.name }}</option>
|
</select>
|
<button class="btn-blue" @click="showToolDialog = true">刀具目录</button>
|
</view>
|
<view class="form-cell">
|
<label class="form-label">设置使用上限:</label>
|
<input class="input" type="number" v-model="useLimitInput" placeholder="每次换刀后手填" :disabled="!selectedToolNo" />
|
<button class="btn-blue" @click="setUseLimit" :disabled="!selectedToolNo || !useLimitInput">保存上限</button>
|
</view>
|
<view class="form-cell">
|
<label class="form-label">刀具名称:</label>
|
<input class="input" v-model="toolName" placeholder="刀具带出" disabled />
|
<label class="form-label" style="margin-left: 16px;">规格型号:</label>
|
<input class="input" v-model="toolModel" placeholder="刀具带出" disabled />
|
</view>
|
</view>
|
|
<!-- 操作按钮 -->
|
<view class="button-row">
|
<button class="save-btn" @click="handleUpTool">上刀提交</button>
|
<button class="save-btn" @click="handleDownTool">下刀提交</button>
|
<button class="cancel-btn" @click="cancel">取消</button>
|
</view>
|
|
<!-- 刀具目录弹窗 -->
|
<view v-if="showToolDialog" class="dialog-overlay">
|
<view class="dialog">
|
<view class="form-group">
|
<input v-model="searchKey" placeholder="输入刀具编码、名称模糊搜索" class="input" />
|
<button class="btn-blue" @click="searchTool">搜索</button>
|
</view>
|
<view class="tool-list">
|
<button v-for="tool in filteredTools" :key="tool.no" class="tool-btn" @click="selectTool(tool)">
|
{{ tool.no }} | {{ tool.name }}
|
</button>
|
</view>
|
<view class="dialog-actions">
|
<div style="display: flex; align-items: center;">
|
<button class="btn-blue" @click="prevPage" :disabled="pageIndex === 1">上一页</button>
|
<span style="margin: 0 12px;">第{{ pageIndex }}页 / 共{{ totalPages }}页</span>
|
<button class="btn-blue" @click="nextPage" :disabled="pageIndex === totalPages">下一页</button>
|
</div>
|
<div>
|
<button class="btn-blue" @click="confirmTool">确定</button>
|
<button class="btn-disabled" @click="showToolDialog = false">取消</button>
|
</div>
|
</view>
|
</view>
|
</view>
|
|
<!-- 刀具使用记录表格 -->
|
<view class="table-section">
|
<table>
|
<thead>
|
<tr>
|
<th>刀具编号</th>
|
<th>刀具名称</th>
|
<th>上刀时间</th>
|
<th>上刀计数</th>
|
<th>下刀时间</th>
|
<th>下刀计数</th>
|
<th>使用次数</th>
|
<th>使用上限</th>
|
<th>寿命比%</th>
|
<th>寿命预警值</th>
|
<th>预警状态</th>
|
</tr>
|
</thead>
|
<tbody>
|
<tr v-for="item in toolRecords" :key="item.id">
|
<td>{{ item.no }}</td>
|
<td>{{ item.name }}</td>
|
<td>{{ item.upTime }}</td>
|
<td>{{ item.upCount }}</td>
|
<td>{{ item.downTime }}</td>
|
<td>{{ item.downCount }}</td>
|
<td>{{ item.useCount }}</td>
|
<td>{{ item.useLimit }}</td>
|
<td>{{ item.lifePercent }}</td>
|
<td>{{ item.lifeWarn }}</td>
|
<td :class="item.warnStatus === '警告' ? 'warn' : ''">{{ item.warnStatus }}</td>
|
</tr>
|
</tbody>
|
</table>
|
</view>
|
|
<!-- 说明 -->
|
<view class="tool-desc">
|
<p style="color:red;">当前工单中,换了几次刀,就会产生几条数据。上刀时间、下刀时间在表中能看到。</p>
|
<p style="color:red;">上刀时间和对应时间用生产计数器匹配,查出当时的生产数(累计计数)。</p>
|
<p style="color:red;">寿命比预警值在刀具上,默认统一。</p>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
machineNo: '',//机台编码
|
workOrderNo: '',//工单号
|
pageIndex: 1,
|
pageSize: 18,
|
total: 0,
|
toolList: [],
|
selectedToolNo: '',
|
toolName: '',
|
toolModel: '',
|
showToolDialog: false,
|
searchKey: '',
|
filteredTools: [],
|
useLimitInput: '',
|
toolRecords: [
|
// 示例数据,实际应从后端接口获取
|
{ id: 1, no: 'T22050338', name: 'm1.5合金长刀', upTime: '7-13 9:00', upCount: 15, downTime: '7-13 19:00', downCount: 3115, useCount: 3100, useLimit: 8888, lifePercent: '34.88%', lifeWarn: '90%', warnStatus: '正常' }
|
]
|
};
|
},
|
computed: {
|
totalPages() {
|
return Math.ceil(this.total / this.pageSize) || 1;
|
}
|
},
|
methods: {
|
async fetchTools(searchKey) {
|
const res = await this.$post({
|
url: '/MesCutterLedger/QueryTools',
|
data: JSON.stringify({
|
searchKey,
|
pageIndex: this.pageIndex,
|
pageSize: this.pageSize
|
}),
|
headers: { 'Content-Type': 'application/json' }
|
});
|
if (res.status === 0) {
|
this.filteredTools = res.data.tbBillList.map(t => ({
|
no: t.cutterId || t.no,
|
name: t.cutterName || t.name,
|
model: t.cutterModel || t.model
|
}));
|
this.total = res.data.total || 0; // 假设后端返回总数
|
} else {
|
this.$showMessage(res.message || '查询失败');
|
}
|
},
|
//翻页
|
async prevPage() {
|
if (this.pageIndex > 1) {
|
this.pageIndex--;
|
await this.fetchTools(this.searchKey);
|
}
|
},
|
async nextPage() {
|
if (this.pageIndex < this.totalPages) {
|
this.pageIndex++;
|
await this.fetchTools(this.searchKey);
|
}
|
},
|
async searchTool() {
|
this.pageIndex = 1; // 搜索时重置到第一页
|
await this.fetchTools(this.searchKey);
|
},
|
selectTool(tool) {
|
this.selectedToolNo = tool.no;
|
this.toolName = tool.name;
|
this.toolModel = tool.model;
|
},
|
confirmTool() {
|
this.showToolDialog = false;
|
},
|
async handleUpTool() {
|
if (!this.workOrderNo) {
|
this.$showMessage('工单号不能为空');
|
return;
|
}
|
if (!this.machineNo) {
|
this.$showMessage('机台号不能为空');
|
return;
|
}
|
if (!this.selectedToolNo) {
|
this.$showMessage('刀具编号不能为空');
|
return;
|
}
|
if (!this.useLimitInput) {
|
this.$showMessage('使用上限不能为空');
|
return;
|
}
|
const useLimit = Number(this.useLimitInput);
|
if (isNaN(useLimit) || useLimit <= 0) {
|
this.$showMessage('请输入有效的使用上限');
|
return;
|
}
|
const payload = {
|
workOrderNo: this.workOrderNo, // 工单号
|
machineNo: this.machineNo, // 机台编号
|
toolNo: this.selectedToolNo, // 刀具编号
|
type: '上刀', // 上刀
|
useLimit: this.useLimitInput ? Number(this.useLimitInput) : null // 使用上限
|
};
|
const res = await this.$post({
|
url: '/MesCutterLedger/SubmitToolAction',
|
data: JSON.stringify(payload),
|
headers: { 'Content-Type': 'application/json' }
|
});
|
if (res.status === 0) {
|
this.$showMessage('上刀提交成功');
|
} else {
|
this.$showMessage(res.message || '上刀提交失败');
|
}
|
},
|
async handleDownTool() {
|
if (!this.workOrderNo) {
|
this.$showMessage('工单号不能为空');
|
return;
|
}
|
if (!this.machineNo) {
|
this.$showMessage('机台号不能为空');
|
return;
|
}
|
if (!this.selectedToolNo) {
|
this.$showMessage('刀具编号不能为空');
|
return;
|
}
|
if (!this.useLimitInput) {
|
this.$showMessage('使用上限不能为空');
|
return;
|
}
|
const useLimit = Number(this.useLimitInput);
|
if (isNaN(useLimit) || useLimit <= 0) {
|
this.$showMessage('请输入有效的使用上限');
|
return;
|
}
|
const payload = {
|
workOrderNo: this.workOrderNo,
|
machineNo: this.machineNo,
|
toolNo: this.selectedToolNo,
|
type: '下刀', // 下刀
|
useLimit: this.useLimitInput ? Number(this.useLimitInput) : null
|
};
|
const res = await this.$post({
|
url: '/MesCutterLedger/SubmitToolAction',
|
data: JSON.stringify(payload),
|
headers: { 'Content-Type': 'application/json' }
|
});
|
if (res.status === 0) {
|
this.$showMessage('下刀提交成功');
|
} else {
|
this.$showMessage(res.message || '下刀提交失败');
|
}
|
},
|
cancel() {
|
this.selectedToolNo = '';
|
this.toolName = '';
|
this.toolModel = '';
|
},
|
async fetchFormData() {
|
const payload = new URLSearchParams();
|
payload.append('workOrderNo', this.workOrderNo);
|
payload.append('machineNo', this.machineNo);
|
const res = await this.$post({
|
url: '/MesCutterLedger/GetFormData',
|
data: payload.toString(),
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
});
|
if (res.status === 0) {
|
this.toolRecords = res.data; // 假设后端直接返回表格数组
|
} else {
|
this.$showMessage(res.message || '获取表单数据失败');
|
}
|
}
|
},
|
mounted() {
|
this.fetchTools('');
|
this.machineNo = uni.getStorageSync('machineNo') || '';
|
this.workOrderNo = uni.getStorageSync('daa001') || '';
|
if (this.machineNo && this.workOrderNo) {
|
this.fetchFormData();
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.top-section-grid {
|
display: flex;
|
justify-content: center;
|
align-items: flex-end;
|
gap: 32px;
|
margin-bottom: 2vh;
|
}
|
|
.form-cell {
|
display: flex;
|
align-items: center;
|
}
|
|
.form-label {
|
width: 90px;
|
font-weight: bold;
|
}
|
|
.input {
|
padding: 1vh;
|
font-size: 1.1vw;
|
border: 1px solid #ccc;
|
width: 10vw;
|
margin-right: 8px;
|
}
|
|
.form-select {
|
width: 12vw;
|
padding: 1vh;
|
font-size: 1.1vw;
|
margin-right: 8px;
|
}
|
|
.btn-blue {
|
background-color: #00A2E9;
|
color: white;
|
border: none;
|
padding: 8px 18px;
|
margin-left: 8px;
|
border-radius: 5px;
|
cursor: pointer;
|
}
|
|
.button-row {
|
display: flex;
|
justify-content: center;
|
gap: 32px;
|
margin: 2vh 0;
|
}
|
|
.save-btn, .cancel-btn {
|
width: 28%;
|
padding: 1.5vh;
|
background-color: #00A2E9;
|
color: white;
|
font-size: 1.2vw;
|
border: none;
|
text-align: center;
|
border-radius: 5px;
|
}
|
|
.cancel-btn {
|
background-color: #ccc;
|
color: #333;
|
}
|
|
.dialog-overlay {
|
position: fixed;
|
top: 0;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
background: rgba(0,0,0,0.3);
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
z-index: 1000;
|
}
|
|
.dialog {
|
background: #fff;
|
padding: 2vh 2vw;
|
border-radius: 8px;
|
width: 60vw;
|
}
|
|
.tool-list {
|
display: flex;
|
flex-wrap: wrap;
|
margin: 1vh 0;
|
max-height: 40vh;
|
overflow-y: auto;
|
}
|
|
.tool-btn {
|
margin: 5px 10px 5px 0;
|
padding: 8px 16px;
|
background: #f5f5f5;
|
border: 1px solid #ccc;
|
border-radius: 4px;
|
cursor: pointer;
|
background: #e0e0e0;
|
color: #888;
|
}
|
|
.dialog-actions {
|
display: flex;
|
justify-content: space-between;
|
margin-top: 2vh;
|
}
|
|
.table-section {
|
margin: 2vh 0;
|
overflow-x: auto;
|
}
|
|
table {
|
width: 100%;
|
border-collapse: collapse;
|
}
|
|
th, td {
|
border: 1px solid #ccc;
|
padding: 8px 4px;
|
text-align: center;
|
font-size: 1vw;
|
}
|
|
.warn {
|
color: red;
|
font-weight: bold;
|
}
|
|
.bottom-section {
|
display: flex;
|
justify-content: space-around;
|
margin-top: 2vh;
|
}
|
|
.tool-desc {
|
margin-top: 2vh;
|
}
|
</style>
|