Browse Source

2025-12-08

pda在物料清单列表优化
master
fengyuan_yang 3 months ago
parent
commit
10bda23ebd
  1. 92
      src/views/modules/other-inout/otherInboundDetail.vue
  2. 94
      src/views/modules/other-inout/otherOutboundDetail.vue
  3. 94
      src/views/modules/production-pick/productionPickingDetail.vue
  4. 261
      src/views/modules/production/productionInboundStorage.vue
  5. 102
      src/views/modules/purchase-return/purchaseReturnDetail.vue
  6. 129
      src/views/modules/sales-return/salesReturnStorage.vue
  7. 94
      src/views/modules/sales/salesOutboundDetail.vue

92
src/views/modules/other-inout/otherInboundDetail.vue

@ -240,7 +240,7 @@
class="table-row"
>
<div class="col-no">{{ index + 1 }}</div>
<div class="col-material-code">{{ item.materialCode }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode }}</div>
<div class="col-required-qty">{{ item.requiredQty || 0 }}</div>
<div class="col-available-qty">{{ item.actualQty || 0 }}</div>
</div>
@ -259,11 +259,45 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container"><i class="el-icon-loading"></i><span>加载中...</span></div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock"><i class="el-icon-box"></i><p>暂无可用库存</p></div>
</div>
<div class="modal-footer"><button class="btn-close" @click="closeStockDialog">关闭</button></div>
</div>
</div>
</div>
</template>
<script>
import { getOtherInboundDetails, getMaterialList, validateLabelWithOtherInbound, confirmOtherInbound, getScannedLabelList } from "@/api/other-inbound/other-inbound.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
@ -282,6 +316,10 @@ export default {
buNo: '',
showMaterialDialog: false,
materialListLoading: false,
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: '',
showLocationDialog: false,
locationCode: '',
//
@ -607,6 +645,36 @@ export default {
this.showMaterialDialog = false;
},
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.inboundInfo.site,
notifyNo: this.inboundNo,
notifyType: '其它入库',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: localStorage.getItem('warehouseId') || ''
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) { this.stockList = data.data || []; }
else { this.$message.error(data.msg || '获取可用库存失败'); this.stockList = []; }
}).catch(error => { this.stockLoading = false; this.$message.error('获取可用库存失败'); this.stockList = []; });
},
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
//
loadInboundDetails() {
const params = {
@ -1325,6 +1393,28 @@ export default {
word-break: break-all;
}
.clickable-part { color: #17B3A3; font-weight: 500; cursor: pointer; text-decoration: underline; }
.clickable-part:hover { color: #0d8f7f; }
.stock-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.stock-modal { background: white; border-radius: 12px; width: 100%; max-width: 800px; max-height: 80vh; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column; }
.stock-modal .modal-header { background: #17B3A3; color: white; padding: 5px 16px; display: flex; justify-content: space-between; align-items: center; min-height: 28px; }
.stock-modal .modal-body { flex: 1; overflow: auto; padding: 0; }
.stock-table { width: 100%; }
.stock-table .table-header { display: flex; background: #f8f9fa; padding: 10px 6px; border-bottom: 2px solid #17B3A3; font-size: 12px; color: #333; font-weight: 600; position: sticky; top: 0; }
.stock-table .table-body { max-height: 400px; overflow-y: auto; }
.stock-table .table-row { display: flex; padding: 10px 6px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333; }
.stock-table .table-row:hover { background-color: #f8f9fa; }
.stock-table .col-roll-no { flex: 1.5; text-align: center; min-width: 100px; }
.stock-table .col-qty { flex: 0.8; text-align: center; min-width: 60px; }
.unit-text { color: #999; font-size: 11px; margin-left: 2px; }
.stock-table .col-location { flex: 0.8; text-align: center; min-width: 60px; }
.stock-table .col-batch { flex: 1; text-align: center; min-width: 80px; }
.stock-table .col-date { flex: 1; text-align: center; min-width: 80px; }
.stock-modal .modal-footer { padding: 15px 20px; display: flex; justify-content: center; border-top: 1px solid #f0f0f0; }
.empty-stock { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; }
.empty-stock i { font-size: 48px; margin-bottom: 16px; color: #ddd; }
.empty-stock p { margin: 0; font-size: 14px; }
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

94
src/views/modules/other-inout/otherOutboundDetail.vue

@ -141,7 +141,7 @@
class="table-row"
>
<div class="col-no">{{ index + 1 }}</div>
<div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode || item.partNo }}</div>
<div class="col-required-qty">{{ item.requiredQty || 0 }}</div>
<div class="col-available-qty">{{ item.availableQty || 0 }}</div>
</div>
@ -160,11 +160,45 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container"><i class="el-icon-loading"></i><span>加载中...</span></div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock"><i class="el-icon-box"></i><p>暂无可用库存</p></div>
</div>
<div class="modal-footer"><button class="btn-close" @click="closeStockDialog">关闭</button></div>
</div>
</div>
</div>
</template>
<script>
import { getOtherOutboundDetails, validateLabelWithOutbound, confirmOtherOutbound, getMaterialList } from "@/api/other-outbound/other-outbound.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
@ -178,7 +212,11 @@ export default {
showMaterialDialog: false,
materialList: [],
materialListLoading: false,
isRemoveMode: false //
isRemoveMode: false, //
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: ''
};
},
methods: {
@ -347,6 +385,36 @@ export default {
this.showMaterialDialog = false;
},
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.outboundInfo.site,
notifyNo: this.outboundNo,
notifyType: '其它出库',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: localStorage.getItem('warehouseId') || ''
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) { this.stockList = data.data || []; }
else { this.$message.error(data.msg || '获取可用库存失败'); this.stockList = []; }
}).catch(error => { this.stockLoading = false; this.$message.error('获取可用库存失败'); this.stockList = []; });
},
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
//
loadOutboundDetails() {
const params = {
@ -883,6 +951,28 @@ export default {
word-break: break-all;
}
.clickable-part { color: #17B3A3; font-weight: 500; cursor: pointer; text-decoration: underline; }
.clickable-part:hover { color: #0d8f7f; }
.stock-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.stock-modal { background: white; border-radius: 12px; width: 100%; max-width: 800px; max-height: 80vh; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column; }
.stock-modal .modal-header { background: #17B3A3; color: white; padding: 5px 16px; display: flex; justify-content: space-between; align-items: center; min-height: 28px; }
.stock-modal .modal-body { flex: 1; overflow: auto; padding: 0; }
.stock-table { width: 100%; }
.stock-table .table-header { display: flex; background: #f8f9fa; padding: 10px 6px; border-bottom: 2px solid #17B3A3; font-size: 12px; color: #333; font-weight: 600; position: sticky; top: 0; }
.stock-table .table-body { max-height: 400px; overflow-y: auto; }
.stock-table .table-row { display: flex; padding: 10px 6px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333; }
.stock-table .table-row:hover { background-color: #f8f9fa; }
.stock-table .col-roll-no { flex: 1.5; text-align: center; min-width: 100px; }
.stock-table .col-qty { flex: 0.8; text-align: center; min-width: 60px; }
.unit-text { color: #999; font-size: 11px; margin-left: 2px; }
.stock-table .col-location { flex: 0.8; text-align: center; min-width: 60px; }
.stock-table .col-batch { flex: 1; text-align: center; min-width: 80px; }
.stock-table .col-date { flex: 1; text-align: center; min-width: 80px; }
.stock-modal .modal-footer { padding: 15px 20px; display: flex; justify-content: center; border-top: 1px solid #f0f0f0; }
.empty-stock { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; }
.empty-stock i { font-size: 48px; margin-bottom: 16px; color: #ddd; }
.empty-stock p { margin: 0; font-size: 14px; }
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

94
src/views/modules/production-pick/productionPickingDetail.vue

@ -145,7 +145,7 @@
class="table-row"
>
<div class="col-no">{{ index + 1 }}</div>
<div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode || item.partNo }}</div>
<div class="col-required-qty">{{ item.requiredQty || 0 }}</div>
<div class="col-picked-qty">{{ item.pickedQty || 0 }}</div>
<div class="col-picked-qty">{{ item.scansQty || 0 }}</div>
@ -165,11 +165,45 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container"><i class="el-icon-loading"></i><span>加载中...</span></div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock"><i class="el-icon-box"></i><p>暂无可用库存</p></div>
</div>
<div class="modal-footer"><button class="btn-close" @click="closeStockDialog">关闭</button></div>
</div>
</div>
</div>
</template>
<script>
import { getOutboundDetails, validateLabelWithOutbound, confirmProductionPicking, getOutboundMaterialList, getScannedLabelList } from "@/api/production.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
@ -185,7 +219,11 @@ export default {
materialList: [],
materialListLoading: false,
isRemoveMode: false, //
relatedNo: ''
relatedNo: '',
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: ''
};
},
methods: {
@ -353,6 +391,36 @@ export default {
this.showMaterialDialog = false;
},
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.outboundInfo.site,
notifyNo: this.outboundNo,
notifyType: '生产领料',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: localStorage.getItem('warehouseId') || ''
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) { this.stockList = data.data || []; }
else { this.$message.error(data.msg || '获取可用库存失败'); this.stockList = []; }
}).catch(error => { this.stockLoading = false; this.$message.error('获取可用库存失败'); this.stockList = []; });
},
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
//
loadOutboundDetails() {
const params = {
@ -917,6 +985,28 @@ export default {
word-break: break-all;
}
.clickable-part { color: #17B3A3; font-weight: 500; cursor: pointer; text-decoration: underline; }
.clickable-part:hover { color: #0d8f7f; }
.stock-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.stock-modal { background: white; border-radius: 12px; width: 100%; max-width: 800px; max-height: 80vh; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column; }
.stock-modal .modal-header { background: #17B3A3; color: white; padding: 5px 16px; display: flex; justify-content: space-between; align-items: center; min-height: 28px; }
.stock-modal .modal-body { flex: 1; overflow: auto; padding: 0; }
.stock-table { width: 100%; }
.stock-table .table-header { display: flex; background: #f8f9fa; padding: 10px 6px; border-bottom: 2px solid #17B3A3; font-size: 12px; color: #333; font-weight: 600; position: sticky; top: 0; }
.stock-table .table-body { max-height: 400px; overflow-y: auto; }
.stock-table .table-row { display: flex; padding: 10px 6px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333; }
.stock-table .table-row:hover { background-color: #f8f9fa; }
.stock-table .col-roll-no { flex: 1.5; text-align: center; min-width: 100px; }
.stock-table .col-qty { flex: 0.8; text-align: center; min-width: 60px; }
.unit-text { color: #999; font-size: 11px; margin-left: 2px; }
.stock-table .col-location { flex: 0.8; text-align: center; min-width: 60px; }
.stock-table .col-batch { flex: 1; text-align: center; min-width: 80px; }
.stock-table .col-date { flex: 1; text-align: center; min-width: 80px; }
.stock-modal .modal-footer { padding: 15px 20px; display: flex; justify-content: center; border-top: 1px solid #f0f0f0; }
.empty-stock { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; }
.empty-stock i { font-size: 48px; margin-bottom: 16px; color: #ddd; }
.empty-stock p { margin: 0; font-size: 14px; }
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

261
src/views/modules/production/productionInboundStorage.vue

@ -186,7 +186,7 @@
>
<div class="col-no">{{ index + 1 }}</div>
<!-- <div class="col-label-code">{{ item.labelCode || item.rollNo }}</div>-->
<div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode || item.partNo }}</div>
<div class="col-required-qty">{{ item.labelCount || 0 }}</div>
<div class="col-inbound-qty">{{ item.totalinLabels || 0 }}</div>
</div>
@ -205,11 +205,58 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container">
<i class="el-icon-loading"></i>
<span>加载中...</span>
</div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock">
<i class="el-icon-box"></i>
<p>暂无可用库存</p>
</div>
</div>
<div class="modal-footer">
<button class="btn-close" @click="closeStockDialog">关闭</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { getInboundDetails, validateLabelWithInbound, confirmInboundStorage, deleteLabel, getMaterialList, getScannedLabelList } from "@/api/production/production-inbound.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
export default {
@ -227,7 +274,12 @@ export default {
showMaterialDialog: false,
materialList: [],
materialListLoading: false,
isRemoveMode: false //
isRemoveMode: false, //
//
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: ''
};
},
methods: {
@ -446,6 +498,49 @@ export default {
this.showMaterialDialog = false;
},
//
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
//
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.materialInfo.site,
notifyNo: this.inboundNo,
notifyType: '生产入库',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: getCurrentWarehouse()
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) {
this.stockList = data.data || [];
} else {
this.$message.error(data.msg || '获取可用库存失败');
this.stockList = [];
}
}).catch(error => {
this.stockLoading = false;
console.error('获取可用库存失败:', error);
this.$message.error('获取可用库存失败');
this.stockList = [];
});
},
//
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
//
loadInboundDetails() {
const params = {
@ -1241,6 +1336,168 @@ export default {
word-break: break-all;
}
/* 可点击的物料编码样式 */
.clickable-part {
color: #17B3A3;
font-weight: 500;
cursor: pointer;
text-decoration: underline;
transition: color 0.2s ease;
}
.clickable-part:hover {
color: #0d8f7f;
}
.clickable-part:active {
color: #0a7a6c;
}
/* 可用库存弹窗样式 */
.stock-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.stock-modal {
background: white;
border-radius: 12px;
width: 100%;
max-width: 800px;
max-height: 80vh;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
overflow: hidden;
display: flex;
flex-direction: column;
}
.stock-modal .modal-header {
background: #17B3A3;
color: white;
padding: 5px 16px;
display: flex;
justify-content: space-between;
align-items: center;
min-height: 28px;
}
.stock-modal .modal-body {
flex: 1;
overflow: auto;
padding: 0;
}
.stock-table {
width: 100%;
}
.stock-table .table-header {
display: flex;
background: #f8f9fa;
padding: 10px 6px;
border-bottom: 2px solid #17B3A3;
font-size: 12px;
color: #333;
font-weight: 600;
position: sticky;
top: 0;
z-index: 1;
}
.stock-table .table-body {
max-height: 400px;
overflow-y: auto;
}
.stock-table .table-row {
display: flex;
padding: 10px 6px;
border-bottom: 1px solid #f0f0f0;
font-size: 12px;
color: #333;
}
.stock-table .table-row:hover {
background-color: #f8f9fa;
}
.stock-table .col-roll-no {
flex: 1.5;
text-align: center;
min-width: 100px;
font-size: 12px;
}
.stock-table .col-qty {
flex: 0.8;
text-align: center;
min-width: 60px;
font-size: 12px;
}
.unit-text {
color: #999;
font-size: 11px;
margin-left: 2px;
}
.stock-table .col-location {
flex: 0.8;
text-align: center;
min-width: 60px;
font-size: 12px;
}
.stock-table .col-batch {
flex: 1;
text-align: center;
min-width: 80px;
font-size: 12px;
}
.stock-table .col-date {
flex: 1;
text-align: center;
min-width: 80px;
font-size: 12px;
}
.stock-modal .modal-footer {
padding: 15px 20px;
display: flex;
justify-content: center;
border-top: 1px solid #f0f0f0;
}
.empty-stock {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 20px;
color: #999;
}
.empty-stock i {
font-size: 48px;
margin-bottom: 16px;
color: #ddd;
}
.empty-stock p {
margin: 0;
font-size: 14px;
}
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

102
src/views/modules/purchase-return/purchaseReturnDetail.vue

@ -140,7 +140,7 @@
class="table-row"
>
<div class="col-no">{{ index + 1 }}</div>
<div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode || item.partNo }}</div>
<div class="col-required-qty">{{ item.requiredQty || 0 }}</div>
<div class="col-available-qty">{{ item.availableQty || 0 }}</div>
</div>
@ -159,11 +159,45 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container"><i class="el-icon-loading"></i><span>加载中...</span></div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock"><i class="el-icon-box"></i><p>暂无可用库存</p></div>
</div>
<div class="modal-footer"><button class="btn-close" @click="closeStockDialog">关闭</button></div>
</div>
</div>
</div>
</template>
<script>
import { getReturnDetails, validateLabelWithReturn, confirmPurchaseReturn, getMaterialList, getScannedLabelList } from "@/api/purchase/purchase-return.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
@ -180,7 +214,11 @@ export default {
showMaterialDialog: false,
materialList: [],
materialListLoading: false,
isRemoveMode: false //
isRemoveMode: false, //
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: ''
};
},
methods: {
@ -349,6 +387,44 @@ export default {
this.showMaterialDialog = false;
},
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.returnInfo.site,
notifyNo: this.returnNo,
notifyType: '采购退货',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: localStorage.getItem('warehouseId') || ''
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) {
this.stockList = data.data || [];
} else {
this.$message.error(data.msg || '获取可用库存失败');
this.stockList = [];
}
}).catch(error => {
this.stockLoading = false;
this.$message.error('获取可用库存失败');
this.stockList = [];
});
},
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
// 退
loadReturnDetails() {
const params = {
@ -916,6 +992,28 @@ export default {
word-break: break-all;
}
.clickable-part { color: #17B3A3; font-weight: 500; cursor: pointer; text-decoration: underline; }
.clickable-part:hover { color: #0d8f7f; }
.stock-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.stock-modal { background: white; border-radius: 12px; width: 100%; max-width: 800px; max-height: 80vh; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column; }
.stock-modal .modal-header { background: #17B3A3; color: white; padding: 5px 16px; display: flex; justify-content: space-between; align-items: center; min-height: 28px; }
.stock-modal .modal-body { flex: 1; overflow: auto; padding: 0; }
.stock-table { width: 100%; }
.stock-table .table-header { display: flex; background: #f8f9fa; padding: 10px 6px; border-bottom: 2px solid #17B3A3; font-size: 12px; color: #333; font-weight: 600; position: sticky; top: 0; }
.stock-table .table-body { max-height: 400px; overflow-y: auto; }
.stock-table .table-row { display: flex; padding: 10px 6px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333; }
.stock-table .table-row:hover { background-color: #f8f9fa; }
.stock-table .col-roll-no { flex: 1.5; text-align: center; min-width: 100px; }
.stock-table .col-qty { flex: 0.8; text-align: center; min-width: 60px; }
.unit-text { color: #999; font-size: 11px; margin-left: 2px; }
.stock-table .col-location { flex: 0.8; text-align: center; min-width: 60px; }
.stock-table .col-batch { flex: 1; text-align: center; min-width: 80px; }
.stock-table .col-date { flex: 1; text-align: center; min-width: 80px; }
.stock-modal .modal-footer { padding: 15px 20px; display: flex; justify-content: center; border-top: 1px solid #f0f0f0; }
.empty-stock { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; }
.empty-stock i { font-size: 48px; margin-bottom: 16px; color: #ddd; }
.empty-stock p { margin: 0; font-size: 14px; }
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

129
src/views/modules/sales-return/salesReturnStorage.vue

@ -175,7 +175,7 @@
class="table-row"
>
<div class="col-no">{{ index + 1 }}</div>
<div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode || item.partNo }}</div>
<div class="col-required-qty">{{ item.labelCount || 0 }}</div>
<div class="col-inbound-qty">{{ item.totalinLabels || 0 }}</div>
</div>
@ -194,11 +194,58 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container">
<i class="el-icon-loading"></i>
<span>加载中...</span>
</div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock">
<i class="el-icon-box"></i>
<p>暂无可用库存</p>
</div>
</div>
<div class="modal-footer">
<button class="btn-close" @click="closeStockDialog">关闭</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { getSalesReturnDetails, validateLabelWithSalesReturn, confirmSalesReturnStorage, getSalesReturnMaterialList, getScannedLabelList } from "@/api/salesReturn.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
export default {
@ -214,7 +261,12 @@ export default {
showMaterialDialog: false,
materialList: [],
materialListLoading: false,
isRemoveMode: false //
isRemoveMode: false, //
//
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: ''
};
},
methods: {
@ -427,6 +479,54 @@ export default {
this.showMaterialDialog = false;
},
//
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
//
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.materialInfo.site,
notifyNo: this.returnNo,
notifyType: '销售退货',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: this.getCurrentWarehouse()
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) {
this.stockList = data.data || [];
} else {
this.$message.error(data.msg || '获取可用库存失败');
this.stockList = [];
}
}).catch(error => {
this.stockLoading = false;
console.error('获取可用库存失败:', error);
this.$message.error('获取可用库存失败');
this.stockList = [];
});
},
//
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
//
getCurrentWarehouse() {
return localStorage.getItem('warehouseId') || '';
},
// 退
loadReturnDetails() {
const params = {
@ -1187,6 +1287,31 @@ export default {
word-break: break-all;
}
/* 可点击的物料编码样式 */
.clickable-part { color: #17B3A3; font-weight: 500; cursor: pointer; text-decoration: underline; }
.clickable-part:hover { color: #0d8f7f; }
/* 可用库存弹窗样式 */
.stock-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.stock-modal { background: white; border-radius: 12px; width: 100%; max-width: 800px; max-height: 80vh; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column; }
.stock-modal .modal-header { background: #17B3A3; color: white; padding: 5px 16px; display: flex; justify-content: space-between; align-items: center; min-height: 28px; }
.stock-modal .modal-body { flex: 1; overflow: auto; padding: 0; }
.stock-table { width: 100%; }
.stock-table .table-header { display: flex; background: #f8f9fa; padding: 10px 6px; border-bottom: 2px solid #17B3A3; font-size: 12px; color: #333; font-weight: 600; position: sticky; top: 0; z-index: 1; }
.stock-table .table-body { max-height: 400px; overflow-y: auto; }
.stock-table .table-row { display: flex; padding: 10px 6px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333; }
.stock-table .table-row:hover { background-color: #f8f9fa; }
.stock-table .col-roll-no { flex: 1.5; text-align: center; min-width: 100px; font-size: 12px; }
.stock-table .col-qty { flex: 0.8; text-align: center; min-width: 60px; font-size: 12px; }
.unit-text { color: #999; font-size: 11px; margin-left: 2px; }
.stock-table .col-location { flex: 0.8; text-align: center; min-width: 60px; font-size: 12px; }
.stock-table .col-batch { flex: 1; text-align: center; min-width: 80px; font-size: 12px; }
.stock-table .col-date { flex: 1; text-align: center; min-width: 80px; font-size: 12px; }
.stock-modal .modal-footer { padding: 15px 20px; display: flex; justify-content: center; border-top: 1px solid #f0f0f0; }
.empty-stock { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; }
.empty-stock i { font-size: 48px; margin-bottom: 16px; color: #ddd; }
.empty-stock p { margin: 0; font-size: 14px; }
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

94
src/views/modules/sales/salesOutboundDetail.vue

@ -161,7 +161,7 @@
class="table-row"
>
<div class="col-no">{{ index + 1 }}</div>
<div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
<div class="col-material-code clickable-part" @click="showStockDialogFn(item)">{{ item.materialCode || item.partNo }}</div>
<div class="col-required-qty">{{ item.requiredQty || 0 }}</div>
<div class="col-available-qty">{{ item.availableQty || 0 }}</div>
</div>
@ -180,11 +180,45 @@
</div>
</div>
</div>
<!-- 可用库存弹窗 -->
<div v-if="showStockDialog" class="stock-overlay">
<div class="stock-modal">
<div class="modal-header">
<span class="modal-title">可用库存 - {{ currentPartNo }}</span>
<i class="el-icon-close close-btn" @click="closeStockDialog"></i>
</div>
<div class="modal-body">
<div v-if="stockLoading" class="loading-container"><i class="el-icon-loading"></i><span>加载中...</span></div>
<div v-else-if="stockList.length > 0" class="stock-table">
<div class="table-header">
<div class="col-roll-no">标签条码</div>
<div class="col-qty">数量</div>
<div class="col-location">库位</div>
<div class="col-batch">合约号码</div>
<div class="col-date">入库日期</div>
</div>
<div class="table-body">
<div v-for="(item, index) in stockList" :key="index" class="table-row">
<div class="col-roll-no">{{ item.rollNo }}</div>
<div class="col-qty">{{ item.rollQty }} <span class="unit-text">{{ item.um }}</span></div>
<div class="col-location">{{ item.location }}</div>
<div class="col-batch">{{ item.batchNo }}</div>
<div class="col-date">{{ item.daysInStock }}</div>
</div>
</div>
</div>
<div v-else class="empty-stock"><i class="el-icon-box"></i><p>暂无可用库存</p></div>
</div>
<div class="modal-footer"><button class="btn-close" @click="closeStockDialog">关闭</button></div>
</div>
</div>
</div>
</template>
<script>
import { getOutboundDetails, validateLabelWithOutbound, confirmSalesOutbound, getMaterialList, getScannedLabelList } from "@/api/sales/sales-outbound.js";
import { getInventoryStock } from "@/api/inbound.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
@ -200,7 +234,11 @@ export default {
showMaterialDialog: false,
materialList: [],
materialListLoading: false,
isRemoveMode: false //
isRemoveMode: false, //
showStockDialog: false,
stockList: [],
stockLoading: false,
currentPartNo: ''
};
},
methods: {
@ -375,6 +413,36 @@ export default {
this.showMaterialDialog = false;
},
showStockDialogFn(item) {
this.currentPartNo = item.materialCode || item.partNo;
this.showStockDialog = true;
this.loadInventoryStock(this.currentPartNo);
},
loadInventoryStock(partNo) {
this.stockLoading = true;
const params = {
site: this.outboundInfo.site,
notifyNo: this.outboundNo,
notifyType: '销售出库',
orderNo: '',
orderLineNo: '',
partNo: partNo,
warehouseId: localStorage.getItem('warehouseId') || ''
};
getInventoryStock(params).then(({ data }) => {
this.stockLoading = false;
if (data && data.code === 0) { this.stockList = data.data || []; }
else { this.$message.error(data.msg || '获取可用库存失败'); this.stockList = []; }
}).catch(error => { this.stockLoading = false; this.$message.error('获取可用库存失败'); this.stockList = []; });
},
closeStockDialog() {
this.showStockDialog = false;
this.stockList = [];
this.currentPartNo = '';
},
//
loadOutboundDetails() {
const params = {
@ -1001,6 +1069,28 @@ export default {
word-break: break-all;
}
.clickable-part { color: #17B3A3; font-weight: 500; cursor: pointer; text-decoration: underline; }
.clickable-part:hover { color: #0d8f7f; }
.stock-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.stock-modal { background: white; border-radius: 12px; width: 100%; max-width: 800px; max-height: 80vh; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); overflow: hidden; display: flex; flex-direction: column; }
.stock-modal .modal-header { background: #17B3A3; color: white; padding: 5px 16px; display: flex; justify-content: space-between; align-items: center; min-height: 28px; }
.stock-modal .modal-body { flex: 1; overflow: auto; padding: 0; }
.stock-table { width: 100%; }
.stock-table .table-header { display: flex; background: #f8f9fa; padding: 10px 6px; border-bottom: 2px solid #17B3A3; font-size: 12px; color: #333; font-weight: 600; position: sticky; top: 0; }
.stock-table .table-body { max-height: 400px; overflow-y: auto; }
.stock-table .table-row { display: flex; padding: 10px 6px; border-bottom: 1px solid #f0f0f0; font-size: 12px; color: #333; }
.stock-table .table-row:hover { background-color: #f8f9fa; }
.stock-table .col-roll-no { flex: 1.5; text-align: center; min-width: 100px; }
.stock-table .col-qty { flex: 0.8; text-align: center; min-width: 60px; }
.unit-text { color: #999; font-size: 11px; margin-left: 2px; }
.stock-table .col-location { flex: 0.8; text-align: center; min-width: 60px; }
.stock-table .col-batch { flex: 1; text-align: center; min-width: 80px; }
.stock-table .col-date { flex: 1; text-align: center; min-width: 80px; }
.stock-modal .modal-footer { padding: 15px 20px; display: flex; justify-content: center; border-top: 1px solid #f0f0f0; }
.empty-stock { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; }
.empty-stock i { font-size: 48px; margin-bottom: 16px; color: #ddd; }
.empty-stock p { margin: 0; font-size: 14px; }
.material-table .col-required-qty {
flex: 0.8;
text-align: center;

Loading…
Cancel
Save