| | |
| | | <template> |
| | | <view class="page"> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="button-row"> |
| | | <button class="save-btn" @click="handleRefresh" :disabled="loadingForm || submitting">刷新</button> |
| | | <button class="expand-btn" @click="toggleExpand"> |
| | | {{ isExpanded ? '收起' : '展开' }} |
| | | </button> |
| | | <button class="save-btn" @click="handleRefresh" :disabled="loadingForm || submitting || loadingInspection">刷新</button> |
| | | </view> |
| | | |
| | | <!-- 刀具使用记录表格 --> |
| | | <view class="table-section" :class="{'expanded': isExpanded}"> |
| | | <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> |
| | |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr v-for="(item, idx) in visibleRecords" :key="item.id" :class="{'row-odd': idx % 2 === 0}"> |
| | | <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> |
| | | <!-- 只有第一行显示 currentCjNum,其它行显示 downCount --> |
| | | <td class="num"> |
| | | <template v-if="idx === 0"> |
| | | <!-- 第一行:下机时不实时显示 currentCjNum,显示 downCount --> |
| | | <template v-if="!item.downTime"> |
| | | {{ item.currentCjNum != null ? item.currentCjNum : '' }} |
| | | </template> |
| | |
| | | {{ 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> |
| | | </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> |
| | |
| | | <tr v-if="!toolRecords.length"> |
| | | <td colspan="12">暂无数据</td> |
| | | </tr> |
| | | <tr v-if="hasMoreRecords && !isExpanded"> |
| | | <tr v-if="hasMoreToolRecords && !toolExpanded"> |
| | | <td colspan="12" class="more-records-tip"> |
| | | <span>还有 {{ remainingRecords }} 条记录,点击"展开"按钮查看全部</span> |
| | | <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> |
| | |
| | | export default { |
| | | data() { |
| | | return { |
| | | machineNo: '',//机台编码 |
| | | workOrderNo: '',//工单号 |
| | | machineNo: '', |
| | | workOrderNo: '', |
| | | selectedToolNo: '', |
| | | toolName: '', |
| | | useLimitInput: '', |
| | | lifeWarnInput: '', // 寿命比预警值原始输入 |
| | | lifeWarnInput: '', |
| | | toolRecords: [], |
| | | inspectionRecords: [], // 首检记录 |
| | | loadingForm: false, |
| | | loadingInspection: false, // 首检记录加载状态 |
| | | submitting: false, |
| | | workOrderCurrentCjNum: null, // 工单当前数采 |
| | | isExpanded: false, // 是否展开表格 |
| | | defaultVisibleRows: 3, // 默认显示的行数(一半高度) |
| | | workOrderCurrentCjNum: null, |
| | | toolExpanded: false, // 刀具表格展开状态 |
| | | inspectionExpanded: false, // 首检表格展开状态 |
| | | defaultVisibleRows: 3, // 默认显示的行数 |
| | | }; |
| | | }, |
| | | computed: { |
| | | // 计算默认显示多少行(总行数的一半) |
| | | defaultRows() { |
| | | // 刀具表格相关计算 |
| | | defaultToolRows() { |
| | | const total = this.toolRecords.length; |
| | | if (total <= 3) return total; // 如果总行数小于等于3,全部显示 |
| | | return Math.max(3, Math.floor(total / 2)); // 最少显示3行,最多显示一半 |
| | | if (total <= 3) return total; |
| | | return Math.max(3, Math.floor(total / 2)); |
| | | }, |
| | | // 当前可见的记录 |
| | | visibleRecords() { |
| | | if (this.isExpanded) { |
| | | visibleToolRecords() { |
| | | if (this.toolExpanded) { |
| | | return this.toolRecords; |
| | | } else { |
| | | return this.toolRecords.slice(0, this.defaultRows); |
| | | return this.toolRecords.slice(0, this.defaultToolRows); |
| | | } |
| | | }, |
| | | // 是否还有更多记录 |
| | | hasMoreRecords() { |
| | | return this.toolRecords.length > this.defaultRows; |
| | | hasMoreToolRecords() { |
| | | return this.toolRecords.length > this.defaultToolRows; |
| | | }, |
| | | // 剩余记录数 |
| | | remainingRecords() { |
| | | return this.toolRecords.length - this.defaultRows; |
| | | 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() { |
| | | this.isExpanded = !this.isExpanded; |
| | | // 切换表格展开状态 |
| | | 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 this.fetchFormData(); |
| | | await this.fetchDefaultToolFromWorkOrder(); |
| | | 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 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); |
| | |
| | | : (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; |
| | |
| | | }; |
| | | }); |
| | | |
| | | // 按上刀时间降序排序(越晚的越上面) |
| | | mapped.sort((a, b) => { |
| | | const parse = s => { |
| | | if (!s) return 0; |
| | |
| | | } |
| | | const date = new Date(dateTimeStr); |
| | | if (!isNaN(date.getTime())) { |
| | | return `${date.getMonth() + 1}-${d.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`; |
| | | 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]}`; |
| | |
| | | if (this.machineNo && this.workOrderNo) { |
| | | this.fetchFormData().then(async () => { |
| | | await this.fetchDefaultToolFromWorkOrder(); |
| | | // 进入页面时赋值第一行 currentCjNum |
| | | await this.fetchInspectionRecords(); |
| | | if (this.toolRecords.length > 0) { |
| | | this.$set(this.toolRecords[0], 'currentCjNum', this.workOrderCurrentCjNum); |
| | | } |
| | | }); |
| | | } else { |
| | | console.warn('机台号或工单号为空,无法获取表单数据'); |
| | | console.warn('机台号或工单号为空,无法获取数据'); |
| | | } |
| | | } |
| | | }; |
| | |
| | | |
| | | <style scoped> |
| | | .page { |
| | | padding: 20px; |
| | | padding: 8px 12px; /* 减少上下内边距 */ |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; /* 减少两个表格之间的间距 */ |
| | | } |
| | | |
| | | .button-row { |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 32px; |
| | | margin: 2vh 0; |
| | | margin: 0.5vh 0; /* 减少上下边距 */ |
| | | } |
| | | |
| | | .save-btn, .cancel-btn, .expand-btn { |
| | | .save-btn { |
| | | width: 20%; |
| | | padding: 1.5vh; |
| | | background-color: #00A2E9; |
| | |
| | | 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: #389e0d; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | background-color: #f5f5f5; |
| | | color: #333; |
| | | } |
| | | |
| | | .save-btn:hover { |
| | | background-color: #40a9ff; |
| | | } |
| | | |
| | | .save-btn:active { |
| | | background-color: #096dd9; |
| | | } |
| | | |
| | | .save-btn:disabled, .cancel-btn:disabled, .expand-btn:disabled { |
| | | opacity: 0.6; |
| | | cursor: not-allowed; |
| | | } |
| | | |
| | | .table-section { |
| | | display: flex; |
| | | justify-content: center; |
| | | margin: 1vh 0; |
| | | overflow-x: auto; |
| | | width: 100%; |
| | | max-height: 300px; /* 默认高度,大约显示3-4行 */ |
| | | overflow-y: hidden; |
| | | transition: max-height 0.3s ease; |
| | | border: 1px solid #f0f0f0; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .table-section.expanded { |
| | | max-height: 800px; /* 展开时的高度,可以显示更多行 */ |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | /* 表格样式 */ |
| | | table.styled-table { |
| | | max-width: 1800px; |
| | | width: 98vw; |
| | | margin: 0 auto; |
| | | margin: 0; |
| | | border-collapse: separate; |
| | | border-spacing: 0; |
| | | border: 2px solid #bfbfbf; |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | box-shadow: 0 2px 12px rgba(0,0,0,0.06); |
| | | } |
| | | |
| | |
| | | font-weight: bold; |
| | | text-align: center; |
| | | font-size: 22px; |
| | | position: sticky; |
| | | position: sticky; /* 表头置顶 */ |
| | | top: 0; |
| | | z-index: 10; |
| | | } |
| | |
| | | font-size: 22px; |
| | | } |
| | | |
| | | .table-section table th:first-child, .table-section table td:first-child { |
| | | border-left: 2px solid #bfbfbf; |
| | | /* 展开状态 - 只改变容器高度 */ |
| | | .table-section.expanded { |
| | | max-height: 450px; /* 展开时的容器高度 */ |
| | | } |
| | | |
| | | .table-section table th:last-child, .table-section table td:last-child { |
| | | border-right: 2px solid #bfbfbf; |
| | | } |
| | | table.styled-table tbody .left { |
| | | text-align: left; |
| | | padding-left: 8px; |
| | | } |
| | | |
| | | .row-odd { |
| | | background: #fff; |
| | |
| | | text-align: center; |
| | | padding-right: 0; |
| | | font-variant-numeric: tabular-nums; |
| | | } |
| | | |
| | | .left { |
| | | text-align: left; |
| | | padding-left: 8px; |
| | | } |
| | | |
| | | .warn-cell { |
| | |
| | | } |
| | | |
| | | .more-records-tip span { |
| | | display: inline-block; |
| | | padding: 5px 15px; |
| | | background-color: #f0f0f0; |
| | | border-radius: 4px; |
| | | border: 1px dashed #ccc; |
| | | 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, .cancel-btn, .expand-btn { |
| | | .save-btn { |
| | | width: 30%; |
| | | } |
| | | |
| | | .table-header { |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .expand-btn { |
| | | align-self: flex-end; |
| | | } |
| | | } |
| | | </style> |