|
|
|
|
@ -38,7 +38,7 @@
|
|
|
|
|
</el-form>
|
|
|
|
|
</ContentWrap>
|
|
|
|
|
|
|
|
|
|
<div class="stock-overview__cards">
|
|
|
|
|
<div v-loading="cardsLoading" class="stock-overview__cards">
|
|
|
|
|
<ContentWrap v-for="item in summaryCards" :key="item.title" class="stock-overview__card-wrap"
|
|
|
|
|
:body-style="{ padding: '22px 24px' }">
|
|
|
|
|
<div class="stock-overview__card">
|
|
|
|
|
@ -177,7 +177,7 @@
|
|
|
|
|
import { DICT_TYPE, getDictObj, getIntDictOptions } from '@/utils/dict'
|
|
|
|
|
import { isHexColor } from '@/utils/color'
|
|
|
|
|
import { formatDate } from '@/utils/formatTime'
|
|
|
|
|
import { StockApi, StockVO } from '@/api/erp/stock/stock'
|
|
|
|
|
import { StockApi, type StockStatisticsCardsRespVO, type StockVO } from '@/api/erp/stock/stock'
|
|
|
|
|
import { StockRecordApi, StockRecordVO } from '@/api/erp/stock/record'
|
|
|
|
|
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
|
|
|
|
|
import { useDictStoreWithOut } from '@/store/modules/dict'
|
|
|
|
|
@ -204,10 +204,12 @@ const queryParams = reactive<{
|
|
|
|
|
dateRange: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const cardsLoading = ref(false)
|
|
|
|
|
const stockLoading = ref(false)
|
|
|
|
|
const recordLoading = ref(false)
|
|
|
|
|
const stockList = ref<StockVO[]>([])
|
|
|
|
|
const recordList = ref<StockRecordVO[]>([])
|
|
|
|
|
const statisticsCards = ref<StockStatisticsCardsRespVO>()
|
|
|
|
|
const stockTotal = ref(0)
|
|
|
|
|
const stockQuery = reactive({
|
|
|
|
|
pageNo: 1,
|
|
|
|
|
@ -218,79 +220,78 @@ const recordQuery = reactive({
|
|
|
|
|
pageSize: 9
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const summaryCards = computed(() => [
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.finishedGoods.title'),
|
|
|
|
|
icon: 'ep:box',
|
|
|
|
|
color: 'blue',
|
|
|
|
|
lines: [
|
|
|
|
|
t('ErpStock.Overview.cards.finishedGoods.line1'),
|
|
|
|
|
t('ErpStock.Overview.cards.finishedGoods.line2'),
|
|
|
|
|
t('ErpStock.Overview.cards.finishedGoods.line3')
|
|
|
|
|
],
|
|
|
|
|
tip: t('ErpStock.Overview.cards.finishedGoods.tip')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.rawMaterial.title'),
|
|
|
|
|
icon: 'ep:collection',
|
|
|
|
|
color: 'green',
|
|
|
|
|
lines: [
|
|
|
|
|
t('ErpStock.Overview.cards.rawMaterial.line1'),
|
|
|
|
|
t('ErpStock.Overview.cards.rawMaterial.line2'),
|
|
|
|
|
t('ErpStock.Overview.cards.rawMaterial.line3'),
|
|
|
|
|
t('ErpStock.Overview.cards.rawMaterial.line4')
|
|
|
|
|
],
|
|
|
|
|
tip: t('ErpStock.Overview.cards.rawMaterial.tip')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.sparePart.title'),
|
|
|
|
|
icon: 'ep:setting',
|
|
|
|
|
color: 'orange',
|
|
|
|
|
lines: [
|
|
|
|
|
t('ErpStock.Overview.cards.sparePart.line1'),
|
|
|
|
|
t('ErpStock.Overview.cards.sparePart.line2'),
|
|
|
|
|
t('ErpStock.Overview.cards.sparePart.line3'),
|
|
|
|
|
t('ErpStock.Overview.cards.sparePart.line4')
|
|
|
|
|
],
|
|
|
|
|
tip: t('ErpStock.Overview.cards.sparePart.tip')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.todayIn.title'),
|
|
|
|
|
icon: 'ep:download',
|
|
|
|
|
color: 'blue',
|
|
|
|
|
lines: [
|
|
|
|
|
t('ErpStock.Overview.cards.todayIn.line1'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayIn.line2'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayIn.line3'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayIn.line4'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayIn.line5')
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.todayOut.title'),
|
|
|
|
|
icon: 'ep:upload',
|
|
|
|
|
color: 'green',
|
|
|
|
|
lines: [
|
|
|
|
|
t('ErpStock.Overview.cards.todayOut.line1'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayOut.line2'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayOut.line3'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayOut.line4'),
|
|
|
|
|
t('ErpStock.Overview.cards.todayOut.line5')
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.warning.title'),
|
|
|
|
|
icon: 'ep:warning-filled',
|
|
|
|
|
color: 'red',
|
|
|
|
|
lines: [
|
|
|
|
|
t('ErpStock.Overview.cards.warning.line1'),
|
|
|
|
|
t('ErpStock.Overview.cards.warning.line2'),
|
|
|
|
|
t('ErpStock.Overview.cards.warning.line3'),
|
|
|
|
|
t('ErpStock.Overview.cards.warning.line4')
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
])
|
|
|
|
|
const displayValue = (value: unknown) => {
|
|
|
|
|
return value === undefined || value === null || value === '' ? '-' : value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const formatCardLine = (label: string, value: unknown) => `${label}: ${displayValue(value)}`
|
|
|
|
|
|
|
|
|
|
const summaryCards = computed(() => {
|
|
|
|
|
const data: StockStatisticsCardsRespVO = statisticsCards.value || {}
|
|
|
|
|
const productStock = data.productStock || {}
|
|
|
|
|
const materialStock = data.materialStock || {}
|
|
|
|
|
const sparePartStock = data.sparePartStock || {}
|
|
|
|
|
const todayIn = data.todayIn || {}
|
|
|
|
|
const todayOut = data.todayOut || {}
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.finishedGoods.title'),
|
|
|
|
|
icon: 'ep:box',
|
|
|
|
|
color: 'blue',
|
|
|
|
|
lines: [
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.sku'), productStock.skuCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.stockSummary'), productStock.stockDisplay),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.todayFinishedIn'), productStock.todayFinishedInDisplay)
|
|
|
|
|
],
|
|
|
|
|
tip: t('ErpStock.Overview.cards.finishedGoods.tip')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.rawMaterial.title'),
|
|
|
|
|
icon: 'ep:collection',
|
|
|
|
|
color: 'green',
|
|
|
|
|
lines: [
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.materialSku'), materialStock.skuCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.stockSummary'), materialStock.stockDisplay)
|
|
|
|
|
],
|
|
|
|
|
tip: t('ErpStock.Overview.cards.rawMaterial.tip')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.sparePart.title'),
|
|
|
|
|
icon: 'ep:setting',
|
|
|
|
|
color: 'orange',
|
|
|
|
|
lines: [
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.sparePartSku'), sparePartStock.skuCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.stockSummary'), sparePartStock.stockDisplay)
|
|
|
|
|
],
|
|
|
|
|
tip: t('ErpStock.Overview.cards.sparePart.tip')
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.todayIn.title'),
|
|
|
|
|
icon: 'ep:download',
|
|
|
|
|
color: 'blue',
|
|
|
|
|
lines: [
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.inboundOrders'), todayIn.orderCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.detailLines'), todayIn.itemCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.productIn'), todayIn.productDisplay),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.materialIn'), todayIn.materialDisplay),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.sparePartIn'), todayIn.sparePartDisplay)
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: t('ErpStock.Overview.cards.todayOut.title'),
|
|
|
|
|
icon: 'ep:upload',
|
|
|
|
|
color: 'green',
|
|
|
|
|
lines: [
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.outboundOrders'), todayOut.orderCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.detailLines'), todayOut.itemCount),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.materialOut'), todayOut.materialDisplay),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.sparePartOut'), todayOut.sparePartDisplay),
|
|
|
|
|
formatCardLine(t('ErpStock.Overview.cardLabels.productOut'), todayOut.productDisplay)
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
const areaOptions = computed(() => {
|
|
|
|
|
const areaMap = new Map<number, { id: number; areaName: string }>()
|
|
|
|
|
warehouseList.value.forEach((warehouse) => {
|
|
|
|
|
@ -323,6 +324,14 @@ const buildBaseQueryParams = () => {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStatisticsCards = async () => {
|
|
|
|
|
cardsLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
statisticsCards.value = await StockApi.getStockStatisticsCards()
|
|
|
|
|
} finally {
|
|
|
|
|
cardsLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const getStockList = async () => {
|
|
|
|
|
stockLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
@ -357,7 +366,7 @@ const getRecordList = async () => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getList = async () => {
|
|
|
|
|
await Promise.all([getStockList(), getRecordList()])
|
|
|
|
|
await Promise.all([getStatisticsCards(), getStockList(), getRecordList()])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleQuery = () => {
|
|
|
|
|
@ -476,7 +485,7 @@ onMounted(async () => {
|
|
|
|
|
|
|
|
|
|
.stock-overview__cards {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
|
|
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
|
|
|
gap: 14px;
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
}
|
|
|
|
|
|