|
|
<template> <div class="pda-container"> <!-- 头部栏 --> <div class="header-bar"> <div class="header-left" @click="$router.back()"> <i class="el-icon-arrow-left"></i> <span>直接领料</span> </div> <div class="header-right" @click="$router.push({ path: '/' })">首页</div> </div>
<!-- 工单号输入 --> <div class="search-container"> <el-input clearable v-model="workOrderNo" placeholder="请输入工单号" prefix-icon="el-icon-search" @keyup.enter.native="handleSearchWorkOrder" ref="workOrderInput" /> </div>
<!-- 工单信息卡片列表 --> <div class="work-order-list" v-if="workOrderList.length > 0"> <div v-for="(workOrder, index) in displayWorkOrderList" :key="index" :class="['work-order-card', { selected: selectedWorkOrder && isSameWorkOrder(selectedWorkOrder, workOrder) }]" @click="selectWorkOrder(workOrder)" > <div class="card-title"> <span class="title-label">工单号:{{ workOrder.orderNo }}-{{workOrder.releaseNo}}-{{workOrder.sequenceNo}}</span> <span class="title-value">{{ workOrder.partNo }}</span> </div>
<!-- 物料描述单独一行 --> <div class="part-desc-row"> <span class="desc-text">{{ workOrder.partDesc }}</span> </div>
<div class="card-details"> <div class="detail-item"> <div class="detail-label">计划数量</div> <div class="detail-value">{{ workOrder.qtyComplete }}</div> </div> <div class="detail-item"> <div class="detail-label">状态</div> <div class="detail-value">{{ workOrder.status || "进行中" }}</div> </div> <div class="detail-item"> <div class="detail-label">单位</div> <div class="detail-value">{{ workOrder.uom || "个" }}</div> </div> </div> </div> </div>
<!-- 材料列表 --> <div class="content-area" v-if="selectedWorkOrder && materialList.length > 0" > <div v-for="(material, index) in materialList" :key="index" class="material-card" @click="selectMaterial(material)" > <div class="card-title"> <span class="title-label" >物料编码:{{ material.componentPartNo }} 行号:{{ material.lineItemNo }}</span > <!-- <span class="title-value">{{ material.componentPartNo }}</span> --> </div>
<!-- 物料描述单独一行 --> <div class="part-desc-row"> <span class="desc-text">{{ material.componentPartDesc }}</span> </div>
<div class="card-details"> <div class="detail-item"> <div class="detail-label">需求数量</div> <div class="detail-value">{{ material.qtyRequired }}</div> </div> <div class="detail-item"> <div class="detail-label">已发数量</div> <div class="detail-value">{{ material.qtyIssued || 0 }}</div> </div> <div class="detail-item"> <div class="detail-label">单位</div> <div class="detail-value">{{ material.uom || "个" }}</div> </div> </div> </div> </div>
<!-- 空状态 --> <div v-if="selectedWorkOrder && materialList.length === 0" class="empty-state" > <i class="el-icon-box"></i> <p>该工单暂无材料清单</p> </div>
<!-- 加载状态 --> <div v-if="loading" class="loading-state"> <i class="el-icon-loading"></i> <p>加载中...</p> </div> </div></template>
<script>import { getWorkOrderInfo, getWorkOrderMaterials,} from "@/api/production/production-issue";import moment from "moment";
export default { data() { return { workOrderNo: "", workOrderList: [], selectedWorkOrder: null, materialList: [], selectedMaterial: null, loading: false, showOnlySelected: false, }; }, computed: { displayWorkOrderList() { if (this.showOnlySelected && this.selectedWorkOrder) { return [this.selectedWorkOrder]; } return this.workOrderList; }, }, methods: { formatDate(date) { return date ? moment(date).format("YYYY-MM-DD") : ""; },
// 查询工单信息
handleSearchWorkOrder() { if (!this.workOrderNo.trim()) { this.$message.warning("请输入工单号"); return; }
this.loading = true; const params = { workOrderNo: this.workOrderNo.trim(), site: this.$store.state.user.site, };
getWorkOrderInfo(params) .then(({ data }) => { this.loading = false; console.log("工单信息", data);
if ( data.workOrders && data.workOrders.length > 0 && data.code === 0 ) { this.workOrderList = data.workOrders; this.selectedWorkOrder = null; this.materialList = []; this.showOnlySelected = false; } else { this.$message.error("未找到该工单信息"); this.workOrderList = []; this.selectedWorkOrder = null; this.materialList = []; this.showOnlySelected = false; } }) .catch((error) => { this.loading = false; console.error("查询工单信息失败:", error); this.$message.error("查询工单信息失败"); }); },
// 判断是否为同一工单
isSameWorkOrder(a, b) { if (!a || !b) return false; return ( a.orderNo === b.orderNo && a.releaseNo === b.releaseNo && a.sequenceNo === b.sequenceNo ); },
// 选择工单(支持再次点击切换显示所有)
selectWorkOrder(workOrder) { if ( this.showOnlySelected && this.selectedWorkOrder && this.isSameWorkOrder(this.selectedWorkOrder, workOrder) ) { // 再次点击同一条,恢复显示所有主数据
this.selectedWorkOrder = null; this.materialList = []; this.showOnlySelected = false; return; }
// 选择并仅显示当前工单
this.selectedWorkOrder = workOrder; this.showOnlySelected = true; this.loadMaterialList(); },
// 加载材料清单
loadMaterialList() { if (!this.selectedWorkOrder) { this.materialList = []; return; }
const params = { workOrderNo: this.selectedWorkOrder.orderNo, site: this.$store.state.user.site, };
getWorkOrderMaterials(params) .then(({ data }) => { console.log("材料清单", data);
if (data && data.code === 0) { this.materialList = (data.materials || []).map((item, index) => ({ ...item, id: index + 1, })); } else { this.$message.error(data.msg || "获取材料清单失败"); this.materialList = []; } }) .catch((error) => { console.error("获取材料清单失败:", error); this.$message.error("获取材料清单失败"); }); },
// 选择材料,跳转到扫描明细页
selectMaterial(material) { console.log("选择材料", material); if(material.reserveIssueMethod != 'Reserve And Backflush'){ this.$message.warning('该物料为'+material.reserveIssueMethod+',不支持直接领料,请选择其他物料!'); return; } this.$router.push({ name: "directIssueDetail", params: { workOrderNo: this.selectedWorkOrder.orderNo+'-'+this.selectedWorkOrder.releaseNo+'-'+this.selectedWorkOrder.sequenceNo, partNo: material.componentPartNo, partDesc: material.componentPartDesc, requiredQty: material.qtyRequired, issuedQty: material.qtyIssued || 0, }, }); }, },
mounted() { // 聚焦工单号输入框
this.$nextTick(() => { if (this.$refs.workOrderInput) { this.$refs.workOrderInput.focus(); } }); },};</script>
<style scoped>.pda-container { width: 100vw; height: 100vh; display: flex; flex-direction: column; background: #f5f5f5;}
/* 头部栏 */.header-bar { display: flex; justify-content: space-between; align-items: center; padding: 8px 16px; background: #17b3a3; color: white; height: 40px; min-height: 40px;}
.header-left { display: flex; align-items: center; cursor: pointer; font-size: 16px; font-weight: 500;}
.header-left i { margin-right: 8px; font-size: 18px;}
.header-right { cursor: pointer; font-size: 16px; font-weight: 500;}
/* 搜索容器 */.search-container { padding: 12px 16px; background: white; display: flex; align-items: center; gap: 12px;}
.search-container .el-input { flex: 1;}
.search-btn { padding: 8px 16px; background: #17b3a3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background-color 0.2s;}
.search-btn:hover { background: #0d8f7f;}
.search-btn:disabled { background: #ccc; cursor: not-allowed;}
/* 工单列表 */.work-order-list { overflow-y: auto; padding: 12px 16px;}
/* 工单卡片 */.work-order-card { background: white; border-radius: 8px; margin-bottom: 12px; padding: 16px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent;}
.work-order-card:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); transform: translateY(-1px);}
.work-order-card.selected { border-color: #17b3a3; background: #f0fffe;}
.work-order-card:active { transform: translateY(0);}
/* 内容区域 */.content-area { flex: 1; overflow-y: auto; padding: 12px 16px;}
/* 材料卡片 */.material-card { background: white; border-radius: 8px; margin-bottom: 12px; padding: 16px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent;}
.material-card:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); transform: translateY(-1px);}
.material-card.selected { border-color: #17b3a3; background: #f0fffe;}
.material-card:active { transform: translateY(0);}
/* 卡片标题 */.card-title { margin-bottom: 12px;}
.title-label { font-size: 12px; color: #666; display: block; margin-bottom: 4px;}
.title-value { font-size: 16px; font-weight: bold; color: #333; margin-left: 16px;}
/* 物料描述行 */.part-desc-row { margin-bottom: 12px; padding: 0 4px;}
.desc-text { font-size: 12px; color: #666; line-height: 1.3; word-break: break-all;}
/* 卡片详情 */.card-details { display: flex; justify-content: space-between; align-items: flex-start; gap: 4px;}
.detail-item { flex: 1; text-align: center; min-width: 50px; max-width: 70px;}
.detail-label { font-size: 11px; color: #666; margin-bottom: 4px; line-height: 1.2; margin-left: -12px;}
.detail-value { font-size: 13px; color: #333; line-height: 1.2; margin-left: -12px;}
/* 扫描区域 */.scan-section { margin-top: 16px;}
/* 扫描容器 */.scan-container { padding: 12px 16px; background: white; display: flex; align-items: center; gap: 12px; border-radius: 0 0 8px 8px; margin-bottom: 12px;}
.scan-container .el-input { width: 240px; margin-right: 12px;}
/* 紧凑型输入框样式 */.compact-input ::v-deep .el-input__inner { height: 36px; padding: 0 12px 0 35px; font-size: 14px;}
.compact-input ::v-deep .el-input__prefix { left: 10px;}
.compact-input ::v-deep .el-input__suffix { right: 30px;}
/* 模式切换开关 */.mode-switch { position: relative; display: inline-block;}
.custom-switch { transform: scale(1.3);}
/* 中间文字 */.switch-text { position: absolute; left: 25%; top: 53%; transform: translate(-50%, -50%); font-size: 12px; font-weight: bold; color: white; pointer-events: none; z-index: 2;}
.switch-text2 { position: absolute; left: 75%; top: 53%; transform: translate(-50%, -50%); font-size: 12px; font-weight: bold; color: white; pointer-events: none; z-index: 2;}
/* 调整 switch 尺寸以便容纳文字 */.custom-switch ::v-deep .el-switch__core { width: 60px; height: 28px;}
/* 已选材料信息 */.selected-material-info { background: #e8f5e8; padding: 12px 16px; margin-bottom: 12px; border-radius: 8px; border-left: 4px solid #17b3a3;}
.info-title { font-size: 14px; font-weight: bold; color: #333; margin-bottom: 8px;}
.info-details { display: flex; gap: 16px; font-size: 12px; color: #666;}
/* 标签列表 */.label-list { background: white; margin-bottom: 12px; border-radius: 8px; overflow: hidden;}
.list-header { display: flex; background: #f8f9fa; padding: 12px 8px; border-bottom: 1px solid #e0e0e0; font-size: 12px; color: #666; font-weight: 500;}
.list-item { display: flex; padding: 12px 8px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333;}
.list-item:last-child { border-bottom: none;}
.col-no { width: 30px; text-align: center;}
.col-label { flex: 2; text-align: center;}
.col-batch { flex: 1; text-align: center;}
.col-qty { width: 60px; text-align: center;}
.empty-labels { padding: 40px 20px; text-align: center; color: #999;}
.empty-labels p { margin: 0; font-size: 14px;}
/* 底部操作按钮 */.bottom-actions { display: flex; padding: 16px; gap: 20px; background: white; border-radius: 8px;}
.action-btn { flex: 1; padding: 12px; border: 1px solid #17b3a3; background: white; color: #17b3a3; border-radius: 20px; font-size: 14px; cursor: pointer; transition: all 0.2s ease;}
.action-btn.primary { background: #17b3a3; color: white;}
.action-btn.primary:hover { background: #0d8f7f;}
.action-btn.secondary:hover { background: #17b3a3; color: white;}
.action-btn:active { transform: scale(0.98);}
.action-btn:disabled { opacity: 0.5; cursor: not-allowed;}
.action-btn:disabled:hover { background: #17b3a3; color: white;}
/* 空状态 */.empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999;}
.empty-state i { font-size: 48px; margin-bottom: 16px;}
.empty-state p { font-size: 14px; margin: 0;}
/* 加载状态 */.loading-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #17b3a3;}
.loading-state i { font-size: 24px; margin-bottom: 12px; animation: spin 1s linear infinite;}
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); }}
.loading-state p { font-size: 14px; margin: 0;}
/* 响应式设计 */@media (max-width: 360px) { .header-bar { padding: 8px 12px; }
.search-container { padding: 8px 12px; }
.work-order-list { padding: 8px 12px; }
.work-order-card { padding: 12px; }
.content-area { padding: 8px 12px; }
.material-card { padding: 12px; }
.card-details { flex-wrap: wrap; gap: 6px; }
.detail-item { flex: 0 0 48%; margin-bottom: 6px; min-width: 50px; }
.list-header, .list-item { font-size: 11px; }
.col-label { flex: 1.5; }}</style>
|