|
|
@@ -0,0 +1,752 @@
|
|
|
+<template>
|
|
|
+ <ele-modal
|
|
|
+ :visible.sync="visible"
|
|
|
+ title="上架"
|
|
|
+ :before-close="cancel"
|
|
|
+ width="80%"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :maxable="true"
|
|
|
+ :append-to-body="true"
|
|
|
+ custom-class="ele-dialog-form"
|
|
|
+ >
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <!-- 左侧:物品清单 -->
|
|
|
+ <el-col :span="10">
|
|
|
+ <div class="section-title">物品清单</div>
|
|
|
+ <div class="dimension-tabs">
|
|
|
+ <span class="dimension-label">维度:</span>
|
|
|
+ <el-radio-group v-model="dimension" @change="dimensionChange" size="small">
|
|
|
+ <el-radio-button :label="1">批次维度</el-radio-button>
|
|
|
+ <!-- <el-radio-button :label="2">物品维度</el-radio-button> -->
|
|
|
+ <el-radio-button :label="3">包装维度</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <el-table
|
|
|
+ ref="tableRef"
|
|
|
+ :data="tableData"
|
|
|
+ style="width: 100%"
|
|
|
+ max-height="300"
|
|
|
+ border
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ type="selection"
|
|
|
+ width="50"
|
|
|
+ fixed="left"
|
|
|
+ align="center"
|
|
|
+ :selectable="checkSelectable"
|
|
|
+ />
|
|
|
+ <el-table-column type="index" label="序号" width="50" align="center" />
|
|
|
+ <el-table-column prop="categoryCode" label="物品编码" min-width="120" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="categoryName" label="名称" min-width="120" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="batchNo" label="批次号" min-width="140" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="measureQuantity" label="数量" width="80" align="center" />
|
|
|
+ <el-table-column prop="measureUnit" label="单位" width="70" align="center" />
|
|
|
+ <el-table-column prop="packingQuantity" label="计量数量" width="90" align="center" />
|
|
|
+ <el-table-column prop="packingUnit" label="计量单位" width="90" align="center" />
|
|
|
+ <el-table-column prop="singleWeight" label="单重" width="80" align="center" />
|
|
|
+ <el-table-column prop="totalWeight" label="总重" width="80" align="center" />
|
|
|
+ <el-table-column prop="weightUnit" label="重量单位" width="90" align="center" />
|
|
|
+ <el-table-column prop="colorKey" label="颜色" width="80" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="categoryModel" label="型号" width="100" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="specification" label="规格" width="100" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="gradeName" label="牌号" width="80" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="voltage" label="电压" width="80" align="center" />
|
|
|
+ <el-table-column prop="approvalNumber" label="批准文号" width="120" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="packingSpec" label="包装规格" width="100" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="allowUnpack" label="允许拆包" width="90" align="center" />
|
|
|
+ <el-table-column prop="supplierName" label="供应商" min-width="120" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="warehouseName" label="仓库" min-width="100" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="productionDate" label="生产日期" width="110" align="center" />
|
|
|
+ <el-table-column prop="purchaseDate" label="采购日期" width="110" align="center" />
|
|
|
+ <el-table-column prop="expiryDate" label="失效日期" width="110" align="center" />
|
|
|
+ </el-table>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <!-- 右侧:上架信息 -->
|
|
|
+ <el-col :span="14">
|
|
|
+ <div class="section-title">上架信息</div>
|
|
|
+ <el-form :model="formData" label-width="100px">
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="选择仓库">
|
|
|
+ <el-select filterable disabled v-model="warehouse" @change="warehouseChange">
|
|
|
+ <el-option
|
|
|
+ v-for="(item, index) in warehouseList"
|
|
|
+ :key="index"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item.id"
|
|
|
+ @click.native="changeWarehouse(item)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="选择库区">
|
|
|
+ <el-select filterable v-model="area" @change="getshelvesList">
|
|
|
+ <el-option
|
|
|
+ v-for="(item, index) in areaList"
|
|
|
+ :key="index"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item.id"
|
|
|
+ @click.native="formData.area = item"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="选择货架">
|
|
|
+ <el-select filterable v-model="formData.shelves" @change="changeshelvesList">
|
|
|
+ <el-option
|
|
|
+ v-for="(item, index) in shelvesList"
|
|
|
+ :key="index"
|
|
|
+ :label="item.goodsshelvesCode"
|
|
|
+ :value="item.goodsshelvesCode"
|
|
|
+ @click.native="formData.shelves = item"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div class="status-legend">
|
|
|
+ <div v-for="(item, index) in locationStatusList" :key="index">
|
|
|
+ <span :style="{ 'background-color': item.color }"></span>{{ item.label }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="content-box">
|
|
|
+ <div
|
|
|
+ v-for="p in locationList"
|
|
|
+ :key="p.id"
|
|
|
+ class="box"
|
|
|
+ @click="handlCur(p)"
|
|
|
+ :class="{ selected: isLocationSelected(p.id) }"
|
|
|
+ :style="{
|
|
|
+ 'background-color': getStatus(p.allocationStatus).color,
|
|
|
+ cursor: [1, 2].includes(p.allocationStatus) ? 'pointer' : 'not-allowed'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ {{ p.goodsAllocationCode }}
|
|
|
+ </div>
|
|
|
+ <div v-for="n in placeholderCount" :key="'ph-' + n" class="placeholder-box"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 添加行 + 上架列表 -->
|
|
|
+ <div style="margin-top: 12px;">
|
|
|
+ <el-button type="primary" size="small" @click="addRow">添加行</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table :data="shelvingList" style="width: 100%; margin-top: 8px;" border>
|
|
|
+ <el-table-column label="序号" type="index" width="50" align="center" />
|
|
|
+ <el-table-column label="货位位置" min-width="320" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-select
|
|
|
+ v-model="scope.row.cargoSpaceId"
|
|
|
+ filterable
|
|
|
+ placeholder="选择货位"
|
|
|
+ size="small"
|
|
|
+ style="width: 300px;"
|
|
|
+ @change="(val) => onLocationChange(val, scope.row)"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="opt in locationOptions"
|
|
|
+ :key="opt.value"
|
|
|
+ :label="opt.label"
|
|
|
+ :value="opt.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="物品批次" min-width="280" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-select
|
|
|
+ v-model="scope.row.itemKey"
|
|
|
+ filterable
|
|
|
+ placeholder="选择物品批次"
|
|
|
+ size="small"
|
|
|
+ style="width: 260px;"
|
|
|
+ @change="(val) => onItemChange(val, scope.row)"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="opt in itemOptions"
|
|
|
+ :key="opt.value"
|
|
|
+ :label="opt.label"
|
|
|
+ :value="opt.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="数量" width="160" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-input-number
|
|
|
+ v-model="scope.row.quantity"
|
|
|
+ :min="0"
|
|
|
+ :max="scope.row.maxQuantity"
|
|
|
+ size="small"
|
|
|
+ controls-position="right"
|
|
|
+ style="width: 130px;"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column width="80" label="操作" fixed="right" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button type="text" @click="delItem(scope.$index)" size="small">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <div class="modal-footer">
|
|
|
+ <el-button @click="handleSelect" type="primary" :loading="confirmLoading">确认</el-button>
|
|
|
+ <el-button @click="cancel">关闭</el-button>
|
|
|
+ </div>
|
|
|
+ </ele-modal>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ import storageApi from '@/api/warehouseManagement';
|
|
|
+ import warehouseDefinition from '@/api/warehouseManagement/warehouseDefinition';
|
|
|
+ import { useDict } from '@/utils/dict/index';
|
|
|
+
|
|
|
+ const locationStatusList = [
|
|
|
+ { code: 1, label: '空置', color: 'rgba(202, 249, 130, 1)' },
|
|
|
+ { code: 2, label: '在用', color: 'rgba(129, 211, 248, 1)' },
|
|
|
+ { code: 3, label: '已满', color: 'rgba(255, 14, 14, 1)' },
|
|
|
+ { code: 4, label: '失效', color: 'rgba(215, 215, 215, 1)' }
|
|
|
+ ];
|
|
|
+
|
|
|
+ export default {
|
|
|
+ name: 'ItemListed',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ locationStatusList,
|
|
|
+ visible: false,
|
|
|
+ rowData: null,
|
|
|
+ dimension: 1, // 1-批次维度 2-物品维度 3-包装维度
|
|
|
+
|
|
|
+ // 物品表格
|
|
|
+ tableLoading: false,
|
|
|
+ tableData: [],
|
|
|
+ allTableData: [],
|
|
|
+ selection: [],
|
|
|
+ shelvedItemKeys: [],
|
|
|
+
|
|
|
+ // 仓库选择
|
|
|
+ warehouseList: [],
|
|
|
+ areaList: [],
|
|
|
+ warehouse: '',
|
|
|
+ area: '',
|
|
|
+ shelves: '',
|
|
|
+ formData: {
|
|
|
+ warehouse: {},
|
|
|
+ area: {},
|
|
|
+ shelves: {}
|
|
|
+ },
|
|
|
+ shelvesList: [],
|
|
|
+ locationList: [],
|
|
|
+ selectedLocations: [],
|
|
|
+
|
|
|
+ // 上架清单
|
|
|
+ shelvingList: [],
|
|
|
+ confirmLoading: false
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ computed: {
|
|
|
+ locationOptions() {
|
|
|
+ return this.selectedLocations.map((l) => ({
|
|
|
+ label: `${l.warehouseName} - ${l.areaName} - ${l.shelfCode} - ${l.goodsAllocationCode}`,
|
|
|
+ value: l.id,
|
|
|
+ ...l
|
|
|
+ }));
|
|
|
+ },
|
|
|
+ itemOptions() {
|
|
|
+ return this.selection
|
|
|
+ .filter((it) => !it._shelved)
|
|
|
+ .map((it) => ({
|
|
|
+ label: `${it.categoryName || ''}${it.batchNo ? '/' + it.batchNo : ''}`,
|
|
|
+ value: this._getRowKey(it),
|
|
|
+ ...it
|
|
|
+ }));
|
|
|
+ },
|
|
|
+ placeholderCount() {
|
|
|
+ const perRow = 5;
|
|
|
+ const remainder = this.locationList.length % perRow;
|
|
|
+ return remainder === 0 ? 0 : perRow - remainder;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ // ==================== 打开/关闭 ====================
|
|
|
+ async open(row) {
|
|
|
+ console.log('open', row);
|
|
|
+ this.rowData = row;
|
|
|
+ this.dimension = 1;
|
|
|
+ this.selection = [];
|
|
|
+ this.shelvingList = [];
|
|
|
+ this.selectedLocations = [];
|
|
|
+ this.warehouse = '';
|
|
|
+ this.area = '';
|
|
|
+ this.shelves = '';
|
|
|
+ this.formData = { warehouse: {}, area: {}, shelves: {} };
|
|
|
+ this.locationList = [];
|
|
|
+ this.shelvesList = [];
|
|
|
+ this.shelvedItemKeys = [];
|
|
|
+ this.visible = true;
|
|
|
+ await this._getWarehouseList();
|
|
|
+ await this._loadTableData();
|
|
|
+
|
|
|
+ if (row?.warehouseId) {
|
|
|
+ this.warehouse = row.warehouseId;
|
|
|
+ const w = this.warehouseList.find((item) => item.id == row.warehouseId);
|
|
|
+ if (w) {
|
|
|
+ this.formData.warehouse = w;
|
|
|
+ await this.changeWarehouse(w);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ cancel() {
|
|
|
+ this.rowData = null;
|
|
|
+ this.formData = { warehouse: {}, area: {}, shelves: {} };
|
|
|
+ this.warehouse = '';
|
|
|
+ this.area = '';
|
|
|
+ this.shelves = '';
|
|
|
+ this.tableData = [];
|
|
|
+ this.allTableData = [];
|
|
|
+ this.selection = [];
|
|
|
+ this.shelvingList = [];
|
|
|
+ this.selectedLocations = [];
|
|
|
+ this.visible = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 维度切换 ====================
|
|
|
+ dimensionChange() {
|
|
|
+ this.selection = [];
|
|
|
+ if (this.$refs.tableRef) {
|
|
|
+ this.$refs.tableRef.clearSelection();
|
|
|
+ }
|
|
|
+ this.shelvingList = [];
|
|
|
+ this._loadTableData();
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 物品表格数据 ====================
|
|
|
+ async _loadTableData() {
|
|
|
+ if (!this.rowData?.id) return;
|
|
|
+ this.tableLoading = true;
|
|
|
+ try {
|
|
|
+ const res = await storageApi.getInboundDetailsById(this.rowData.id);
|
|
|
+ if (res) {
|
|
|
+ const items = this._parseRecords(res);
|
|
|
+ this.allTableData = items;
|
|
|
+ this.shelvedItemKeys = this._extractShelvedKeys(items);
|
|
|
+ this.tableData = items;
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('加载物品清单失败:', e);
|
|
|
+ this.$message.error('加载物品清单失败');
|
|
|
+ } finally {
|
|
|
+ this.tableLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ _parseRecords(res) {
|
|
|
+ const detailList = res.outInDetailList || [];
|
|
|
+ const extInfo = res.extInfo || {};
|
|
|
+ return detailList.map((item, index) => {
|
|
|
+ const recordList = item.outInDetailRecordRequestList || [];
|
|
|
+ const isUpper = recordList.some(
|
|
|
+ (r) => r.areaId && r.goodsShelfId && r.goodsAllocationId
|
|
|
+ );
|
|
|
+ return {
|
|
|
+ ...item,
|
|
|
+ _index: index,
|
|
|
+ _shelved: isUpper,
|
|
|
+ categoryCode: item.categoryCode || '',
|
|
|
+ categoryName: item.categoryName || '',
|
|
|
+ batchNo: item.batchNo || '',
|
|
|
+ measureQuantity: item.measureQuantity || 0,
|
|
|
+ measureUnit: item.measureUnit || '',
|
|
|
+ packingQuantity: item.packingQuantity || item.measureQuantity || 0,
|
|
|
+ packingUnit: item.packingUnit || item.measureUnit || '',
|
|
|
+ singleWeight: item.singleWeight || '',
|
|
|
+ totalWeight: item.totalWeight || '',
|
|
|
+ weightUnit: item.weightUnit || '',
|
|
|
+ colorKey: item.colorKey || '',
|
|
|
+ categoryModel: item.categoryModel || '',
|
|
|
+ specification: item.specification || '',
|
|
|
+ gradeName: item.gradeName || '',
|
|
|
+ voltage: item.voltage || '',
|
|
|
+ approvalNumber: item.approvalNumber || '',
|
|
|
+ packingSpec: item.packingSpec || '',
|
|
|
+ allowUnpack:
|
|
|
+ item.allowUnpack != null ? (item.allowUnpack ? '是' : '否') : '',
|
|
|
+ supplierName: item.supplierName || extInfo.supplierName || '',
|
|
|
+ warehouseName: item.warehouseName || '',
|
|
|
+ productionDate: item.productionDate || '',
|
|
|
+ purchaseDate: item.purchaseDate || '',
|
|
|
+ expiryDate: item.expiryDate || ''
|
|
|
+ };
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ _extractShelvedKeys(items) {
|
|
|
+ return items.filter((it) => it._shelved).map((it) => this._getRowKey(it));
|
|
|
+ },
|
|
|
+
|
|
|
+ _getRowKey(row) {
|
|
|
+ return `${row.categoryId || ''}_${row.batchNo || ''}`;
|
|
|
+ },
|
|
|
+
|
|
|
+ checkSelectable(row) {
|
|
|
+ return !this.shelvedItemKeys.includes(this._getRowKey(row));
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSelectionChange(selection) {
|
|
|
+ this.selection = selection;
|
|
|
+ this.buildDefaultShelvingList();
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 自动匹配上架列表 ====================
|
|
|
+ buildDefaultShelvingList() {
|
|
|
+ const items = this.selection.filter((it) => !it._shelved);
|
|
|
+ const locs = this.selectedLocations;
|
|
|
+
|
|
|
+ if (items.length === 0 || locs.length === 0) {
|
|
|
+ this.shelvingList = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let newList = null;
|
|
|
+
|
|
|
+ // ① 单个物品 + 单个货位
|
|
|
+ if (items.length === 1 && locs.length === 1) {
|
|
|
+ const item = items[0];
|
|
|
+ newList = [
|
|
|
+ {
|
|
|
+ cargoSpaceId: locs[0].id,
|
|
|
+ cargoSpaceCode: locs[0].goodsAllocationCode,
|
|
|
+ itemKey: this._getRowKey(item),
|
|
|
+ quantity: item.measureQuantity,
|
|
|
+ maxQuantity: item.measureQuantity
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ // ② 多个物品 + 单个货位
|
|
|
+ else if (items.length > 1 && locs.length === 1) {
|
|
|
+ newList = items.map((item) => ({
|
|
|
+ cargoSpaceId: locs[0].id,
|
|
|
+ cargoSpaceCode: locs[0].goodsAllocationCode,
|
|
|
+ itemKey: this._getRowKey(item),
|
|
|
+ quantity: item.measureQuantity,
|
|
|
+ maxQuantity: item.measureQuantity
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ // ③ 多个物品 + 多个货位,且数量相等
|
|
|
+ else if (items.length > 1 && locs.length > 1 && items.length === locs.length) {
|
|
|
+ newList = items.map((item, idx) => ({
|
|
|
+ cargoSpaceId: locs[idx].id,
|
|
|
+ cargoSpaceCode: locs[idx].goodsAllocationCode,
|
|
|
+ itemKey: this._getRowKey(item),
|
|
|
+ quantity: item.measureQuantity,
|
|
|
+ maxQuantity: item.measureQuantity
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (newList) {
|
|
|
+ this.shelvingList = newList;
|
|
|
+ }
|
|
|
+ // ④ 其他情况:无法默认,保持现有内容(如果有)
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 仓库/库区/货架/货位 ====================
|
|
|
+ async _getWarehouseList() {
|
|
|
+ const res = await warehouseDefinition.list({});
|
|
|
+ this.warehouseList = res.map((item) => {
|
|
|
+ return { ...item, name: item.name };
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ warehouseChange() {
|
|
|
+ this.cur = {};
|
|
|
+ this.shelves = '';
|
|
|
+ this.locationList = [];
|
|
|
+ this.area = '';
|
|
|
+ this.selectedLocations = [];
|
|
|
+ this.shelvingList = [];
|
|
|
+ },
|
|
|
+
|
|
|
+ async changeWarehouse(val) {
|
|
|
+ this.formData.warehouse = val;
|
|
|
+ const res = await warehouseDefinition.getListByWarehouseId(val.id);
|
|
|
+ this.area = '';
|
|
|
+ this.shelves = '';
|
|
|
+ this.areaList = res || [];
|
|
|
+ this.selectedLocations = [];
|
|
|
+ this.shelvingList = [];
|
|
|
+ },
|
|
|
+
|
|
|
+ async getshelvesList(e) {
|
|
|
+ this.cur = {};
|
|
|
+ this.shelves = '';
|
|
|
+ this.locationList = [];
|
|
|
+ this.selectedLocations = [];
|
|
|
+ this.shelvingList = [];
|
|
|
+ const rep = await warehouseDefinition.getListByAreaId(e);
|
|
|
+ this.shelvesList = rep || [];
|
|
|
+ },
|
|
|
+
|
|
|
+ async changeshelvesList(id) {
|
|
|
+ this.cur = {};
|
|
|
+ this.selectedLocations = [];
|
|
|
+ this.shelvingList = [];
|
|
|
+ if (!this.shelvesList.length) {
|
|
|
+ this.locationList = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const matched = this.shelvesList.find((item) => item.goodsshelvesCode == id);
|
|
|
+ if (!matched) {
|
|
|
+ this.locationList = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const res = await warehouseDefinition.getListByGoodId(matched.id);
|
|
|
+ this.locationList = res || [];
|
|
|
+ },
|
|
|
+
|
|
|
+ getStatus: useDict(locationStatusList),
|
|
|
+
|
|
|
+ // ==================== 货位点击(多选) ====================
|
|
|
+ handlCur(row) {
|
|
|
+ if (![1, 2].includes(row.allocationStatus)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const { area, shelves, warehouse } = this.formData;
|
|
|
+ if (!warehouse?.id || !area?.id || !shelves?.id) {
|
|
|
+ this.$message.warning('请先选择仓库、库区和货架');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const idx = this.selectedLocations.findIndex((l) => l.id === row.id);
|
|
|
+ if (idx > -1) {
|
|
|
+ this.selectedLocations.splice(idx, 1);
|
|
|
+ } else {
|
|
|
+ this.selectedLocations.push({
|
|
|
+ id: row.id,
|
|
|
+ goodsAllocationCode: row.goodsAllocationCode,
|
|
|
+ warehouseId: warehouse.id,
|
|
|
+ warehouseName: warehouse.name,
|
|
|
+ areaId: area.id,
|
|
|
+ areaName: area.name,
|
|
|
+ shelfId: shelves.id,
|
|
|
+ shelfCode: shelves.goodsshelvesCode
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ this.buildDefaultShelvingList();
|
|
|
+ },
|
|
|
+
|
|
|
+ isLocationSelected(id) {
|
|
|
+ return this.selectedLocations.some((l) => l.id === id);
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 上架清单操作 ====================
|
|
|
+ addRow() {
|
|
|
+ this.shelvingList.push({
|
|
|
+ cargoSpaceId: '',
|
|
|
+ cargoSpaceCode: '',
|
|
|
+ itemKey: '',
|
|
|
+ quantity: 0,
|
|
|
+ maxQuantity: 0
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ delItem(index) {
|
|
|
+ this.shelvingList.splice(index, 1);
|
|
|
+ },
|
|
|
+
|
|
|
+ onLocationChange(val, row) {
|
|
|
+ const loc = this.selectedLocations.find((l) => l.id === val);
|
|
|
+ if (loc) {
|
|
|
+ row.cargoSpaceCode = loc.goodsAllocationCode;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ onItemChange(val, row) {
|
|
|
+ const item = this.allTableData.find((it) => this._getRowKey(it) === val);
|
|
|
+ if (item) {
|
|
|
+ row.maxQuantity = parseFloat(item.measureQuantity) || 0;
|
|
|
+ if (row.quantity > row.maxQuantity) {
|
|
|
+ row.quantity = row.maxQuantity;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // ==================== 确认提交 ====================
|
|
|
+ handleSelect() {
|
|
|
+ const items = this.selection.filter((it) => !it._shelved);
|
|
|
+ if (items.length === 0) {
|
|
|
+ this.$message.error('请选择需要上架的物品');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.shelvingList.length === 0) {
|
|
|
+ this.$message.error('请配置上架信息');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查每行必填
|
|
|
+ for (let i = 0; i < this.shelvingList.length; i++) {
|
|
|
+ const row = this.shelvingList[i];
|
|
|
+ if (!row.cargoSpaceId) {
|
|
|
+ this.$message.error(`第 ${i + 1} 行未选择货位`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!row.itemKey) {
|
|
|
+ this.$message.error(`第 ${i + 1} 行未选择物品批次`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (row.quantity === null || row.quantity === undefined || row.quantity <= 0) {
|
|
|
+ this.$message.error(`第 ${i + 1} 行数量必须大于0`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 校验每个物品的总上架数量必须等于物品数量
|
|
|
+ const itemTotalMap = {};
|
|
|
+ this.shelvingList.forEach((row) => {
|
|
|
+ if (!itemTotalMap[row.itemKey]) itemTotalMap[row.itemKey] = 0;
|
|
|
+ itemTotalMap[row.itemKey] += parseFloat(row.quantity) || 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ for (const item of items) {
|
|
|
+ const key = this._getRowKey(item);
|
|
|
+ const total = itemTotalMap[key] || 0;
|
|
|
+ const expect = parseFloat(item.measureQuantity) || 0;
|
|
|
+ if (total !== expect) {
|
|
|
+ this.$message.error(
|
|
|
+ `物品 ${item.categoryName || ''}(${item.batchNo || ''})的上架数量 ${total} 不等于物品数量 ${expect},请确认全部上架`
|
|
|
+ );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 组装提交数据
|
|
|
+ this.confirmLoading = true;
|
|
|
+ const outInDetailList = [];
|
|
|
+ this.shelvingList.forEach((row) => {
|
|
|
+ const matchedItem = this.allTableData.find(
|
|
|
+ (it) => this._getRowKey(it) === row.itemKey
|
|
|
+ );
|
|
|
+ const loc = this.selectedLocations.find((l) => l.id === row.cargoSpaceId);
|
|
|
+ if (matchedItem && loc) {
|
|
|
+ outInDetailList.push({
|
|
|
+ id: matchedItem.id,
|
|
|
+ warehouseId: loc.warehouseId,
|
|
|
+ warehouseName: loc.warehouseName,
|
|
|
+ areaId: loc.areaId,
|
|
|
+ areaName: loc.areaName,
|
|
|
+ goodsShelfId: loc.shelfId,
|
|
|
+ goodsShelfName: loc.shelfCode,
|
|
|
+ goodsAllocationId: row.cargoSpaceId,
|
|
|
+ goodsAllocationName: row.cargoSpaceCode,
|
|
|
+ measureQuantity: row.quantity,
|
|
|
+ categoryId: matchedItem.categoryId,
|
|
|
+ batchNo: matchedItem.batchNo
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const payload = {
|
|
|
+ id: this.rowData.id,
|
|
|
+ outInDetailList
|
|
|
+ };
|
|
|
+
|
|
|
+ storageApi
|
|
|
+ .upperLowerShelves(payload)
|
|
|
+ .then(() => {
|
|
|
+ this.$message.success('上架成功');
|
|
|
+ this.$emit('done');
|
|
|
+ this.cancel();
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ this.$message.error(e.message || '上架失败');
|
|
|
+ })
|
|
|
+ .finally(() => {
|
|
|
+ this.confirmLoading = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .section-title {
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 14px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ border-left: 3px solid #409eff;
|
|
|
+ padding-left: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dimension-tabs {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ .dimension-label {
|
|
|
+ font-weight: bold;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .status-legend {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin: 12px 0;
|
|
|
+ div {
|
|
|
+ margin: 0 12px;
|
|
|
+ }
|
|
|
+ span {
|
|
|
+ display: inline-block;
|
|
|
+ width: 13px;
|
|
|
+ height: 13px;
|
|
|
+ margin: 0 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .content-box {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ max-height: 40vh;
|
|
|
+ overflow: auto;
|
|
|
+ .box {
|
|
|
+ cursor: pointer;
|
|
|
+ width: 134px;
|
|
|
+ height: 64px;
|
|
|
+ background-clip: content-box;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ line-height: 64px;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 13px;
|
|
|
+ border: 2px solid transparent;
|
|
|
+ &:hover,
|
|
|
+ &.selected {
|
|
|
+ box-shadow: 2px 2px 2px 2px #ccc;
|
|
|
+ }
|
|
|
+ &.selected {
|
|
|
+ border-color: #409eff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .placeholder-box {
|
|
|
+ width: 134px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-footer {
|
|
|
+ text-align: right;
|
|
|
+ margin-top: 16px;
|
|
|
+ }
|
|
|
+</style>
|