Commit 097317d3 by qinjianhui

Merge branch 'dev'

parents 4cd242e7 95ca82ad
......@@ -16,6 +16,7 @@ declare module 'vue' {
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
......@@ -54,7 +55,6 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElUpload: typeof import('element-plus/es')['ElUpload']
......
......@@ -14,6 +14,7 @@
"axios": "^1.6.7",
"bignumber.js": "^9.3.0",
"dayjs": "^1.11.13",
"echarts": "^6.0.0",
"element-plus": "^2.6.0",
"lodash-es": "^4.17.21",
"luxon": "^3.7.1",
......@@ -3635,6 +3636,16 @@
"node": ">= 0.4"
}
},
"node_modules/echarts": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-6.0.0.tgz",
"integrity": "sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "2.3.0",
"zrender": "6.0.0"
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.157",
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.157.tgz",
......@@ -6009,6 +6020,12 @@
"typescript": ">=4.2.0"
}
},
"node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
"license": "0BSD"
},
"node_modules/type": {
"version": "2.7.3",
"resolved": "https://registry.npmmirror.com/type/-/type-2.7.3.tgz",
......@@ -6848,6 +6865,15 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zrender": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-6.0.0.tgz",
"integrity": "sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==",
"license": "BSD-3-Clause",
"dependencies": {
"tslib": "2.3.0"
}
}
}
}
......@@ -16,6 +16,7 @@
"axios": "^1.6.7",
"bignumber.js": "^9.3.0",
"dayjs": "^1.11.13",
"echarts": "^6.0.0",
"element-plus": "^2.6.0",
"lodash-es": "^4.17.21",
"luxon": "^3.7.1",
......
import axios from './axios'
import { BaseRespData } from '@/types/api'
import { statisticData, trendType } from '@/types/api/statistic'
//1、核心数据看板
export function getStatisticData() {
return axios.get<never, BaseRespData<statisticData>>(
'factory/overview/statistic',
)
}
//2、趋势图(订单趋势+24/48发货率图+超时发货率图)
export function trendApi(params: {
timeUnit: string | number
trendType: string
}) {
return axios.post<never, BaseRespData<trendType[]>>(
'/factory/overview/trend',
params,
)
}
......@@ -20,6 +20,7 @@
>
复制店铺单号
</div>
<div v-if="showCopyCount" class="menu-item" @click="onChangeCopy('count')">
统计数量
</div>
......@@ -28,7 +29,7 @@
</template>
<script setup lang="ts">
import { ref, defineExpose, onMounted, onUnmounted } from 'vue'
import { ref, onMounted, onUnmounted } from 'vue'
const visible = ref(false)
const position = ref({ x: 0, y: 0 })
......
export interface statisticData {
todayNewOrderNum: number
todayNewProductNum: number
todayConfirmOrderNum: number
todayConfirmProductNum: number
notShipmentOrderNum: number
overTimeNotShipmentOrderNum: number
yesterdayShipmentOrderNum: number
beforeYesterdayShipmentOrderNum: number
compareYesterdayShipmentOrderNum: number
shipmentRateOf24Hour: number
compareLastDayShipmentRateOf24Hour: number
shipmentRateOf48Hour: number
compareLastDayShipmentRateOf48Hour: number
overTimeShipmentRate: number
compareLastDayOverTimeShipmentRate: number
waitCreateLogisticOrderNum: number
waitArrangeOrderNum: number
producingOrderNum: number
waitShipmentNum: number
blockApplyOrderNum: number
exceptionOrderNum: number
outOfStockOrderNum: number
outOfStock24HourOrderNum: number
outOfStock48HourOrderNum: number
outOfStockOver48HourOrderNum: number
outOfStockSkuNum: number
outOfStockProductNum: number
yesterdayOverTimeShipmentOrderNum: number
}
export interface trendType {
confirmNum: number // 接单数
produceNum: number // 生产数
shipmentNum: number // 发货数
shipmentRateOf24Hour: number // 24小时发货率
shipmentRateOf48Hour: number // 48小时发货率
overtimeShipmentRate: number // 超48小时发货率
overtimeShipmentOrderNum: number // 超时发货单数
startTime: string // 周期开始时间
endTime: string // 周期结束时间
}
<template>
<div class="card h-100 dashboard">
<div
v-if="userInfo"
class="factory-info flex h-100 flex-center"
>
<span class="title">{{ userInfo.factory.title }}</span>
<span>欢迎您!</span>
<div class="dashboard-wrapper">
<div class="card-wrapper">
<div class="dashboard-title">核心数据看板</div>
<div class="card-container-wrapper">
<div class="card-container">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">今日新单(件/单)</div>
<el-tooltip
class="item"
effect="light"
content="今日新增订单的订单数量"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{
(statisticData?.todayNewProductNum ?? '-') +
'/' +
(statisticData?.todayNewOrderNum ?? '-')
}}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">今日接单(件/单)</div>
<el-tooltip
class="item"
effect="light"
content="今日新增确认生产的订单数量"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{
(statisticData?.todayConfirmProductNum ?? '-') +
'/' +
(statisticData?.todayConfirmOrderNum ?? '-')
}}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">未发货订单(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前确认生产后还未转为已发货状态的总订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.notShipmentOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">超时未发订单(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前确认生产后超过48H还未转为已发货状态的总订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-red">
{{ statisticData?.overTimeNotShipmentOrderNum ?? '-' }}
</div>
</div>
</div>
</div>
<div class="card-container" :gutter="20">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">昨日发货数(单)</div>
<el-tooltip
class="item"
effect="light"
content="昨日转为已发货状态的总订单数(昨日北京时间0-24点数据)"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.yesterdayShipmentOrderNum ?? '-' }}
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareYesterdayShipmentOrderNum >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-red">
{{ statisticData?.compareYesterdayShipmentOrderNum }}
</div>
<div class="up-icon"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareYesterdayShipmentOrderNum || 0,
)
}}
</div>
<div class="down-icon"></div>
</div>
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">24h发货率</div>
<el-tooltip
class="item"
effect="light"
content="昨日已发货订单中从接单转为已发货状态在24小时内的比例(昨日北京时间0-24点数据)"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ (statisticData?.shipmentRateOf24Hour ?? '-') + '%' }}
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayShipmentRateOf24Hour >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-red">
{{
(statisticData?.compareLastDayShipmentRateOf24Hour ??
'-') + '%'
}}
</div>
<div class="up-icon"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayShipmentRateOf24Hour || 0,
) + '%'
}}
</div>
<div class="down-icon"></div>
</div>
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">48h发货率</div>
<el-tooltip
class="item"
effect="light"
content="昨日已发货订单中从接单转为已发货状态在48小时内的比例(昨日北京时间0-24点数据)"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ (statisticData?.shipmentRateOf48Hour ?? '-') + '%' }}
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayShipmentRateOf48Hour >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-red">
{{
(statisticData?.compareLastDayShipmentRateOf48Hour ??
'-') + '%'
}}
</div>
<div class="up-icon"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayShipmentRateOf48Hour || 0,
) + '%'
}}
</div>
<div class="down-icon"></div>
</div>
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">发货超时率</div>
<el-tooltip
class="item"
effect="light"
content="昨日已发货订单中从接单转为已发货状态大于48小时的比例(昨日北京时间0-24点数据)"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-red">
{{
(statisticData?.overTimeShipmentRate ?? '-') +
'%(' +
(statisticData?.yesterdayOverTimeShipmentOrderNum ?? '-') +
')'
}}
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayOverTimeShipmentRate >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-red">
{{
(statisticData?.compareLastDayOverTimeShipmentRate ??
'-') + '%'
}}
</div>
<div class="up-icon"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayOverTimeShipmentRate || 0,
) + '%'
}}
</div>
<div class="down-icon"></div>
</div>
</div>
</div>
</div>
</div>
<div class="card-container">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">待创建物流(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前订单中待创建物流的总订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.waitCreateLogisticOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">待排单(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前订单中待排单的总生产数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.waitArrangeOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">生产中(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前订单中排单完成后到发货前的总生产单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.producingOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">待发货(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前订单中待发货状态的总订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.waitShipmentNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">拦截申请(单)</div>
<el-tooltip
class="item"
effect="light"
content="目前在生产拦截申请和发货拦截申请中的总订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-yellow">
{{ statisticData?.blockApplyOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">异常单(单)</div>
<el-tooltip
class="item"
effect="light"
content="所有订单中的异常单总单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div class="card-item-content text-red">
{{ statisticData?.exceptionOrderNum ?? '-' }}
</div>
</div>
</div>
</div>
<div class="card-container">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货中订单(单)</div>
<el-tooltip
class="item"
effect="light"
content="缺货统计中的商品总订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-yellow">
{{ statisticData?.outOfStockOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货&lt;24h单(单)</div>
<el-tooltip
class="item"
effect="light"
content="缺货总订单中的缺货时长在24h内的订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-yellow">
{{ statisticData?.outOfStock24HourOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货&lt;48h单(单)</div>
<el-tooltip
class="item"
effect="light"
content="缺货总订单中的缺货时长在48h内的订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div class="card-item-content text-yellow">
{{ statisticData?.outOfStock48HourOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货≥48h单(单)</div>
<el-tooltip
class="item"
effect="light"
content="缺货总订单中的缺货时长大于48h内的订单数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-red">
{{ statisticData?.outOfStockOver48HourOrderNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货库存SKU数</div>
<el-tooltip
class="item"
effect="light"
content="缺货的库存SKU的总数目"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-red">
{{ statisticData?.outOfStockSkuNum ?? '-' }}
</div>
</div>
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货总件数</div>
<el-tooltip
class="item"
effect="light"
content="缺货的货物总件数"
placement="bottom"
>
<div class="card-icon"></div>
</el-tooltip>
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-yellow">
{{ statisticData?.outOfStockProductNum ?? '-' }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="chart-wrapper" style="width: 100%">
<el-radio-group
v-model="chartTimes1"
size="small"
class="chart-controls"
@change="getchartTimes($event, 'ORDER_TREND')"
>
<el-radio-button
v-for="time in timeOptions"
:key="time.type"
:value="time.type"
:label="time.name"
>
</el-radio-button>
</el-radio-group>
<div
ref="orderChart1"
v-loading="orderChart1Loading"
class="chart-container"
style="width: 100%"
/>
</div>
<div class="charts-row">
<div class="chart-wrapper chart-half">
<el-radio-group
v-model="chartTimes2"
size="small"
class="chart-controls"
@change="getchartTimes($event, 'SHIPMENT_TREND')"
>
<el-radio-button
v-for="time in timeOptions"
:key="time.type"
:value="time.type"
:label="time.name"
>
</el-radio-button>
</el-radio-group>
<div
ref="orderChart2"
v-loading="orderChart2Loading"
class="chart-container"
style="width: 100%"
/>
</div>
<div class="chart-wrapper chart-half">
<el-radio-group
v-model="chartTimes3"
size="small"
class="chart-controls"
@change="getchartTimes($event, 'OVERTIME_SHIPMENT_TREND')"
>
<el-radio-button
v-for="time in timeOptions"
:key="time.type"
:value="time.type"
:label="time.name"
>
</el-radio-button>
</el-radio-group>
<div
ref="orderChart3"
v-loading="orderChart3Loading"
class="chart-container"
style="width: 100%"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import useUserStore from '@/store/user'
const userInfo = useUserStore().user
import { ref, onMounted, onBeforeUnmount, nextTick, type Ref } from 'vue'
import * as echarts from 'echarts/core'
import {
TitleComponent,
GridComponent,
LegendComponent,
} from 'echarts/components'
import { LineChart } from 'echarts/charts'
import { UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'
import { getStatisticData, trendApi } from '@/api/statistic'
import type {
statisticData as StatisticData,
trendType as trendType,
} from '@/types/api/statistic'
import { TooltipComponent } from 'echarts/components'
echarts.use([TooltipComponent])
echarts.use([
TitleComponent,
GridComponent,
LegendComponent,
LineChart,
CanvasRenderer,
UniversalTransition,
])
// 获取统计数据
const statisticData = ref<StatisticData | null>(null)
// 图表 loading 状态(无数据时展示 loading)
const orderChart1Loading = ref<boolean>(true)
const orderChart2Loading = ref<boolean>(true)
const orderChart3Loading = ref<boolean>(true)
const timeOptions = ref<{ type: string; name: string }[]>([
{ type: '0', name: '日数据' },
{ type: '1', name: '周数据' },
{ type: '2', name: '月数据' },
])
const chartTimes1 = ref<string>('0')
const chartTimes2 = ref<string>('0')
const chartTimes3 = ref<string>('0')
// 图表容器引用
const orderChart1 = ref<HTMLDivElement | null>(null)
const orderChart2 = ref<HTMLDivElement | null>(null)
const orderChart3 = ref<HTMLDivElement | null>(null)
// 图表实例数组
const chartInstances: (echarts.ECharts | null)[] = [null, null, null]
type ChartSeriesItem = {
name: string
data: (number | { value: number; count?: number })[]
color: string
}
type ChartConfig = {
title: string
legend: string[]
xAxisData: string[]
series: ChartSeriesItem[]
}
// 图表配置
const chartConfig1 = ref<ChartConfig>({
title: '订单趋势统计(单)',
legend: ['接单数', '生产数', '发货数'],
xAxisData: [''],
series: [
{
name: '接单数',
data: [0],
color: '#30d2cb',
},
{
name: '生产数',
data: [0],
color: '#9e95ff',
},
{
name: '发货数',
data: [0],
color: '#6bb3fd',
},
],
})
const chartConfig2 = ref<ChartConfig>({
title: '订单发货效率',
legend: ['24H发货率', '48H发货率'],
xAxisData: [''],
series: [
{
name: '24H发货率',
data: [0],
color: '#3e9fff',
},
{
name: '48H发货率',
data: [0],
color: '#ac84ff',
},
],
})
const chartConfig3 = ref<ChartConfig>({
title: '订单超时情况',
legend: ['发货超时率'],
xAxisData: [''],
series: [
{
name: '发货超时率',
data: [{ value: 0, count: 0 }],
color: '#ff6845',
},
],
})
const overtimeTooltipFormatter = (params: TooltipParam[]) =>
params
.map((item) => {
const dataObj =
item.data && typeof item.data === 'object'
? (item.data as { value: number | string; count?: number })
: null
const count =
dataObj && typeof dataObj.count === 'number' ? dataObj.count : null
const valueText = `${item.value}%`
return `${item.marker}${item.seriesName}: ${valueText}${
count !== null ? `(${count}单)` : ''
}`
})
.join('<br/>')
// 创建图表配置的函数
type TooltipParam = {
marker: string
seriesName: string
value: number | string
data?: unknown
}
const createChartOption = (
config: Ref<ChartConfig>,
isPercent = false,
customFormatter?: (params: TooltipParam[]) => string,
) => {
const data = config.value
return {
title: {
text: data.title,
left: 'left',
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
type: 'dashed',
},
label: {
backgroundColor: '#6a7985',
},
},
formatter:
customFormatter ??
((params: TooltipParam[]) =>
params
.map(
(item) =>
`${item.marker}${item.seriesName}: ${
isPercent ? `${item.value}%` : item.value
}`,
)
.join('<br/>')),
},
legend: {
data: data.legend,
top: 'top',
left: 'center',
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: data.xAxisData,
axisLabel: {
// 关键配置:添加省略号
overflow: 'truncate', // 截断显示
width: 120, // 每个标签的最大宽度(像素)
formatter: function (value: string) {
// 手动截断,超过6个字符加省略号
if (value.length > 10) {
return value.substring(0, 10) + '...'
}
return value
},
},
},
yAxis: {
type: 'value',
axisLabel: isPercent
? {
formatter: '{value}%',
color: '#666',
}
: {
color: '#666',
},
axisLine: {
lineStyle: { color: '#ccc' },
},
splitLine: {
lineStyle: { color: '#eee' },
},
},
series: data.series.map((item) => ({
name: item.name,
type: 'line',
data: item.data,
smooth: true,
lineStyle: {
color: item.color,
width: 3,
},
itemStyle: {
color: item.color,
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: item.color,
},
{
offset: 1,
color: item.color + '00', // 添加透明度,00 表示完全透明
},
],
globalCoord: false,
},
},
})),
}
}
// 自动缩放文字:保证卡片内数字不超出边框宽度,超出则减小字号
const adjustTextSize = (el: HTMLElement) => {
const maxFontSize = 45
const minFontSize = 16
const card = el.closest('.card-item') as HTMLElement | null
const containerWidth = card?.clientWidth ?? el.parentElement?.clientWidth ?? 0
// 获取 card-item-content-text 的实际宽度
const contentBox = el.parentElement
const contentText = contentBox?.querySelector(
'.card-item-content-text',
) as HTMLElement | null
let contentTextWidth = 0
let gap = 0
let marginRight = 0
if (contentText && contentBox) {
contentTextWidth = contentText.offsetWidth
// 获取 gap 值
const contentBoxStyle = window.getComputedStyle(contentBox)
gap = parseFloat(contentBoxStyle.gap) || 0
// 获取 margin-right 值
const contentTextStyle = window.getComputedStyle(contentText)
marginRight = parseFloat(contentTextStyle.marginRight) || 0
}
const limitWidth = containerWidth - contentTextWidth - gap - marginRight - 20
el.style.fontSize = `${maxFontSize}px`
let current = maxFontSize
while (current > minFontSize && el.scrollWidth > limitWidth) {
current -= 1
el.style.fontSize = `${current}px`
}
}
const vAutoFitText = {
mounted(el: HTMLElement) {
nextTick(() => {
adjustTextSize(el)
})
const card = el.closest('.card-item') as HTMLElement | null
if (card && 'ResizeObserver' in window) {
const observer = new ResizeObserver(() => {
adjustTextSize(el)
})
observer.observe(card)
;(el as { __autoFitObserver__?: ResizeObserver }).__autoFitObserver__ =
observer
}
},
updated(el: HTMLElement) {
nextTick(() => {
adjustTextSize(el)
})
},
unmounted(el: HTMLElement) {
const observer = (el as { __autoFitObserver__?: ResizeObserver })
.__autoFitObserver__
if (observer) {
observer.disconnect()
delete (el as { __autoFitObserver__?: ResizeObserver })
.__autoFitObserver__
}
},
}
const getStatisticDataApi = async () => {
// 统计数据
getStatisticData()
.then((res) => {
if (res.code === 200) {
statisticData.value = res.data
}
})
.catch((error) => {
console.error('获取统计数据失败:', error)
})
// 订单趋势统计
trendApi({
timeUnit: 0,
trendType: 'ORDER_TREND',
})
.then((res) => {
if (res.code === 200) {
updateOrderTrendChart(res.data, 0)
chartInstances[0]?.setOption(createChartOption(chartConfig1))
// 无数据时保持 loading,有数据则关闭
orderChart1Loading.value = !(res.data && res.data.length > 0)
}
})
.catch((error) => {
console.error('获取订单趋势数据失败:', error)
})
// 订单发货效率
trendApi({
timeUnit: 0,
trendType: 'SHIPMENT_TREND',
})
.then((res) => {
if (res.code === 200) {
updateShipmentTrendChart(res.data, 0)
chartInstances[1]?.setOption(createChartOption(chartConfig2, true))
orderChart2Loading.value = !(res.data && res.data.length > 0)
}
})
.catch((error) => {
console.error('获取发货趋势数据失败:', error)
})
// 订单生产效率
trendApi({
timeUnit: 0,
trendType: 'OVERTIME_SHIPMENT_TREND',
})
.then((res) => {
if (res.code === 200) {
updateOvertimeTrendChart(res.data, 0)
chartInstances[2]?.setOption(
createChartOption(chartConfig3, true, overtimeTooltipFormatter),
)
orderChart3Loading.value = !(res.data && res.data.length > 0)
}
})
.catch((error) => {
console.error('获取超时发货趋势数据失败:', error)
})
}
onMounted(async () => {
await nextTick()
// 订单趋势统计
if (orderChart1.value) {
chartInstances[0] = echarts.init(orderChart1.value)
chartInstances[0]?.setOption(createChartOption(chartConfig1))
}
// 订单发货效率
if (orderChart2.value) {
chartInstances[1] = echarts.init(orderChart2.value)
chartInstances[1]?.setOption(createChartOption(chartConfig2, true))
}
// 订单生产效率
if (orderChart3.value) {
chartInstances[2] = echarts.init(orderChart3.value)
chartInstances[2]?.setOption(
createChartOption(chartConfig3, true, overtimeTooltipFormatter),
)
}
// 请求成功后立即更新对应的图表
getStatisticDataApi()
// 监听窗口大小变化,自动调整图表大小
window.addEventListener('resize', handleResize)
})
const getchartTimes = async (v: string, type: string) => {
try {
// 切换时间维度时先开启对应 loading,等数据返回后根据是否有数据决定是否保留
if (type === 'ORDER_TREND') {
orderChart1Loading.value = true
} else if (type === 'SHIPMENT_TREND') {
orderChart2Loading.value = true
} else if (type === 'OVERTIME_SHIPMENT_TREND') {
orderChart3Loading.value = true
}
const { data } = await trendApi({
timeUnit: v,
trendType: type,
})
if (type == 'ORDER_TREND') {
updateOrderTrendChart(data, v)
chartInstances[0]?.setOption(createChartOption(chartConfig1))
orderChart1Loading.value = !(data && data.length > 0)
} else if (type == 'SHIPMENT_TREND') {
updateShipmentTrendChart(data, v)
chartInstances[1]?.setOption(createChartOption(chartConfig2, true))
orderChart2Loading.value = !(data && data.length > 0)
} else {
updateOvertimeTrendChart(data, v)
chartInstances[2]?.setOption(
createChartOption(chartConfig3, true, overtimeTooltipFormatter),
)
orderChart3Loading.value = !(data && data.length > 0)
}
} catch (error) {
console.log(error)
}
}
const updateOrderTrendChart = (data: trendType[], type: number | string) => {
const confirmNums = data.map((el) => el.confirmNum)
const produceNums = data.map((el) => el.produceNum)
const shipmentNums = data.map((el) => el.shipmentNum)
const startTimes = data.map((el) => el.startTime)
const timerange = data.map((el) => `${el.startTime}——${el.endTime}`)
if (type == 0) {
chartConfig1.value.xAxisData = startTimes
} else {
chartConfig1.value.xAxisData = timerange
}
chartConfig1.value.series[0].data = confirmNums
chartConfig1.value.series[1].data = produceNums
chartConfig1.value.series[2].data = shipmentNums
}
const updateShipmentTrendChart = (data: trendType[], type: number | string) => {
const shipmentRateOf24Hours = data.map((el) => el.shipmentRateOf24Hour)
const shipmentRateOf48Hours = data.map((el) => el.shipmentRateOf48Hour)
const startTimes = data.map((el) => el.startTime)
const timerange = data.map((el) => `${el.startTime}-${el.endTime}`)
if (type == 0) {
chartConfig2.value.xAxisData = startTimes
} else {
chartConfig2.value.xAxisData = timerange
}
chartConfig2.value.series[0].data = shipmentRateOf24Hours
chartConfig2.value.series[1].data = shipmentRateOf48Hours
}
const updateOvertimeTrendChart = (data: trendType[], type: number | string) => {
const overtimeShipmentOrderNums = data.map(
(el) => el.overtimeShipmentOrderNum,
)
const overtimeShipmentRates = data.map((el) => el.overtimeShipmentRate)
const startTimes = data.map((el) => el.startTime)
const timerange = data.map((el) => `${el.startTime}-${el.endTime}`)
if (type == 0) {
chartConfig3.value.xAxisData = startTimes
} else {
chartConfig3.value.xAxisData = timerange
}
chartConfig3.value.series[0].data = overtimeShipmentRates.map(
(rate, idx) => ({
value: rate,
count: overtimeShipmentOrderNums[idx],
}),
)
}
const handleResize = () => {
chartInstances.forEach((instance) => {
instance?.resize()
})
}
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
chartInstances.forEach((instance, index) => {
instance?.dispose()
chartInstances[index] = null
})
})
</script>
<style lang="scss" scoped>
.factory-info {
font-size: 24px;
.title {
margin-right: 10px;
font-weight: 500;
color: green;
.dashboard-title {
font-size: 20px;
font-weight: 600;
color: #333;
padding: 10px 20px;
}
.card-wrapper {
background-color: #fff;
}
.card-container-wrapper {
padding: 0 20px 20px;
}
.card-container {
width: 100%;
background-color: #fff;
border-radius: 5px;
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
&:not(:last-child) {
margin-bottom: 20px;
}
.card-item {
min-width: 270px;
height: 120px;
background-color: #f7f7f7;
border-radius: 5px;
padding: 8px 15px;
display: flex;
flex-direction: column;
justify-content: space-between;
.card-item-header {
display: flex;
align-items: center;
.card-title {
font-size: 18px;
font-weight: 600;
color: #333;
}
.card-icon {
width: 20px;
height: 20px;
cursor: pointer;
background-size: 100% 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256' viewBox='0 0 256 256'%3E%3Cpath fill='%238e8d8d' d='M140 180a12 12 0 1 1-12-12a12 12 0 0 1 12 12M128 72c-22.06 0-40 16.15-40 36v4a8 8 0 0 0 16 0v-4c0-11 10.77-20 24-20s24 9 24 20s-10.77 20-24 20a8 8 0 0 0-8 8v8a8 8 0 0 0 16 0v-.72c18.24-3.35 32-17.9 32-35.28c0-19.85-17.94-36-40-36m104 56A104 104 0 1 1 128 24a104.11 104.11 0 0 1 104 104m-16 0a88 88 0 1 0-88 88a88.1 88.1 0 0 0 88-88'/%3E%3C/svg%3E");
}
}
.card-item-content-box {
display: flex;
align-items: flex-end;
gap: 10px;
.card-item-content {
font-size: 50px;
font-weight: 500;
white-space: nowrap;
}
.card-item-content-text {
font-size: 14px;
color: #666;
display: flex;
align-items: center;
margin-right: 10px;
width: 100%;
white-space: nowrap;
margin-bottom: 3px;
}
.up-icon {
width: 18px;
height: 18px;
background-size: 100% 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256' viewBox='0 0 24 24'%3E%3Cpath fill='%23f56c6c' d='M12.725 2.451a.75.75 0 0 0-1.007-.013L3.504 9.69A.75.75 0 0 0 4 11.003h4.382c.138 1.255.057 2.576-.252 3.969c-.318 1.434-1.722 3.25-4.515 5.438a.75.75 0 0 0 .535 1.337c3.311-.322 6.112-1.537 8.365-3.662c2.08-1.963 3.228-4.334 3.422-7.082H20a.75.75 0 0 0 .511-1.299z'/%3E%3C/svg%3E");
}
.down-icon {
width: 18px;
height: 18px;
background-size: 100% 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256' viewBox='0 0 24 24'%3E%3Cpath fill='%2367C23A' d='M4.15 2.253a.75.75 0 0 0-.535 1.337C6.408 5.778 7.812 7.594 8.13 9.028c.309 1.393.39 2.714.252 3.969H4a.75.75 0 0 0-.496 1.312l8.214 7.253a.75.75 0 0 0 1.007-.013l7.786-7.253a.75.75 0 0 0-.511-1.3h-4.063c-.194-2.747-1.342-5.118-3.422-7.08C10.262 3.79 7.46 2.574 4.15 2.252'/%3E%3C/svg%3E");
}
}
}
}
.text-blue {
color: #409eff;
}
.text-green {
color: #67c23a;
}
.text-red {
color: #f56c6c;
}
.text-yellow {
color: #e6a23c;
}
.dashboard-wrapper {
height: 100%;
width: 100%;
margin: 0 auto;
overflow-x: hidden;
}
.chart-wrapper {
position: relative;
margin-top: 20px;
}
.chart-container {
min-height: 500px;
height: 500px;
background-color: #fff;
border-radius: 5px;
padding: 20px;
box-sizing: border-box;
}
.chart-controls {
position: absolute;
top: 30px;
right: 30px;
z-index: 10;
}
.charts-row {
display: flex;
gap: 10px;
}
.chart-half {
width: 50%;
}
@media (max-width: 1000px) {
.charts-row {
flex-direction: column;
}
.chart-half {
width: 100%;
}
}
</style>
......@@ -706,6 +706,44 @@ function changeChinaTime(zone: string) {
})
}
const handleRadioGroupClick = (event: Event) => {
const target = event.target as HTMLElement
const radioButton = target.closest('.el-radio-button')
if (radioButton) {
const input = radioButton.querySelector(
'input[type="radio"]',
) as HTMLInputElement
if (input) {
const value = input.value
if (searchForm.value.customizedQuantity === value) {
event.preventDefault()
event.stopPropagation()
searchForm.value.customizedQuantity = ''
}
}
}
}
const handleMultiRadioGroupClick = (event: Event) => {
const target = event.target as HTMLElement
const radioButton = target.closest('.el-radio-button')
if (radioButton) {
const input = radioButton.querySelector(
'input[type="radio"]',
) as HTMLInputElement
if (input) {
const value = input.value === 'true' ? true : false
if (searchForm.value.multi === value) {
event.preventDefault()
event.stopPropagation()
searchForm.value.multi = null
}
}
}
}
const resultConfirm = () => {
search()
loadTabData()
......@@ -796,7 +834,7 @@ onMounted(() => {
clearable
filterable
popper-class="customize-select-style"
style="width: 150px"
style="width: 180px"
>
<ElOption
v-for="(item, index) in platformJson"
......@@ -878,16 +916,27 @@ onMounted(() => {
</ElSelect>
</ElFormItem>
<ElFormItem label="类型">
<ElFormItem
label="印刷"
@click.stop="(e: Event) => handleRadioGroupClick(e)"
>
<el-radio-group v-model="searchForm.customizedQuantity">
<el-radio-button value="single">单面</el-radio-button>
<el-radio-button value="multiple">多面</el-radio-button>
<el-radio-button value="normal">普品</el-radio-button>
</el-radio-group>
</ElFormItem>
<ElFormItem label="数量">
<el-radio-group v-model="searchForm.multi">
<el-radio-button :value="false">单件</el-radio-button>
<el-radio-button :value="true">多件</el-radio-button>
<el-radio-group
v-model="searchForm.multi"
@click.stop="(e: Event) => handleMultiRadioGroupClick(e)"
>
<el-radio-button :value="false" class="radioBtn"
>单件</el-radio-button
>
<el-radio-button :value="true" class="radioBtn"
>多件</el-radio-button
>
</el-radio-group>
</ElFormItem>
<ElFormItem>
......@@ -1283,12 +1332,9 @@ onMounted(() => {
}
}
}
.search-form {
::v-deep .el-radio-button {
.radioBtn {
::v-deep .el-radio-button__inner {
width: 75px;
.el-radio-button__inner {
width: 100%;
}
}
}
</style>
......@@ -102,7 +102,8 @@ const tableColumns = computed(() => {
prop: 'replaceShipment',
width: 120,
align: 'center',
},{
},
{
label: '物流类型',
slot: 'shipmentType',
prop: 'shipmentType',
......@@ -297,6 +298,24 @@ const goodsColumns = computed(() => {
},
]
})
const productMarkList = [
{
label: '普通商品',
value: 'normal',
},
{
label: 'pod商品',
value: 'pod',
},
{
label: '一件定制局部印',
value: 'custom_part',
},
{
label: '一件定制满印',
value: 'custom_full',
},
]
const tableData = ref<PodCnOrderListData[]>([])
const goodsData = ref<ProductList[]>([])
const searchVisible = ref(false)
......@@ -377,7 +396,7 @@ const search = () => {
goodsData.value = []
logList.value = []
getOrderListFn()
if(tabValue.value==='2'){
if (tabValue.value === '2') {
zoneType.value = 'Asia/Shanghai'
operationLog()
}
......@@ -442,10 +461,10 @@ const submitExportForm = async () => {
...params,
...(resourceType === 2
? {
...searchForm.value,
startTime: timeRange.value?.[0] || null,
endTime: timeRange.value?.[1] || null,
}
...searchForm.value,
startTime: timeRange.value?.[0] || null,
endTime: timeRange.value?.[1] || null,
}
: {}),
})
ElMessage.success('请求成功,请稍后到右上角[我的下载]中查看')
......@@ -652,7 +671,7 @@ const refreshAddress = async () => {
ElMessage.success('操作成功')
search()
await loadTabData()
if(tabValue.value==='2'){
if (tabValue.value === '2') {
zoneType.value = 'Asia/Shanghai'
await operationLog()
}
......@@ -663,7 +682,6 @@ const refreshAddress = async () => {
}
}
/**
* @description: 获取打印面单
*/
......@@ -751,6 +769,44 @@ const handleSelectionChange = (val: PodCnOrderListData[]) => {
selection.value = val
}
const handleRadioGroupClick = (event: Event) => {
const target = event.target as HTMLElement
const radioButton = target.closest('.el-radio-button')
if (radioButton) {
const input = radioButton.querySelector(
'input[type="radio"]',
) as HTMLInputElement
if (input) {
const value = input.value
if (searchForm.value.customizedQuantity === value) {
event.preventDefault()
event.stopPropagation()
searchForm.value.customizedQuantity = ''
}
}
}
}
const handleMultiRadioGroupClick = (event: Event) => {
const target = event.target as HTMLElement
const radioButton = target.closest('.el-radio-button')
if (radioButton) {
const input = radioButton.querySelector(
'input[type="radio"]',
) as HTMLInputElement
if (input) {
const value = input.value === 'true' ? true : false
if (searchForm.value.multi === value) {
event.preventDefault()
event.stopPropagation()
searchForm.value.multi = null
}
}
}
}
/**
* @description: 页面添加回车监听
*/
......@@ -814,7 +870,7 @@ onMounted(() => {
clearable
filterable
placeholder="请输入"
style="width: 150px"
style="width: 180px"
>
<el-option
v-for="item in warehouseList"
......@@ -900,16 +956,27 @@ onMounted(() => {
</ElSelect>
</ElFormItem>
<!-- <ElFormItem label="类型">
<el-radio-group v-model="searchForm.customizedQuantity">
<ElFormItem label="印刷">
<el-radio-group
v-model="searchForm.customizedQuantity"
@click.stop="(e: Event) => handleRadioGroupClick(e)"
>
<el-radio-button value="single">单面</el-radio-button>
<el-radio-button value="multiple">多面</el-radio-button>
<el-radio-button value="normal">普品</el-radio-button>
</el-radio-group>
</ElFormItem> -->
</ElFormItem>
<ElFormItem label="数量">
<el-radio-group v-model="searchForm.multi">
<el-radio-button :value="false">单件</el-radio-button>
<el-radio-button :value="true">多件</el-radio-button>
<el-radio-group
v-model="searchForm.multi"
@click.stop="(e: Event) => handleMultiRadioGroupClick(e)"
>
<el-radio-button :value="false" class="radioBtn"
>单件</el-radio-button
>
<el-radio-button :value="true" class="radioBtn"
>多件</el-radio-button
>
</el-radio-group>
</ElFormItem>
<ElFormItem>
......@@ -1042,7 +1109,32 @@ onMounted(() => {
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem v-if="searchForm.replaceShipment || searchForm.replaceShipment===0" label="物流类型">
<ElFormItem label="商品类型">
<ElSelect
v-model="searchForm.productMark"
placeholder="请选择商品类型"
clearable
filterable
collapse-tags
collapse-tags-tooltip
:teleported="false"
style="width: 150px"
>
<ElOption
v-for="(item, index) in productMarkList"
:key="index"
:value="item.value"
:label="item.label"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem
v-if="
searchForm.replaceShipment ||
searchForm.replaceShipment === 0
"
label="物流类型"
>
<ElSelect
v-model="searchForm.shipmentType"
placeholder="物流类型"
......@@ -1050,7 +1142,9 @@ onMounted(() => {
style="width: 150px"
>
<ElOption
v-for="(item, index) in searchForm.replaceShipment === 0? ['自提', '快递']:['自有物流', '工厂物流']"
v-for="(item, index) in searchForm.replaceShipment === 0
? ['自提', '快递']
: ['自有物流', '工厂物流']"
:key="index"
:value="index"
:label="item"
......@@ -1084,7 +1178,7 @@ onMounted(() => {
<ElFormItem>
<span>
<ElButton link @click="resetSearchForm" style="font-size: 12px"
><span title="重置查询条件">重置</span></ElButton
><span title="重置查询条件">重置</span></ElButton
>
</span>
</ElFormItem>
......@@ -1098,14 +1192,14 @@ onMounted(() => {
<ElFormItem>
<span>
<ElButton type="primary" @click="getOrderByIdApi('getPrintOrder')"
>获取打印面单</ElButton
>获取打印面单</ElButton
>
</span>
</ElFormItem>
<ElFormItem>
<span>
<ElButton type="success" @click="refreshAddress"
>刷新地址</ElButton
>刷新地址</ElButton
>
</span>
</ElFormItem>
......@@ -1136,10 +1230,14 @@ onMounted(() => {
<div>{{ getStatus(row.status) }}</div>
</template>
<template #shipmentType="{ row }">
{{ (row.replaceShipment === 0 ? ['自提', '快递'] : ['自有物流', '工厂物流'])[row.shipmentType] }}
{{
(row.replaceShipment === 0
? ['自提', '快递']
: ['自有物流', '工厂物流'])[row.shipmentType]
}}
</template>
<template #replaceShipment="{ row }">
{{['不代发', '代发'][row.replaceShipment] }}
{{ ['不代发', '代发'][row.replaceShipment] }}
</template>
</TableView>
</div>
......@@ -1163,7 +1261,7 @@ onMounted(() => {
<template #other>
<div class="bottom-table">
<el-tabs v-model="tabValue">
<el-tab-pane name="1" label="商品明细">
<el-tab-pane name="1" label="商品明细">
<TableView
ref="goodsRef"
v-loading="goodsLoading"
......@@ -1176,7 +1274,7 @@ onMounted(() => {
</template>
</TableView>
</el-tab-pane>
<el-tab-pane name="2" label="操作日志" @tab-click="operationLog">
<el-tab-pane name="2" label="操作日志" @tab-click="operationLog">
<div>
<el-button
:type="zoneType === 'Asia/Shanghai' ? 'primary' : ''"
......@@ -1184,27 +1282,24 @@ onMounted(() => {
link
style="margin-left: 10px"
@click="changeChinaTime('Asia/Shanghai')"
>北京时间
</el-button
>
>北京时间
</el-button>
<el-button
:type="zoneType === 'America/New_York' ? 'primary' : ''"
size="small"
link
style="margin-left: 10px"
@click="changeChinaTime('America/New_York')"
>新泽西时间
</el-button
>
>新泽西时间
</el-button>
<el-button
:type="zoneType === 'America/Los_Angeles' ? 'primary' : ''"
size="small"
link
style="margin-left: 10px"
@click="changeChinaTime('America/Los_Angeles')"
>洛杉矶时间
</el-button
>
>洛杉矶时间
</el-button>
</div>
<LogList
......@@ -1239,7 +1334,7 @@ onMounted(() => {
:loading="exportLoading"
type="primary"
@click="submitExportForm"
>确认</el-button
>确认</el-button
>
</span>
</template>
......@@ -1334,14 +1429,9 @@ onMounted(() => {
}
}
}
.search-form {
::v-deep .el-radio-button {
.radioBtn {
::v-deep .el-radio-button__inner {
width: 75px;
.el-radio-button__inner {
width: 100%;
}
}
}
</style>
......@@ -167,7 +167,7 @@
v-model.trim="searchForm.thirdSkuCode"
placeholder="库存SKU"
clearable
style="width: 150px"
style="width: 180px"
></ElInput>
</ElFormItem>
<ElFormItem label="款号" v-if="status !== 'BATCH_DOWNLOAD'">
......@@ -229,13 +229,14 @@
<el-option value="desc" label="倒序"></el-option>
</el-select>
</ElFormItem>
<ElFormItem label="类型" v-if="status !== 'BATCH_DOWNLOAD'">
<ElFormItem label="印刷" v-if="status !== 'BATCH_DOWNLOAD'">
<el-radio-group
v-model="searchForm.customizedQuantity"
@click.stop="(e: Event) => handleRadioGroupClick(e)"
>
<el-radio-button value="single">单面</el-radio-button>
<el-radio-button value="multiple">多面</el-radio-button>
<el-radio-button label="single">单面</el-radio-button>
<el-radio-button label="multiple">多面</el-radio-button>
<el-radio-button label="normal">普品</el-radio-button>
</el-radio-group>
</ElFormItem>
<ElFormItem label="数量" v-if="status !== 'BATCH_DOWNLOAD'">
......@@ -243,8 +244,12 @@
v-model="searchForm.multi"
@click.stop="(e: Event) => handleMultiRadioGroupClick(e)"
>
<el-radio-button :value="false">单件</el-radio-button>
<el-radio-button :value="true">多件</el-radio-button>
<el-radio-button :value="false" class="radioBtn"
>单件</el-radio-button
>
<el-radio-button :value="true" class="radioBtn"
>多件</el-radio-button
>
</el-radio-group>
</ElFormItem>
<ElFormItem v-if="status !== 'BATCH_DOWNLOAD'">
......@@ -372,6 +377,7 @@
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem
v-if="searchForm.replaceShipment === 0"
label="物流类型"
......@@ -1653,6 +1659,15 @@
{{ row.prepaidAmount || 0 }}
</span>
</div>
<div
v-if="['COMPLETE'].includes(status)"
class="order-price-item"
>
<span class="order-price-item-label">实际运费¥:</span>
<span class="order-price-item-value">
{{ row.actualAmount || 0 }}
</span>
</div>
<!-- <div
v-if="
['WAIT_TRACK', 'IN_TRANSIT', 'COMPLETE', 'CANCEL'].includes(
......@@ -2296,6 +2311,9 @@
<div class="menu-item" @click="rightChange('order-number')">
复制订单号
</div>
<div class="menu-item" @click="rightChange('factorySubOrderNumber')">
复制生产单号
</div>
</template>
</RightClickMenu>
<el-dialog
......@@ -2873,7 +2891,11 @@ const totalAmountPrice = (item: PodCnOrderListData): string => {
const productAmount = new BigNumber(item?.productAmount ?? 0)
const serviceAmount = new BigNumber(item?.serviceAmount ?? 0)
// const freightAmount = usePrepaid ? item?.prepaidAmount : item?.actualAmount
const actualFreight = new BigNumber(item?.actualAmount ?? 0)
const payFreight = new BigNumber(item?.prepaidAmount ?? 0)
if (item.status === 'COMPLETE') {
return productAmount.plus(serviceAmount).plus(actualFreight).toString()
}
return productAmount.plus(serviceAmount).plus(payFreight).toString()
}
const countryList = ref([])
......@@ -4567,13 +4589,40 @@ const rightChange = async (code: string) => {
} else if (code === 'copy_shopNumber') {
const str = (tableData.value as ProductList[] | PodCnOrderListData[])
.map((item) => item?.shopNumber)
.join()
.filter(Boolean)
.join(',')
if (!str) return ElMessage.warning('当前数据没有店铺单号')
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
} else if (code === 'order-number') {
const str = (tableData.value as ProductList[] | PodCnOrderListData[])
.map((item) => item?.factoryOrderNumber)
.join()
.filter(Boolean)
.join(',')
if (!str) return ElMessage.warning('当前数据没有订单号')
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
} else if (code === 'factorySubOrderNumber') {
let str
if (flat) {
str = (tableData.value as (ProductList | PodCnOrderListData)[])
.flatMap(
(item) =>
(item as PodCnOrderListData)?.productList
?.map((product) => product.factorySubOrderNumber)
?.filter(Boolean) ?? [],
)
.filter(Boolean)
.join(',')
} else {
str = (tableData.value as ProductList[])
.map((item) => item?.factorySubOrderNumber)
.filter(Boolean)
.join(',')
}
if (!str) return ElMessage.warning('当前数据没有生产单号')
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
}
......@@ -6166,14 +6215,14 @@ useEnterKeyTrigger({
color: white;
font-weight: bold;
}
.search-form {
::v-deep .el-radio-button {
width: 75px;
.el-radio-button__inner {
width: 100%;
}
}
}
// .search-form {
// ::v-deep .el-radio-button {
// width: 75px;
// .el-radio-button__inner {
// width: 100%;
// }
// }
// }
.triangle-container-wrap {
position: absolute;
top: 0;
......@@ -6202,6 +6251,11 @@ useEnterKeyTrigger({
font-size: 12px;
}
}
.radioBtn {
::v-deep .el-radio-button__inner {
width: 75px;
}
}
</style>
<style lang="scss">
.customize-select-style {
......
......@@ -132,7 +132,7 @@
<LogisticsWaySelect
v-model="searchForm.craftCode"
:company-list="craftList"
:start-width="'178px'"
:start-width="'150px'"
search-placeholder="搜索工艺名称"
start-placeholder="请选择工艺名称"
></LogisticsWaySelect>
......@@ -142,7 +142,7 @@
v-model.trim="searchForm.thirdSkuCode"
placeholder="库存SKU"
clearable
style="width: 150px"
style="width: 180px"
></ElInput>
</ElFormItem>
<ElFormItem label="款号" v-if="status !== 'BATCH_DOWNLOAD'">
......@@ -219,7 +219,7 @@
</ElSelect>
</ElFormItem>
<!-- </div> -->
<ElFormItem label="类型" v-if="status !== 'BATCH_DOWNLOAD'">
<ElFormItem label="印刷" v-if="status !== 'BATCH_DOWNLOAD'">
<el-radio-group
v-model="searchForm.customizedQuantity"
@click.stop="(e: Event) => handleRadioGroupClick(e)"
......@@ -234,8 +234,12 @@
v-model="searchForm.multi"
@click.stop="(e: Event) => handleMultiRadioGroupClick(e)"
>
<el-radio-button :label="false">单件</el-radio-button>
<el-radio-button :label="true">多件</el-radio-button>
<el-radio-button :label="false" class="radioBtn"
>单件</el-radio-button
>
<el-radio-button :label="true" class="radioBtn"
>多件</el-radio-button
>
</el-radio-group>
</ElFormItem>
<ElFormItem>
......@@ -2542,6 +2546,9 @@
<div class="menu-item" @click="rightChange('order-number')">
复制订单号
</div>
<div class="menu-item" @click="rightChange('factorySubOrderNumber')">
复制生产单号
</div>
</template>
</RightClickMenu>
<el-dialog
......@@ -5178,13 +5185,38 @@ const rightChange = async (code: string) => {
} else if (code === 'copy_shopNumber') {
const str = (tableData.value as ProductList[] | PodUsOrderListData[])
.map((item) => item?.shopNumber)
.join()
.filter(Boolean)
.join(',')
if (!str) return ElMessage.warning('当前数据没有店铺单号')
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
} else if (code === 'order-number') {
const str = (tableData.value as ProductList[] | PodUsOrderListData[])
.map((item) => item?.factoryOrderNumber)
.join()
.filter(Boolean)
.join(',')
if (!str) return ElMessage.warning('当前数据没有订单号')
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
} else if (code === 'factorySubOrderNumber') {
let str
if (flat) {
str = (tableData.value as (ProductList | PodUsOrderListData)[])
.flatMap(
(item) =>
(item as PodUsOrderListData)?.productList
?.map((product) => product.factorySubOrderNumber)
?.filter(Boolean) ?? [],
)
.filter(Boolean)
.join(',')
} else {
str = (tableData.value as ProductList[])
.map((item) => item?.factorySubOrderNumber)
.filter(Boolean)
.join(',')
}
if (!str) return ElMessage.warning('当前数据没有生产单号')
navigator.clipboard.writeText(str)
ElMessage.success('复制成功')
}
......@@ -7218,6 +7250,11 @@ const printNormal = async () => {
font-size: 12px;
}
}
.radioBtn {
::v-deep .el-radio-button__inner {
width: 75px;
}
}
</style>
<style lang="scss">
.customize-select-style {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment