feat(wms):优化首页的代码实现

wms
YunaiV 2026-05-14 22:35:53 +08:00
parent 58537a34c7
commit ae54f938cf
21 changed files with 1184 additions and 979 deletions

View File

@ -3,26 +3,26 @@ import request from '@/config/axios'
// WMS 首页统计查询参数
export interface WmsHomeStatisticsReqVO {
warehouseId?: number
goodsLimit?: number
warehouseLimit?: number
}
// WMS 首页单据状态统计 VO
export interface WmsHomeOrderStatusVO {
status: number
statusName: string
count: number
}
// WMS 首页单据汇总统计 VO
export interface WmsHomeOrderSummaryVO {
orderType: number
orderTypeName: string
type: number
total: number
statusList: WmsHomeOrderStatusVO[]
statuses: WmsHomeOrderStatusVO[]
}
// WMS 首页单据趋势 VO
export interface WmsHomeOrderTrendVO {
date: string
time: string | number
receiptCount: number
shipmentCount: number
movementCount: number
@ -31,15 +31,15 @@ export interface WmsHomeOrderTrendVO {
// WMS 首页商品库存排行 VO
export interface WmsHomeInventoryItemRankVO {
itemId: number
itemName: string
id: number
name: string
quantity: number
}
// WMS 首页仓库库存排行 VO
export interface WmsHomeInventoryWarehouseRankVO {
warehouseId: number
warehouseName: string
id: number
name: string
quantity: number
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -1,29 +1,25 @@
<!-- TODO @AI组件拆分下 -->
<template>
<div class="wms-home">
<div class="wms-home__toolbar">
<div class="wms-home__toolbar-main">
<div class="[--wms-card-radius:8px]">
<div
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 class="wms-home__title">WMS 首页</div>
<div class="wms-home__subtitle">单据工作台 / 库存概览</div>
<div class="text-20px font-600 leading-28px text-[var(--el-text-color-primary)]">
WMS 首页
</div>
<div class="text-13px text-[var(--el-text-color-secondary)]">单据工作台 / 库存概览</div>
</div>
<div class="wms-home__filters">
<el-select
<div class="flex flex-wrap items-center gap-8px lt-sm:w-full">
<WarehouseSelect
v-model="warehouseId"
class="!w-220px"
clearable
filterable
placeholder="全部仓库"
@change="refresh"
>
<el-option
v-for="warehouse in warehouseList"
:key="warehouse.id!"
:label="warehouse.name"
:value="warehouse.id!"
/>
</el-select>
<el-button :loading="loading || trendLoading || inventoryLoading" @click="refresh">
@change="refresh()"
/>
<el-button :loading="loading" @click="refresh">
<Icon class="mr-5px" icon="ep:refresh" />
刷新
</el-button>
@ -31,97 +27,13 @@
</div>
</div>
<el-skeleton :loading="loading" animated>
<template #template>
<div class="wms-home__summary-grid">
<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>
<WmsHomeOrderSummaryCards ref="orderSummaryCardsRef" />
<WmsHomeOrderTrendChart ref="orderTrendChartRef" />
<WmsHomeInventoryCharts ref="inventoryChartsRef" />
<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>
<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">
<div
class="mt-2px flex items-center justify-center text-13px text-[var(--el-text-color-secondary)]"
>
<Icon class="mr-5px" icon="ep:clock" />
统计时间{{ statTime }}
</div>
@ -129,562 +41,38 @@
</template>
<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 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 首页 */
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 trendLoading = ref(false)
const inventoryLoading = ref(false)
const warehouseId = ref<number>()
const warehouseList = ref<WarehouseVO[]>([])
const statTime = ref(formatDate(new Date()))
const orderSummaries = ref<OrderSummary[]>(
orderDefinitions.map((item) => ({
...item,
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
}
}
const orderSummaryCardsRef = ref<InstanceType<typeof WmsHomeOrderSummaryCards>>()
const orderTrendChartRef = ref<InstanceType<typeof WmsHomeOrderTrendChart>>()
const inventoryChartsRef = ref<InstanceType<typeof WmsHomeInventoryCharts>>()
/** 刷新:重新加载各个组件的数据(传入 warehouseId 以进行针对性查询),并更新时间戳 */
const refresh = async () => {
loading.value = true
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())
} finally {
loading.value = false
}
}
const loadWarehouseList = async () => {
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
}
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
}
onMounted(() => {
refresh()
})
</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>

View File

@ -102,7 +102,7 @@
<div class="mb-12px text-16px font-500">库存流水</div>
<el-table
v-loading="loading"
:cell-class-name="'wms-inventory-history-cell'"
cell-class-name="!align-top"
:data="list"
:show-overflow-tooltip="true"
border
@ -231,9 +231,3 @@ onMounted(async () => {
await getList()
})
</script>
<style scoped>
:deep(.wms-inventory-history-cell) {
vertical-align: top;
}
</style>

View File

@ -11,11 +11,7 @@
>
<el-form-item label="统计维度" prop="type">
<el-radio-group v-model="queryParams.type" class="!w-240px" @change="handleTypeChange">
<el-radio-button
v-for="item in dimensionOptions"
:key="item.value"
:label="item.value"
>
<el-radio-button v-for="item in dimensionOptions" :key="item.value" :label="item.value">
{{ item.label }}
</el-radio-button>
</el-radio-group>
@ -82,7 +78,7 @@
</div>
<el-table
v-loading="loading"
:cell-class-name="'wms-inventory-cell'"
cell-class-name="!align-top"
:data="list"
:show-overflow-tooltip="true"
:span-method="spanMethod"
@ -283,9 +279,3 @@ onMounted(async () => {
await getList()
})
</script>
<style scoped>
:deep(.wms-inventory-cell) {
vertical-align: top;
}
</style>

View File

@ -91,7 +91,9 @@
<div v-if="row.itemCode" class="text-12px text-gray-500">
商品编号{{ row.itemCode }}
</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>
</el-table-column>
<el-table-column label="规格信息" min-width="220">
@ -104,13 +106,17 @@
<el-table-column label="金额(元)" min-width="160">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column label="重量(kg)" min-width="160">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column align="right" label="长宽高(cm)" min-width="180">

View File

@ -5,7 +5,9 @@
<div class="mb-16px text-18px font-bold">单据信息</div>
<el-descriptions :column="2" border>
<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="单据日期">
{{ formatNullableDate(detailData.orderTime, 'YYYY-MM-DD') }}
</el-descriptions-item>
@ -45,7 +47,9 @@
<el-descriptions-item label="更新人">
{{ detailData.updaterName || detailData.updater || '-' }}
</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>
<div class="mb-16px mt-24px text-18px font-bold">商品明细</div>
@ -53,13 +57,17 @@
<el-table-column label="商品信息" min-width="200">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column label="规格信息" min-width="200">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column align="right" label="账面数量" prop="quantity" width="120">
@ -83,7 +91,9 @@
</el-table-column>
<el-table-column align="right" label="实际盈亏金额(元)" prop="differencePrice" width="160">
<template #default="{ row }">
<span :class="getLossClass(getDifferencePrice(row))">{{ formatPrice(getDifferencePrice(row)) || '-' }}</span>
<span :class="getLossClass(getDifferencePrice(row))">{{
formatPrice(getDifferencePrice(row)) || '-'
}}</span>
</template>
</el-table-column>
</el-table>
@ -116,9 +126,15 @@ const dialogVisible = ref(false)
const detailData = ref<CheckOrderVO>({})
const getOrderDifferencePrice = (order: CheckOrderVO) =>
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) => {
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 roundPrice(Number(detail.checkQuantity) * Number(detail.price))
@ -129,20 +145,36 @@ const getDifferencePrice = (detail: CheckOrderDetailVO) => {
}
return roundPrice(getDifferenceQuantity(detail) * Number(detail.price))
}
const renderLossText = (value: number | string | null | undefined, formatter: (value?: number | string | null) => string) =>
h('span', { class: getLossClass(value) }, formatter(value))
const renderLossText = (
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[] }) =>
columns.map((column, index) => {
if (index === 0) return '合计'
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 (index === 0) {
return '合计'
}
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') {
return renderLossText(sumQuantity(data, (detail) => getDifferenceQuantity(detail)), formatQuantity)
return renderLossText(
sumQuantity(data, (detail) => getDifferenceQuantity(detail)),
formatQuantity
)
}
if (column.property === 'differencePrice') {
return renderLossText(sumPrice(data, (detail) => getDifferencePrice(detail)), formatPrice)
return renderLossText(
sumPrice(data, (detail) => getDifferencePrice(detail)),
formatPrice
)
}
return ''
})

View File

@ -1,7 +1,13 @@
<!-- WMS 盘库单表单 -->
<template>
<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-col :span="8">
<el-form-item label="盘库单号" prop="no">
@ -31,7 +37,13 @@
</el-col>
<el-col :span="16">
<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-col>
</el-row>
@ -40,7 +52,12 @@
<span class="text-14px font-bold">盘库明细</span>
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
<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" />
添加商品
</el-button>
@ -57,13 +74,17 @@
<el-table-column label="商品信息" min-width="210">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column label="规格信息" min-width="210">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column align="right" label="账面库存" prop="quantity" width="120">
@ -110,12 +131,16 @@
</el-table-column>
<el-table-column align="right" label="盈亏数" prop="differenceQuantity" width="120">
<template #default="{ row }">
<span :class="getLossClass(getDifferenceQuantity(row))">{{ formatQuantity(getDifferenceQuantity(row)) }}</span>
<span :class="getLossClass(getDifferenceQuantity(row))">{{
formatQuantity(getDifferenceQuantity(row))
}}</span>
</template>
</el-table-column>
<el-table-column align="right" label="实际盈亏金额(元)" prop="differencePrice" width="160">
<template #default="{ row }">
<span :class="getLossClass(getDifferencePrice(row))">{{ formatPrice(getDifferencePrice(row)) }}</span>
<span :class="getLossClass(getDifferencePrice(row))">{{
formatPrice(getDifferencePrice(row))
}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="80">
@ -153,7 +178,13 @@
</el-button>
</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>
</div>
</div>
@ -166,7 +197,9 @@ import { FormRules } from 'element-plus'
import { h } from 'vue'
import { CheckOrderApi, CheckOrderVO } from '@/api/wms/order/check'
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 { OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
import {
@ -217,20 +250,30 @@ const formRules = reactive<FormRules>({
const formRef = 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 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) => {
if (detail.price === undefined || detail.price === null) {
return undefined
}
return roundPrice(getDifferenceQuantity(detail) * Number(detail.price))
}
const renderLossText = (value: number | string | null | undefined, formatter: (value?: number | string | null) => string) =>
h('span', { class: getLossClass(value) }, formatter(value))
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 renderLossText = (
value: number | string | null | undefined,
formatter: (value?: number | string | null) => string
) => h('span', { class: getLossClass(value) }, formatter(value))
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 isPrepareOrder = computed(
() =>
@ -329,10 +372,14 @@ const getDetailSummaries = ({ columns, data }: { columns: any[]; data: CheckOrde
columns.map((column, index) => {
if (index === 0) return '合计'
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') return renderLossText(totalQuantity.value, formatQuantity)
if (column.property === 'differencePrice') return renderLossText(differencePrice.value, formatPrice)
if (column.property === 'checkQuantity')
return formatSumQuantity(data, (detail) => detail.checkQuantity)
if (column.property === 'actualPrice')
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 ''
})
@ -357,14 +404,18 @@ const validateDetails = (required: boolean) => {
/** 构建提交数据 */
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 {
...order,
details: (details || []).map(({
actualPrice: _rowActualPrice,
availableQuantity: _availableQuantity,
...detail
}) => detail)
details: (details || []).map(
({ actualPrice: _rowActualPrice, availableQuantity: _availableQuantity, ...detail }) => detail
)
} as CheckOrderVO
}

View File

@ -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
>
</tr>
</thead>
<tbody>
@ -145,9 +149,15 @@ interface PrintRow extends CheckOrderDetailVO {
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) => {
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 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 totalDifferencePrice = computed(() => sumPrice(printRows.value, (detail) => detail.differencePrice))
const totalDifferenceQuantity = computed(() =>
sumQuantity(printRows.value, (detail) => detail.differenceQuantity)
)
const totalDifferencePrice = computed(() =>
sumPrice(printRows.value, (detail) => detail.differencePrice)
)
/** 打印盘库单 */
const print = async (id: number) => {

View File

@ -1,12 +1,29 @@
<!-- WMS 盘库单 -->
<template>
<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-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 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
v-for="dict in getIntDictOptions(DICT_TYPE.WMS_ORDER_STATUS)"
:key="dict.value"
@ -127,7 +144,7 @@
<Icon class="mr-5px" icon="ep:refresh" />
重置
</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>
<el-button>
<Icon class="mr-5px" icon="ep:setting" />
@ -136,14 +153,24 @@
</template>
<el-checkbox-group
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 }}
</el-checkbox>
</el-checkbox-group>
</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" />
新增
</el-button>
@ -164,7 +191,7 @@
<ContentWrap>
<el-table
v-loading="loading"
:cell-class-name="'wms-check-order-cell'"
cell-class-name="!align-top"
:data="list"
:show-overflow-tooltip="true"
border
@ -176,26 +203,34 @@
<el-table-column label="商品信息" min-width="220">
<template #default="{ row: detail }">
<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>
</el-table-column>
<el-table-column label="规格信息" min-width="220">
<template #default="{ row: detail }">
<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>
</el-table-column>
<el-table-column align="right" label="账面数量" width="120">
<template #default="{ row: detail }">{{ formatQuantity(detail.quantity) }}</template>
</el-table-column>
<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 align="right" label="单价(元)" width="120">
<template #default="{ row: detail }">{{ formatPrice(detail.price) }}</template>
</el-table-column>
<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 align="right" label="盈亏数量" width="120">
<template #default="{ row: detail }">
@ -231,20 +266,22 @@
<dict-tag :type="DICT_TYPE.WMS_ORDER_STATUS" :value="row.status" />
</template>
</el-table-column>
<el-table-column
v-if="isTableColumnVisible('warehouse')"
label="仓库"
min-width="180"
>
<el-table-column v-if="isTableColumnVisible('warehouse')" label="仓库" min-width="180">
<template #default="{ row }">
{{ row.warehouseName || '-' }}
</template>
</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 }">
<div class="flex items-center justify-between">
<span>盈亏数</span>
<span :class="getLossClass(row.totalQuantity)">{{ formatQuantity(row.totalQuantity) }}</span>
<span :class="getLossClass(row.totalQuantity)">{{
formatQuantity(row.totalQuantity)
}}</span>
</div>
<div class="flex items-center justify-between">
<span>总金额</span>
@ -256,20 +293,37 @@
</div>
<div class="flex items-center justify-between">
<span>盈亏金额</span>
<span :class="getLossClass(getDifferencePrice(row))">{{ formatPrice(getDifferencePrice(row)) }}</span>
<span :class="getLossClass(getDifferencePrice(row))">{{
formatPrice(getDifferencePrice(row))
}}</span>
</div>
</template>
</el-table-column>
<el-table-column v-if="isTableColumnVisible('operateInfo')" label="操作信息" min-width="280">
<template #default="{ row }">
<div>创建{{ formatNullableDate(row.createTime) }} / {{ row.creatorName || row.creator || '-' }}</div>
<div>更新{{ formatNullableDate(row.updateTime) }} / {{ row.updaterName || row.updater || '-' }}</div>
<div
>创建{{ formatNullableDate(row.createTime) }} /
{{ row.creatorName || row.creator || '-' }}</div
>
<div
>更新{{ formatNullableDate(row.updateTime) }} /
{{ row.updaterName || row.updater || '-' }}</div
>
</template>
</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">
<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>
<el-button
v-hasPermi="['wms:check-order:update']"
@ -282,7 +336,11 @@
</el-button>
</span>
</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>
<el-button
v-hasPermi="['wms:check-order:delete']"
@ -306,7 +364,12 @@
</template>
</el-table-column>
</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>
<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 { CheckOrderDetailVO } from '@/api/wms/order/check/detail'
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 {
formatPrice,
formatQuantity,
@ -387,8 +454,10 @@ const queryFormRef = ref()
const exportLoading = ref(false)
const detailMap = reactive<Record<number, CheckOrderDetailVO[]>>({})
const canUpdate = (status?: number) => status !== undefined && OrderUpdateStatusList.includes(status)
const canDelete = (status?: number) => status !== undefined && OrderDeleteStatusList.includes(status)
const canUpdate = (status?: number) =>
status !== undefined && OrderUpdateStatusList.includes(status)
const canDelete = (status?: number) =>
status !== undefined && OrderDeleteStatusList.includes(status)
const getUpdateTip = (status?: number) => {
if (status === OrderStatusEnum.FINISHED) return '已盘库,无法修改'
if (status === OrderStatusEnum.CANCELED) return '已作废,无法修改'
@ -398,11 +467,17 @@ const getDeleteTip = (status?: number) => {
if (status === OrderStatusEnum.FINISHED) 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) =>
Number(detail.checkQuantity || 0) - Number(detail.quantity || 0)
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 roundPrice(Number(detail.checkQuantity) * Number(detail.price))
@ -465,27 +540,3 @@ const handleExport = async () => {
onMounted(() => getList())
</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>

View File

@ -50,13 +50,17 @@
<el-table-column label="商品信息" min-width="200">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column label="规格信息" min-width="200">
<template #default="{ row }">
<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>
</el-table-column>
<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 { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
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 移库单详情 */
defineOptions({ name: 'WmsMovementOrderDetail' })

View File

@ -1,7 +1,13 @@
<!-- WMS 移库单表单 -->
<template>
<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-col :span="8">
<el-form-item label="移库单号" prop="no">
@ -10,12 +16,18 @@
</el-col>
<el-col :span="8">
<el-form-item label="来源仓库" prop="sourceWarehouseId">
<WarehouseSelect v-model="formData.sourceWarehouseId" @change="handleSourceWarehouseChange" />
<WarehouseSelect
v-model="formData.sourceWarehouseId"
@change="handleSourceWarehouseChange"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="目标仓库" prop="targetWarehouseId">
<WarehouseSelect v-model="formData.targetWarehouseId" @change="handleTargetWarehouseChange" />
<WarehouseSelect
v-model="formData.targetWarehouseId"
@change="handleTargetWarehouseChange"
/>
</el-form-item>
</el-col>
<el-col :span="8">
@ -31,16 +43,31 @@
</el-col>
<el-col :span="16">
<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-col>
</el-row>
<div class="mb-12px flex items-center justify-between">
<span class="text-14px font-bold">移库明细</span>
<el-tooltip content="请先选择来源仓库" :disabled="!!formData.sourceWarehouseId" placement="top">
<el-tooltip
content="请先选择来源仓库"
:disabled="!!formData.sourceWarehouseId"
placement="top"
>
<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" />
添加商品
</el-button>
@ -57,13 +84,17 @@
<el-table-column label="商品信息" min-width="210">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column label="规格信息" min-width="210">
<template #default="{ row }">
<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>
</el-table-column>
<el-table-column align="right" label="可用库存" width="120">
@ -143,7 +174,13 @@
</el-button>
</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>
</div>
</div>
@ -155,7 +192,9 @@
import { FormRules } from 'element-plus'
import { MovementOrderApi, MovementOrderVO } from '@/api/wms/order/movement'
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 { OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
import {
@ -201,7 +240,9 @@ const formRules = reactive<FormRules>({
const formRef = 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(
() =>
!formData.value.id ||
@ -273,10 +314,7 @@ const handleSelectInventory = (inventories: InventorySelectRow[]) => {
/** 判断库存是否已选择 */
const isInventorySelected = (inventory: InventorySelectRow) =>
(formData.value.details || []).some((detail) => {
return (
detail.skuId === inventory.skuId &&
detail.sourceWarehouseId === inventory.warehouseId
)
return detail.skuId === inventory.skuId && detail.sourceWarehouseId === inventory.warehouseId
})
const handleDeleteDetail = (index: number) => {
@ -358,7 +396,12 @@ const validateDetails = (required: boolean) => {
/** 构建提交数据 */
const buildSubmitData = () => {
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, details, ...order } = formData.value
const {
totalQuantity: _totalQuantity,
totalPrice: _totalPrice,
details,
...order
} = formData.value
return {
...order,
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)

View File

@ -1,12 +1,29 @@
<!-- WMS 移库单 -->
<template>
<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-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 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
v-for="dict in getIntDictOptions(DICT_TYPE.WMS_ORDER_STATUS)"
:key="dict.value"
@ -111,7 +128,7 @@
<Icon class="mr-5px" icon="ep:refresh" />
重置
</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>
<el-button>
<Icon class="mr-5px" icon="ep:setting" />
@ -120,14 +137,24 @@
</template>
<el-checkbox-group
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 }}
</el-checkbox>
</el-checkbox-group>
</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" />
新增
</el-button>
@ -148,7 +175,7 @@
<ContentWrap>
<el-table
v-loading="loading"
:cell-class-name="'wms-movement-order-cell'"
cell-class-name="!align-top"
:data="list"
:show-overflow-tooltip="true"
border
@ -160,13 +187,17 @@
<el-table-column label="商品信息" min-width="220">
<template #default="{ row: detail }">
<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>
</el-table-column>
<el-table-column label="规格信息" min-width="220">
<template #default="{ row: detail }">
<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>
</el-table-column>
<el-table-column align="right" label="移库数量" width="120">
@ -176,7 +207,9 @@
<template #default="{ row: detail }">{{ formatPrice(detail.price) || '-' }}</template>
</el-table-column>
<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>
</template>
@ -216,7 +249,11 @@
{{ row.targetWarehouseName || '-' }}
</template>
</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 }">
<div class="flex items-center justify-between">
<span>数量</span>
@ -230,14 +267,29 @@
</el-table-column>
<el-table-column v-if="isTableColumnVisible('operateInfo')" label="操作信息" min-width="280">
<template #default="{ row }">
<div>创建{{ formatNullableDate(row.createTime) }} / {{ row.creatorName || row.creator || '-' }}</div>
<div>更新{{ formatNullableDate(row.updateTime) }} / {{ row.updaterName || row.updater || '-' }}</div>
<div
>创建{{ formatNullableDate(row.createTime) }} /
{{ row.creatorName || row.creator || '-' }}</div
>
<div
>更新{{ formatNullableDate(row.updateTime) }} /
{{ row.updaterName || row.updater || '-' }}</div
>
</template>
</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">
<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>
<el-button
v-hasPermi="['wms:movement-order:update']"
@ -250,7 +302,11 @@
</el-button>
</span>
</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>
<el-button
v-hasPermi="['wms:movement-order:delete']"
@ -266,7 +322,12 @@
</template>
</el-table-column>
</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>
<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 { MovementOrderDetailVO } from '@/api/wms/order/movement/detail'
import WarehouseSelect from '@/views/wms/md/warehouse/components/WarehouseSelect.vue'
import { OrderDeleteStatusList, OrderStatusEnum, OrderUpdateStatusList } from '@/views/wms/utils/constants'
import { formatPrice, formatQuantity, PRICE_PRECISION, QUANTITY_PRECISION } from '@/views/wms/utils/format'
import {
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 MovementOrderDetail from './MovementOrderDetail.vue'
import MovementOrderForm from './MovementOrderForm.vue'
@ -346,8 +416,10 @@ const queryFormRef = ref()
const exportLoading = ref(false)
const detailMap = reactive<Record<number, MovementOrderDetailVO[]>>({})
const canUpdate = (status?: number) => status !== undefined && OrderUpdateStatusList.includes(status)
const canDelete = (status?: number) => status !== undefined && OrderDeleteStatusList.includes(status)
const canUpdate = (status?: number) =>
status !== undefined && OrderUpdateStatusList.includes(status)
const canDelete = (status?: number) =>
status !== undefined && OrderDeleteStatusList.includes(status)
const getUpdateTip = (status?: number) => {
if (status === OrderStatusEnum.FINISHED) return '已移库,无法修改'
if (status === OrderStatusEnum.CANCELED) return '已作废,无法修改'
@ -413,27 +485,3 @@ const handleExport = async () => {
onMounted(() => getList())
</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>

View File

@ -44,11 +44,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="供应商" prop="merchantId">
<MerchantSelect
v-model="formData.merchantId"
placeholder="请选择供应商"
supplier
/>
<MerchantSelect v-model="formData.merchantId" placeholder="请选择供应商" supplier />
</el-form-item>
</el-col>
<el-col :span="8">
@ -71,13 +67,14 @@
<div class="mb-12px flex items-center justify-between">
<span class="text-14px font-bold">入库明细</span>
<el-tooltip
content="请先选择仓库"
:disabled="!!formData.warehouseId"
placement="top"
>
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
<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" />
添加商品
</el-button>
@ -177,7 +174,12 @@
</el-button>
</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 @click="dialogVisible = false"> </el-button>
@ -241,7 +243,9 @@ const formRules = reactive<FormRules>({
const formRef = ref() // 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(
() =>
!formData.value.id ||
@ -393,7 +397,12 @@ const validateDetails = (required: boolean) => {
/** 构建提交数据 */
const buildSubmitData = () => {
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, details, ...order } = formData.value
const {
totalQuantity: _totalQuantity,
totalPrice: _totalPrice,
details,
...order
} = formData.value
return {
...order,
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)

View File

@ -80,7 +80,12 @@ import { formatNullableDate } from '@/utils/formatTime'
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
import { ReceiptOrderApi, ReceiptOrderVO } from '@/api/wms/order/receipt'
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 入库单打印 */
defineOptions({ name: 'WmsReceiptOrderPrint' })

View File

@ -117,18 +117,10 @@
</el-select>
</el-form-item>
<el-form-item label="创建用户" prop="creator">
<UserSelectV2
v-model="queryParams.creator"
class="!w-240px"
placeholder="请选择创建用户"
/>
<UserSelectV2 v-model="queryParams.creator" class="!w-240px" placeholder="请选择创建用户" />
</el-form-item>
<el-form-item label="更新用户" prop="updater">
<UserSelectV2
v-model="queryParams.updater"
class="!w-240px"
placeholder="请选择更新用户"
/>
<UserSelectV2 v-model="queryParams.updater" class="!w-240px" placeholder="请选择更新用户" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
@ -161,11 +153,7 @@
<Icon class="mr-5px" icon="ep:refresh" />
重置
</el-button>
<el-popover
popper-class="wms-receipt-order-table-setting-popover"
trigger="click"
width="520"
>
<el-popover popper-class="!p-12px" trigger="click" width="520">
<template #reference>
<el-button>
<Icon class="mr-5px" icon="ep:setting" />
@ -174,11 +162,12 @@
</template>
<el-checkbox-group
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
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 }}
@ -212,7 +201,7 @@
<ContentWrap>
<el-table
v-loading="loading"
:cell-class-name="'wms-receipt-order-cell'"
cell-class-name="!align-top"
:data="list"
:show-overflow-tooltip="true"
border
@ -255,7 +244,12 @@
</el-table>
</template>
</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">
<div>
单号
@ -289,11 +283,7 @@
<dict-tag :type="DICT_TYPE.WMS_RECEIPT_ORDER_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column
v-if="isTableColumnVisible('warehouse')"
label="仓库"
min-width="160"
>
<el-table-column v-if="isTableColumnVisible('warehouse')" label="仓库" min-width="160">
<template #default="scope">
{{ scope.row.warehouseName || '-' }}
</template>
@ -332,7 +322,12 @@
</div>
</template>
</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">
<template #default="scope">
<el-tooltip
@ -407,7 +402,12 @@ import {
OrderStatusEnum,
OrderUpdateStatusList
} 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 ReceiptOrderDetail from './ReceiptOrderDetail.vue'
import ReceiptOrderForm from './ReceiptOrderForm.vue'
@ -604,27 +604,3 @@ onMounted(async () => {
await getList()
})
</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>

View File

@ -44,11 +44,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="merchantId">
<MerchantSelect
v-model="formData.merchantId"
placeholder="请选择客户"
customer
/>
<MerchantSelect v-model="formData.merchantId" placeholder="请选择客户" customer />
</el-form-item>
</el-col>
<el-col :span="8">
@ -71,13 +67,14 @@
<div class="mb-12px flex items-center justify-between">
<span class="text-14px font-bold">出库明细</span>
<el-tooltip
content="请先选择仓库"
:disabled="!!formData.warehouseId"
placement="top"
>
<el-tooltip content="请先选择仓库" :disabled="!!formData.warehouseId" placement="top">
<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" />
添加商品
</el-button>
@ -186,7 +183,12 @@
</el-button>
</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 @click="dialogVisible = false"> </el-button>
@ -252,7 +254,9 @@ const formRules = reactive<FormRules>({
const formRef = 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(
() =>
!formData.value.id ||
@ -334,10 +338,7 @@ const handleSelectInventory = (inventories: InventorySelectRow[]) => {
/** 判断库存是否已选择 */
const isInventorySelected = (inventory: InventorySelectRow) => {
return (formData.value.details || []).some((detail) => {
return (
detail.skuId === inventory.skuId &&
detail.warehouseId === inventory.warehouseId
)
return detail.skuId === inventory.skuId && detail.warehouseId === inventory.warehouseId
})
}
@ -417,7 +418,12 @@ const validateDetails = (required: boolean) => {
/** 构建提交数据 */
const buildSubmitData = () => {
const { totalQuantity: _totalQuantity, totalPrice: _totalPrice, details, ...order } = formData.value
const {
totalQuantity: _totalQuantity,
totalPrice: _totalPrice,
details,
...order
} = formData.value
return {
...order,
details: (details || []).map(({ totalPrice: _rowTotalPrice, ...detail }) => detail)

View File

@ -80,7 +80,12 @@ import { formatNullableDate } from '@/utils/formatTime'
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
import { ShipmentOrderApi, ShipmentOrderVO } from '@/api/wms/order/shipment'
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 出库单打印 */
defineOptions({ name: 'WmsShipmentOrderPrint' })

View File

@ -117,18 +117,10 @@
</el-select>
</el-form-item>
<el-form-item label="创建用户" prop="creator">
<UserSelectV2
v-model="queryParams.creator"
class="!w-240px"
placeholder="请选择创建用户"
/>
<UserSelectV2 v-model="queryParams.creator" class="!w-240px" placeholder="请选择创建用户" />
</el-form-item>
<el-form-item label="更新用户" prop="updater">
<UserSelectV2
v-model="queryParams.updater"
class="!w-240px"
placeholder="请选择更新用户"
/>
<UserSelectV2 v-model="queryParams.updater" class="!w-240px" placeholder="请选择更新用户" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
@ -161,11 +153,7 @@
<Icon class="mr-5px" icon="ep:refresh" />
重置
</el-button>
<el-popover
popper-class="wms-shipment-order-table-setting-popover"
trigger="click"
width="520"
>
<el-popover popper-class="!p-12px" trigger="click" width="520">
<template #reference>
<el-button>
<Icon class="mr-5px" icon="ep:setting" />
@ -174,11 +162,12 @@
</template>
<el-checkbox-group
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
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 }}
@ -212,7 +201,7 @@
<ContentWrap>
<el-table
v-loading="loading"
:cell-class-name="'wms-shipment-order-cell'"
cell-class-name="!align-top"
:data="list"
:show-overflow-tooltip="true"
border
@ -255,7 +244,12 @@
</el-table>
</template>
</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">
<div>
单号
@ -289,11 +283,7 @@
<dict-tag :type="DICT_TYPE.WMS_SHIPMENT_ORDER_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column
v-if="isTableColumnVisible('warehouse')"
label="仓库"
min-width="160"
>
<el-table-column v-if="isTableColumnVisible('warehouse')" label="仓库" min-width="160">
<template #default="scope">
{{ scope.row.warehouseName || '-' }}
</template>
@ -332,7 +322,12 @@
</div>
</template>
</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">
<template #default="scope">
<el-tooltip
@ -407,7 +402,12 @@ import {
OrderStatusEnum,
OrderUpdateStatusList
} 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 ShipmentOrderDetail from './ShipmentOrderDetail.vue'
import ShipmentOrderForm from './ShipmentOrderForm.vue'
@ -604,27 +604,3 @@ onMounted(async () => {
await getList()
})
</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>