<template>
|
<view class="page">
|
<!-- 操作按钮 -->
|
<view class="button-row">
|
<button class="save-btn" @click="handleRefresh" :disabled="loadingForm || submitting || loadingInspection">刷新</button>
|
</view>
|
|
<!-- 刀具使用记录表格 -->
|
<view class="table-section" :class="{'expanded': toolExpanded}">
|
<view class="table-header">
|
<h3>上下刀记录</h3>
|
<button class="expand-btn" @click="toggleExpand('tool')">
|
{{ toolExpanded ? '收起' : '展开' }}
|
</button>
|
</view>
|
<table class="styled-table">
|
<thead>
|
<tr>
|
<th style="width:7%">刀具编号</th>
|
<th style="width:12%">刀具名称</th>
|
<th style="width:10%">上刀时间</th>
|
<th class="num" style="width:7%">上刀计数</th>
|
<th style="width:10%">下刀时间</th>
|
<th class="num" style="width:7%">下刀计数</th>
|
<th class="num" style="width:7%">使用次数</th>
|
<th class="num" style="width:7%">使用上限</th>
|
<th class="num" style="width:7%">寿命比%</th>
|
<th class="num" style="width:7%">寿命比预警值</th>
|
<th style="width:7%">预警状态</th>
|
<th style="width:7%">刀具在机状态</th>
|
</tr>
|
</thead>
|
<tbody>
|
<tr v-for="(item, idx) in visibleToolRecords" :key="item.id" :class="{'row-odd': idx % 2 === 0}">
|
<td>{{ item.no }}</td>
|
<td class="left">{{ item.name }}</td>
|
<td>{{ item.upTime }}</td>
|
<td class="num">{{ item.upCount != null ? item.upCount : '' }}</td>
|
<td>{{ item.downTime }}</td>
|
<td class="num">
|
<template v-if="idx === 0">
|
<template v-if="!item.downTime">
|
{{ item.currentCjNum != null ? item.currentCjNum : '' }}
|
</template>
|
<template v-else>
|
{{ item.downCount != null ? item.downCount : '' }}
|
</template>
|
</template>
|
<template v-else>
|
{{ item.downCount != null ? item.downCount : '' }}
|
</template>
|
</td>
|
<td class="num">
|
<template v-if="idx === 0">
|
<template v-if="!item.downTime">
|
{{item.currentCjNum != null && item.upCount != null ? (Number(item.currentCjNum) - Number(item.upCount)) : (item.useCount != null ? item.useCount : '') }}
|
</template>
|
<template v-else>
|
{{ item.useCount != null ? item.useCount : '' }}
|
</template>
|
</template>
|
<template v-else>
|
{{ item.useCount != null ? item.useCount : '' }}
|
</template>
|
</td>
|
<td class="num">{{ item.useLimit != null ? item.useLimit : '' }}</td>
|
<td class="num">
|
<template v-if="idx === 0">
|
<template v-if="!item.downTime">
|
{{item.currentCjNum != null && item.upCount != null && item.useLimit != null && Number(item.useLimit) > 0 ? Math.round((Number(item.currentCjNum) - Number(item.upCount)) / Number(item.useLimit) * 100) + '%' : (item.lifePercent != null ? item.lifePercent : '') }}
|
</template>
|
<template v-else>
|
{{ item.lifePercent != null ? item.lifePercent : '' }}
|
</template>
|
</template>
|
<template v-else>
|
{{ item.lifePercent }}
|
</template>
|
</td>
|
<td class="num">{{ item.lifeWarn }}</td>
|
<td :class="item.warnStatus === '预警' ? 'warn-cell' : (item.warnStatus === '正常' ? 'ok-cell' : '')">
|
<span v-if="item.warnStatus === '预警'" class="warn-badge">警告</span>
|
<span v-else>{{ item.warnStatus }}</span>
|
</td>
|
<td>
|
{{ item.downTime ? '下机' : '在机' }}
|
</td>
|
</tr>
|
<tr v-if="!toolRecords.length">
|
<td colspan="12">暂无数据</td>
|
</tr>
|
<tr v-if="hasMoreToolRecords && !toolExpanded">
|
<td colspan="12" class="more-records-tip">
|
<span>还有 {{ remainingToolRecords }} 条记录,点击</span>
|
<button class="inline-expand-btn" @click="toggleExpand('tool')">展开</button>
|
<span>按钮查看全部</span>
|
</td>
|
</tr>
|
</tbody>
|
</table>
|
</view>
|
|
<!-- 工单首检记录表格 -->
|
<view class="table-section" :class="{'expanded': inspectionExpanded}">
|
<view class="table-header">
|
<h3>工单首检记录</h3>
|
<button class="expand-btn" @click="toggleExpand('inspection')">
|
{{ inspectionExpanded ? '收起' : '展开' }}
|
</button>
|
</view>
|
<table class="styled-table">
|
<thead>
|
<tr>
|
<th style="width:10%">检验单号</th>
|
<th style="width:10%">检验人员</th>
|
<th style="width:10%">检验日期</th>
|
<th style="width:10%">机台编号</th>
|
<th style="width:10%">提交标识</th>
|
<th style="width:10%">检验结果</th>
|
<th style="width:10%">作废标识</th>
|
<th style="width:10%">备注</th>
|
</tr>
|
</thead>
|
<tbody>
|
<tr v-for="(item, idx) in visibleInspectionRecords" :key="item.id || idx" :class="{'row-odd': idx % 2 === 0}">
|
<!-- 修改为小驼峰格式 -->
|
<td>{{ item.releaseNo || '' }}</td>
|
<td>{{ item.fcheckBy || '' }}</td>
|
<td>{{ formatDate(item.fcheckDate) }}</td>
|
<td>{{ item.lineNo || '' }}</td>
|
<td>{{ item.fsubmit == 1 ? '已提交' : '未提交' }}</td>
|
<td>{{ item.fcancel == 'Y' ? '作废' : '未作废' }}</td>
|
<td>{{ item.fsecondResu || '' }}</td>
|
<td class="left">{{ item.remeke || '' }}</td>
|
</tr>
|
<tr v-if="!inspectionRecords.length">
|
<td colspan="10">暂无首检记录</td>
|
</tr>
|
<tr v-if="hasMoreInspectionRecords && !inspectionExpanded">
|
<td colspan="10" class="more-records-tip">
|
<span>还有 {{ remainingInspectionRecords }} 条记录,点击</span>
|
<button class="inline-expand-btn" @click="toggleExpand('inspection')">展开</button>
|
<span>按钮查看全部</span>
|
</td>
|
</tr>
|
</tbody>
|
</table>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
machineNo: '',
|
workOrderNo: '',
|
selectedToolNo: '',
|
toolName: '',
|
useLimitInput: '',
|
lifeWarnInput: '',
|
toolRecords: [],
|
inspectionRecords: [], // 首检记录
|
loadingForm: false,
|
loadingInspection: false, // 首检记录加载状态
|
submitting: false,
|
workOrderCurrentCjNum: null,
|
toolExpanded: false, // 刀具表格展开状态
|
inspectionExpanded: false, // 首检表格展开状态
|
defaultVisibleRows: 3, // 默认显示的行数
|
};
|
},
|
computed: {
|
// 刀具表格相关计算
|
defaultToolRows() {
|
const total = this.toolRecords.length;
|
if (total <= 3) return total;
|
return Math.max(3, Math.floor(total / 2));
|
},
|
visibleToolRecords() {
|
if (this.toolExpanded) {
|
return this.toolRecords;
|
} else {
|
return this.toolRecords.slice(0, this.defaultToolRows);
|
}
|
},
|
hasMoreToolRecords() {
|
return this.toolRecords.length > this.defaultToolRows;
|
},
|
remainingToolRecords() {
|
return this.toolRecords.length - this.defaultToolRows;
|
},
|
|
// 首检表格相关计算
|
defaultInspectionRows() {
|
const total = this.inspectionRecords.length;
|
if (total <= 2) return total; // 首检表格默认显示2行
|
return Math.max(2, Math.floor(total / 2));
|
},
|
visibleInspectionRecords() {
|
if (this.inspectionExpanded) {
|
return this.inspectionRecords;
|
} else {
|
return this.inspectionRecords.slice(0, this.defaultInspectionRows);
|
}
|
},
|
hasMoreInspectionRecords() {
|
return this.inspectionRecords.length > this.defaultInspectionRows;
|
},
|
remainingInspectionRecords() {
|
return this.inspectionRecords.length - this.defaultInspectionRows;
|
}
|
},
|
methods: {
|
// 切换表格展开状态
|
toggleExpand(tableType) {
|
if (tableType === 'tool') {
|
this.toolExpanded = !this.toolExpanded;
|
} else if (tableType === 'inspection') {
|
this.inspectionExpanded = !this.inspectionExpanded;
|
}
|
},
|
|
// 刷新按钮处理方法
|
async handleRefresh() {
|
if (this.machineNo && this.workOrderNo) {
|
await Promise.all([
|
this.fetchFormData(),
|
this.fetchDefaultToolFromWorkOrder(),
|
this.fetchInspectionRecords()
|
]);
|
// 刷新后赋值第一行 currentCjNum
|
if (this.toolRecords.length > 0) {
|
this.$set(this.toolRecords[0], 'currentCjNum', this.workOrderCurrentCjNum);
|
}
|
}
|
this.$showMessage('刷新完成');
|
},
|
|
// 获取工单首检记录
|
async fetchInspectionRecords() {
|
if (!this.workOrderNo) {
|
console.warn('工单号为空,跳过获取首检记录');
|
return;
|
}
|
this.loadingInspection = true;
|
try {
|
const res = await this.$post({
|
url: '/MesCutterLedger/GetInspectionRecords',
|
data: JSON.stringify({
|
aufnr: this.workOrderNo,
|
ftype: '首检'
|
}),
|
headers: { 'Content-Type': 'application/json' }
|
});
|
|
if (res.status === 0) {
|
// 根据实际接口返回结构调整
|
const list = Array.isArray(res.data) ? res.data
|
: (res.data && res.data.tbBillList) ? res.data.tbBillList
|
: (res.data && res.data.data) ? res.data.data
|
: [];
|
this.inspectionRecords = list || [];
|
} else {
|
this.$showMessage(res.message || '获取首检记录失败');
|
this.inspectionRecords = [];
|
}
|
} catch (error) {
|
console.error('获取首检记录错误:', error);
|
this.$showMessage('获取首检记录失败,请检查网络连接');
|
this.inspectionRecords = [];
|
} finally {
|
this.loadingInspection = false;
|
}
|
},
|
|
// 格式化日期
|
formatDate(dateStr) {
|
if (!dateStr) return '';
|
try {
|
const date = new Date(dateStr);
|
if (isNaN(date.getTime())) return String(dateStr);
|
return `${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
|
} catch {
|
return String(dateStr);
|
}
|
},
|
|
// 其他已有方法保持不变...
|
async fetchDefaultToolFromWorkOrder() {
|
if (!this.machineNo) return;
|
try {
|
const res = await this.$post({
|
url: '/Womdaa/GetWomdaasByShow',
|
data: JSON.stringify({ machineNo: this.machineNo }),
|
headers: { 'Content-Type': 'application/json' }
|
});
|
if (res.status === 0 && Array.isArray(res.data?.tbBillList) && res.data.tbBillList.length > 0) {
|
const order = res.data.tbBillList[0];
|
this.selectedToolNo = order.cutterId || order.cutteR_ID || '';
|
this.toolName = order.cutterName || order.cutteR_NAME || '';
|
this.workOrderCurrentCjNum = order.CurrentCjNum ?? order.currentCjNum ?? null;
|
if (order.modlLifeWorning !== undefined && order.modlLifeWorning !== null) {
|
const warn = Number(order.modlLifeWorning);
|
this.lifeWarnInput = warn <= 1 ? (warn * 100).toFixed(0) : warn.toFixed(0);
|
} else {
|
this.lifeWarnInput = '';
|
}
|
} else {
|
this.workOrderCurrentCjNum = null;
|
}
|
} catch (e) {
|
console.warn('自动带出工单刀具失败', e);
|
this.workOrderCurrentCjNum = null;
|
}
|
},
|
|
async fetchFormData() {
|
if (!this.workOrderNo || !this.machineNo) {
|
console.warn('工单号或机台号为空,跳过获取表单数据');
|
return;
|
}
|
this.loadingForm = true;
|
const payload = {
|
workOrderNo: this.workOrderNo.trim(),
|
machineNo: this.machineNo.trim()
|
};
|
try {
|
const res = await this.$post({
|
url: '/MesCutterLedger/GetFormData',
|
data: JSON.stringify(payload),
|
headers: { 'Content-Type': 'application/json' }
|
});
|
if (res.status !== 0) {
|
this.$showMessage(res.message || '获取表单数据失败');
|
this.toolRecords = [];
|
return;
|
}
|
const list = Array.isArray(res.data) ? res.data
|
: (res.data && res.data.tbBillList) ? res.data.tbBillList
|
: (res.data && res.data.data) ? res.data.data
|
: [];
|
|
// 数据处理逻辑保持不变...
|
const getField = (obj, ...keys) => {
|
for (const k of keys) if (obj?.[k] !== undefined && obj?.[k] !== null) return obj[k];
|
return null;
|
};
|
|
const mapped = (list || []).map(t => {
|
const upTimeRaw = getField(t, 'uP_TIME', 'UP_TIME', 'uPTime', 'UPTIME', 'UpTime');
|
const downTimeRaw = getField(t, 'dowN_TIME', 'DOWN_TIME', 'downTime', 'DOWNTIME');
|
const lifeWarnRaw = getField(t, 'lifE_WARN', 'LIFE_WARN', 'lifeWarn', 'LIFEWARN');
|
const currentCjNum = getField(t, 'currentCjNum', 'CURRENTCJNUM', 'CurrentCjNum');
|
|
const useCount = getField(t, 'usE_COUNT', 'USE_COUNT', 'useCount');
|
const useLimit = getField(t, 'usE_LIMIT', 'USE_LIMIT', 'useLimit');
|
|
let percent = '';
|
if (useCount != null && useLimit != null && !isNaN(useCount) && !isNaN(useLimit) && Number(useLimit) > 0) {
|
percent = ((Number(useCount) / Number(useLimit)) * 100).toFixed(0) + '%';
|
}
|
|
const parseNumber = v => {
|
if (v === null || v === undefined || v === '') return null;
|
const s = String(v).replace(/[,%%]/g, '').trim();
|
const n = parseFloat(s);
|
return Number.isFinite(n) ? n : null;
|
};
|
const formatPercent = n => {
|
if (n === null || n === undefined || isNaN(n)) return '';
|
if (n <= 1) return `${(n * 100).toFixed(0)}%`;
|
return `${Number(n).toFixed(0)}%`;
|
};
|
const lifeWarnNum = parseNumber(lifeWarnRaw);
|
|
let warnStatus = getField(t, 'status', 'STATUS') || '';
|
if (lifeWarnNum !== null && useCount != null && useLimit != null && !isNaN(useCount) && !isNaN(useLimit) && Number(useLimit) > 0) {
|
const percentNum = Number(useCount) / Number(useLimit);
|
warnStatus = (percentNum >= lifeWarnNum) ? '预警' : '正常';
|
} else {
|
warnStatus = warnStatus || '未知';
|
}
|
|
return {
|
id: getField(t, 'id', 'ID') || `${getField(t, 'cutteR_ID') || getField(t, 'CUTTER_ID') || ''}-${upTimeRaw || ''}`,
|
no: getField(t, 'cutteR_ID', 'CUTTER_ID', 'cutterId', 'no') || '',
|
name: getField(t, 'cutteR_NAME', 'CUTTER_NAME', 'cutterName', 'name') || '',
|
upTime: this.formatDateTime(upTimeRaw),
|
upCount: getField(t, 'uP_COUNT', 'UP_COUNT', 'upCount') ?? '',
|
downTime: this.formatDateTime(downTimeRaw),
|
downCount: getField(t, 'dowN_COUNT', 'DOWN_COUNT', 'downCount') ?? '',
|
useCount: useCount ?? '',
|
useLimit: useLimit ?? '',
|
lifePercent: percent,
|
lifeWarn: formatPercent(lifeWarnNum),
|
warnStatus,
|
currentCjNum
|
};
|
});
|
|
mapped.sort((a, b) => {
|
const parse = s => {
|
if (!s) return 0;
|
const year = new Date().getFullYear();
|
return new Date(`${year}-${s.replace(/-/g, '-')}:00`).getTime();
|
};
|
return parse(b.upTime) - parse(a.upTime);
|
});
|
|
this.toolRecords = mapped;
|
} catch (error) {
|
console.error('获取表单数据错误:', error);
|
this.$showMessage('获取数据失败,请检查网络连接');
|
this.toolRecords = [];
|
} finally {
|
this.loadingForm = false;
|
}
|
},
|
|
formatDateTime(dateTimeStr) {
|
if (!dateTimeStr) return '';
|
try {
|
const s = String(dateTimeStr).trim();
|
if (/^\d{10}$/.test(s)) {
|
const d = new Date(Number(s) * 1000);
|
return `${d.getMonth() + 1}-${d.getDate()} ${d.getHours()}:${String(d.getMinutes()).padStart(2, '0')}`;
|
}
|
if (/^\d{13}$/.test(s)) {
|
const d = new Date(Number(s));
|
return `${d.getMonth() + 1}-${d.getDate()} ${d.getHours()}:${String(d.getMinutes()).padStart(2, '0')}`;
|
}
|
const date = new Date(dateTimeStr);
|
if (!isNaN(date.getTime())) {
|
return `${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
|
}
|
const match = String(dateTimeStr).match(/(\d{1,4}[-\/]\d{1,2}[-\/]\d{1,2}).*?(\d{1,2}:\d{2})/);
|
if (match) return `${match[1].replace(/-/g, '/').replace(/^\d{4}\//, (m) => m)} ${match[2]}`;
|
return String(dateTimeStr);
|
} catch {
|
return String(dateTimeStr);
|
}
|
}
|
},
|
mounted() {
|
this.machineNo = uni.getStorageSync('machineNo') || '';
|
this.workOrderNo = uni.getStorageSync('daa001') || '';
|
|
if (this.machineNo && this.workOrderNo) {
|
this.fetchFormData().then(async () => {
|
await this.fetchDefaultToolFromWorkOrder();
|
await this.fetchInspectionRecords();
|
if (this.toolRecords.length > 0) {
|
this.$set(this.toolRecords[0], 'currentCjNum', this.workOrderCurrentCjNum);
|
}
|
});
|
} else {
|
console.warn('机台号或工单号为空,无法获取数据');
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.page {
|
padding: 8px 12px; /* 减少上下内边距 */
|
display: flex;
|
flex-direction: column;
|
gap: 8px; /* 减少两个表格之间的间距 */
|
}
|
|
.button-row {
|
display: flex;
|
justify-content: center;
|
margin: 0.5vh 0; /* 减少上下边距 */
|
}
|
|
.save-btn {
|
width: 20%;
|
padding: 1.5vh;
|
background-color: #00A2E9;
|
color: white;
|
border: none;
|
text-align: center;
|
border-radius: 4px;
|
transition: all 0.3s;
|
font-size: 22px;
|
font-weight: 500;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
}
|
|
.save-btn:hover {
|
background-color: #40a9ff;
|
}
|
|
.save-btn:active {
|
background-color: #096dd9;
|
}
|
|
.save-btn:disabled {
|
opacity: 0.6;
|
cursor: not-allowed;
|
}
|
|
/* 表格容器样式 */
|
.table-section {
|
display: flex;
|
flex-direction: column;
|
margin: 0;
|
overflow: auto; /* 统一滚动条 */
|
width: 100%;
|
border: 1px solid #f0f0f0;
|
border-radius: 8px;
|
background: #fff;
|
max-height: 220px; /* 默认高度 */
|
transition: max-height 0.3s ease;
|
}
|
|
.table-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 12px 16px;
|
background: #fafafa;
|
border-bottom: 1px solid #e8e8e8;
|
}
|
|
.table-header h3 {
|
margin: 0;
|
font-size: 24px;
|
color: #333;
|
font-weight: 600;
|
}
|
|
.expand-btn {
|
padding: 8px 20px;
|
background-color: #52c41a;
|
color: white;
|
border: none;
|
border-radius: 4px;
|
font-size: 20px;
|
cursor: pointer;
|
transition: all 0.3s;
|
}
|
|
.expand-btn:hover {
|
background-color: #73d13d;
|
}
|
|
.expand-btn:active {
|
background-color: #389e0d;
|
}
|
|
/* 表格样式 */
|
table.styled-table {
|
max-width: 1800px;
|
width: 98vw;
|
margin: 0;
|
border-collapse: separate;
|
border-spacing: 0;
|
border: 2px solid #bfbfbf;
|
background: #fff;
|
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
|
}
|
|
table.styled-table thead th {
|
background: #fafafa;
|
border-bottom: 2px solid #bfbfbf;
|
padding: 16px 10px;
|
font-weight: bold;
|
text-align: center;
|
font-size: 22px;
|
position: sticky; /* 表头置顶 */
|
top: 0;
|
z-index: 10;
|
}
|
|
table.styled-table tbody td {
|
border-bottom: 1px solid #e8e8e8;
|
padding: 14px 10px;
|
vertical-align: middle;
|
text-align: center;
|
font-size: 22px;
|
}
|
|
/* 展开状态 - 只改变容器高度 */
|
.table-section.expanded {
|
max-height: 450px; /* 展开时的容器高度 */
|
}
|
|
table.styled-table tbody .left {
|
text-align: left;
|
padding-left: 8px;
|
}
|
|
.row-odd {
|
background: #fff;
|
}
|
|
.row-odd + tr {
|
background: #fafafa;
|
}
|
|
.num {
|
text-align: center;
|
padding-right: 0;
|
font-variant-numeric: tabular-nums;
|
}
|
|
.warn-cell {
|
color: #d93025;
|
font-weight: bold;
|
}
|
|
.ok-cell {
|
color: #333;
|
}
|
|
.warn-badge {
|
display: inline-block;
|
background: #ff4d4f;
|
color: #fff;
|
padding: 2px 6px;
|
border-radius: 3px;
|
font-weight: bold;
|
}
|
|
.more-records-tip {
|
text-align: center;
|
color: #666;
|
font-size: 18px;
|
padding: 20px !important;
|
background-color: #f9f9f9;
|
}
|
|
.more-records-tip span {
|
display: inline;
|
font-size: 20px;
|
color: #666;
|
}
|
|
/* 行内展开按钮样式 - 蓝色 */
|
.inline-expand-btn {
|
display: inline-block;
|
padding: 2px 12px; /* 减小内边距,与文字高度一致 */
|
margin: 0 6px;
|
background-color: #00A2E9; /* 蓝色 */
|
color: white;
|
border: none;
|
border-radius: 3px;
|
font-size: 20px; /* 与提示文字大小一致 */
|
font-weight: 500;
|
cursor: pointer;
|
transition: all 0.3s;
|
box-shadow: 0 2px 4px rgba(0, 162, 233, 0.2);
|
vertical-align: baseline; /* 与文字基线对齐 */
|
line-height: 1.2; /* 控制行高 */
|
}
|
|
.inline-expand-btn:hover {
|
background-color: #40a9ff; /* 悬停时变淡 */
|
box-shadow: 0 4px 8px rgba(0, 162, 233, 0.3);
|
transform: translateY(-1px);
|
}
|
|
.inline-expand-btn:active {
|
background-color: #096dd9; /* 点击时变深 */
|
transform: translateY(0);
|
}
|
|
/* 响应式调整 */
|
@media (max-width: 1200px) {
|
.save-btn {
|
width: 30%;
|
}
|
|
.table-header {
|
flex-direction: column;
|
gap: 8px;
|
align-items: flex-start;
|
}
|
|
.expand-btn {
|
align-self: flex-end;
|
}
|
}
|
</style>
|