feat(wms):优化首页的代码实现
parent
58537a34c7
commit
ae54f938cf
|
|
@ -3,26 +3,26 @@ import request from '@/config/axios'
|
||||||
// WMS 首页统计查询参数
|
// WMS 首页统计查询参数
|
||||||
export interface WmsHomeStatisticsReqVO {
|
export interface WmsHomeStatisticsReqVO {
|
||||||
warehouseId?: number
|
warehouseId?: number
|
||||||
|
goodsLimit?: number
|
||||||
|
warehouseLimit?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// WMS 首页单据状态统计 VO
|
// WMS 首页单据状态统计 VO
|
||||||
export interface WmsHomeOrderStatusVO {
|
export interface WmsHomeOrderStatusVO {
|
||||||
status: number
|
status: number
|
||||||
statusName: string
|
|
||||||
count: number
|
count: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// WMS 首页单据汇总统计 VO
|
// WMS 首页单据汇总统计 VO
|
||||||
export interface WmsHomeOrderSummaryVO {
|
export interface WmsHomeOrderSummaryVO {
|
||||||
orderType: number
|
type: number
|
||||||
orderTypeName: string
|
|
||||||
total: number
|
total: number
|
||||||
statusList: WmsHomeOrderStatusVO[]
|
statuses: WmsHomeOrderStatusVO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// WMS 首页单据趋势 VO
|
// WMS 首页单据趋势 VO
|
||||||
export interface WmsHomeOrderTrendVO {
|
export interface WmsHomeOrderTrendVO {
|
||||||
date: string
|
time: string | number
|
||||||
receiptCount: number
|
receiptCount: number
|
||||||
shipmentCount: number
|
shipmentCount: number
|
||||||
movementCount: number
|
movementCount: number
|
||||||
|
|
@ -31,15 +31,15 @@ export interface WmsHomeOrderTrendVO {
|
||||||
|
|
||||||
// WMS 首页商品库存排行 VO
|
// WMS 首页商品库存排行 VO
|
||||||
export interface WmsHomeInventoryItemRankVO {
|
export interface WmsHomeInventoryItemRankVO {
|
||||||
itemId: number
|
id: number
|
||||||
itemName: string
|
name: string
|
||||||
quantity: number
|
quantity: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// WMS 首页仓库库存排行 VO
|
// WMS 首页仓库库存排行 VO
|
||||||
export interface WmsHomeInventoryWarehouseRankVO {
|
export interface WmsHomeInventoryWarehouseRankVO {
|
||||||
warehouseId: number
|
id: number
|
||||||
warehouseName: string
|
name: string
|
||||||
quantity: number
|
quantity: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
<template>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :lg="12" :md="24" :sm="24" :xl="12" :xs="24">
|
||||||
|
<div
|
||||||
|
class="mb-16px border border-[var(--el-border-color-light)] border-solid rounded-[var(--wms-card-radius)] bg-[var(--el-bg-color)] p-18px shadow-[0_8px_24px_rgba(15,23,42,0.04)]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mb-12px flex items-center justify-between gap-12px lt-sm:flex-col lt-sm:items-start"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="text-16px font-600 text-[var(--el-text-color-primary)]">货物占比</div>
|
||||||
|
<div class="text-13px text-[var(--el-text-color-secondary)]">
|
||||||
|
按商品库存数量汇总 Top 5
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-skeleton :loading="loading" animated>
|
||||||
|
<Echart :height="300" :options="goodsShareChartOptions" />
|
||||||
|
</el-skeleton>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :lg="12" :md="24" :sm="24" :xl="12" :xs="24">
|
||||||
|
<div
|
||||||
|
class="mb-16px border border-[var(--el-border-color-light)] border-solid rounded-[var(--wms-card-radius)] bg-[var(--el-bg-color)] p-18px shadow-[0_8px_24px_rgba(15,23,42,0.04)]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mb-12px flex items-center justify-between gap-12px lt-sm:flex-col lt-sm:items-start"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="text-16px font-600 text-[var(--el-text-color-primary)]">库存分布</div>
|
||||||
|
<div class="text-13px text-[var(--el-text-color-secondary)]">按仓库库存数量汇总</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-14px font-600 text-[var(--el-text-color-primary)]">
|
||||||
|
总库存 {{ formatQuantityText(totalQuantity) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-skeleton :loading="loading" animated>
|
||||||
|
<Echart :height="300" :options="inventoryDistributionChartOptions" />
|
||||||
|
</el-skeleton>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { EChartsOption } from 'echarts'
|
||||||
|
import { WmsHomeStatisticsApi } from '@/api/wms/home'
|
||||||
|
import { formatQuantity } from '@/views/wms/utils/format'
|
||||||
|
|
||||||
|
defineOptions({ name: 'WmsHomeInventoryCharts' })
|
||||||
|
|
||||||
|
interface ChartItem {
|
||||||
|
name: string
|
||||||
|
value: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const GOODS_SHARE_LIMIT = 5
|
||||||
|
const WAREHOUSE_DISTRIBUTION_LIMIT = 8
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const totalQuantity = ref(0)
|
||||||
|
const goodsShareList = ref<ChartItem[]>([])
|
||||||
|
const inventoryDistributionList = ref<ChartItem[]>([])
|
||||||
|
|
||||||
|
/** 格式化库存数量展示 */
|
||||||
|
const formatQuantityText = (value: number) => formatQuantity(value) || '0.00'
|
||||||
|
|
||||||
|
const chartFontFamily =
|
||||||
|
"Inter, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif"
|
||||||
|
const chartTextStyle = {
|
||||||
|
color: '#303133',
|
||||||
|
fontFamily: chartFontFamily,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 400,
|
||||||
|
textBorderWidth: 0,
|
||||||
|
textShadowBlur: 0
|
||||||
|
}
|
||||||
|
const chartAxisLabelStyle = {
|
||||||
|
color: '#8a9099',
|
||||||
|
fontFamily: chartFontFamily,
|
||||||
|
fontSize: 12,
|
||||||
|
textBorderWidth: 0,
|
||||||
|
textShadowBlur: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 构建图表数据项,并过滤零库存数据 */
|
||||||
|
const buildChartItemList = <T,>(
|
||||||
|
list: T[] | undefined,
|
||||||
|
nameGetter: (item: T) => string,
|
||||||
|
valueGetter: (item: T) => number | undefined
|
||||||
|
) => {
|
||||||
|
return (list || [])
|
||||||
|
.map((item) => ({
|
||||||
|
name: nameGetter(item),
|
||||||
|
value: Number(valueGetter(item) || 0)
|
||||||
|
}))
|
||||||
|
.filter((item) => item.value > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化货物占比图例,补充库存占比 */
|
||||||
|
const formatGoodsLegend = (name: string) => {
|
||||||
|
const total = goodsShareList.value.reduce((sum, item) => sum + item.value, 0)
|
||||||
|
const item = goodsShareList.value.find((goods) => goods.name === name)
|
||||||
|
if (!total || !item) {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return `${name} ${((item.value / total) * 100).toFixed(1)}%`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载库存汇总数据 */
|
||||||
|
const load = async (warehouseId?: number) => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await WmsHomeStatisticsApi.getInventorySummary({
|
||||||
|
...(warehouseId ? { warehouseId } : {}),
|
||||||
|
goodsLimit: GOODS_SHARE_LIMIT,
|
||||||
|
warehouseLimit: WAREHOUSE_DISTRIBUTION_LIMIT
|
||||||
|
})
|
||||||
|
totalQuantity.value = Number(data.totalQuantity || 0)
|
||||||
|
goodsShareList.value = buildChartItemList(
|
||||||
|
data.goodsShareList,
|
||||||
|
(item) => item.name || '未命名商品',
|
||||||
|
(item) => item.quantity
|
||||||
|
)
|
||||||
|
inventoryDistributionList.value = buildChartItemList(
|
||||||
|
data.warehouseDistributionList,
|
||||||
|
(item) => item.name || '未指定仓库',
|
||||||
|
(item) => item.quantity
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 货物占比图表配置 */
|
||||||
|
const goodsShareChartOptions = computed<EChartsOption>(() => ({
|
||||||
|
color: ['#2f7df6', '#18a058', '#f59e0b', '#7c3aed', '#14b8a6'],
|
||||||
|
textStyle: chartTextStyle,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{b}<br/>库存:{c} ({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: 'scroll',
|
||||||
|
orient: 'vertical',
|
||||||
|
right: 10,
|
||||||
|
top: 'middle',
|
||||||
|
itemWidth: 10,
|
||||||
|
itemHeight: 10,
|
||||||
|
formatter: formatGoodsLegend,
|
||||||
|
textStyle: chartTextStyle
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '货物占比',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['48%', '70%'],
|
||||||
|
center: ['34%', '52%'],
|
||||||
|
avoidLabelOverlap: true,
|
||||||
|
label: { show: false },
|
||||||
|
labelLine: { show: false },
|
||||||
|
data: goodsShareList.value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
|
||||||
|
/** 库存分布图表配置 */
|
||||||
|
const inventoryDistributionChartOptions = computed<EChartsOption>(() => ({
|
||||||
|
color: ['#2f7df6'],
|
||||||
|
grid: { top: 12, left: 24, right: 40, bottom: 16, containLabel: true },
|
||||||
|
textStyle: chartTextStyle,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: { type: 'shadow' },
|
||||||
|
formatter: (params: any) => {
|
||||||
|
const item = Array.isArray(params) ? params[0] : params
|
||||||
|
return `${item.name}<br/>库存:${formatQuantityText(item.value)}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: chartAxisLabelStyle,
|
||||||
|
splitLine: { lineStyle: { color: '#eef2f7' } }
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: inventoryDistributionList.value.map((item) => item.name).reverse(),
|
||||||
|
axisLabel: chartAxisLabelStyle,
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLine: { show: false }
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '库存',
|
||||||
|
type: 'bar',
|
||||||
|
barMaxWidth: 16,
|
||||||
|
data: inventoryDistributionList.value.map((item) => item.value).reverse(),
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'right',
|
||||||
|
...chartTextStyle,
|
||||||
|
formatter: ({ value }) => formatQuantityText(Number(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
|
||||||
|
defineExpose({ load })
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
<template>
|
||||||
|
<el-skeleton :loading="loading" animated>
|
||||||
|
<template #template>
|
||||||
|
<div class="mb-16px grid grid-cols-4 gap-16px lt-sm:grid-cols-1 lt-xl:grid-cols-2">
|
||||||
|
<el-skeleton-item
|
||||||
|
v-for="item in 4"
|
||||||
|
:key="item"
|
||||||
|
class="h-174px w-full rounded-[var(--wms-card-radius)]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="mb-16px grid grid-cols-4 gap-16px lt-sm:grid-cols-1 lt-xl:grid-cols-2">
|
||||||
|
<div
|
||||||
|
v-for="item in summaryList"
|
||||||
|
:key="item.orderType"
|
||||||
|
class="min-h-154px border border-t-3 border-[var(--el-border-color-light)] border-t-[var(--theme-color)] border-solid rounded-[var(--wms-card-radius)] bg-[var(--el-bg-color)] px-18px py-16px shadow-[0_8px_24px_rgba(15,23,42,0.04)]"
|
||||||
|
:style="{ '--theme-color': item.color }"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between gap-12px">
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-8px text-15px font-600 text-[var(--el-text-color-primary)]"
|
||||||
|
>
|
||||||
|
<span class="h-8px w-8px rounded-full" :style="{ backgroundColor: item.color }"></span>
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
<el-button link type="primary" @click="handleNavigate(item.routeName)">查看</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-18px flex items-baseline gap-8px">
|
||||||
|
<em class="not-italic text-[var(--el-text-color-secondary)]">合计</em>
|
||||||
|
<span class="text-32px font-700 leading-38px text-[var(--el-text-color-primary)]">{{
|
||||||
|
formatCount(item.total)
|
||||||
|
}}</span>
|
||||||
|
<em class="not-italic text-[var(--el-text-color-secondary)]">单</em>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-14px h-8px flex overflow-hidden rounded-full bg-[var(--el-fill-color-light)]"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-for="status in statusList"
|
||||||
|
:key="status.value"
|
||||||
|
class="h-full"
|
||||||
|
:style="{
|
||||||
|
width: getStatusPercent(item, status.value),
|
||||||
|
backgroundColor: status.color
|
||||||
|
}"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-14px grid grid-cols-3 gap-8px">
|
||||||
|
<div v-for="status in statusList" :key="status.value" class="min-w-0">
|
||||||
|
<span class="block truncate text-12px text-[var(--el-text-color-secondary)]">
|
||||||
|
{{ status.label }}
|
||||||
|
</span>
|
||||||
|
<strong class="mt-2px block text-16px" :style="{ color: status.color }">{{
|
||||||
|
item.statusCounts[status.value]
|
||||||
|
}}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-skeleton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { WmsHomeStatisticsApi } from '@/api/wms/home'
|
||||||
|
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
||||||
|
import { OrderStatusEnum } from '@/views/wms/utils/constants'
|
||||||
|
|
||||||
|
defineOptions({ name: 'WmsHomeOrderSummaryCards' })
|
||||||
|
|
||||||
|
interface StatusItem {
|
||||||
|
label: string
|
||||||
|
value: number
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderDefinition {
|
||||||
|
orderType: number
|
||||||
|
title: string
|
||||||
|
color: string
|
||||||
|
routeName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OrderSummaryItem extends OrderDefinition {
|
||||||
|
total: number
|
||||||
|
statusCounts: Record<number, number>
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const OrderTypeEnum = {
|
||||||
|
RECEIPT: 1,
|
||||||
|
SHIPMENT: 2,
|
||||||
|
MOVEMENT: 3,
|
||||||
|
CHECK: 4
|
||||||
|
} as const
|
||||||
|
|
||||||
|
/** 获取单据类型名称 */
|
||||||
|
const getOrderTypeTitle = (type: number, defaultTitle: string) => {
|
||||||
|
const label = getDictLabel(DICT_TYPE.WMS_ORDER_TYPE, type) || defaultTitle
|
||||||
|
return label.endsWith('单') ? label.slice(0, -1) : label
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取单据状态名称 */
|
||||||
|
const getOrderStatusLabel = (status: number, defaultLabel: string) => {
|
||||||
|
return getDictLabel(DICT_TYPE.WMS_ORDER_STATUS, status) || defaultLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const statusList: StatusItem[] = [
|
||||||
|
{
|
||||||
|
label: getOrderStatusLabel(OrderStatusEnum.PREPARE, '草稿'),
|
||||||
|
value: OrderStatusEnum.PREPARE,
|
||||||
|
color: '#409eff'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: getOrderStatusLabel(OrderStatusEnum.FINISHED, '已完成'),
|
||||||
|
value: OrderStatusEnum.FINISHED,
|
||||||
|
color: '#67c23a'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: getOrderStatusLabel(OrderStatusEnum.CANCELED, '已作废'),
|
||||||
|
value: OrderStatusEnum.CANCELED,
|
||||||
|
color: '#909399'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const orderDefinitions: OrderDefinition[] = [
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.RECEIPT,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.RECEIPT, '入库'),
|
||||||
|
color: '#2f7df6',
|
||||||
|
routeName: 'WmsReceiptOrder'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.SHIPMENT,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.SHIPMENT, '出库'),
|
||||||
|
color: '#18a058',
|
||||||
|
routeName: 'WmsShipmentOrder'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.MOVEMENT,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.MOVEMENT, '移库'),
|
||||||
|
color: '#f59e0b',
|
||||||
|
routeName: 'WmsMovementOrder'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.CHECK,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.CHECK, '盘库'),
|
||||||
|
color: '#7c3aed',
|
||||||
|
routeName: 'WmsCheckOrder'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 构建默认的状态数量集合 */
|
||||||
|
const buildEmptyStatusCounts = () => {
|
||||||
|
return statusList.reduce(
|
||||||
|
(result, status) => {
|
||||||
|
result[status.value] = 0
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
{} as Record<number, number>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const summaryList = ref<OrderSummaryItem[]>(
|
||||||
|
orderDefinitions.map((item) => ({
|
||||||
|
...item,
|
||||||
|
total: 0,
|
||||||
|
statusCounts: buildEmptyStatusCounts()
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 加载单据汇总数据 */
|
||||||
|
const load = async (warehouseId?: number) => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await WmsHomeStatisticsApi.getOrderSummary(warehouseId ? { warehouseId } : {})
|
||||||
|
summaryList.value = orderDefinitions.map((definition) => {
|
||||||
|
const summary = data.find((item) => item.type === definition.orderType)
|
||||||
|
const statusCounts = statusList.reduce((result, status) => {
|
||||||
|
const statusItem = summary?.statuses?.find((item) => item.status === status.value)
|
||||||
|
result[status.value] = statusItem?.count || 0
|
||||||
|
return result
|
||||||
|
}, buildEmptyStatusCounts())
|
||||||
|
return {
|
||||||
|
...definition,
|
||||||
|
total: summary?.total || 0,
|
||||||
|
statusCounts
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 跳转到对应单据列表 */
|
||||||
|
const handleNavigate = async (name: string) => {
|
||||||
|
try {
|
||||||
|
await router.push({ name })
|
||||||
|
} catch {
|
||||||
|
message.warning('当前菜单尚未加载,请从左侧菜单进入对应页面')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 计算状态进度条占比 */
|
||||||
|
const getStatusPercent = (item: OrderSummaryItem, status: number) => {
|
||||||
|
const count = item.statusCounts[status] || 0
|
||||||
|
if (!item.total || !count) {
|
||||||
|
return '0%'
|
||||||
|
}
|
||||||
|
return `${Math.max((count / item.total) * 100, 4)}%`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化单据数量 */
|
||||||
|
const formatCount = (value: number) => value.toLocaleString()
|
||||||
|
|
||||||
|
defineExpose({ load })
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="mb-16px border border-[var(--el-border-color-light)] border-solid rounded-[var(--wms-card-radius)] bg-[var(--el-bg-color)] p-18px shadow-[0_8px_24px_rgba(15,23,42,0.04)]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mb-12px flex items-center justify-between gap-12px lt-sm:flex-col lt-sm:items-start"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="text-16px font-600 text-[var(--el-text-color-primary)]">单据趋势</div>
|
||||||
|
<div class="text-13px text-[var(--el-text-color-secondary)]">
|
||||||
|
入库、出库、移库、盘库单据数量
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-segmented
|
||||||
|
v-model="trendDays"
|
||||||
|
:options="trendDayOptions"
|
||||||
|
@change="handleTrendDaysChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-skeleton :loading="loading" animated>
|
||||||
|
<Echart :height="330" :options="chartOptions" />
|
||||||
|
</el-skeleton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { EChartsOption } from 'echarts'
|
||||||
|
import { WmsHomeStatisticsApi, type WmsHomeOrderTrendVO } from '@/api/wms/home'
|
||||||
|
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
||||||
|
import { formatDate } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
defineOptions({ name: 'WmsHomeOrderTrendChart' })
|
||||||
|
|
||||||
|
interface OrderDefinition {
|
||||||
|
orderType: number
|
||||||
|
title: string
|
||||||
|
color: string
|
||||||
|
trendField: keyof Pick<
|
||||||
|
WmsHomeOrderTrendVO,
|
||||||
|
'receiptCount' | 'shipmentCount' | 'movementCount' | 'checkCount'
|
||||||
|
>
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrderTypeEnum = {
|
||||||
|
RECEIPT: 1,
|
||||||
|
SHIPMENT: 2,
|
||||||
|
MOVEMENT: 3,
|
||||||
|
CHECK: 4
|
||||||
|
} as const
|
||||||
|
|
||||||
|
/** 获取单据类型名称 */
|
||||||
|
const getOrderTypeTitle = (type: number, defaultTitle: string) => {
|
||||||
|
const label = getDictLabel(DICT_TYPE.WMS_ORDER_TYPE, type) || defaultTitle
|
||||||
|
return label.endsWith('单') ? label.slice(0, -1) : label
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderDefinitions: OrderDefinition[] = [
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.RECEIPT,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.RECEIPT, '入库'),
|
||||||
|
color: '#2f7df6',
|
||||||
|
trendField: 'receiptCount'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.SHIPMENT,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.SHIPMENT, '出库'),
|
||||||
|
color: '#18a058',
|
||||||
|
trendField: 'shipmentCount'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.MOVEMENT,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.MOVEMENT, '移库'),
|
||||||
|
color: '#f59e0b',
|
||||||
|
trendField: 'movementCount'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
orderType: OrderTypeEnum.CHECK,
|
||||||
|
title: getOrderTypeTitle(OrderTypeEnum.CHECK, '盘库'),
|
||||||
|
color: '#7c3aed',
|
||||||
|
trendField: 'checkCount'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const trendDayOptions = [
|
||||||
|
{ label: '近7天', value: 7 },
|
||||||
|
{ label: '近30天', value: 30 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const warehouseId = ref<number>()
|
||||||
|
const trendDays = ref(7)
|
||||||
|
const trendLabels = ref<string[]>([])
|
||||||
|
const trendSeriesMap = reactive<Record<number, number[]>>({
|
||||||
|
[OrderTypeEnum.RECEIPT]: [],
|
||||||
|
[OrderTypeEnum.SHIPMENT]: [],
|
||||||
|
[OrderTypeEnum.MOVEMENT]: [],
|
||||||
|
[OrderTypeEnum.CHECK]: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const chartFontFamily =
|
||||||
|
"Inter, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif"
|
||||||
|
const chartTextStyle = {
|
||||||
|
color: '#303133',
|
||||||
|
fontFamily: chartFontFamily,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 400,
|
||||||
|
textBorderWidth: 0,
|
||||||
|
textShadowBlur: 0
|
||||||
|
}
|
||||||
|
const chartAxisLabelStyle = {
|
||||||
|
color: '#8a9099',
|
||||||
|
fontFamily: chartFontFamily,
|
||||||
|
fontSize: 12,
|
||||||
|
textBorderWidth: 0,
|
||||||
|
textShadowBlur: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载单据趋势数据 */
|
||||||
|
const load = async (selectedWarehouseId?: number) => {
|
||||||
|
warehouseId.value = selectedWarehouseId
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await WmsHomeStatisticsApi.getOrderTrend(
|
||||||
|
trendDays.value,
|
||||||
|
selectedWarehouseId ? { warehouseId: selectedWarehouseId } : {}
|
||||||
|
)
|
||||||
|
trendLabels.value = data.map((item) => formatDate(new Date(item.time), 'MM-DD'))
|
||||||
|
orderDefinitions.forEach((definition) => {
|
||||||
|
trendSeriesMap[definition.orderType] = data.map((item) =>
|
||||||
|
Number(item[definition.trendField] || 0)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 切换趋势统计天数 */
|
||||||
|
const handleTrendDaysChange = async () => {
|
||||||
|
await load(warehouseId.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 单据趋势图表配置 */
|
||||||
|
const chartOptions = computed<EChartsOption>(() => ({
|
||||||
|
color: orderDefinitions.map((item) => item.color),
|
||||||
|
grid: { top: 48, left: 28, right: 24, bottom: 24, containLabel: true },
|
||||||
|
textStyle: chartTextStyle,
|
||||||
|
legend: { top: 6, itemWidth: 10, itemHeight: 10, textStyle: chartTextStyle },
|
||||||
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: trendLabels.value,
|
||||||
|
axisLabel: chartAxisLabelStyle,
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLine: { lineStyle: { color: '#dcdfe6' } }
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '单据数',
|
||||||
|
nameTextStyle: chartAxisLabelStyle,
|
||||||
|
axisLabel: chartAxisLabelStyle,
|
||||||
|
minInterval: 1,
|
||||||
|
splitLine: { lineStyle: { color: '#eef2f7' } }
|
||||||
|
},
|
||||||
|
series: orderDefinitions.map((item) => ({
|
||||||
|
name: item.title,
|
||||||
|
type: 'bar',
|
||||||
|
barMaxWidth: 18,
|
||||||
|
data: trendSeriesMap[item.orderType],
|
||||||
|
emphasis: { focus: 'series' }
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
|
||||||
|
defineExpose({ load })
|
||||||
|
</script>
|
||||||
|
|
@ -1,29 +1,25 @@
|
||||||
<!-- TODO @AI:组件拆分下。 -->
|
|
||||||
<template>
|
<template>
|
||||||
<div class="wms-home">
|
<div class="[--wms-card-radius:8px]">
|
||||||
<div class="wms-home__toolbar">
|
<div
|
||||||
<div class="wms-home__toolbar-main">
|
class="mb-16px flex flex-wrap justify-between gap-16px rounded-[var(--wms-card-radius)] border border-[var(--el-border-color-light)] border-solid bg-[var(--el-bg-color)] p-16px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex min-w-320px flex-1 flex-wrap items-center justify-between gap-16px lt-sm:w-full"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="wms-home__title">WMS 首页</div>
|
<div class="text-20px font-600 leading-28px text-[var(--el-text-color-primary)]">
|
||||||
<div class="wms-home__subtitle">单据工作台 / 库存概览</div>
|
WMS 首页
|
||||||
|
</div>
|
||||||
|
<div class="text-13px text-[var(--el-text-color-secondary)]">单据工作台 / 库存概览</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wms-home__filters">
|
<div class="flex flex-wrap items-center gap-8px lt-sm:w-full">
|
||||||
<el-select
|
<WarehouseSelect
|
||||||
v-model="warehouseId"
|
v-model="warehouseId"
|
||||||
class="!w-220px"
|
class="!w-220px"
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
placeholder="全部仓库"
|
placeholder="全部仓库"
|
||||||
@change="refresh"
|
@change="refresh()"
|
||||||
>
|
/>
|
||||||
<el-option
|
<el-button :loading="loading" @click="refresh">
|
||||||
v-for="warehouse in warehouseList"
|
|
||||||
:key="warehouse.id!"
|
|
||||||
:label="warehouse.name"
|
|
||||||
:value="warehouse.id!"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
<el-button :loading="loading || trendLoading || inventoryLoading" @click="refresh">
|
|
||||||
<Icon class="mr-5px" icon="ep:refresh" />
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
刷新
|
刷新
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -31,97 +27,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-skeleton :loading="loading" animated>
|
<WmsHomeOrderSummaryCards ref="orderSummaryCardsRef" />
|
||||||
<template #template>
|
<WmsHomeOrderTrendChart ref="orderTrendChartRef" />
|
||||||
<div class="wms-home__summary-grid">
|
<WmsHomeInventoryCharts ref="inventoryChartsRef" />
|
||||||
<el-skeleton-item v-for="item in 4" :key="item" class="wms-home__summary-skeleton" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="wms-home__summary-grid">
|
|
||||||
<div
|
|
||||||
v-for="item in orderSummaries"
|
|
||||||
:key="item.key"
|
|
||||||
class="wms-home__summary-card"
|
|
||||||
:style="{ '--theme-color': item.color }"
|
|
||||||
>
|
|
||||||
<div class="wms-home__summary-head">
|
|
||||||
<div class="wms-home__summary-title">
|
|
||||||
<span :style="{ backgroundColor: item.color }"></span>
|
|
||||||
{{ item.title }}
|
|
||||||
</div>
|
|
||||||
<el-button link type="primary" @click="handleNavigate(item.routeName)">查看</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="wms-home__summary-total">
|
|
||||||
<em>合计</em>
|
|
||||||
<span>{{ formatCount(item.total) }}</span>
|
|
||||||
<em>单</em>
|
|
||||||
</div>
|
|
||||||
<div class="wms-home__status-bar">
|
|
||||||
<span
|
|
||||||
v-for="status in statusList"
|
|
||||||
:key="status.key"
|
|
||||||
:style="{
|
|
||||||
width: getStatusPercent(item, status.key),
|
|
||||||
backgroundColor: status.color
|
|
||||||
}"
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
<div class="wms-home__status-list">
|
|
||||||
<div v-for="status in statusList" :key="status.key">
|
|
||||||
<span>{{ status.label }}</span>
|
|
||||||
<strong :style="{ color: status.color }">{{ item.statusCounts[status.key] }}</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-skeleton>
|
|
||||||
|
|
||||||
<div class="wms-home__chart-card">
|
<div
|
||||||
<div class="wms-home__card-head">
|
class="mt-2px flex items-center justify-center text-13px text-[var(--el-text-color-secondary)]"
|
||||||
<div>
|
>
|
||||||
<div class="wms-home__card-title">单据趋势</div>
|
|
||||||
<div class="wms-home__card-subtitle">入库、出库、移库、盘库单据数量</div>
|
|
||||||
</div>
|
|
||||||
<el-segmented v-model="trendDays" :options="trendDayOptions" @change="loadTrendData" />
|
|
||||||
</div>
|
|
||||||
<el-skeleton :loading="trendLoading" animated>
|
|
||||||
<Echart :height="330" :options="trendChartOptions" />
|
|
||||||
</el-skeleton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-row :gutter="16">
|
|
||||||
<el-col :lg="12" :md="24" :sm="24" :xl="12" :xs="24">
|
|
||||||
<div class="wms-home__chart-card">
|
|
||||||
<div class="wms-home__card-head">
|
|
||||||
<div>
|
|
||||||
<div class="wms-home__card-title">货物占比</div>
|
|
||||||
<div class="wms-home__card-subtitle">按商品库存数量汇总 Top 5</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<el-skeleton :loading="inventoryLoading" animated>
|
|
||||||
<Echart :height="300" :options="goodsShareChartOptions" />
|
|
||||||
</el-skeleton>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :lg="12" :md="24" :sm="24" :xl="12" :xs="24">
|
|
||||||
<div class="wms-home__chart-card">
|
|
||||||
<div class="wms-home__card-head">
|
|
||||||
<div>
|
|
||||||
<div class="wms-home__card-title">库存分布</div>
|
|
||||||
<div class="wms-home__card-subtitle">按仓库库存数量汇总</div>
|
|
||||||
</div>
|
|
||||||
<div class="wms-home__total-quantity"
|
|
||||||
>总库存 {{ formatQuantityText(totalQuantity) }}</div
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<el-skeleton :loading="inventoryLoading" animated>
|
|
||||||
<Echart :height="300" :options="inventoryDistributionChartOptions" />
|
|
||||||
</el-skeleton>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<div class="wms-home__stat-time">
|
|
||||||
<Icon class="mr-5px" icon="ep:clock" />
|
<Icon class="mr-5px" icon="ep:clock" />
|
||||||
统计时间:{{ statTime }}
|
统计时间:{{ statTime }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -129,562 +41,38 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { EChartsOption } from 'echarts'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { WmsHomeOrderTrendVO, WmsHomeStatisticsApi, WmsHomeStatisticsReqVO } from '@/api/wms/home'
|
|
||||||
import { WarehouseApi, WarehouseVO } from '@/api/wms/md/warehouse'
|
|
||||||
import { OrderStatusEnum } from '@/views/wms/utils/constants'
|
|
||||||
import { formatQuantity } from '@/views/wms/utils/format'
|
|
||||||
import { formatDate } from '@/utils/formatTime'
|
import { formatDate } from '@/utils/formatTime'
|
||||||
|
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
||||||
|
import WmsHomeInventoryCharts from './components/WmsHomeInventoryCharts.vue'
|
||||||
|
import WmsHomeOrderSummaryCards from './components/WmsHomeOrderSummaryCards.vue'
|
||||||
|
import WmsHomeOrderTrendChart from './components/WmsHomeOrderTrendChart.vue'
|
||||||
|
|
||||||
/** WMS 首页 */
|
/** WMS 首页 */
|
||||||
defineOptions({ name: 'WmsHome' })
|
defineOptions({ name: 'WmsHome' })
|
||||||
|
|
||||||
type StatusKey = 'prepare' | 'finished' | 'canceled'
|
|
||||||
type OrderKey = 'receipt' | 'shipment' | 'movement' | 'check'
|
|
||||||
|
|
||||||
interface OrderDefinition {
|
|
||||||
key: OrderKey
|
|
||||||
orderType: number
|
|
||||||
title: string
|
|
||||||
color: string
|
|
||||||
routeName: string
|
|
||||||
trendField: keyof Pick<
|
|
||||||
WmsHomeOrderTrendVO,
|
|
||||||
'receiptCount' | 'shipmentCount' | 'movementCount' | 'checkCount'
|
|
||||||
>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OrderSummary extends OrderDefinition {
|
|
||||||
total: number
|
|
||||||
statusCounts: Record<StatusKey, number>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ChartItem {
|
|
||||||
name: string
|
|
||||||
value: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const message = useMessage()
|
|
||||||
|
|
||||||
const statusList: Array<{ key: StatusKey; label: string; value: number; color: string }> = [
|
|
||||||
{ key: 'prepare', label: '草稿', value: OrderStatusEnum.PREPARE, color: '#409eff' },
|
|
||||||
{ key: 'finished', label: '已完成', value: OrderStatusEnum.FINISHED, color: '#67c23a' },
|
|
||||||
{ key: 'canceled', label: '已作废', value: OrderStatusEnum.CANCELED, color: '#909399' }
|
|
||||||
]
|
|
||||||
|
|
||||||
const OrderTypeEnum = {
|
|
||||||
RECEIPT: 1,
|
|
||||||
SHIPMENT: 2,
|
|
||||||
MOVEMENT: 3,
|
|
||||||
CHECK: 4
|
|
||||||
} as const
|
|
||||||
|
|
||||||
const orderDefinitions: OrderDefinition[] = [
|
|
||||||
{
|
|
||||||
key: 'receipt',
|
|
||||||
orderType: OrderTypeEnum.RECEIPT,
|
|
||||||
title: '入库',
|
|
||||||
color: '#2f7df6',
|
|
||||||
routeName: 'WmsReceiptOrder',
|
|
||||||
trendField: 'receiptCount'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'shipment',
|
|
||||||
orderType: OrderTypeEnum.SHIPMENT,
|
|
||||||
title: '出库',
|
|
||||||
color: '#18a058',
|
|
||||||
routeName: 'WmsShipmentOrder',
|
|
||||||
trendField: 'shipmentCount'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'movement',
|
|
||||||
orderType: OrderTypeEnum.MOVEMENT,
|
|
||||||
title: '移库',
|
|
||||||
color: '#f59e0b',
|
|
||||||
routeName: 'WmsMovementOrder',
|
|
||||||
trendField: 'movementCount'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'check',
|
|
||||||
orderType: OrderTypeEnum.CHECK,
|
|
||||||
title: '盘库',
|
|
||||||
color: '#7c3aed',
|
|
||||||
routeName: 'WmsCheckOrder',
|
|
||||||
trendField: 'checkCount'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const trendDayOptions = [
|
|
||||||
{ label: '近7天', value: 7 },
|
|
||||||
{ label: '近30天', value: 30 }
|
|
||||||
]
|
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const trendLoading = ref(false)
|
|
||||||
const inventoryLoading = ref(false)
|
|
||||||
const warehouseId = ref<number>()
|
const warehouseId = ref<number>()
|
||||||
const warehouseList = ref<WarehouseVO[]>([])
|
|
||||||
const statTime = ref(formatDate(new Date()))
|
const statTime = ref(formatDate(new Date()))
|
||||||
const orderSummaries = ref<OrderSummary[]>(
|
const orderSummaryCardsRef = ref<InstanceType<typeof WmsHomeOrderSummaryCards>>()
|
||||||
orderDefinitions.map((item) => ({
|
const orderTrendChartRef = ref<InstanceType<typeof WmsHomeOrderTrendChart>>()
|
||||||
...item,
|
const inventoryChartsRef = ref<InstanceType<typeof WmsHomeInventoryCharts>>()
|
||||||
total: 0,
|
|
||||||
statusCounts: { prepare: 0, finished: 0, canceled: 0 }
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
const trendDays = ref(7)
|
|
||||||
const trendLabels = ref<string[]>([])
|
|
||||||
const trendSeriesMap = reactive<Record<OrderKey, number[]>>({
|
|
||||||
receipt: [],
|
|
||||||
shipment: [],
|
|
||||||
movement: [],
|
|
||||||
check: []
|
|
||||||
})
|
|
||||||
const totalQuantity = ref(0)
|
|
||||||
const goodsShareList = ref<ChartItem[]>([])
|
|
||||||
const inventoryDistributionList = ref<ChartItem[]>([])
|
|
||||||
|
|
||||||
const getStatisticsParams = (): WmsHomeStatisticsReqVO => {
|
|
||||||
return warehouseId.value ? { warehouseId: warehouseId.value } : {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadOrderSummaries = async () => {
|
|
||||||
const data = await WmsHomeStatisticsApi.getOrderSummary(getStatisticsParams())
|
|
||||||
orderSummaries.value = orderDefinitions.map((definition) => {
|
|
||||||
const summary = data.find((item) => item.orderType === definition.orderType)
|
|
||||||
const statusCounts = statusList.reduce(
|
|
||||||
(result, status) => {
|
|
||||||
const statusItem = summary?.statusList?.find((item) => item.status === status.value)
|
|
||||||
result[status.key] = statusItem?.count || 0
|
|
||||||
return result
|
|
||||||
},
|
|
||||||
{ prepare: 0, finished: 0, canceled: 0 } as Record<StatusKey, number>
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
...definition,
|
|
||||||
total: summary?.total || 0,
|
|
||||||
statusCounts
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildChartItemList = <T,>(
|
|
||||||
list: T[] | undefined,
|
|
||||||
nameGetter: (item: T) => string,
|
|
||||||
valueGetter: (item: T) => number | undefined
|
|
||||||
) => {
|
|
||||||
return (list || [])
|
|
||||||
.map((item) => ({
|
|
||||||
name: nameGetter(item),
|
|
||||||
value: Number(valueGetter(item) || 0)
|
|
||||||
}))
|
|
||||||
.filter((item) => item.value > 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadTrendData = async () => {
|
|
||||||
trendLoading.value = true
|
|
||||||
try {
|
|
||||||
const data = await WmsHomeStatisticsApi.getOrderTrend(trendDays.value, getStatisticsParams())
|
|
||||||
trendLabels.value = data.map((item) => item.date.substring(5))
|
|
||||||
orderDefinitions.forEach((definition) => {
|
|
||||||
trendSeriesMap[definition.key] = data.map((item) => Number(item[definition.trendField] || 0))
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
trendLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadInventoryData = async () => {
|
|
||||||
inventoryLoading.value = true
|
|
||||||
try {
|
|
||||||
const data = await WmsHomeStatisticsApi.getInventorySummary(getStatisticsParams())
|
|
||||||
totalQuantity.value = Number(data.totalQuantity || 0)
|
|
||||||
goodsShareList.value = buildChartItemList(
|
|
||||||
data.goodsShareList,
|
|
||||||
(item) => item.itemName || '未命名商品',
|
|
||||||
(item) => item.quantity
|
|
||||||
)
|
|
||||||
inventoryDistributionList.value = buildChartItemList(
|
|
||||||
data.warehouseDistributionList,
|
|
||||||
(item) => item.warehouseName || '未指定仓库',
|
|
||||||
(item) => item.quantity
|
|
||||||
)
|
|
||||||
} finally {
|
|
||||||
inventoryLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** 刷新:重新加载各个组件的数据(传入 warehouseId 以进行针对性查询),并更新时间戳 */
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
await Promise.all([loadOrderSummaries(), loadTrendData(), loadInventoryData()])
|
await Promise.all([
|
||||||
|
orderSummaryCardsRef.value?.load(warehouseId.value),
|
||||||
|
orderTrendChartRef.value?.load(warehouseId.value),
|
||||||
|
inventoryChartsRef.value?.load(warehouseId.value)
|
||||||
|
])
|
||||||
statTime.value = formatDate(new Date())
|
statTime.value = formatDate(new Date())
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadWarehouseList = async () => {
|
onMounted(() => {
|
||||||
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
|
refresh()
|
||||||
}
|
|
||||||
|
|
||||||
const handleNavigate = async (name: string) => {
|
|
||||||
try {
|
|
||||||
await router.push({ name })
|
|
||||||
} catch {
|
|
||||||
message.warning('当前菜单尚未加载,请从左侧菜单进入对应页面')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getStatusPercent = (item: OrderSummary, key: StatusKey) => {
|
|
||||||
if (!item.total) {
|
|
||||||
return `${100 / statusList.length}%`
|
|
||||||
}
|
|
||||||
return `${Math.max((item.statusCounts[key] / item.total) * 100, 4)}%`
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatCount = (value: number) => value.toLocaleString()
|
|
||||||
const formatQuantityText = (value: number) => formatQuantity(value) || '0.00'
|
|
||||||
const chartFontFamily =
|
|
||||||
"Inter, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif"
|
|
||||||
const chartTextStyle = {
|
|
||||||
color: '#303133',
|
|
||||||
fontFamily: chartFontFamily,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 400,
|
|
||||||
textBorderWidth: 0,
|
|
||||||
textShadowBlur: 0
|
|
||||||
}
|
|
||||||
const chartAxisLabelStyle = {
|
|
||||||
color: '#8a9099',
|
|
||||||
fontFamily: chartFontFamily,
|
|
||||||
fontSize: 12,
|
|
||||||
textBorderWidth: 0,
|
|
||||||
textShadowBlur: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatGoodsLegend = (name: string) => {
|
|
||||||
const total = goodsShareList.value.reduce((sum, item) => sum + item.value, 0)
|
|
||||||
const item = goodsShareList.value.find((goods) => goods.name === name)
|
|
||||||
if (!total || !item) {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
return `${name} ${((item.value / total) * 100).toFixed(1)}%`
|
|
||||||
}
|
|
||||||
|
|
||||||
const trendChartOptions = computed<EChartsOption>(() => ({
|
|
||||||
color: orderDefinitions.map((item) => item.color),
|
|
||||||
grid: { top: 48, left: 28, right: 24, bottom: 24, containLabel: true },
|
|
||||||
textStyle: chartTextStyle,
|
|
||||||
legend: { top: 6, itemWidth: 10, itemHeight: 10, textStyle: chartTextStyle },
|
|
||||||
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: trendLabels.value,
|
|
||||||
axisLabel: chartAxisLabelStyle,
|
|
||||||
axisTick: { show: false },
|
|
||||||
axisLine: { lineStyle: { color: '#dcdfe6' } }
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value',
|
|
||||||
name: '单据数',
|
|
||||||
nameTextStyle: chartAxisLabelStyle,
|
|
||||||
axisLabel: chartAxisLabelStyle,
|
|
||||||
minInterval: 1,
|
|
||||||
splitLine: { lineStyle: { color: '#eef2f7' } }
|
|
||||||
},
|
|
||||||
series: orderDefinitions.map((item) => ({
|
|
||||||
name: item.title,
|
|
||||||
type: 'bar',
|
|
||||||
barMaxWidth: 18,
|
|
||||||
data: trendSeriesMap[item.key],
|
|
||||||
emphasis: { focus: 'series' }
|
|
||||||
}))
|
|
||||||
}))
|
|
||||||
|
|
||||||
const goodsShareChartOptions = computed<EChartsOption>(() => ({
|
|
||||||
color: ['#2f7df6', '#18a058', '#f59e0b', '#7c3aed', '#14b8a6'],
|
|
||||||
textStyle: chartTextStyle,
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item',
|
|
||||||
formatter: '{b}<br/>库存:{c} ({d}%)'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
type: 'scroll',
|
|
||||||
orient: 'vertical',
|
|
||||||
right: 10,
|
|
||||||
top: 'middle',
|
|
||||||
itemWidth: 10,
|
|
||||||
itemHeight: 10,
|
|
||||||
formatter: formatGoodsLegend,
|
|
||||||
textStyle: chartTextStyle
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: '货物占比',
|
|
||||||
type: 'pie',
|
|
||||||
radius: ['48%', '70%'],
|
|
||||||
center: ['34%', '52%'],
|
|
||||||
avoidLabelOverlap: true,
|
|
||||||
label: { show: false },
|
|
||||||
labelLine: { show: false },
|
|
||||||
data: goodsShareList.value
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}))
|
|
||||||
|
|
||||||
const inventoryDistributionChartOptions = computed<EChartsOption>(() => ({
|
|
||||||
color: ['#2f7df6'],
|
|
||||||
grid: { top: 12, left: 24, right: 40, bottom: 16, containLabel: true },
|
|
||||||
textStyle: chartTextStyle,
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
axisPointer: { type: 'shadow' },
|
|
||||||
formatter: (params: any) => {
|
|
||||||
const item = Array.isArray(params) ? params[0] : params
|
|
||||||
return `${item.name}<br/>库存:${formatQuantityText(item.value)}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'value',
|
|
||||||
axisLabel: chartAxisLabelStyle,
|
|
||||||
splitLine: { lineStyle: { color: '#eef2f7' } }
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: inventoryDistributionList.value.map((item) => item.name).reverse(),
|
|
||||||
axisLabel: chartAxisLabelStyle,
|
|
||||||
axisTick: { show: false },
|
|
||||||
axisLine: { show: false }
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: '库存',
|
|
||||||
type: 'bar',
|
|
||||||
barMaxWidth: 16,
|
|
||||||
data: inventoryDistributionList.value.map((item) => item.value).reverse(),
|
|
||||||
label: {
|
|
||||||
show: true,
|
|
||||||
position: 'right',
|
|
||||||
...chartTextStyle,
|
|
||||||
formatter: ({ value }) => formatQuantityText(Number(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}))
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
await loadWarehouseList()
|
|
||||||
await refresh()
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.wms-home {
|
|
||||||
--wms-card-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__toolbar {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 16px;
|
|
||||||
background: var(--el-bg-color);
|
|
||||||
border: 1px solid var(--el-border-color-light);
|
|
||||||
border-radius: var(--wms-card-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__toolbar-main {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 16px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
min-width: 320px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__title {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 28px;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__subtitle,
|
|
||||||
.wms-home__card-subtitle,
|
|
||||||
.wms-home__stat-time {
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--el-text-color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__filters {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
||||||
gap: 16px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-skeleton {
|
|
||||||
width: 100%;
|
|
||||||
height: 174px;
|
|
||||||
border-radius: var(--wms-card-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-card,
|
|
||||||
.wms-home__chart-card {
|
|
||||||
background: var(--el-bg-color);
|
|
||||||
border: 1px solid var(--el-border-color-light);
|
|
||||||
border-radius: var(--wms-card-radius);
|
|
||||||
box-shadow: 0 8px 24px rgb(15 23 42 / 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-card {
|
|
||||||
min-height: 154px;
|
|
||||||
padding: 16px 18px;
|
|
||||||
border-top: 3px solid var(--theme-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-head,
|
|
||||||
.wms-home__card-head {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-title {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-title span {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-total {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
align-items: baseline;
|
|
||||||
margin-top: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-total span {
|
|
||||||
font-size: 32px;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 38px;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-total em {
|
|
||||||
font-style: normal;
|
|
||||||
color: var(--el-text-color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__status-bar {
|
|
||||||
display: flex;
|
|
||||||
height: 8px;
|
|
||||||
margin-top: 14px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: var(--el-fill-color-light);
|
|
||||||
border-radius: 999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__status-list {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
gap: 8px;
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__status-list div {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__status-list span {
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--el-text-color-secondary);
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__status-list strong {
|
|
||||||
display: block;
|
|
||||||
margin-top: 2px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__chart-card {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__card-head {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__card-title {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__total-quantity {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__stat-time {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.wms-home__summary-grid {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.wms-home__toolbar-main,
|
|
||||||
.wms-home__filters {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__summary-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wms-home__card-head {
|
|
||||||
align-items: flex-start;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@
|
||||||
<div class="mb-12px text-16px font-500">库存流水</div>
|
<div class="mb-12px text-16px font-500">库存流水</div>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:cell-class-name="'wms-inventory-history-cell'"
|
cell-class-name="!align-top"
|
||||||
:data="list"
|
:data="list"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
border
|
border
|
||||||
|
|
@ -231,9 +231,3 @@ onMounted(async () => {
|
||||||
await getList()
|
await getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.wms-inventory-history-cell) {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,7 @@
|
||||||
>
|
>
|
||||||
<el-form-item label="统计维度" prop="type">
|
<el-form-item label="统计维度" prop="type">
|
||||||
<el-radio-group v-model="queryParams.type" class="!w-240px" @change="handleTypeChange">
|
<el-radio-group v-model="queryParams.type" class="!w-240px" @change="handleTypeChange">
|
||||||
<el-radio-button
|
<el-radio-button v-for="item in dimensionOptions" :key="item.value" :label="item.value">
|
||||||
v-for="item in dimensionOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</el-radio-button>
|
</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|
@ -82,7 +78,7 @@
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:cell-class-name="'wms-inventory-cell'"
|
cell-class-name="!align-top"
|
||||||
:data="list"
|
:data="list"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
:span-method="spanMethod"
|
:span-method="spanMethod"
|
||||||
|
|
@ -283,9 +279,3 @@ onMounted(async () => {
|
||||||
await getList()
|
await getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.wms-inventory-cell) {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,9 @@
|
||||||
<div v-if="row.itemCode" class="text-12px text-gray-500">
|
<div v-if="row.itemCode" class="text-12px text-gray-500">
|
||||||
商品编号:{{ row.itemCode }}
|
商品编号:{{ row.itemCode }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="row.brandName" class="text-12px text-gray-500">品牌:{{ row.brandName }}</div>
|
<div v-if="row.brandName" class="text-12px text-gray-500">
|
||||||
|
品牌:{{ row.brandName }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="220">
|
<el-table-column label="规格信息" min-width="220">
|
||||||
|
|
@ -104,13 +106,17 @@
|
||||||
<el-table-column label="金额(元)" min-width="160">
|
<el-table-column label="金额(元)" min-width="160">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div v-if="row.costPrice !== undefined">成本价:{{ formatPrice(row.costPrice) }}</div>
|
<div v-if="row.costPrice !== undefined">成本价:{{ formatPrice(row.costPrice) }}</div>
|
||||||
<div v-if="row.sellingPrice !== undefined">销售价:{{ formatPrice(row.sellingPrice) }}</div>
|
<div v-if="row.sellingPrice !== undefined">
|
||||||
|
销售价:{{ formatPrice(row.sellingPrice) }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="重量(kg)" min-width="160">
|
<el-table-column label="重量(kg)" min-width="160">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div v-if="row.netWeight !== undefined">净重:{{ formatWeight(row.netWeight) }}</div>
|
<div v-if="row.netWeight !== undefined">净重:{{ formatWeight(row.netWeight) }}</div>
|
||||||
<div v-if="row.grossWeight !== undefined">毛重:{{ formatWeight(row.grossWeight) }}</div>
|
<div v-if="row.grossWeight !== undefined">
|
||||||
|
毛重:{{ formatWeight(row.grossWeight) }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="长宽高(cm)" min-width="180">
|
<el-table-column align="right" label="长宽高(cm)" min-width="180">
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
<div class="mb-16px text-18px font-bold">单据信息</div>
|
<div class="mb-16px text-18px font-bold">单据信息</div>
|
||||||
<el-descriptions :column="2" border>
|
<el-descriptions :column="2" border>
|
||||||
<el-descriptions-item label="盘库单号">{{ detailData.no || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="盘库单号">{{ detailData.no || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="仓库">{{ detailData.warehouseName || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="仓库">
|
||||||
|
{{ detailData.warehouseName || '-' }}
|
||||||
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="单据日期">
|
<el-descriptions-item label="单据日期">
|
||||||
{{ formatNullableDate(detailData.orderTime, 'YYYY-MM-DD') }}
|
{{ formatNullableDate(detailData.orderTime, 'YYYY-MM-DD') }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
@ -45,7 +47,9 @@
|
||||||
<el-descriptions-item label="更新人">
|
<el-descriptions-item label="更新人">
|
||||||
{{ detailData.updaterName || detailData.updater || '-' }}
|
{{ detailData.updaterName || detailData.updater || '-' }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item :span="2" label="备注">{{ detailData.remark || '-' }}</el-descriptions-item>
|
<el-descriptions-item :span="2" label="备注">
|
||||||
|
{{ detailData.remark || '-' }}
|
||||||
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
<div class="mb-16px mt-24px text-18px font-bold">商品明细</div>
|
<div class="mb-16px mt-24px text-18px font-bold">商品明细</div>
|
||||||
|
|
@ -53,13 +57,17 @@
|
||||||
<el-table-column label="商品信息" min-width="200">
|
<el-table-column label="商品信息" min-width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.itemName || '-' }}</div>
|
<div>{{ row.itemName || '-' }}</div>
|
||||||
<div v-if="row.itemCode" class="text-12px text-gray-500">商品编号:{{ row.itemCode }}</div>
|
<div v-if="row.itemCode" class="text-12px text-gray-500"
|
||||||
|
>商品编号:{{ row.itemCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="200">
|
<el-table-column label="规格信息" min-width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.skuName || '-' }}</div>
|
<div>{{ row.skuName || '-' }}</div>
|
||||||
<div v-if="row.skuCode" class="text-12px text-gray-500">规格编号:{{ row.skuCode }}</div>
|
<div v-if="row.skuCode" class="text-12px text-gray-500"
|
||||||
|
>规格编号:{{ row.skuCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="账面数量" prop="quantity" width="120">
|
<el-table-column align="right" label="账面数量" prop="quantity" width="120">
|
||||||
|
|
@ -83,7 +91,9 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="实际盈亏金额(元)" prop="differencePrice" width="160">
|
<el-table-column align="right" label="实际盈亏金额(元)" prop="differencePrice" width="160">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span :class="getLossClass(getDifferencePrice(row))">{{ formatPrice(getDifferencePrice(row)) || '-' }}</span>
|
<span :class="getLossClass(getDifferencePrice(row))">{{
|
||||||
|
formatPrice(getDifferencePrice(row)) || '-'
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -116,9 +126,15 @@ const dialogVisible = ref(false)
|
||||||
const detailData = ref<CheckOrderVO>({})
|
const detailData = ref<CheckOrderVO>({})
|
||||||
const getOrderDifferencePrice = (order: CheckOrderVO) =>
|
const getOrderDifferencePrice = (order: CheckOrderVO) =>
|
||||||
roundPrice(Number(order.actualPrice || 0) - Number(order.totalPrice || 0))
|
roundPrice(Number(order.actualPrice || 0) - Number(order.totalPrice || 0))
|
||||||
const getDifferenceQuantity = (detail: CheckOrderDetailVO) => Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
const getDifferenceQuantity = (detail: CheckOrderDetailVO) =>
|
||||||
|
Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
||||||
const getActualPrice = (detail: CheckOrderDetailVO) => {
|
const getActualPrice = (detail: CheckOrderDetailVO) => {
|
||||||
if (detail.checkQuantity === undefined || detail.checkQuantity === null || detail.price === undefined || detail.price === null) {
|
if (
|
||||||
|
detail.checkQuantity === undefined ||
|
||||||
|
detail.checkQuantity === null ||
|
||||||
|
detail.price === undefined ||
|
||||||
|
detail.price === null
|
||||||
|
) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return roundPrice(Number(detail.checkQuantity) * Number(detail.price))
|
return roundPrice(Number(detail.checkQuantity) * Number(detail.price))
|
||||||
|
|
@ -129,20 +145,36 @@ const getDifferencePrice = (detail: CheckOrderDetailVO) => {
|
||||||
}
|
}
|
||||||
return roundPrice(getDifferenceQuantity(detail) * Number(detail.price))
|
return roundPrice(getDifferenceQuantity(detail) * Number(detail.price))
|
||||||
}
|
}
|
||||||
const renderLossText = (value: number | string | null | undefined, formatter: (value?: number | string | null) => string) =>
|
const renderLossText = (
|
||||||
h('span', { class: getLossClass(value) }, formatter(value))
|
value: number | string | null | undefined,
|
||||||
|
formatter: (value?: number | string | null) => string
|
||||||
|
) => h('span', { class: getLossClass(value) }, formatter(value))
|
||||||
|
|
||||||
const getSummaries = ({ columns, data }: { columns: any[]; data: CheckOrderDetailVO[] }) =>
|
const getSummaries = ({ columns, data }: { columns: any[]; data: CheckOrderDetailVO[] }) =>
|
||||||
columns.map((column, index) => {
|
columns.map((column, index) => {
|
||||||
if (index === 0) return '合计'
|
if (index === 0) {
|
||||||
if (column.property === 'quantity') return formatSumQuantity(data, (detail) => detail.quantity)
|
return '合计'
|
||||||
if (column.property === 'checkQuantity') return formatSumQuantity(data, (detail) => detail.checkQuantity)
|
}
|
||||||
if (column.property === 'actualPrice') return formatSumPrice(data, (detail) => getActualPrice(detail))
|
if (column.property === 'quantity') {
|
||||||
|
return formatSumQuantity(data, (detail) => detail.quantity)
|
||||||
|
}
|
||||||
|
if (column.property === 'checkQuantity') {
|
||||||
|
return formatSumQuantity(data, (detail) => detail.checkQuantity)
|
||||||
|
}
|
||||||
|
if (column.property === 'actualPrice') {
|
||||||
|
return formatSumPrice(data, (detail) => getActualPrice(detail))
|
||||||
|
}
|
||||||
if (column.property === 'differenceQuantity') {
|
if (column.property === 'differenceQuantity') {
|
||||||
return renderLossText(sumQuantity(data, (detail) => getDifferenceQuantity(detail)), formatQuantity)
|
return renderLossText(
|
||||||
|
sumQuantity(data, (detail) => getDifferenceQuantity(detail)),
|
||||||
|
formatQuantity
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (column.property === 'differencePrice') {
|
if (column.property === 'differencePrice') {
|
||||||
return renderLossText(sumPrice(data, (detail) => getDifferencePrice(detail)), formatPrice)
|
return renderLossText(
|
||||||
|
sumPrice(data, (detail) => getDifferencePrice(detail)),
|
||||||
|
formatPrice
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
<!-- WMS 盘库单表单 -->
|
<!-- WMS 盘库单表单 -->
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1280px">
|
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1280px">
|
||||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="92px">
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
v-loading="formLoading"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="92px"
|
||||||
|
>
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="盘库单号" prop="no">
|
<el-form-item label="盘库单号" prop="no">
|
||||||
|
|
@ -31,7 +37,13 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="formData.remark" maxlength="255" placeholder="请输入备注" :rows="3" type="textarea" />
|
<el-input
|
||||||
|
v-model="formData.remark"
|
||||||
|
maxlength="255"
|
||||||
|
placeholder="请输入备注"
|
||||||
|
:rows="3"
|
||||||
|
type="textarea"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
@ -40,7 +52,12 @@
|
||||||
<span class="text-14px font-bold">盘库明细</span>
|
<span class="text-14px font-bold">盘库明细</span>
|
||||||
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
|
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
|
||||||
<span>
|
<span>
|
||||||
<el-button :disabled="!formData.warehouseId" plain type="primary" @click="handleAddDetail">
|
<el-button
|
||||||
|
:disabled="!formData.warehouseId"
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
@click="handleAddDetail"
|
||||||
|
>
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
添加商品
|
添加商品
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -57,13 +74,17 @@
|
||||||
<el-table-column label="商品信息" min-width="210">
|
<el-table-column label="商品信息" min-width="210">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.itemName || '-' }}</div>
|
<div>{{ row.itemName || '-' }}</div>
|
||||||
<div v-if="row.itemCode" class="text-12px text-gray-500">商品编号:{{ row.itemCode }}</div>
|
<div v-if="row.itemCode" class="text-12px text-gray-500"
|
||||||
|
>商品编号:{{ row.itemCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="210">
|
<el-table-column label="规格信息" min-width="210">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.skuName || '-' }}</div>
|
<div>{{ row.skuName || '-' }}</div>
|
||||||
<div v-if="row.skuCode" class="text-12px text-gray-500">规格编号:{{ row.skuCode }}</div>
|
<div v-if="row.skuCode" class="text-12px text-gray-500"
|
||||||
|
>规格编号:{{ row.skuCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="账面库存" prop="quantity" width="120">
|
<el-table-column align="right" label="账面库存" prop="quantity" width="120">
|
||||||
|
|
@ -110,12 +131,16 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="盈亏数" prop="differenceQuantity" width="120">
|
<el-table-column align="right" label="盈亏数" prop="differenceQuantity" width="120">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span :class="getLossClass(getDifferenceQuantity(row))">{{ formatQuantity(getDifferenceQuantity(row)) }}</span>
|
<span :class="getLossClass(getDifferenceQuantity(row))">{{
|
||||||
|
formatQuantity(getDifferenceQuantity(row))
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="实际盈亏金额(元)" prop="differencePrice" width="160">
|
<el-table-column align="right" label="实际盈亏金额(元)" prop="differencePrice" width="160">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span :class="getLossClass(getDifferencePrice(row))">{{ formatPrice(getDifferencePrice(row)) }}</span>
|
<span :class="getLossClass(getDifferencePrice(row))">{{
|
||||||
|
formatPrice(getDifferencePrice(row))
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="操作" width="80">
|
<el-table-column align="center" label="操作" width="80">
|
||||||
|
|
@ -153,7 +178,13 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button v-if="isPrepareOrder" :disabled="formLoading" type="primary" @click="submitForm">保存</el-button>
|
<el-button
|
||||||
|
v-if="isPrepareOrder"
|
||||||
|
:disabled="formLoading"
|
||||||
|
type="primary"
|
||||||
|
@click="submitForm"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -166,7 +197,9 @@ import { FormRules } from 'element-plus'
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { CheckOrderApi, CheckOrderVO } from '@/api/wms/order/check'
|
import { CheckOrderApi, CheckOrderVO } from '@/api/wms/order/check'
|
||||||
import { CheckOrderDetailVO } from '@/api/wms/order/check/detail'
|
import { CheckOrderDetailVO } from '@/api/wms/order/check/detail'
|
||||||
import InventorySelect, { InventorySelectRow } from '@/views/wms/inventory/components/InventorySelect.vue'
|
import InventorySelect, {
|
||||||
|
InventorySelectRow
|
||||||
|
} from '@/views/wms/inventory/components/InventorySelect.vue'
|
||||||
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
||||||
import { OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
|
import { OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
|
||||||
import {
|
import {
|
||||||
|
|
@ -217,20 +250,30 @@ const formRules = reactive<FormRules>({
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const inventorySelectRef = ref()
|
const inventorySelectRef = ref()
|
||||||
|
|
||||||
const getDifferenceQuantity = (detail: CheckOrderFormDetail) => Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
const getDifferenceQuantity = (detail: CheckOrderFormDetail) =>
|
||||||
|
Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
||||||
const getBookPrice = (detail: CheckOrderFormDetail) => multiplyPrice(detail.quantity, detail.price)
|
const getBookPrice = (detail: CheckOrderFormDetail) => multiplyPrice(detail.quantity, detail.price)
|
||||||
const getActualPrice = (detail: CheckOrderFormDetail) => detail.actualPrice ?? multiplyPrice(detail.checkQuantity, detail.price)
|
const getActualPrice = (detail: CheckOrderFormDetail) =>
|
||||||
|
detail.actualPrice ?? multiplyPrice(detail.checkQuantity, detail.price)
|
||||||
const getDifferencePrice = (detail: CheckOrderFormDetail) => {
|
const getDifferencePrice = (detail: CheckOrderFormDetail) => {
|
||||||
if (detail.price === undefined || detail.price === null) {
|
if (detail.price === undefined || detail.price === null) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return roundPrice(getDifferenceQuantity(detail) * Number(detail.price))
|
return roundPrice(getDifferenceQuantity(detail) * Number(detail.price))
|
||||||
}
|
}
|
||||||
const renderLossText = (value: number | string | null | undefined, formatter: (value?: number | string | null) => string) =>
|
const renderLossText = (
|
||||||
h('span', { class: getLossClass(value) }, formatter(value))
|
value: number | string | null | undefined,
|
||||||
const totalQuantity = computed(() => sumQuantity(formData.value.details || [], (detail) => getDifferenceQuantity(detail)))
|
formatter: (value?: number | string | null) => string
|
||||||
const totalPrice = computed(() => sumPrice(formData.value.details || [], (detail) => getBookPrice(detail)))
|
) => h('span', { class: getLossClass(value) }, formatter(value))
|
||||||
const actualPrice = computed(() => sumPrice(formData.value.details || [], (detail) => getActualPrice(detail)))
|
const totalQuantity = computed(() =>
|
||||||
|
sumQuantity(formData.value.details || [], (detail) => getDifferenceQuantity(detail))
|
||||||
|
)
|
||||||
|
const totalPrice = computed(() =>
|
||||||
|
sumPrice(formData.value.details || [], (detail) => getBookPrice(detail))
|
||||||
|
)
|
||||||
|
const actualPrice = computed(() =>
|
||||||
|
sumPrice(formData.value.details || [], (detail) => getActualPrice(detail))
|
||||||
|
)
|
||||||
const differencePrice = computed(() => roundPrice(actualPrice.value - totalPrice.value) || 0)
|
const differencePrice = computed(() => roundPrice(actualPrice.value - totalPrice.value) || 0)
|
||||||
const isPrepareOrder = computed(
|
const isPrepareOrder = computed(
|
||||||
() =>
|
() =>
|
||||||
|
|
@ -329,10 +372,14 @@ const getDetailSummaries = ({ columns, data }: { columns: any[]; data: CheckOrde
|
||||||
columns.map((column, index) => {
|
columns.map((column, index) => {
|
||||||
if (index === 0) return '合计'
|
if (index === 0) return '合计'
|
||||||
if (column.property === 'quantity') return formatSumQuantity(data, (detail) => detail.quantity)
|
if (column.property === 'quantity') return formatSumQuantity(data, (detail) => detail.quantity)
|
||||||
if (column.property === 'checkQuantity') return formatSumQuantity(data, (detail) => detail.checkQuantity)
|
if (column.property === 'checkQuantity')
|
||||||
if (column.property === 'actualPrice') return formatSumPrice(data, (detail) => getActualPrice(detail))
|
return formatSumQuantity(data, (detail) => detail.checkQuantity)
|
||||||
if (column.property === 'differenceQuantity') return renderLossText(totalQuantity.value, formatQuantity)
|
if (column.property === 'actualPrice')
|
||||||
if (column.property === 'differencePrice') return renderLossText(differencePrice.value, formatPrice)
|
return formatSumPrice(data, (detail) => getActualPrice(detail))
|
||||||
|
if (column.property === 'differenceQuantity')
|
||||||
|
return renderLossText(totalQuantity.value, formatQuantity)
|
||||||
|
if (column.property === 'differencePrice')
|
||||||
|
return renderLossText(differencePrice.value, formatPrice)
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -357,14 +404,18 @@ const validateDetails = (required: boolean) => {
|
||||||
|
|
||||||
/** 构建提交数据 */
|
/** 构建提交数据 */
|
||||||
const buildSubmitData = () => {
|
const buildSubmitData = () => {
|
||||||
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, actualPrice: _actualPrice, details, ...order } = formData.value
|
const {
|
||||||
|
totalQuantity: _totalQuantity,
|
||||||
|
totalPrice: _totalPrice,
|
||||||
|
actualPrice: _actualPrice,
|
||||||
|
details,
|
||||||
|
...order
|
||||||
|
} = formData.value
|
||||||
return {
|
return {
|
||||||
...order,
|
...order,
|
||||||
details: (details || []).map(({
|
details: (details || []).map(
|
||||||
actualPrice: _rowActualPrice,
|
({ actualPrice: _rowActualPrice, availableQuantity: _availableQuantity, ...detail }) => detail
|
||||||
availableQuantity: _availableQuantity,
|
)
|
||||||
...detail
|
|
||||||
}) => detail)
|
|
||||||
} as CheckOrderVO
|
} as CheckOrderVO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,13 @@
|
||||||
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">账面库存</th>
|
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">账面库存</th>
|
||||||
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">单价(元)</th>
|
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">单价(元)</th>
|
||||||
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">实际库存</th>
|
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">实际库存</th>
|
||||||
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">实际金额(元)</th>
|
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left"
|
||||||
|
>实际金额(元)</th
|
||||||
|
>
|
||||||
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">盈亏数</th>
|
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">盈亏数</th>
|
||||||
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left">实际盈亏金额(元)</th>
|
<th class="border border-solid border-#dcdfe6 bg-#f5f7fa p-8px text-left"
|
||||||
|
>实际盈亏金额(元)</th
|
||||||
|
>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
@ -145,9 +149,15 @@ interface PrintRow extends CheckOrderDetailVO {
|
||||||
differencePrice?: number
|
differencePrice?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDifferenceQuantity = (detail: CheckOrderDetailVO) => Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
const getDifferenceQuantity = (detail: CheckOrderDetailVO) =>
|
||||||
|
Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
||||||
const getActualPrice = (detail: CheckOrderDetailVO) => {
|
const getActualPrice = (detail: CheckOrderDetailVO) => {
|
||||||
if (detail.checkQuantity === undefined || detail.checkQuantity === null || detail.price === undefined || detail.price === null) {
|
if (
|
||||||
|
detail.checkQuantity === undefined ||
|
||||||
|
detail.checkQuantity === null ||
|
||||||
|
detail.price === undefined ||
|
||||||
|
detail.price === null
|
||||||
|
) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return roundPrice(Number(detail.checkQuantity) * Number(detail.price))
|
return roundPrice(Number(detail.checkQuantity) * Number(detail.price))
|
||||||
|
|
@ -171,8 +181,12 @@ const printRows = computed<PrintRow[]>(() =>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const totalDifferenceQuantity = computed(() => sumQuantity(printRows.value, (detail) => detail.differenceQuantity))
|
const totalDifferenceQuantity = computed(() =>
|
||||||
const totalDifferencePrice = computed(() => sumPrice(printRows.value, (detail) => detail.differencePrice))
|
sumQuantity(printRows.value, (detail) => detail.differenceQuantity)
|
||||||
|
)
|
||||||
|
const totalDifferencePrice = computed(() =>
|
||||||
|
sumPrice(printRows.value, (detail) => detail.differencePrice)
|
||||||
|
)
|
||||||
|
|
||||||
/** 打印盘库单 */
|
/** 打印盘库单 */
|
||||||
const print = async (id: number) => {
|
const print = async (id: number) => {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,29 @@
|
||||||
<!-- WMS 盘库单 -->
|
<!-- WMS 盘库单 -->
|
||||||
<template>
|
<template>
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px" label-width="90px">
|
<el-form
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
:model="queryParams"
|
||||||
|
class="-mb-15px"
|
||||||
|
label-width="90px"
|
||||||
|
>
|
||||||
<el-form-item label="盘库单号" prop="no">
|
<el-form-item label="盘库单号" prop="no">
|
||||||
<el-input v-model="queryParams.no" class="!w-240px" clearable placeholder="请输入盘库单号" @keyup.enter="handleQuery" />
|
<el-input
|
||||||
|
v-model="queryParams.no"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入盘库单号"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="单据状态" prop="status">
|
<el-form-item label="单据状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="请选择单据状态">
|
<el-select
|
||||||
|
v-model="queryParams.status"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请选择单据状态"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in getIntDictOptions(DICT_TYPE.WMS_ORDER_STATUS)"
|
v-for="dict in getIntDictOptions(DICT_TYPE.WMS_ORDER_STATUS)"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
|
|
@ -127,7 +144,7 @@
|
||||||
<Icon class="mr-5px" icon="ep:refresh" />
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
重置
|
重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-popover popper-class="wms-check-order-table-setting-popover" trigger="click" width="520">
|
<el-popover popper-class="!p-12px" trigger="click" width="520">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button>
|
<el-button>
|
||||||
<Icon class="mr-5px" icon="ep:setting" />
|
<Icon class="mr-5px" icon="ep:setting" />
|
||||||
|
|
@ -136,14 +153,24 @@
|
||||||
</template>
|
</template>
|
||||||
<el-checkbox-group
|
<el-checkbox-group
|
||||||
v-model="checkedTableColumns"
|
v-model="checkedTableColumns"
|
||||||
class="wms-check-order-table-setting grid grid-cols-3 gap-y-14px rounded p-16px"
|
class="grid grid-cols-3 gap-y-14px rounded bg-[var(--el-fill-color-light)] p-16px"
|
||||||
>
|
>
|
||||||
<el-checkbox v-for="column in tableColumnOptions" :key="column.value" :label="column.value">
|
<el-checkbox
|
||||||
|
v-for="column in tableColumnOptions"
|
||||||
|
:key="column.value"
|
||||||
|
class="!h-28px !mr-0 [&_.el-checkbox__label]:font-600 [&_.el-checkbox__label]:text-16px"
|
||||||
|
:label="column.value"
|
||||||
|
>
|
||||||
{{ column.label }}
|
{{ column.label }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<el-button v-hasPermi="['wms:check-order:create']" plain type="primary" @click="openForm('create')">
|
<el-button
|
||||||
|
v-hasPermi="['wms:check-order:create']"
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
@click="openForm('create')"
|
||||||
|
>
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -164,7 +191,7 @@
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:cell-class-name="'wms-check-order-cell'"
|
cell-class-name="!align-top"
|
||||||
:data="list"
|
:data="list"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
border
|
border
|
||||||
|
|
@ -176,26 +203,34 @@
|
||||||
<el-table-column label="商品信息" min-width="220">
|
<el-table-column label="商品信息" min-width="220">
|
||||||
<template #default="{ row: detail }">
|
<template #default="{ row: detail }">
|
||||||
<div>{{ detail.itemName || '-' }}</div>
|
<div>{{ detail.itemName || '-' }}</div>
|
||||||
<div v-if="detail.itemCode" class="text-12px text-gray-500">商品编号:{{ detail.itemCode }}</div>
|
<div v-if="detail.itemCode" class="text-12px text-gray-500"
|
||||||
|
>商品编号:{{ detail.itemCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="220">
|
<el-table-column label="规格信息" min-width="220">
|
||||||
<template #default="{ row: detail }">
|
<template #default="{ row: detail }">
|
||||||
<div>{{ detail.skuName || '-' }}</div>
|
<div>{{ detail.skuName || '-' }}</div>
|
||||||
<div v-if="detail.skuCode" class="text-12px text-gray-500">规格编号:{{ detail.skuCode }}</div>
|
<div v-if="detail.skuCode" class="text-12px text-gray-500"
|
||||||
|
>规格编号:{{ detail.skuCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="账面数量" width="120">
|
<el-table-column align="right" label="账面数量" width="120">
|
||||||
<template #default="{ row: detail }">{{ formatQuantity(detail.quantity) }}</template>
|
<template #default="{ row: detail }">{{ formatQuantity(detail.quantity) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="实盘数量" width="120">
|
<el-table-column align="right" label="实盘数量" width="120">
|
||||||
<template #default="{ row: detail }">{{ formatQuantity(detail.checkQuantity) }}</template>
|
<template #default="{ row: detail }">{{
|
||||||
|
formatQuantity(detail.checkQuantity)
|
||||||
|
}}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="单价(元)" width="120">
|
<el-table-column align="right" label="单价(元)" width="120">
|
||||||
<template #default="{ row: detail }">{{ formatPrice(detail.price) }}</template>
|
<template #default="{ row: detail }">{{ formatPrice(detail.price) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="实际金额(元)" width="140">
|
<el-table-column align="right" label="实际金额(元)" width="140">
|
||||||
<template #default="{ row: detail }">{{ formatPrice(getDetailActualPrice(detail)) }}</template>
|
<template #default="{ row: detail }">{{
|
||||||
|
formatPrice(getDetailActualPrice(detail))
|
||||||
|
}}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="盈亏数量" width="120">
|
<el-table-column align="right" label="盈亏数量" width="120">
|
||||||
<template #default="{ row: detail }">
|
<template #default="{ row: detail }">
|
||||||
|
|
@ -231,20 +266,22 @@
|
||||||
<dict-tag :type="DICT_TYPE.WMS_ORDER_STATUS" :value="row.status" />
|
<dict-tag :type="DICT_TYPE.WMS_ORDER_STATUS" :value="row.status" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column v-if="isTableColumnVisible('warehouse')" label="仓库" min-width="180">
|
||||||
v-if="isTableColumnVisible('warehouse')"
|
|
||||||
label="仓库"
|
|
||||||
min-width="180"
|
|
||||||
>
|
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.warehouseName || '-' }}
|
{{ row.warehouseName || '-' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('quantityAmount')" label="盈亏/金额(元)" min-width="200">
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('quantityAmount')"
|
||||||
|
label="盈亏/金额(元)"
|
||||||
|
min-width="200"
|
||||||
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>盈亏数:</span>
|
<span>盈亏数:</span>
|
||||||
<span :class="getLossClass(row.totalQuantity)">{{ formatQuantity(row.totalQuantity) }}</span>
|
<span :class="getLossClass(row.totalQuantity)">{{
|
||||||
|
formatQuantity(row.totalQuantity)
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>总金额:</span>
|
<span>总金额:</span>
|
||||||
|
|
@ -256,20 +293,37 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>盈亏金额:</span>
|
<span>盈亏金额:</span>
|
||||||
<span :class="getLossClass(getDifferencePrice(row))">{{ formatPrice(getDifferencePrice(row)) }}</span>
|
<span :class="getLossClass(getDifferencePrice(row))">{{
|
||||||
|
formatPrice(getDifferencePrice(row))
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('operateInfo')" label="操作信息" min-width="280">
|
<el-table-column v-if="isTableColumnVisible('operateInfo')" label="操作信息" min-width="280">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>创建:{{ formatNullableDate(row.createTime) }} / {{ row.creatorName || row.creator || '-' }}</div>
|
<div
|
||||||
<div>更新:{{ formatNullableDate(row.updateTime) }} / {{ row.updaterName || row.updater || '-' }}</div>
|
>创建:{{ formatNullableDate(row.createTime) }} /
|
||||||
|
{{ row.creatorName || row.creator || '-' }}</div
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
>更新:{{ formatNullableDate(row.updateTime) }} /
|
||||||
|
{{ row.updaterName || row.updater || '-' }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('remark')" label="备注" min-width="160" prop="remark" />
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('remark')"
|
||||||
|
label="备注"
|
||||||
|
min-width="160"
|
||||||
|
prop="remark"
|
||||||
|
/>
|
||||||
<el-table-column align="center" fixed="right" label="操作" width="150">
|
<el-table-column align="center" fixed="right" label="操作" width="150">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tooltip :content="getUpdateTip(row.status)" :disabled="canUpdate(row.status)" placement="top">
|
<el-tooltip
|
||||||
|
:content="getUpdateTip(row.status)"
|
||||||
|
:disabled="canUpdate(row.status)"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['wms:check-order:update']"
|
v-hasPermi="['wms:check-order:update']"
|
||||||
|
|
@ -282,7 +336,11 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip :content="getDeleteTip(row.status)" :disabled="canDelete(row.status)" placement="top">
|
<el-tooltip
|
||||||
|
:content="getDeleteTip(row.status)"
|
||||||
|
:disabled="canDelete(row.status)"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['wms:check-order:delete']"
|
v-hasPermi="['wms:check-order:delete']"
|
||||||
|
|
@ -306,7 +364,12 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<Pagination v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo" :total="total" @pagination="getList" />
|
<Pagination
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
:total="total"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<CheckOrderForm ref="formRef" @success="getList" />
|
<CheckOrderForm ref="formRef" @success="getList" />
|
||||||
|
|
@ -320,7 +383,11 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import { CheckOrderApi, CheckOrderVO } from '@/api/wms/order/check'
|
import { CheckOrderApi, CheckOrderVO } from '@/api/wms/order/check'
|
||||||
import { CheckOrderDetailVO } from '@/api/wms/order/check/detail'
|
import { CheckOrderDetailVO } from '@/api/wms/order/check/detail'
|
||||||
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
||||||
import { OrderDeleteStatusList, OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
|
import {
|
||||||
|
OrderDeleteStatusList,
|
||||||
|
OrderStatusEnum,
|
||||||
|
OrderUpdateStatusList
|
||||||
|
} from '@/views/wms/utils/constants'
|
||||||
import {
|
import {
|
||||||
formatPrice,
|
formatPrice,
|
||||||
formatQuantity,
|
formatQuantity,
|
||||||
|
|
@ -387,8 +454,10 @@ const queryFormRef = ref()
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
const detailMap = reactive<Record<number, CheckOrderDetailVO[]>>({})
|
const detailMap = reactive<Record<number, CheckOrderDetailVO[]>>({})
|
||||||
|
|
||||||
const canUpdate = (status?: number) => status !== undefined && OrderUpdateStatusList.includes(status)
|
const canUpdate = (status?: number) =>
|
||||||
const canDelete = (status?: number) => status !== undefined && OrderDeleteStatusList.includes(status)
|
status !== undefined && OrderUpdateStatusList.includes(status)
|
||||||
|
const canDelete = (status?: number) =>
|
||||||
|
status !== undefined && OrderDeleteStatusList.includes(status)
|
||||||
const getUpdateTip = (status?: number) => {
|
const getUpdateTip = (status?: number) => {
|
||||||
if (status === OrderStatusEnum.FINISHED) return '已盘库,无法修改'
|
if (status === OrderStatusEnum.FINISHED) return '已盘库,无法修改'
|
||||||
if (status === OrderStatusEnum.CANCELED) return '已作废,无法修改'
|
if (status === OrderStatusEnum.CANCELED) return '已作废,无法修改'
|
||||||
|
|
@ -398,11 +467,17 @@ const getDeleteTip = (status?: number) => {
|
||||||
if (status === OrderStatusEnum.FINISHED) return '已盘库,无法删除'
|
if (status === OrderStatusEnum.FINISHED) return '已盘库,无法删除'
|
||||||
return '当前状态无法删除'
|
return '当前状态无法删除'
|
||||||
}
|
}
|
||||||
const getDifferencePrice = (row: CheckOrderVO) => roundPrice(Number(row.actualPrice || 0) - Number(row.totalPrice || 0))
|
const getDifferencePrice = (row: CheckOrderVO) =>
|
||||||
|
roundPrice(Number(row.actualPrice || 0) - Number(row.totalPrice || 0))
|
||||||
const getDetailDifferenceQuantity = (detail: CheckOrderDetailVO) =>
|
const getDetailDifferenceQuantity = (detail: CheckOrderDetailVO) =>
|
||||||
Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
|
||||||
const getDetailActualPrice = (detail: CheckOrderDetailVO) => {
|
const getDetailActualPrice = (detail: CheckOrderDetailVO) => {
|
||||||
if (detail.checkQuantity === undefined || detail.checkQuantity === null || detail.price === undefined || detail.price === null) {
|
if (
|
||||||
|
detail.checkQuantity === undefined ||
|
||||||
|
detail.checkQuantity === null ||
|
||||||
|
detail.price === undefined ||
|
||||||
|
detail.price === null
|
||||||
|
) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return roundPrice(Number(detail.checkQuantity) * Number(detail.price))
|
return roundPrice(Number(detail.checkQuantity) * Number(detail.price))
|
||||||
|
|
@ -465,27 +540,3 @@ const handleExport = async () => {
|
||||||
|
|
||||||
onMounted(() => getList())
|
onMounted(() => getList())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.wms-check-order-cell) {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-check-order-table-setting-popover) {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-check-order-table-setting) {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-check-order-table-setting .el-checkbox) {
|
|
||||||
height: 28px;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-check-order-table-setting .el-checkbox__label) {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,17 @@
|
||||||
<el-table-column label="商品信息" min-width="200">
|
<el-table-column label="商品信息" min-width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.itemName || '-' }}</div>
|
<div>{{ row.itemName || '-' }}</div>
|
||||||
<div v-if="row.itemCode" class="text-12px text-gray-500">商品编号:{{ row.itemCode }}</div>
|
<div v-if="row.itemCode" class="text-12px text-gray-500"
|
||||||
|
>商品编号:{{ row.itemCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="200">
|
<el-table-column label="规格信息" min-width="200">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.skuName || '-' }}</div>
|
<div>{{ row.skuName || '-' }}</div>
|
||||||
<div v-if="row.skuCode" class="text-12px text-gray-500">规格编号:{{ row.skuCode }}</div>
|
<div v-if="row.skuCode" class="text-12px text-gray-500"
|
||||||
|
>规格编号:{{ row.skuCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="数量" prop="quantity" width="120">
|
<el-table-column align="right" label="数量" prop="quantity" width="120">
|
||||||
|
|
@ -78,7 +82,12 @@ import { formatNullableDate } from '@/utils/formatTime'
|
||||||
import { DICT_TYPE } from '@/utils/dict'
|
import { DICT_TYPE } from '@/utils/dict'
|
||||||
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
|
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
|
||||||
import { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
|
import { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
|
||||||
import { formatPrice, formatQuantity, formatSumPrice, formatSumQuantity } from '@/views/wms/utils/format'
|
import {
|
||||||
|
formatPrice,
|
||||||
|
formatQuantity,
|
||||||
|
formatSumPrice,
|
||||||
|
formatSumQuantity
|
||||||
|
} from '@/views/wms/utils/format'
|
||||||
|
|
||||||
/** WMS 移库单详情 */
|
/** WMS 移库单详情 */
|
||||||
defineOptions({ name: 'WmsMovementOrderDetail' })
|
defineOptions({ name: 'WmsMovementOrderDetail' })
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
<!-- WMS 移库单表单 -->
|
<!-- WMS 移库单表单 -->
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1280px">
|
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1280px">
|
||||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="98px">
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
v-loading="formLoading"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="98px"
|
||||||
|
>
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="移库单号" prop="no">
|
<el-form-item label="移库单号" prop="no">
|
||||||
|
|
@ -10,12 +16,18 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="来源仓库" prop="sourceWarehouseId">
|
<el-form-item label="来源仓库" prop="sourceWarehouseId">
|
||||||
<WarehouseSelect v-model="formData.sourceWarehouseId" @change="handleSourceWarehouseChange" />
|
<WarehouseSelect
|
||||||
|
v-model="formData.sourceWarehouseId"
|
||||||
|
@change="handleSourceWarehouseChange"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="目标仓库" prop="targetWarehouseId">
|
<el-form-item label="目标仓库" prop="targetWarehouseId">
|
||||||
<WarehouseSelect v-model="formData.targetWarehouseId" @change="handleTargetWarehouseChange" />
|
<WarehouseSelect
|
||||||
|
v-model="formData.targetWarehouseId"
|
||||||
|
@change="handleTargetWarehouseChange"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
|
@ -31,16 +43,31 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="formData.remark" maxlength="255" placeholder="请输入备注" :rows="3" type="textarea" />
|
<el-input
|
||||||
|
v-model="formData.remark"
|
||||||
|
maxlength="255"
|
||||||
|
placeholder="请输入备注"
|
||||||
|
:rows="3"
|
||||||
|
type="textarea"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<div class="mb-12px flex items-center justify-between">
|
<div class="mb-12px flex items-center justify-between">
|
||||||
<span class="text-14px font-bold">移库明细</span>
|
<span class="text-14px font-bold">移库明细</span>
|
||||||
<el-tooltip content="请先选择来源仓库" :disabled="!!formData.sourceWarehouseId" placement="top">
|
<el-tooltip
|
||||||
|
content="请先选择来源仓库"
|
||||||
|
:disabled="!!formData.sourceWarehouseId"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<el-button :disabled="!formData.sourceWarehouseId" plain type="primary" @click="handleAddDetail">
|
<el-button
|
||||||
|
:disabled="!formData.sourceWarehouseId"
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
@click="handleAddDetail"
|
||||||
|
>
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
添加商品
|
添加商品
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -57,13 +84,17 @@
|
||||||
<el-table-column label="商品信息" min-width="210">
|
<el-table-column label="商品信息" min-width="210">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.itemName || '-' }}</div>
|
<div>{{ row.itemName || '-' }}</div>
|
||||||
<div v-if="row.itemCode" class="text-12px text-gray-500">商品编号:{{ row.itemCode }}</div>
|
<div v-if="row.itemCode" class="text-12px text-gray-500"
|
||||||
|
>商品编号:{{ row.itemCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="210">
|
<el-table-column label="规格信息" min-width="210">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>{{ row.skuName || '-' }}</div>
|
<div>{{ row.skuName || '-' }}</div>
|
||||||
<div v-if="row.skuCode" class="text-12px text-gray-500">规格编号:{{ row.skuCode }}</div>
|
<div v-if="row.skuCode" class="text-12px text-gray-500"
|
||||||
|
>规格编号:{{ row.skuCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="可用库存" width="120">
|
<el-table-column align="right" label="可用库存" width="120">
|
||||||
|
|
@ -143,7 +174,13 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button v-if="isPrepareOrder" :disabled="formLoading" type="primary" @click="submitForm">保存</el-button>
|
<el-button
|
||||||
|
v-if="isPrepareOrder"
|
||||||
|
:disabled="formLoading"
|
||||||
|
type="primary"
|
||||||
|
@click="submitForm"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -155,7 +192,9 @@
|
||||||
import { FormRules } from 'element-plus'
|
import { FormRules } from 'element-plus'
|
||||||
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
|
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
|
||||||
import { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
|
import { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
|
||||||
import InventorySelect, { InventorySelectRow } from '@/views/wms/inventory/components/InventorySelect.vue'
|
import InventorySelect, {
|
||||||
|
InventorySelectRow
|
||||||
|
} from '@/views/wms/inventory/components/InventorySelect.vue'
|
||||||
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
||||||
import { OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
|
import { OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
|
||||||
import {
|
import {
|
||||||
|
|
@ -201,7 +240,9 @@ const formRules = reactive<FormRules>({
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const inventorySelectRef = ref()
|
const inventorySelectRef = ref()
|
||||||
|
|
||||||
const detailPriceSum = computed(() => sumPrice(formData.value.details || [], (detail) => detail.price))
|
const detailPriceSum = computed(() =>
|
||||||
|
sumPrice(formData.value.details || [], (detail) => detail.price)
|
||||||
|
)
|
||||||
const isPrepareOrder = computed(
|
const isPrepareOrder = computed(
|
||||||
() =>
|
() =>
|
||||||
!formData.value.id ||
|
!formData.value.id ||
|
||||||
|
|
@ -273,10 +314,7 @@ const handleSelectInventory = (inventories: InventorySelectRow[]) => {
|
||||||
/** 判断库存是否已选择 */
|
/** 判断库存是否已选择 */
|
||||||
const isInventorySelected = (inventory: InventorySelectRow) =>
|
const isInventorySelected = (inventory: InventorySelectRow) =>
|
||||||
(formData.value.details || []).some((detail) => {
|
(formData.value.details || []).some((detail) => {
|
||||||
return (
|
return detail.skuId === inventory.skuId && detail.sourceWarehouseId === inventory.warehouseId
|
||||||
detail.skuId === inventory.skuId &&
|
|
||||||
detail.sourceWarehouseId === inventory.warehouseId
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleDeleteDetail = (index: number) => {
|
const handleDeleteDetail = (index: number) => {
|
||||||
|
|
@ -358,7 +396,12 @@ const validateDetails = (required: boolean) => {
|
||||||
|
|
||||||
/** 构建提交数据 */
|
/** 构建提交数据 */
|
||||||
const buildSubmitData = () => {
|
const buildSubmitData = () => {
|
||||||
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, details, ...order } = formData.value
|
const {
|
||||||
|
totalQuantity: _totalQuantity,
|
||||||
|
totalPrice: _totalPrice,
|
||||||
|
details,
|
||||||
|
...order
|
||||||
|
} = formData.value
|
||||||
return {
|
return {
|
||||||
...order,
|
...order,
|
||||||
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)
|
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,29 @@
|
||||||
<!-- WMS 移库单 -->
|
<!-- WMS 移库单 -->
|
||||||
<template>
|
<template>
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-form ref="queryFormRef" :inline="true" :model="queryParams" class="-mb-15px" label-width="90px">
|
<el-form
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
:model="queryParams"
|
||||||
|
class="-mb-15px"
|
||||||
|
label-width="90px"
|
||||||
|
>
|
||||||
<el-form-item label="移库单号" prop="no">
|
<el-form-item label="移库单号" prop="no">
|
||||||
<el-input v-model="queryParams.no" class="!w-240px" clearable placeholder="请输入移库单号" @keyup.enter="handleQuery" />
|
<el-input
|
||||||
|
v-model="queryParams.no"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入移库单号"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="单据状态" prop="status">
|
<el-form-item label="单据状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="请选择单据状态">
|
<el-select
|
||||||
|
v-model="queryParams.status"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请选择单据状态"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in getIntDictOptions(DICT_TYPE.WMS_ORDER_STATUS)"
|
v-for="dict in getIntDictOptions(DICT_TYPE.WMS_ORDER_STATUS)"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
|
|
@ -111,7 +128,7 @@
|
||||||
<Icon class="mr-5px" icon="ep:refresh" />
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
重置
|
重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-popover popper-class="wms-movement-order-table-setting-popover" trigger="click" width="520">
|
<el-popover popper-class="!p-12px" trigger="click" width="520">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button>
|
<el-button>
|
||||||
<Icon class="mr-5px" icon="ep:setting" />
|
<Icon class="mr-5px" icon="ep:setting" />
|
||||||
|
|
@ -120,14 +137,24 @@
|
||||||
</template>
|
</template>
|
||||||
<el-checkbox-group
|
<el-checkbox-group
|
||||||
v-model="checkedTableColumns"
|
v-model="checkedTableColumns"
|
||||||
class="wms-movement-order-table-setting grid grid-cols-3 gap-y-14px rounded p-16px"
|
class="grid grid-cols-3 gap-y-14px rounded bg-[var(--el-fill-color-light)] p-16px"
|
||||||
>
|
>
|
||||||
<el-checkbox v-for="column in tableColumnOptions" :key="column.value" :label="column.value">
|
<el-checkbox
|
||||||
|
v-for="column in tableColumnOptions"
|
||||||
|
:key="column.value"
|
||||||
|
class="!h-28px !mr-0 [&_.el-checkbox__label]:font-600 [&_.el-checkbox__label]:text-16px"
|
||||||
|
:label="column.value"
|
||||||
|
>
|
||||||
{{ column.label }}
|
{{ column.label }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<el-button v-hasPermi="['wms:movement-order:create']" plain type="primary" @click="openForm('create')">
|
<el-button
|
||||||
|
v-hasPermi="['wms:movement-order:create']"
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
@click="openForm('create')"
|
||||||
|
>
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -148,7 +175,7 @@
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:cell-class-name="'wms-movement-order-cell'"
|
cell-class-name="!align-top"
|
||||||
:data="list"
|
:data="list"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
border
|
border
|
||||||
|
|
@ -160,13 +187,17 @@
|
||||||
<el-table-column label="商品信息" min-width="220">
|
<el-table-column label="商品信息" min-width="220">
|
||||||
<template #default="{ row: detail }">
|
<template #default="{ row: detail }">
|
||||||
<div>{{ detail.itemName || '-' }}</div>
|
<div>{{ detail.itemName || '-' }}</div>
|
||||||
<div v-if="detail.itemCode" class="text-12px text-gray-500">商品编号:{{ detail.itemCode }}</div>
|
<div v-if="detail.itemCode" class="text-12px text-gray-500"
|
||||||
|
>商品编号:{{ detail.itemCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格信息" min-width="220">
|
<el-table-column label="规格信息" min-width="220">
|
||||||
<template #default="{ row: detail }">
|
<template #default="{ row: detail }">
|
||||||
<div>{{ detail.skuName || '-' }}</div>
|
<div>{{ detail.skuName || '-' }}</div>
|
||||||
<div v-if="detail.skuCode" class="text-12px text-gray-500">规格编号:{{ detail.skuCode }}</div>
|
<div v-if="detail.skuCode" class="text-12px text-gray-500"
|
||||||
|
>规格编号:{{ detail.skuCode }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="移库数量" width="120">
|
<el-table-column align="right" label="移库数量" width="120">
|
||||||
|
|
@ -176,7 +207,9 @@
|
||||||
<template #default="{ row: detail }">{{ formatPrice(detail.price) || '-' }}</template>
|
<template #default="{ row: detail }">{{ formatPrice(detail.price) || '-' }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="right" label="金额(元)" width="120">
|
<el-table-column align="right" label="金额(元)" width="120">
|
||||||
<template #default="{ row: detail }">{{ formatPrice(getDetailTotalPrice(detail)) || '-' }}</template>
|
<template #default="{ row: detail }">{{
|
||||||
|
formatPrice(getDetailTotalPrice(detail)) || '-'
|
||||||
|
}}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -216,7 +249,11 @@
|
||||||
{{ row.targetWarehouseName || '-' }}
|
{{ row.targetWarehouseName || '-' }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('quantityAmount')" label="总数量/总金额(元)" min-width="180">
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('quantityAmount')"
|
||||||
|
label="总数量/总金额(元)"
|
||||||
|
min-width="180"
|
||||||
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>数量:</span>
|
<span>数量:</span>
|
||||||
|
|
@ -230,14 +267,29 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('operateInfo')" label="操作信息" min-width="280">
|
<el-table-column v-if="isTableColumnVisible('operateInfo')" label="操作信息" min-width="280">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>创建:{{ formatNullableDate(row.createTime) }} / {{ row.creatorName || row.creator || '-' }}</div>
|
<div
|
||||||
<div>更新:{{ formatNullableDate(row.updateTime) }} / {{ row.updaterName || row.updater || '-' }}</div>
|
>创建:{{ formatNullableDate(row.createTime) }} /
|
||||||
|
{{ row.creatorName || row.creator || '-' }}</div
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
>更新:{{ formatNullableDate(row.updateTime) }} /
|
||||||
|
{{ row.updaterName || row.updater || '-' }}</div
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('remark')" label="备注" min-width="160" prop="remark" />
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('remark')"
|
||||||
|
label="备注"
|
||||||
|
min-width="160"
|
||||||
|
prop="remark"
|
||||||
|
/>
|
||||||
<el-table-column align="center" fixed="right" label="操作" width="150">
|
<el-table-column align="center" fixed="right" label="操作" width="150">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tooltip :content="getUpdateTip(row.status)" :disabled="canUpdate(row.status)" placement="top">
|
<el-tooltip
|
||||||
|
:content="getUpdateTip(row.status)"
|
||||||
|
:disabled="canUpdate(row.status)"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['wms:movement-order:update']"
|
v-hasPermi="['wms:movement-order:update']"
|
||||||
|
|
@ -250,7 +302,11 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip :content="getDeleteTip(row.status)" :disabled="canDelete(row.status)" placement="top">
|
<el-tooltip
|
||||||
|
:content="getDeleteTip(row.status)"
|
||||||
|
:disabled="canDelete(row.status)"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPermi="['wms:movement-order:delete']"
|
v-hasPermi="['wms:movement-order:delete']"
|
||||||
|
|
@ -266,7 +322,12 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<Pagination v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNo" :total="total" @pagination="getList" />
|
<Pagination
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
:total="total"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
|
|
||||||
<MovementOrderForm ref="formRef" @success="getList" />
|
<MovementOrderForm ref="formRef" @success="getList" />
|
||||||
|
|
@ -279,8 +340,17 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
|
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
|
||||||
import { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
|
import { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
|
||||||
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
|
||||||
import { OrderDeleteStatusList, OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
|
import {
|
||||||
import { formatPrice, formatQuantity, PRICE_PRECISION, QUANTITY_PRECISION } from '@/views/wms/utils/format'
|
OrderDeleteStatusList,
|
||||||
|
OrderStatusEnum,
|
||||||
|
OrderUpdateStatusList
|
||||||
|
} from '@/views/wms/utils/constants'
|
||||||
|
import {
|
||||||
|
formatPrice,
|
||||||
|
formatQuantity,
|
||||||
|
PRICE_PRECISION,
|
||||||
|
QUANTITY_PRECISION
|
||||||
|
} from '@/views/wms/utils/format'
|
||||||
import UserSelectV2 from '@/views/system/user/components/UserSelectV2.vue'
|
import UserSelectV2 from '@/views/system/user/components/UserSelectV2.vue'
|
||||||
import MovementOrderDetail from './MovementOrderDetail.vue'
|
import MovementOrderDetail from './MovementOrderDetail.vue'
|
||||||
import MovementOrderForm from './MovementOrderForm.vue'
|
import MovementOrderForm from './MovementOrderForm.vue'
|
||||||
|
|
@ -346,8 +416,10 @@ const queryFormRef = ref()
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
const detailMap = reactive<Record<number, MovementOrderDetailVO[]>>({})
|
const detailMap = reactive<Record<number, MovementOrderDetailVO[]>>({})
|
||||||
|
|
||||||
const canUpdate = (status?: number) => status !== undefined && OrderUpdateStatusList.includes(status)
|
const canUpdate = (status?: number) =>
|
||||||
const canDelete = (status?: number) => status !== undefined && OrderDeleteStatusList.includes(status)
|
status !== undefined && OrderUpdateStatusList.includes(status)
|
||||||
|
const canDelete = (status?: number) =>
|
||||||
|
status !== undefined && OrderDeleteStatusList.includes(status)
|
||||||
const getUpdateTip = (status?: number) => {
|
const getUpdateTip = (status?: number) => {
|
||||||
if (status === OrderStatusEnum.FINISHED) return '已移库,无法修改'
|
if (status === OrderStatusEnum.FINISHED) return '已移库,无法修改'
|
||||||
if (status === OrderStatusEnum.CANCELED) return '已作废,无法修改'
|
if (status === OrderStatusEnum.CANCELED) return '已作废,无法修改'
|
||||||
|
|
@ -413,27 +485,3 @@ const handleExport = async () => {
|
||||||
|
|
||||||
onMounted(() => getList())
|
onMounted(() => getList())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.wms-movement-order-cell) {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-movement-order-table-setting-popover) {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-movement-order-table-setting) {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-movement-order-table-setting .el-checkbox) {
|
|
||||||
height: 28px;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-movement-order-table-setting .el-checkbox__label) {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="供应商" prop="merchantId">
|
<el-form-item label="供应商" prop="merchantId">
|
||||||
<MerchantSelect
|
<MerchantSelect v-model="formData.merchantId" placeholder="请选择供应商" supplier />
|
||||||
v-model="formData.merchantId"
|
|
||||||
placeholder="请选择供应商"
|
|
||||||
supplier
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
|
@ -71,13 +67,14 @@
|
||||||
|
|
||||||
<div class="mb-12px flex items-center justify-between">
|
<div class="mb-12px flex items-center justify-between">
|
||||||
<span class="text-14px font-bold">入库明细</span>
|
<span class="text-14px font-bold">入库明细</span>
|
||||||
<el-tooltip
|
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
|
||||||
content="请先选择仓库"
|
|
||||||
:disabled="!!formData.warehouseId"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
<el-button :disabled="!formData.warehouseId" plain type="primary" @click="handleAddDetail">
|
<el-button
|
||||||
|
:disabled="!formData.warehouseId"
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
@click="handleAddDetail"
|
||||||
|
>
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
添加商品
|
添加商品
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -177,7 +174,12 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button v-if="isPrepareOrder" :disabled="formLoading" type="primary" @click="submitForm">
|
<el-button
|
||||||
|
v-if="isPrepareOrder"
|
||||||
|
:disabled="formLoading"
|
||||||
|
type="primary"
|
||||||
|
@click="submitForm"
|
||||||
|
>
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
|
@ -241,7 +243,9 @@ const formRules = reactive<FormRules>({
|
||||||
const formRef = ref() // 表单 Ref
|
const formRef = ref() // 表单 Ref
|
||||||
const skuSelectRef = ref() // 商品 SKU 选择弹窗 Ref
|
const skuSelectRef = ref() // 商品 SKU 选择弹窗 Ref
|
||||||
|
|
||||||
const detailPriceSum = computed(() => sumPrice(formData.value.details || [], (detail) => detail.price))
|
const detailPriceSum = computed(() =>
|
||||||
|
sumPrice(formData.value.details || [], (detail) => detail.price)
|
||||||
|
)
|
||||||
const isPrepareOrder = computed(
|
const isPrepareOrder = computed(
|
||||||
() =>
|
() =>
|
||||||
!formData.value.id ||
|
!formData.value.id ||
|
||||||
|
|
@ -393,7 +397,12 @@ const validateDetails = (required: boolean) => {
|
||||||
|
|
||||||
/** 构建提交数据 */
|
/** 构建提交数据 */
|
||||||
const buildSubmitData = () => {
|
const buildSubmitData = () => {
|
||||||
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, details, ...order } = formData.value
|
const {
|
||||||
|
totalQuantity: _totalQuantity,
|
||||||
|
totalPrice: _totalPrice,
|
||||||
|
details,
|
||||||
|
...order
|
||||||
|
} = formData.value
|
||||||
return {
|
return {
|
||||||
...order,
|
...order,
|
||||||
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)
|
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,12 @@ import { formatNullableDate } from '@/utils/formatTime'
|
||||||
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
||||||
import { ReceiptOrderApi, ReceiptOrderVO } from '@/api/wms/order/receipt'
|
import { ReceiptOrderApi, ReceiptOrderVO } from '@/api/wms/order/receipt'
|
||||||
import { ReceiptOrderDetailVO } from '@/api/wms/order/receipt/detail'
|
import { ReceiptOrderDetailVO } from '@/api/wms/order/receipt/detail'
|
||||||
import { formatPrice, formatQuantity, formatSumPrice, formatSumQuantity } from '@/views/wms/utils/format'
|
import {
|
||||||
|
formatPrice,
|
||||||
|
formatQuantity,
|
||||||
|
formatSumPrice,
|
||||||
|
formatSumQuantity
|
||||||
|
} from '@/views/wms/utils/format'
|
||||||
|
|
||||||
/** WMS 入库单打印 */
|
/** WMS 入库单打印 */
|
||||||
defineOptions({ name: 'WmsReceiptOrderPrint' })
|
defineOptions({ name: 'WmsReceiptOrderPrint' })
|
||||||
|
|
|
||||||
|
|
@ -117,18 +117,10 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建用户" prop="creator">
|
<el-form-item label="创建用户" prop="creator">
|
||||||
<UserSelectV2
|
<UserSelectV2 v-model="queryParams.creator" class="!w-240px" placeholder="请选择创建用户" />
|
||||||
v-model="queryParams.creator"
|
|
||||||
class="!w-240px"
|
|
||||||
placeholder="请选择创建用户"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="更新用户" prop="updater">
|
<el-form-item label="更新用户" prop="updater">
|
||||||
<UserSelectV2
|
<UserSelectV2 v-model="queryParams.updater" class="!w-240px" placeholder="请选择更新用户" />
|
||||||
v-model="queryParams.updater"
|
|
||||||
class="!w-240px"
|
|
||||||
placeholder="请选择更新用户"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" prop="createTime">
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
|
@ -161,11 +153,7 @@
|
||||||
<Icon class="mr-5px" icon="ep:refresh" />
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
重置
|
重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-popover
|
<el-popover popper-class="!p-12px" trigger="click" width="520">
|
||||||
popper-class="wms-receipt-order-table-setting-popover"
|
|
||||||
trigger="click"
|
|
||||||
width="520"
|
|
||||||
>
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button>
|
<el-button>
|
||||||
<Icon class="mr-5px" icon="ep:setting" />
|
<Icon class="mr-5px" icon="ep:setting" />
|
||||||
|
|
@ -174,11 +162,12 @@
|
||||||
</template>
|
</template>
|
||||||
<el-checkbox-group
|
<el-checkbox-group
|
||||||
v-model="checkedTableColumns"
|
v-model="checkedTableColumns"
|
||||||
class="wms-receipt-order-table-setting grid grid-cols-3 gap-y-14px rounded p-16px"
|
class="grid grid-cols-3 gap-y-14px rounded bg-[var(--el-fill-color-light)] p-16px"
|
||||||
>
|
>
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-for="column in tableColumnOptions"
|
v-for="column in tableColumnOptions"
|
||||||
:key="column.value"
|
:key="column.value"
|
||||||
|
class="!h-28px !mr-0 [&_.el-checkbox__label]:font-600 [&_.el-checkbox__label]:text-16px"
|
||||||
:label="column.value"
|
:label="column.value"
|
||||||
>
|
>
|
||||||
{{ column.label }}
|
{{ column.label }}
|
||||||
|
|
@ -212,7 +201,7 @@
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:cell-class-name="'wms-receipt-order-cell'"
|
cell-class-name="!align-top"
|
||||||
:data="list"
|
:data="list"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
border
|
border
|
||||||
|
|
@ -255,7 +244,12 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('no')" fixed="left" label="单号/业务单号" width="290">
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('no')"
|
||||||
|
fixed="left"
|
||||||
|
label="单号/业务单号"
|
||||||
|
width="290"
|
||||||
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div>
|
<div>
|
||||||
单号:
|
单号:
|
||||||
|
|
@ -289,11 +283,7 @@
|
||||||
<dict-tag :type="DICT_TYPE.WMS_RECEIPT_ORDER_TYPE" :value="scope.row.type" />
|
<dict-tag :type="DICT_TYPE.WMS_RECEIPT_ORDER_TYPE" :value="scope.row.type" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column v-if="isTableColumnVisible('warehouse')" label="仓库" min-width="160">
|
||||||
v-if="isTableColumnVisible('warehouse')"
|
|
||||||
label="仓库"
|
|
||||||
min-width="160"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.warehouseName || '-' }}
|
{{ scope.row.warehouseName || '-' }}
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -332,7 +322,12 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('remark')" label="备注" min-width="160" prop="remark" />
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('remark')"
|
||||||
|
label="备注"
|
||||||
|
min-width="160"
|
||||||
|
prop="remark"
|
||||||
|
/>
|
||||||
<el-table-column align="center" fixed="right" label="操作" width="180">
|
<el-table-column align="center" fixed="right" label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
|
|
@ -407,7 +402,12 @@ import {
|
||||||
OrderStatusEnum,
|
OrderStatusEnum,
|
||||||
OrderUpdateStatusList
|
OrderUpdateStatusList
|
||||||
} from '@/views/wms/utils/constants'
|
} from '@/views/wms/utils/constants'
|
||||||
import { formatPrice, formatQuantity, PRICE_PRECISION, QUANTITY_PRECISION } from '@/views/wms/utils/format'
|
import {
|
||||||
|
formatPrice,
|
||||||
|
formatQuantity,
|
||||||
|
PRICE_PRECISION,
|
||||||
|
QUANTITY_PRECISION
|
||||||
|
} from '@/views/wms/utils/format'
|
||||||
import UserSelectV2 from '@/views/system/user/components/UserSelectV2.vue'
|
import UserSelectV2 from '@/views/system/user/components/UserSelectV2.vue'
|
||||||
import ReceiptOrderDetail from './ReceiptOrderDetail.vue'
|
import ReceiptOrderDetail from './ReceiptOrderDetail.vue'
|
||||||
import ReceiptOrderForm from './ReceiptOrderForm.vue'
|
import ReceiptOrderForm from './ReceiptOrderForm.vue'
|
||||||
|
|
@ -604,27 +604,3 @@ onMounted(async () => {
|
||||||
await getList()
|
await getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.wms-receipt-order-cell) {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-receipt-order-table-setting-popover) {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-receipt-order-table-setting) {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-receipt-order-table-setting .el-checkbox) {
|
|
||||||
height: 28px;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-receipt-order-table-setting .el-checkbox__label) {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="客户" prop="merchantId">
|
<el-form-item label="客户" prop="merchantId">
|
||||||
<MerchantSelect
|
<MerchantSelect v-model="formData.merchantId" placeholder="请选择客户" customer />
|
||||||
v-model="formData.merchantId"
|
|
||||||
placeholder="请选择客户"
|
|
||||||
customer
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
|
@ -71,13 +67,14 @@
|
||||||
|
|
||||||
<div class="mb-12px flex items-center justify-between">
|
<div class="mb-12px flex items-center justify-between">
|
||||||
<span class="text-14px font-bold">出库明细</span>
|
<span class="text-14px font-bold">出库明细</span>
|
||||||
<el-tooltip
|
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
|
||||||
content="请先选择仓库"
|
|
||||||
:disabled="!!formData.warehouseId"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
<el-button :disabled="!formData.warehouseId" plain type="primary" @click="handleAddDetail">
|
<el-button
|
||||||
|
:disabled="!formData.warehouseId"
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
@click="handleAddDetail"
|
||||||
|
>
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
添加商品
|
添加商品
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -186,7 +183,12 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button v-if="isPrepareOrder" :disabled="formLoading" type="primary" @click="submitForm">
|
<el-button
|
||||||
|
v-if="isPrepareOrder"
|
||||||
|
:disabled="formLoading"
|
||||||
|
type="primary"
|
||||||
|
@click="submitForm"
|
||||||
|
>
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
|
@ -252,7 +254,9 @@ const formRules = reactive<FormRules>({
|
||||||
const formRef = ref() // 表单 Ref
|
const formRef = ref() // 表单 Ref
|
||||||
const inventorySelectRef = ref() // 库存选择弹窗 Ref
|
const inventorySelectRef = ref() // 库存选择弹窗 Ref
|
||||||
|
|
||||||
const detailPriceSum = computed(() => sumPrice(formData.value.details || [], (detail) => detail.price))
|
const detailPriceSum = computed(() =>
|
||||||
|
sumPrice(formData.value.details || [], (detail) => detail.price)
|
||||||
|
)
|
||||||
const isPrepareOrder = computed(
|
const isPrepareOrder = computed(
|
||||||
() =>
|
() =>
|
||||||
!formData.value.id ||
|
!formData.value.id ||
|
||||||
|
|
@ -334,10 +338,7 @@ const handleSelectInventory = (inventories: InventorySelectRow[]) => {
|
||||||
/** 判断库存是否已选择 */
|
/** 判断库存是否已选择 */
|
||||||
const isInventorySelected = (inventory: InventorySelectRow) => {
|
const isInventorySelected = (inventory: InventorySelectRow) => {
|
||||||
return (formData.value.details || []).some((detail) => {
|
return (formData.value.details || []).some((detail) => {
|
||||||
return (
|
return detail.skuId === inventory.skuId && detail.warehouseId === inventory.warehouseId
|
||||||
detail.skuId === inventory.skuId &&
|
|
||||||
detail.warehouseId === inventory.warehouseId
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,7 +418,12 @@ const validateDetails = (required: boolean) => {
|
||||||
|
|
||||||
/** 构建提交数据 */
|
/** 构建提交数据 */
|
||||||
const buildSubmitData = () => {
|
const buildSubmitData = () => {
|
||||||
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, details, ...order } = formData.value
|
const {
|
||||||
|
totalQuantity: _totalQuantity,
|
||||||
|
totalPrice: _totalPrice,
|
||||||
|
details,
|
||||||
|
...order
|
||||||
|
} = formData.value
|
||||||
return {
|
return {
|
||||||
...order,
|
...order,
|
||||||
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)
|
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,12 @@ import { formatNullableDate } from '@/utils/formatTime'
|
||||||
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
||||||
import { ShipmentOrderApi, ShipmentOrderVO } from '@/api/wms/order/shipment'
|
import { ShipmentOrderApi, ShipmentOrderVO } from '@/api/wms/order/shipment'
|
||||||
import { ShipmentOrderDetailVO } from '@/api/wms/order/shipment/detail'
|
import { ShipmentOrderDetailVO } from '@/api/wms/order/shipment/detail'
|
||||||
import { formatPrice, formatQuantity, formatSumPrice, formatSumQuantity } from '@/views/wms/utils/format'
|
import {
|
||||||
|
formatPrice,
|
||||||
|
formatQuantity,
|
||||||
|
formatSumPrice,
|
||||||
|
formatSumQuantity
|
||||||
|
} from '@/views/wms/utils/format'
|
||||||
|
|
||||||
/** WMS 出库单打印 */
|
/** WMS 出库单打印 */
|
||||||
defineOptions({ name: 'WmsShipmentOrderPrint' })
|
defineOptions({ name: 'WmsShipmentOrderPrint' })
|
||||||
|
|
|
||||||
|
|
@ -117,18 +117,10 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建用户" prop="creator">
|
<el-form-item label="创建用户" prop="creator">
|
||||||
<UserSelectV2
|
<UserSelectV2 v-model="queryParams.creator" class="!w-240px" placeholder="请选择创建用户" />
|
||||||
v-model="queryParams.creator"
|
|
||||||
class="!w-240px"
|
|
||||||
placeholder="请选择创建用户"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="更新用户" prop="updater">
|
<el-form-item label="更新用户" prop="updater">
|
||||||
<UserSelectV2
|
<UserSelectV2 v-model="queryParams.updater" class="!w-240px" placeholder="请选择更新用户" />
|
||||||
v-model="queryParams.updater"
|
|
||||||
class="!w-240px"
|
|
||||||
placeholder="请选择更新用户"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" prop="createTime">
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
|
@ -161,11 +153,7 @@
|
||||||
<Icon class="mr-5px" icon="ep:refresh" />
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
重置
|
重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-popover
|
<el-popover popper-class="!p-12px" trigger="click" width="520">
|
||||||
popper-class="wms-shipment-order-table-setting-popover"
|
|
||||||
trigger="click"
|
|
||||||
width="520"
|
|
||||||
>
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button>
|
<el-button>
|
||||||
<Icon class="mr-5px" icon="ep:setting" />
|
<Icon class="mr-5px" icon="ep:setting" />
|
||||||
|
|
@ -174,11 +162,12 @@
|
||||||
</template>
|
</template>
|
||||||
<el-checkbox-group
|
<el-checkbox-group
|
||||||
v-model="checkedTableColumns"
|
v-model="checkedTableColumns"
|
||||||
class="wms-shipment-order-table-setting grid grid-cols-3 gap-y-14px rounded p-16px"
|
class="grid grid-cols-3 gap-y-14px rounded bg-[var(--el-fill-color-light)] p-16px"
|
||||||
>
|
>
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-for="column in tableColumnOptions"
|
v-for="column in tableColumnOptions"
|
||||||
:key="column.value"
|
:key="column.value"
|
||||||
|
class="!h-28px !mr-0 [&_.el-checkbox__label]:font-600 [&_.el-checkbox__label]:text-16px"
|
||||||
:label="column.value"
|
:label="column.value"
|
||||||
>
|
>
|
||||||
{{ column.label }}
|
{{ column.label }}
|
||||||
|
|
@ -212,7 +201,7 @@
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:cell-class-name="'wms-shipment-order-cell'"
|
cell-class-name="!align-top"
|
||||||
:data="list"
|
:data="list"
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
border
|
border
|
||||||
|
|
@ -255,7 +244,12 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('no')" fixed="left" label="单号/业务单号" width="290">
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('no')"
|
||||||
|
fixed="left"
|
||||||
|
label="单号/业务单号"
|
||||||
|
width="290"
|
||||||
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div>
|
<div>
|
||||||
单号:
|
单号:
|
||||||
|
|
@ -289,11 +283,7 @@
|
||||||
<dict-tag :type="DICT_TYPE.WMS_SHIPMENT_ORDER_TYPE" :value="scope.row.type" />
|
<dict-tag :type="DICT_TYPE.WMS_SHIPMENT_ORDER_TYPE" :value="scope.row.type" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column v-if="isTableColumnVisible('warehouse')" label="仓库" min-width="160">
|
||||||
v-if="isTableColumnVisible('warehouse')"
|
|
||||||
label="仓库"
|
|
||||||
min-width="160"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.warehouseName || '-' }}
|
{{ scope.row.warehouseName || '-' }}
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -332,7 +322,12 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column v-if="isTableColumnVisible('remark')" label="备注" min-width="160" prop="remark" />
|
<el-table-column
|
||||||
|
v-if="isTableColumnVisible('remark')"
|
||||||
|
label="备注"
|
||||||
|
min-width="160"
|
||||||
|
prop="remark"
|
||||||
|
/>
|
||||||
<el-table-column align="center" fixed="right" label="操作" width="180">
|
<el-table-column align="center" fixed="right" label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
|
|
@ -407,7 +402,12 @@ import {
|
||||||
OrderStatusEnum,
|
OrderStatusEnum,
|
||||||
OrderUpdateStatusList
|
OrderUpdateStatusList
|
||||||
} from '@/views/wms/utils/constants'
|
} from '@/views/wms/utils/constants'
|
||||||
import { formatPrice, formatQuantity, PRICE_PRECISION, QUANTITY_PRECISION } from '@/views/wms/utils/format'
|
import {
|
||||||
|
formatPrice,
|
||||||
|
formatQuantity,
|
||||||
|
PRICE_PRECISION,
|
||||||
|
QUANTITY_PRECISION
|
||||||
|
} from '@/views/wms/utils/format'
|
||||||
import UserSelectV2 from '@/views/system/user/components/UserSelectV2.vue'
|
import UserSelectV2 from '@/views/system/user/components/UserSelectV2.vue'
|
||||||
import ShipmentOrderDetail from './ShipmentOrderDetail.vue'
|
import ShipmentOrderDetail from './ShipmentOrderDetail.vue'
|
||||||
import ShipmentOrderForm from './ShipmentOrderForm.vue'
|
import ShipmentOrderForm from './ShipmentOrderForm.vue'
|
||||||
|
|
@ -604,27 +604,3 @@ onMounted(async () => {
|
||||||
await getList()
|
await getList()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
:deep(.wms-shipment-order-cell) {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-shipment-order-table-setting-popover) {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-shipment-order-table-setting) {
|
|
||||||
background-color: var(--el-fill-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-shipment-order-table-setting .el-checkbox) {
|
|
||||||
height: 28px;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.wms-shipment-order-table-setting .el-checkbox__label) {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue