feat: 新增托盘库存网格(任务6)
This commit is contained in:
@@ -0,0 +1,168 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { LmsStockingIvtApi } from '#/api/lms/stockingivt';
|
||||||
|
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { Spin, Tooltip } from 'antdv-next';
|
||||||
|
|
||||||
|
import { getPaperVehicleInventory } from '#/api/lms/stockingivt';
|
||||||
|
|
||||||
|
interface PalletCell {
|
||||||
|
colNum: number;
|
||||||
|
inventory?: LmsStockingIvtApi.PaperVehicleInventory;
|
||||||
|
rowNum: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vehicleCode = ref('');
|
||||||
|
const inventoryList = ref<LmsStockingIvtApi.PaperVehicleInventory[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const modalTitle = computed(() => `托盘 ${vehicleCode.value} 的库存`);
|
||||||
|
const occupiedCount = computed(() => inventoryList.value.length);
|
||||||
|
const cells = computed<PalletCell[]>(() => {
|
||||||
|
const inventoryMap = new Map(
|
||||||
|
inventoryList.value.map((item) => [`${item.rowNum}:${item.colNum}`, item]),
|
||||||
|
);
|
||||||
|
return Array.from({ length: 25 }, (_, index) => {
|
||||||
|
const rowNum = Math.floor(index / 5) + 1;
|
||||||
|
const colNum = (index % 5) + 1;
|
||||||
|
return {
|
||||||
|
colNum,
|
||||||
|
inventory: inventoryMap.get(`${rowNum}:${colNum}`),
|
||||||
|
rowNum,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
footer: false,
|
||||||
|
async onOpenChange(isOpen) {
|
||||||
|
if (!isOpen) {
|
||||||
|
vehicleCode.value = '';
|
||||||
|
inventoryList.value = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = modalApi.getData<{ vehicleCode: string }>();
|
||||||
|
if (!data?.vehicleCode) return;
|
||||||
|
vehicleCode.value = data.vehicleCode;
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
inventoryList.value = await getPaperVehicleInventory(data.vehicleCode);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal class="w-[900px] max-w-[96vw]" :title="modalTitle">
|
||||||
|
<Spin :spinning="loading">
|
||||||
|
<div class="px-3 pb-4">
|
||||||
|
<div class="mb-4 flex justify-end gap-6 text-sm">
|
||||||
|
<span>已占用 {{ occupiedCount }} / 25</span>
|
||||||
|
<span>空位 {{ 25 - occupiedCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="pallet-grid">
|
||||||
|
<div></div>
|
||||||
|
<div v-for="col in 5" :key="`header-${col}`" class="axis-label">
|
||||||
|
列 {{ col }}
|
||||||
|
</div>
|
||||||
|
<template v-for="row in 5" :key="`row-${row}`">
|
||||||
|
<div class="axis-label">行 {{ row }}</div>
|
||||||
|
<Tooltip
|
||||||
|
v-for="cell in cells.slice((row - 1) * 5, row * 5)"
|
||||||
|
:key="`${cell.rowNum}-${cell.colNum}`"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<div>位置:第 {{ cell.rowNum }} 行,第 {{ cell.colNum }} 列</div>
|
||||||
|
<template v-if="cell.inventory">
|
||||||
|
<div>物料编码:{{ cell.inventory.materialCode }}</div>
|
||||||
|
<div>物料名称:{{ cell.inventory.materialName }}</div>
|
||||||
|
<div>数量:{{ cell.inventory.qty }}</div>
|
||||||
|
</template>
|
||||||
|
<div v-else>空位</div>
|
||||||
|
</template>
|
||||||
|
<div :class="['pallet-cell', { occupied: cell.inventory }]">
|
||||||
|
<template v-if="cell.inventory">
|
||||||
|
<strong>{{ cell.inventory.materialCode }}</strong>
|
||||||
|
<span>{{ cell.inventory.materialName }}</span>
|
||||||
|
</template>
|
||||||
|
<span v-else>空</span>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex gap-6 text-sm text-gray-500">
|
||||||
|
<span class="legend"><i class="legend-block occupied"></i>有物料(1 根)</span>
|
||||||
|
<span class="legend"><i class="legend-block"></i>空位</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pallet-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 48px repeat(5, minmax(100px, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.axis-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pallet-cell {
|
||||||
|
display: flex;
|
||||||
|
min-height: 72px;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 8px;
|
||||||
|
color: #999;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pallet-cell.occupied {
|
||||||
|
color: #1f1f1f;
|
||||||
|
border: 1px solid #91caff;
|
||||||
|
background: #e6f4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pallet-cell span {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 12px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-block {
|
||||||
|
width: 13px;
|
||||||
|
height: 13px;
|
||||||
|
margin-right: 6px;
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-block.occupied {
|
||||||
|
border: 1px solid #91caff;
|
||||||
|
background: #e6f4ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user