|
|
<template> <div> <div class="status-bar"> <div class="goBack" @click="handleBack"><i class="el-icon-arrow-left"></i>上一页</div> <div class="goBack">{{ functionTitle }}</div> <div class="network" style="color: #fff" @click="$router.push({ path: '/' })">🏠首页</div> </div> <div class="input-section"> <!-- PO号输入 --> <div v-if="processFlag === 1"> <div class="input-group"> <div class="input-group"> <label>PO号</label> <div class="input-with-scan"> <input v-model="poNo" placeholder="请输入或扫描PO号" @keyup.enter="loadMaterials" /> </div> </div> <div class="input-group"> <button @click="loadMaterials" class="scan-btn">确认</button> </div> </div> <div class="materials-section" v-if="materialList.length"> <div class="material-list"> <div v-for="(material, index) in materialList" :key="index" class="material-item" :class="{ selected: selectedMaterial && selectedMaterial.partNo === material.partNo }" @click="goToDetail(material)"> <div class="material-info"> <div class="part-no">{{ material.partNo }}</div> <div class="part-desc">{{ material.desc }}</div> <div class="qty-info"> 需求: {{ material.qty }} | 已发: {{ material.recvQty }} | 剩余: {{ material.thisRecvQty }} </div> </div> <div class="material-status"> <span v-if="material.thisRecvQty > 0" class="status-pending">待发料</span> <span v-else class="status-complete">已完成</span> </div> </div> </div> </div> </div> <!-- 扫描标签/发料详情 --> <div class="scan-section" v-if="processFlag === 2"> <div class="label-info" v-if="labelInfo"> <div class="info-row"><span class="label">物料编码:</span><span class="value">{{ labelInfo.partNo }}</span></div> <div class="info-row"><span class="label">批次号:</span><span class="value">{{ labelInfo.batchNo }}</span></div> <div class="info-row"><span class="label">可用数量:</span><span class="value">{{ labelInfo.availableQty }}</span> </div> </div> <div class="qty-input" v-if="labelInfo"> <div class="input-group"> <label>发料数量</label> <input v-model="issueQty" type="number" :max="Math.min(selectedMaterial.thisRecvQty, labelInfo.availableQty)" placeholder="请输入发料数量" /> </div> <div class="input-group"> <label>备注</label> <el-input type="textarea" v-model="remark" placeholder="可选" /> </div> <button @click="confirmIssue" class="confirm-btn" :disabled="!issueQty">确认发料</button> </div> </div> <!-- 消息提示 --> <div class="message" v-if="message" :class="messageType">{{ message }}</div> </div> </div></template><script>import { getPoList } from '@/api/po/po.js'export default { name: 'DirectIssue', props: { functionTitle: { type: String, default: '', }, }, data() { return { processFlag: 1, // 1=PO号输入, 2=物料列表, 3=扫描标签/发料详情
poNo: '', materialList: [], selectedMaterial: null, scannedLabel: '', labelInfo: null, issueQty: null, remark: '', message: '', messageType: 'info', } }, methods: { handleBack() { if (this.processFlag === 2) { this.processFlag = 1 } else if (this.processFlag === 1) { this.$emit('back') } }, async loadMaterials() { if (!this.poNo) { this.showMessage('请输入PO号', 'error') return } // 调用API获取PO物料
try { const { data } = await getPoList({ poNumber: this.poNo, site: localStorage.getItem('site'), }) if (data.code === 0 && data.rows && data.rows.length > 0) { this.materialList = data.rows } else { this.showMessage(data.msg || '未找到PO物料', 'warning') } } catch (e) { this.showMessage('网络错误', 'error') } }, goToDetail(material) { if (material.thisRecvQty <= 0) { this.showMessage('该物料已发料完成', 'warning') return } this.selectedMaterial = material this.scannedLabel = '' this.labelInfo = { partNo: this.selectedMaterial.partNo, batchNo: 'BATCH001', availableQty: 100, } this.issueQty = null this.processFlag = 2 }, resetPO() { this.poNo = '' this.materialList = [] this.selectedMaterial = null this.scannedLabel = '' this.labelInfo = null this.issueQty = null this.processFlag = 1 }, parseMaterialLabel() { // TODO: 调用解析标签API,获取labelInfo
this.labelInfo = { partNo: this.selectedMaterial.partNo, batchNo: 'BATCH001', availableQty: 100, } this.issueQty = null this.showMessage('标签解析成功', 'success') }, confirmIssue() { if (!this.issueQty || this.issueQty <= 0) { this.showMessage('请输入有效的发料数量', 'error') return } // TODO: 调用发料API
this.showMessage('发料成功', 'success') // 刷新物料列表
this.loadMaterials() this.selectedMaterial = null this.scannedLabel = '' this.labelInfo = null this.issueQty = null this.processFlag = 1 }, showMessage(text, type = 'info') { this.message = text this.messageType = type setTimeout(() => { this.message = '' }, 2000) }, },}</script><style scoped>.input-section { background: white; border-radius: 8px; padding: 15px; margin-bottom: 15px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);}.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #eee;}.reset-btn { background: #17b3a3; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 12px;}.input-group { margin-bottom: 15px;}.input-group label { display: block; margin-bottom: 5px; font-weight: bold; color: #333;}.input-with-scan { display: flex; gap: 10px;}.input-with-scan input { flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px;}.scan-btn,.confirm-btn { background: #17b3a3; color: white; border: none; padding: 10px 15px; border-radius: 4px; cursor: pointer; font-size: 14px; white-space: nowrap;}.scan-btn:hover,.confirm-btn:hover { background: #13998c;}.confirm-btn:disabled { background: #6c757d; cursor: not-allowed;}.material-list { display: flex; flex-direction: column; gap: 10px;}.material-item { display: flex; justify-content: space-between; align-items: center; padding: 15px; border: 1px solid #ddd; border-radius: 6px; cursor: pointer; transition: all 0.3s;}.material-item.selected { border-color: #007bff; background-color: #e3f2fd;}.material-info { flex: 1;}.part-no { font-weight: bold; font-size: 16px; color: #333; margin-bottom: 4px;}.part-desc { color: #666; font-size: 14px; margin-bottom: 4px;}.qty-info { font-size: 12px; color: #666;}.material-status { text-align: right;}.status-pending { background: #ffc107; color: #212529; padding: 4px 8px; border-radius: 12px; font-size: 12px;}.status-complete { background: #28a745; color: white; padding: 4px 8px; border-radius: 12px; font-size: 12px;}.label-info { background: #f8f9fa; border-radius: 6px; padding: 15px; margin-bottom: 15px;}.info-row { display: flex; justify-content: space-between; margin-bottom: 8px; padding: 5px 0; border-bottom: 1px solid #eee;}.info-row:last-child { border-bottom: none; margin-bottom: 0;}.info-row .label { font-weight: bold; color: #666;}.info-row .value { color: #333;}.qty-input { margin-top: 15px;}.qty-input input[type='number'] { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px;}.message { margin-top: 10px; padding: 8px 12px; border-radius: 4px; font-weight: bold;}.message.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb;}.message.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb;}.message.warning { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7;}.message.info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb;}.confirm-btn { width: 100%;}.scan-btn { width: 100%;}</style>
|