Commit 007a584d by zhuzhequan

Merge remote-tracking branch 'origin/dev' into dev

parents 06de53c3 9f5792ba
......@@ -483,12 +483,13 @@ export function refreshProductInformationApi(data: {
}
// 设计图排版
export function composingDesignImages(
url: string,
data: number[],
type?: string,
templateWidth?: number,
) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderCn/composingDesignImages?type=${type}&templateWidth=${templateWidth}`,
`${url}?type=${type}&templateWidth=${templateWidth}`,
data,
)
}
......@@ -770,7 +771,7 @@ export function updateCustomDeclarationInfoApi({
formData.append(key, String(value))
}
})
return axios.post<never, BaseRespData<never>>(
'factory/podJomallOrderCn/batchUpdateCustomsClearanceInfo',
formData,
......@@ -779,3 +780,14 @@ export function updateCustomDeclarationInfoApi({
},
)
}
// 标记缺货/移除缺货共用
export function updateProductOutOfStockApi(params: {
productIds: (number | string)[]
orderFrom: string
outOfStock: boolean
}) {
return axios.post<never, BaseRespData<never>>(
`/factory/podJomallOrderProductCnUs/updateProductOutOfStock`,
params,
)
}
......@@ -286,7 +286,10 @@ export function clearBoxApi(
},
)
}
export function clearAllBoxApi(warehouseId: string | number, factoryNo: string | number | undefined) {
export function clearAllBoxApi(
warehouseId: string | number,
factoryNo: string | number | undefined,
) {
return axios.get<never, BaseRespData<never>>(
'factory/podJomallOrderUs/delPodBoxOrderDetails',
{
......@@ -394,12 +397,13 @@ export function updateSelfLogistics(params: {
// 更改物流
export function composingDesignImages(
url: string,
data: number[],
type?: string,
templateWidth?: number,
) {
return axios.post<never, BaseRespData<never>>(
`factory/podJomallOrderUs/composingDesignImages?type=${type}&templateWidth=${templateWidth}`,
`${url}?type=${type}&templateWidth=${templateWidth}`,
data,
)
}
......@@ -685,3 +689,14 @@ export function printNormalPickPdfApi(ids: string) {
{ params: { ids } },
)
}
// 标记缺货/移除缺货共用
export function updateProductOutOfStockApi(params: {
productIds: (number | string)[]
orderFrom: string
outOfStock: boolean
}) {
return axios.post<never, BaseRespData<never>>(
`/factory/podJomallOrderProductCnUs/updateProductOutOfStock`,
params,
)
}
......@@ -54,6 +54,7 @@ export interface SearchForm {
automaticComposing?: number
employeeId?: number
blocking?: boolean
outOfStock?: boolean
}
export interface PodCnOrderListData {
id: number
......@@ -158,6 +159,7 @@ export interface ProductList {
batchArrangeNumber?: string | null
sizeType?: number | null
customTagList?: { name: string }[]
outOfStock?: boolean
}
export interface cardImages {
title: string
......
......@@ -50,6 +50,7 @@ export interface SearchForm {
automaticComposing?: number
employeeId?: number
blocking?: boolean
outOfStock?: boolean
}
export interface PodUsOrderListData {
id: number
......@@ -157,6 +158,7 @@ export interface ProductList {
sizeType?: number | null
productMark?: string | null
customTagList?: { name: string }[]
outOfStock?: boolean
}
export interface cardImages {
title: string
......
......@@ -6,11 +6,11 @@
<div class="card-container">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">今日新单(件/单)</div>
<div class="card-title">今日新单(件/单)</div>
<el-tooltip
class="item"
effect="light"
content="今日新增订单的订单数量"
:content="`今日新增订单的订单数量(${today}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="card-icon"></div>
......@@ -28,11 +28,11 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">今日接单(件/单)</div>
<div class="card-title">今日接单(件/单)</div>
<el-tooltip
class="item"
effect="light"
content="今日新增确认生产的订单数量"
:content="`今日新增确认生产的订单数量(${today}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="card-icon"></div>
......@@ -50,7 +50,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">未发货订单(单)</div>
<div class="card-title">未发货订单(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -68,7 +68,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">超时未发订单(单)</div>
<div class="card-title">超时未发订单(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -86,197 +86,247 @@
</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 ?? '-' }}
<el-tooltip class="item" effect="light" placement="bottom-end">
<template #content>
<div style="display: flex; align-items: center; gap: 4px">
<div class="up-icon-green"></div>
<div>为正向趋势,</div>
<div class="down-icon-red"></div>
<div>为负向趋势</div>
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareYesterdayShipmentOrderNum >= 0
"
style="display: flex; margin-left: 10px"
</template>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">昨日发货数(订单)</div>
<el-tooltip
class="item"
effect="light"
:content="`昨日转为已发货状态的总订单数(${yesterday}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="text-red">
{{ statisticData?.compareYesterdayShipmentOrderNum }}
</div>
<div class="up-icon"></div>
<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 v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareYesterdayShipmentOrderNum || 0,
)
}}
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareYesterdayShipmentOrderNum >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-green">
{{
statisticData?.compareYesterdayShipmentOrderNum.toFixed(
2,
)
}}
</div>
<div class="up-icon-green"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-red">
{{
Math.abs(
statisticData?.compareYesterdayShipmentOrderNum || 0,
).toFixed(2)
}}
</div>
<div class="down-icon-red"></div>
</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 ?? '-') + '%' }}
</el-tooltip>
<el-tooltip class="item" effect="light" placement="bottom-end">
<template #content>
<div style="display: flex; align-items: center; gap: 4px">
<div class="up-icon-green"></div>
<div>为正向趋势,</div>
<div class="down-icon-red"></div>
<div>为负向趋势</div>
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayShipmentRateOf24Hour >= 0
"
style="display: flex; margin-left: 10px"
</template>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">24h发货率</div>
<el-tooltip
class="item"
effect="light"
:content="`昨日已发货订单中从接单转为已发货状态在24小时内的比例(${yesterday}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="text-red">
{{
(statisticData?.compareLastDayShipmentRateOf24Hour ??
'-') + '%'
}}
</div>
<div class="up-icon"></div>
<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 v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayShipmentRateOf24Hour || 0,
) + '%'
}}
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayShipmentRateOf24Hour >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-green">
{{
(statisticData?.compareLastDayShipmentRateOf24Hour.toFixed(
2,
) ?? '-') + '%'
}}
</div>
<div class="up-icon-green"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-red">
{{
Math.abs(
statisticData?.compareLastDayShipmentRateOf24Hour ||
0,
).toFixed(2) + '%'
}}
</div>
<div class="down-icon-red"></div>
</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 ?? '-') + '%' }}
</el-tooltip>
<el-tooltip class="item" effect="light" placement="bottom-end">
<template #content>
<div style="display: flex; align-items: center; gap: 4px">
<div class="up-icon-green"></div>
<div>为正向趋势,</div>
<div class="down-icon-red"></div>
<div>为负向趋势</div>
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayShipmentRateOf48Hour >= 0
"
style="display: flex; margin-left: 10px"
</template>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">48h发货率</div>
<el-tooltip
class="item"
effect="light"
:content="`昨日已发货订单中从接单转为已发货状态在48小时内的比例(${yesterday}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="text-red">
{{
(statisticData?.compareLastDayShipmentRateOf48Hour ??
'-') + '%'
}}
</div>
<div class="up-icon"></div>
<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 v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayShipmentRateOf48Hour || 0,
) + '%'
}}
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayShipmentRateOf48Hour >= 0
"
style="display: flex; margin-left: 10px"
>
<div class="text-green">
{{
(statisticData?.compareLastDayShipmentRateOf48Hour.toFixed(
2,
) ?? '-') + '%'
}}
</div>
<div class="up-icon-green"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-red">
{{
Math.abs(
statisticData?.compareLastDayShipmentRateOf48Hour ||
0,
).toFixed(2) + '%'
}}
</div>
<div class="down-icon-red"></div>
</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 ?? '-') +
')'
}}
</el-tooltip>
<el-tooltip class="item" effect="light" placement="bottom-end">
<template #content>
<div style="display: flex; align-items: center; gap: 4px">
<div class="down-icon-green"></div>
<div>为正向趋势,</div>
<div class="up-icon-red"></div>
<div>为负向趋势</div>
</div>
<div class="card-item-content-text">
较前天
<div
v-if="
statisticData &&
statisticData.compareLastDayOverTimeShipmentRate >= 0
"
style="display: flex; margin-left: 10px"
</template>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">发货超时率</div>
<el-tooltip
class="item"
effect="light"
:content="`昨日已发货订单中从接单转为已发货状态大于48小时的比例(${yesterday}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="text-red">
{{
(statisticData?.compareLastDayOverTimeShipmentRate ??
'-') + '%'
}}
</div>
<div class="up-icon"></div>
<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 v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayOverTimeShipmentRate || 0,
) + '%'
}}
<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.toFixed(
2,
) ?? '-') + '%'
}}
</div>
<div class="up-icon-red"></div>
</div>
<div v-else style="display: flex; margin-left: 10px">
<div class="text-green">
{{
Math.abs(
statisticData?.compareLastDayOverTimeShipmentRate ||
0,
).toFixed(2) + '%'
}}
</div>
<div class="down-icon-green"></div>
</div>
<div class="down-icon"></div>
</div>
</div>
</div>
</div>
</el-tooltip>
</div>
<div class="card-container">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">待创建物流(单)</div>
<div class="card-title">待创建物流(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -294,11 +344,11 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">待排单(单)</div>
<div class="card-title">待排单(生产单)</div>
<el-tooltip
class="item"
effect="light"
content="目前订单中待排单的总生产数"
content="目前订单中待排单的总生产数"
placement="bottom"
>
<div class="card-icon"></div>
......@@ -312,7 +362,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">生产中(单)</div>
<div class="card-title">生产中(生产单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -330,7 +380,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">待发货(单)</div>
<div class="card-title">待发货(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -348,7 +398,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">拦截申请(单)</div>
<div class="card-title">拦截申请(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -366,11 +416,11 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">异常单(单)</div>
<div class="card-title">异常单(单)</div>
<el-tooltip
class="item"
effect="light"
content="所有订单中的异常单总单数"
content="所有订单中的异常单总单数"
placement="bottom"
>
<div class="card-icon"></div>
......@@ -386,7 +436,7 @@
<div class="card-container">
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货中订单(单)</div>
<div class="card-title">缺货中订单(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -404,7 +454,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货&lt;24h单(单)</div>
<div class="card-title">缺货&lt;24h单(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -422,7 +472,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货&lt;48h单(单)</div>
<div class="card-title">缺货&lt;48h单(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -440,7 +490,7 @@
</div>
<div class="card-item">
<div class="card-item-header">
<div class="card-title">缺货≥48h单(单)</div>
<div class="card-title">缺货≥48h单(单)</div>
<el-tooltip
class="item"
effect="light"
......@@ -593,6 +643,22 @@ echarts.use([
UniversalTransition,
])
const today = new Date()
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
const yesterday = new Date(new Date().setDate(new Date().getDate() - 1))
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
// 获取统计数据
const statisticData = ref<StatisticData | null>(null)
......@@ -755,7 +821,6 @@ const createChartOption = (
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
......@@ -918,9 +983,16 @@ const getStatisticDataApi = async () => {
})
.then((res) => {
if (res.code === 200) {
const isEmpty = checkOrderTrendDataEmpty(res.data)
// 无论数据是否为空,都要更新 x 轴数据
updateOrderTrendChart(res.data, 0)
chartInstances[0]?.setOption(createChartOption(chartConfig1))
// 无数据时保持 loading,有数据则关闭
updateChart(
chartInstances[0],
chartConfig1,
isEmpty,
false,
chartTimes1.value,
)
orderChart1Loading.value = !(res.data && res.data.length > 0)
}
})
......@@ -935,8 +1007,16 @@ const getStatisticDataApi = async () => {
})
.then((res) => {
if (res.code === 200) {
const isEmpty = checkShipmentTrendDataEmpty(res.data)
// 无论数据是否为空,都要更新 x 轴数据
updateShipmentTrendChart(res.data, 0)
chartInstances[1]?.setOption(createChartOption(chartConfig2, true))
updateChart(
chartInstances[1],
chartConfig2,
isEmpty,
true,
chartTimes2.value,
)
orderChart2Loading.value = !(res.data && res.data.length > 0)
}
})
......@@ -951,9 +1031,17 @@ const getStatisticDataApi = async () => {
})
.then((res) => {
if (res.code === 200) {
const isEmpty = checkOvertimeTrendDataEmpty(res.data)
// 无论数据是否为空,都要更新 x 轴数据
updateOvertimeTrendChart(res.data, 0)
chartInstances[2]?.setOption(
createChartOption(chartConfig3, true, overtimeTooltipFormatter),
updateChart(
chartInstances[2],
chartConfig3,
isEmpty,
true,
chartTimes3.value,
overtimeTooltipFormatter,
)
orderChart3Loading.value = !(res.data && res.data.length > 0)
}
......@@ -1004,17 +1092,40 @@ const getchartTimes = async (v: string, type: string) => {
trendType: type,
})
if (type == 'ORDER_TREND') {
const isEmpty = checkOrderTrendDataEmpty(data)
// 无论数据是否为空,都要更新 x 轴数据
updateOrderTrendChart(data, v)
chartInstances[0]?.setOption(createChartOption(chartConfig1))
updateChart(
chartInstances[0],
chartConfig1,
isEmpty,
false,
chartTimes1.value,
)
orderChart1Loading.value = !(data && data.length > 0)
} else if (type == 'SHIPMENT_TREND') {
const isEmpty = checkShipmentTrendDataEmpty(data)
// 无论数据是否为空,都要更新 x 轴数据
updateShipmentTrendChart(data, v)
chartInstances[1]?.setOption(createChartOption(chartConfig2, true))
updateChart(
chartInstances[1],
chartConfig2,
isEmpty,
true,
chartTimes2.value,
)
orderChart2Loading.value = !(data && data.length > 0)
} else {
const isEmpty = checkOvertimeTrendDataEmpty(data)
// 无论数据是否为空,都要更新 x 轴数据
updateOvertimeTrendChart(data, v)
chartInstances[2]?.setOption(
createChartOption(chartConfig3, true, overtimeTooltipFormatter),
updateChart(
chartInstances[2],
chartConfig3,
isEmpty,
true,
chartTimes3.value,
overtimeTooltipFormatter,
)
orderChart3Loading.value = !(data && data.length > 0)
}
......@@ -1023,6 +1134,217 @@ const getchartTimes = async (v: string, type: string) => {
}
}
// 空数据提示文字
const generatePeriodText = (timeRange: string): string => {
if (timeRange === '0') {
const startTime = new Date(new Date().setDate(new Date().getDate() - 14))
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
return `当前周期(${startTime}${yesterday})暂无订单数据\n\n请在订单流转后等待数据更新查看趋势`
} else if (timeRange === '1') {
// 8周前该周周一的日期
const now = new Date()
const eightWeeksAgo = new Date(now.getTime() - 8 * 7 * 24 * 60 * 60 * 1000)
const dayOfWeek = eightWeeksAgo.getDay() // 0=周日, 1=周一, ..., 6=周六
const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek // 如果是周日,往前6天;否则往前到周一
const mondayDate = new Date(
eightWeeksAgo.getTime() + daysToMonday * 24 * 60 * 60 * 1000,
)
const startTime = mondayDate
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
// 上个周日的日期
const today = new Date()
const todayDayOfWeek = today.getDay() // 0=周日, 1=周一, ..., 6=周六
const daysToLastSunday = todayDayOfWeek === 0 ? -7 : -todayDayOfWeek // 如果是周日,往前7天;否则往前到上一个周日
const lastSunday = new Date(
today.getTime() + daysToLastSunday * 24 * 60 * 60 * 1000,
)
const endTime = lastSunday
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
return `当前周期(${startTime}${endTime})暂无订单数据\n\n请在订单流转后等待数据更新查看趋势`
} else if (timeRange === '2') {
// 六个月前该月第一天的日期
const now = new Date()
const sixMonthsAgo = new Date(now.getFullYear(), now.getMonth() - 6, 1)
const startTime = sixMonthsAgo
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
// 上一月第一天的日期
const currentDate = new Date()
const lastMonthFirstDay = new Date(
currentDate.getFullYear(),
currentDate.getMonth() - 1,
1,
)
const endTime = lastMonthFirstDay
.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-')
return `当前周期(${startTime}${endTime})暂无订单数据\n\n请在订单流转后等待数据更新查看趋势`
}
return ''
}
// 更新图表(统一处理空状态和正常状态)
const updateChart = (
instance: echarts.ECharts | null,
config: Ref<ChartConfig>,
isEmpty: boolean,
isPercent = false,
timeRange: string,
customFormatter?: (params: TooltipParam[]) => string,
) => {
if (!instance) return
if (isEmpty) {
const periodText = generatePeriodText(timeRange)
setNotopt(instance, config, periodText, isPercent)
} else {
// 使用 notMerge: true 完全替换配置,确保从空状态切换回来时配置正确
instance.setOption(
createChartOption(config, isPercent, customFormatter),
true,
)
}
}
// 图表空状态
const setNotopt = (
demo: echarts.ECharts | null,
config: Ref<ChartConfig>,
subtext = '暂无数据',
isPercent = false,
) => {
if (!demo) return
const chartData = config.value
const option = {
title: [
{
text: chartData.title,
left: 'left',
},
{
text: ' {a|}',
x: 'center',
y: 'center',
subtext,
itemGap: -20,
textStyle: {
rich: {
a: {
color: '#000',
fontSize: '16',
height: 120,
width: 220,
backgroundColor: {
image:
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA2NCA0MSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbFJ1bGU9ImV2ZW5vZGQiPg0KICAgIDxlbGxpcHNlIGZpbGw9IiNkZGQiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3IiAvPg0KICAgIDxnIGZpbGxSdWxlPSJub256ZXJvIiBzdHJva2U9IiM5OTkiPg0KICAgICAgPHBhdGgNCiAgICAgICAgZD0iTTU1IDEyLjc2TDQ0Ljg1NCAxLjI1OEM0NC4zNjcuNDc0IDQzLjY1NiAwIDQyLjkwNyAwSDIxLjA5M2MtLjc0OSAwLTEuNDYuNDc0LTEuOTQ3IDEuMjU3TDkgMTIuNzYxVjIyaDQ2di05LjI0eiIgLz4NCiAgICAgIDxwYXRoDQogICAgICAgIGQ9Ik00MS42MTMgMTUuOTMxYzAtMS42MDUuOTk0LTIuOTMgMi4yMjctMi45MzFINTV2MTguMTM3QzU1IDMzLjI2IDUzLjY4IDM1IDUyLjA1IDM1aC00MC4xQzEwLjMyIDM1IDkgMzMuMjU5IDkgMzEuMTM3VjEzaDExLjE2YzEuMjMzIDAgMi4yMjcgMS4zMjMgMi4yMjcgMi45Mjh2LjAyMmMwIDEuNjA1IDEuMDA1IDIuOTAxIDIuMjM3IDIuOTAxaDE0Ljc1MmMxLjIzMiAwIDIuMjM3LTEuMzA4IDIuMjM3LTIuOTEzdi0uMDA3eiINCiAgICAgICAgZmlsbD0iI2UxZTFlMSIgLz4NCiAgICA8L2c+DQogIDwvZz4NCjwvc3ZnPg==',
},
},
},
},
subtextStyle: {
fontSize: 16,
},
},
],
// 图例
legend: {
data: chartData.legend,
top: 'top',
left: 'center',
},
// 横坐标
xAxis: {
type: 'category',
boundaryGap: false,
data: chartData.xAxisData,
axisLabel: {
overflow: 'truncate',
width: 120,
formatter: function (value: string) {
if (value.length > 10) {
return value.substring(0, 10) + '...'
}
return value
},
},
},
// 网格配置
grid: {
left: '3%',
right: '4%',
bottom: '3%',
},
// 纵坐标,默认范围从0到1
yAxis: {
type: 'value',
min: 0,
max: 1,
axisLabel: isPercent
? {
formatter: '{value}%',
color: '#666',
}
: {
color: '#666',
},
axisLine: {
lineStyle: { color: '#ccc' },
},
splitLine: {
show: false,
},
},
// 清空 series 数据
series: chartData.series.map((item) => ({
name: item.name,
type: 'line',
data: [],
color: item.color,
})),
}
demo.setOption(option, true)
}
// 检查订单趋势数据是否为空
const checkOrderTrendDataEmpty = (data: trendType[]): boolean => {
const confirmNums = data.map((el) => el.confirmNum)
const produceNums = data.map((el) => el.produceNum)
const shipmentNums = data.map((el) => el.shipmentNum)
const hasData =
confirmNums.some((item) => item !== 0) ||
produceNums.some((item) => item !== 0) ||
shipmentNums.some((item) => item !== 0)
return !hasData
}
// 更新订单趋势图表数据
const updateOrderTrendChart = (data: trendType[], type: number | string) => {
const confirmNums = data.map((el) => el.confirmNum)
const produceNums = data.map((el) => el.produceNum)
......@@ -1035,11 +1357,23 @@ const updateOrderTrendChart = (data: trendType[], type: number | string) => {
} else {
chartConfig1.value.xAxisData = timerange
}
chartConfig1.value.series[0].data = confirmNums
chartConfig1.value.series[1].data = produceNums
chartConfig1.value.series[2].data = shipmentNums
}
// 检查发货效率数据是否为空
const checkShipmentTrendDataEmpty = (data: trendType[]): boolean => {
const shipmentRateOf24Hours = data.map((el) => el.shipmentRateOf24Hour)
const shipmentRateOf48Hours = data.map((el) => el.shipmentRateOf48Hour)
const hasData =
shipmentRateOf24Hours.some((item) => item !== 0) ||
shipmentRateOf48Hours.some((item) => item !== 0)
return !hasData
}
// 更新发货效率图表数据
const updateShipmentTrendChart = (data: trendType[], type: number | string) => {
const shipmentRateOf24Hours = data.map((el) => el.shipmentRateOf24Hour)
const shipmentRateOf48Hours = data.map((el) => el.shipmentRateOf48Hour)
......@@ -1056,6 +1390,14 @@ const updateShipmentTrendChart = (data: trendType[], type: number | string) => {
chartConfig2.value.series[1].data = shipmentRateOf48Hours
}
// 检查超时情况数据是否为空
const checkOvertimeTrendDataEmpty = (data: trendType[]): boolean => {
const overtimeShipmentRates = data.map((el) => el.overtimeShipmentRate)
const hasData = overtimeShipmentRates.some((item) => item !== 0)
return !hasData
}
// 更新超时情况图表数据
const updateOvertimeTrendChart = (data: trendType[], type: number | string) => {
const overtimeShipmentOrderNums = data.map(
(el) => el.overtimeShipmentOrderNum,
......@@ -1069,6 +1411,7 @@ const updateOvertimeTrendChart = (data: trendType[], type: number | string) => {
} else {
chartConfig3.value.xAxisData = timerange
}
chartConfig3.value.series[0].data = overtimeShipmentRates.map(
(rate, idx) => ({
value: rate,
......@@ -1166,19 +1509,6 @@ onBeforeUnmount(() => {
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");
}
}
}
}
......@@ -1246,3 +1576,30 @@ onBeforeUnmount(() => {
}
}
</style>
<style lang="scss">
.up-icon-red {
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");
}
.up-icon-green {
width: 18px;
height: 18px;
background-size: 100% 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2367C23A' 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-green {
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");
}
.down-icon-red {
width: 18px;
height: 18px;
background-size: 100% 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23F56C6C' 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");
}
</style>
......@@ -16,6 +16,15 @@
<span>播种墙配货</span>
<span v-if="socketConnect === 'online'" class="online">[在线]</span>
<span v-else class="offline">[离线]</span>
<ElButton
v-if="socketConnect === 'offline'"
type="success"
size="small"
:icon="Refresh"
@click="reconnectWebSocket"
>
刷新
</ElButton>
</div>
</template>
<div class="pod-make-order-content">
......@@ -268,7 +277,7 @@ import {
printNormalPdf,
} from '@/api/podCnOrder'
import useUserStore from '@/store/user'
import { Check } from '@element-plus/icons-vue'
import { Check, Refresh } from '@element-plus/icons-vue'
import socket from '@/utils/cnWebsocket'
import { WarehouseListData } from '@/types/api/podUsOrder'
import { ElMessage } from 'element-plus'
......@@ -1086,6 +1095,27 @@ const handleWarehouseChange = (value: string | number) => {
_warehouseId.value = value
initOrderDetailBox()
}
const reconnectWebSocket = async () => {
if (!userStore.user?.factory.id) return
try {
await socket.init(
{
account: userStore.user?.account.toString(),
factoryNo: userStore.user?.factory.id.toString(),
},
messageChange,
)
socket.send({
code: 'STARTORDERCN',
factoryNo: userStore.user?.factory.id,
warehouseId: warehouseId.value,
})
} catch (error) {
console.error('WebSocket 重连失败:', error)
ElMessage.error('WebSocket 重连失败,请稍后重试')
}
}
</script>
<style scoped lang="scss">
......
......@@ -16,6 +16,15 @@
<span>超级播种墙配货</span>
<span v-if="socketConnect === 'online'" class="online">[在线]</span>
<span v-else class="offline">[离线]</span>
<ElButton
v-if="socketConnect === 'offline'"
type="success"
size="small"
:icon="Refresh"
@click="reconnectWebSocket"
>
刷新
</ElButton>
</div>
</template>
<div class="pod-make-order-content">
......@@ -241,7 +250,7 @@ import {
printNormalPdf,
} from '@/api/podCnOrder'
import useUserStore from '@/store/user'
import { Check } from '@element-plus/icons-vue'
import { Check, Refresh } from '@element-plus/icons-vue'
import socket from '@/utils/cnSuperWebsocket'
import { ElMessage } from 'element-plus'
import { filePath } from '@/api/axios.ts'
......@@ -969,6 +978,25 @@ const handleCurrentChange = (url: string) => {
coverImage.value = url || ''
}
}
const reconnectWebSocket = async () => {
if (userStore.user?.factory.id) {
try {
await socket.init(
{
account: userStore.user?.account.toString(),
factoryNo: userStore.user?.factory.id.toString(),
},
messageChange,
)
socket.send({
code: 'SUPERFACTORYSTARTORDER',
factoryNo: userStore.user?.factory.id,
})
} catch (error) {
console.error(error)
}
}
}
</script>
<style scoped lang="scss">
......
......@@ -252,6 +252,25 @@
>
</el-radio-group>
</ElFormItem>
<ElFormItem
label="标签"
v-if="status == 'TO_BE_REPLENISHMENT' || status == 'PICKING'"
>
<ElSelect
v-model="searchForm.outOfStock"
clearable
filterable
placeholder="请输入标签"
style="width: 150px"
>
<el-option
v-for="item in labelList"
:key="item.value"
:label="item.name"
:value="item.value"
></el-option>
</ElSelect>
</ElFormItem>
<ElFormItem v-if="status !== 'BATCH_DOWNLOAD'">
<ElPopover placement="bottom" width="600" trigger="click">
<ElForm
......@@ -416,10 +435,10 @@
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="标签">
<ElFormItem label="ERP标签">
<ElSelect
v-model="searchForm.tagsIdArr"
placeholder="请选择标签"
placeholder="请选择ERP标签"
clearable
filterable
multiple
......@@ -593,38 +612,6 @@
</ElDropdown>
</ElFormItem>
<ElFormItem>
<!-- <span
v-if="
status === 'PICKING' ||
status === 'TO_BE_REPLENISHMENT' ||
status === 'IN_PRODUCTION'
"
class="item"
>
<ElButton
:loading="tifDownloadLoading"
type="warning"
@click="downloadTif('tiff')"
>
TIF排版
</ElButton>
</span>
<span
v-if="
status === 'PICKING' ||
status === 'TO_BE_REPLENISHMENT' ||
status === 'IN_PRODUCTION'
"
class="item"
>
<ElButton
:loading="pngDownloadLoading"
type="warning"
@click="downloadTif('png')"
>
PNG排版
</ElButton>
</span> -->
<span v-if="status === 'TO_BE_CONFIRMED'" class="item">
<ElButton type="success" @click="confirmProduct">
确认生产
......@@ -676,9 +663,9 @@
拣胚完成
</ElButton>
</span>
<span v-if="status === 'PICKING'" class="item">
<!-- <span v-if="status === 'PICKING'" class="item">
<ElButton type="success" @click="toOutOfStock"> 转至缺货 </ElButton>
</span>
</span> -->
<span v-if="status === 'TO_BE_CONFIRMED'" class="item">
<ElButton type="warning" @click="changeExceptionOrder">
转为异常单
......@@ -916,6 +903,35 @@
</ElDropdown>
</span>
<span
v-if="status === 'PICKING' || status === 'TO_BE_REPLENISHMENT'"
class="item"
>
<ElDropdown>
<el-button type="warning">
标签管理<el-icon class="el-icon--right"><ArrowDown /></el-icon>
</el-button>
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem
:disabled="
selection.length === 0 && cardSelection.length === 0
"
@click="labelFn(true)"
>添加缺货标签</ElDropdownItem
>
<ElDropdownItem
:disabled="
selection.length === 0 && cardSelection.length === 0
"
@click="labelFn(false)"
>移除缺货标签</ElDropdownItem
>
</ElDropdownMenu>
</template>
</ElDropdown>
</span>
<span
v-if="['WAIT_TRACK', 'COMPLETE', 'IN_TRANSIT'].includes(status)"
class="item"
>
......@@ -1940,6 +1956,26 @@
<template #top_left>
<el-tooltip
v-if="
cardItem.outOfStock &&
(status === 'PICKING' || status === 'TO_BE_REPLENISHMENT')
"
effect="light"
content="生产中缺货"
placement="bottom"
>
<div
style="
background-color: #bd3124;
color: #fff;
padding: 2px 4px;
border-radius: 4px;
"
>
</div>
</el-tooltip>
<el-tooltip
v-if="
cardItem.interceptStatus == 0 ||
cardItem.interceptStatus == 2
"
......@@ -2786,7 +2822,7 @@ import {
confirmProductApi,
applyForReplenishmentApi,
replenishmentSuccessApi,
toOutOfStockApi,
// toOutOfStockApi,
arrangeFinishApi,
getListCraftApi,
batchDownloadApi,
......@@ -2815,6 +2851,7 @@ import {
changeLogisticsApi,
getEmployeeListApi,
allErpCodeListApi,
updateProductOutOfStockApi,
} from '@/api/podCnOrder'
// import { logisticsCompanyAllCodelist } from '@/api/logistics.ts'
......@@ -3140,6 +3177,11 @@ const sizeList = ref<{ name: string; value: number }[]>([
{ name: '正常码', value: 1 },
{ name: '大码', value: 2 },
])
// 标签类型表
const labelList = ref<{ name: string; value: boolean }[]>([
{ name: '生产中缺货', value: true },
{ name: '无标签', value: false },
])
const handleRefreshAddress = async (row: PodCnOrderListData) => {
try {
......@@ -4185,13 +4227,18 @@ const downloadTif = async (type: string, templateWidth: number) => {
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const url =
status.value === 'TO_BE_REPLENISHMENT'
? 'factory/podJomallOrderCn/replenishmentComposingDesignImages'
: 'factory/podJomallOrderCn/composingDesignImages'
try {
const res = await composingDesignImages(
url,
cardSelection.value.map((el) => el.id),
type,
templateWidth,
)
const url =
const filePathUrl =
type === 'tiff'
? res.message?.startsWith('/temp')
? `https://factory.jomalls.com/upload/factory` + res.message
......@@ -4199,10 +4246,10 @@ const downloadTif = async (type: string, templateWidth: number) => {
: filePath + res.message
if (type === 'tiff') {
window.open(url, '_blank')
window.open(filePathUrl, '_blank')
tifDownloadLoading.value = false
} else {
fetch(url)
fetch(filePathUrl)
.then((response) => {
// 确保响应是 OK
if (!response.ok) {
......@@ -4278,9 +4325,13 @@ const downloadSingleType = async (
templateWidth?: number,
) => {
try {
const res = await composingDesignImages([id], type, templateWidth)
const url =
status.value === 'TO_BE_REPLENISHMENT'
? 'factory/podJomallOrderCn/replenishmentComposingDesignImages'
: 'factory/podJomallOrderCn/composingDesignImages'
const res = await composingDesignImages(url, [id], type, templateWidth)
const isTiff = type === 'tiff'
const url = isTiff
const filePathUrl = isTiff
? res.message?.startsWith('/temp')
? `https://factory.jomalls.com/upload/factory` + res.message
: `https://ps.jomalls.com/tiff/` + res.message
......@@ -4288,10 +4339,10 @@ const downloadSingleType = async (
if (isTiff) {
// 对于tiff类型,直接在新窗口打开
window.open(url, '_blank')
window.open(filePathUrl, '_blank')
} else {
// 对于其他类型,使用下载方式
await downloadFile(url, res.message as string)
await downloadFile(filePathUrl, res.message as string)
}
} catch (error) {
console.error(`下载类型 ${type} 时出错:`, error)
......@@ -4495,37 +4546,37 @@ const pickingComplete = async () => {
loading.close()
}
}
const toOutOfStock = async () => {
if (cardSelection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
const orderIds = cardSelection.value.map((item) => item.podJomallOrderCnId)
try {
await ElMessageBox.confirm('确定转至缺货吗?', '提示', {
cancelButtonText: '取消',
confirmButtonText: '确认',
type: 'warning',
})
} catch {
return
}
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const res = await toOutOfStockApi(orderIds)
if (res.code !== 200) return
search()
loadTabData()
cardSelection.value = []
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
// const toOutOfStock = async () => {
// if (cardSelection.value.length === 0) {
// return ElMessage.warning('请选择数据')
// }
// const orderIds = cardSelection.value.map((item) => item.podJomallOrderCnId)
// try {
// await ElMessageBox.confirm('确定转至缺货吗?', '提示', {
// cancelButtonText: '取消',
// confirmButtonText: '确认',
// type: 'warning',
// })
// } catch {
// return
// }
// const loading = ElLoading.service({
// fullscreen: true,
// text: '操作中...',
// background: 'rgba(0, 0, 0, 0.3)',
// })
// try {
// const res = await toOutOfStockApi(orderIds)
// if (res.code !== 200) return
// search()
// loadTabData()
// cardSelection.value = []
// } catch (e) {
// console.error(e)
// } finally {
// loading.close()
// }
// }
const inputBlur = () => {
if (!pageSize.value || Number(pageSize.value) <= 0) {
pageSize.value = initPageSize.value
......@@ -5844,6 +5895,43 @@ const getNewImageFn = (img: string) => {
}
}
const labelFn = async (type: boolean) => {
try {
await ElMessageBox.confirm(
`确定${type ? '添加' : '移除'}“生产中缺货”标签?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
},
)
} catch {
return
}
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const params = {
productIds: cardSelection.value.map((item) => item.id),
orderFrom: 'CN',
outOfStock: type,
}
await updateProductOutOfStockApi(params)
ElMessage.success('操作成功')
search()
loadTabData()
} catch (error) {
console.log(error)
} finally {
loading.close()
}
}
useRouter().beforeEach((to, from, next) => {
handleBeforeRouteLeave(to, from, next)
})
......
......@@ -16,6 +16,15 @@
<span>播种墙配货</span>
<span v-if="socketConnect === 'online'" class="online">[在线]</span>
<span v-else class="offline">[离线]</span>
<ElButton
v-if="socketConnect === 'offline'"
type="success"
size="small"
:icon="Refresh"
@click="reconnectWebSocket"
>
刷新
</ElButton>
</div>
</template>
<div class="pod-make-order-content">
......@@ -256,10 +265,11 @@ import {
printNormalPickPdfApi,
} from '@/api/podUsOrder'
import useUserStore from '@/store/user'
import { Check } from '@element-plus/icons-vue'
import { Check, Refresh } from '@element-plus/icons-vue'
import socket from '@/utils/websocket'
import { WarehouseListData } from '@/types/api/podUsOrder'
import { filePath } from '@/api/axios.ts'
import { ElButton, ElIcon } from 'element-plus'
const { getCLodop } = useLodop()
......@@ -468,7 +478,7 @@ const renderItemBox = (bool: boolean) => {
renderLock = true
let boxItem = podBoxList.value?.find((item) => item.box === boxIndex.value)
console.log(boxItem,'boxItem')
console.log(boxItem, 'boxItem')
if (!boxItem) boxItem = { data: { productList: [] } }
const { data } = boxItem
data?.productList?.forEach((el) => {
......@@ -530,7 +540,7 @@ const renderItemBox = (bool: boolean) => {
console.log(408, data)
if (productList.every((item) => item.power)) {
if(userStore.user?.id!==boxItem.fromUser) return
if (userStore.user?.id !== boxItem.fromUser) return
print(data, false, () => {
renderLock = false
})
......@@ -562,7 +572,7 @@ const messageChange = (data: WebSocketMessage) => {
}
}
const setPodBoxList = (data: WebSocketMessage) => {
console.log(data,'datatatata')
console.log(data, 'datatatata')
const obj = data.txt
if (obj && typeof obj === 'string') {
const parsedData = JSON.parse(obj)
......@@ -745,7 +755,7 @@ const initOrderDetailBox = async () => {
}
orderStore.setPodBoxList({
boxList: res.data,
fromUser: userStore.user?userStore.user.id : 0,
fromUser: userStore.user ? userStore.user.id : 0,
factoryNo,
warehouseId: warehouseId.value,
})
......@@ -1013,7 +1023,7 @@ const print = (data: OrderData, forcePrint = false, callback?: () => void) => {
const factoryNo = userStore.user?.factory.id
if (!factoryNo) return
orderStore.setPodBoxList({
fromUser:userStore.user?userStore.user.id:0,
fromUser: userStore.user ? userStore.user.id : 0,
boxList: item ? (item.data as PodMakeOrderData[]) : null,
factoryNo,
box: _boxIndex || undefined,
......@@ -1032,7 +1042,10 @@ const clearAllBox = async () => {
return
}
try {
const res = await clearAllBoxApi(warehouseId.value,userStore.user?.factory.id)
const res = await clearAllBoxApi(
warehouseId.value,
userStore.user?.factory.id,
)
if (res.code !== 200) return
// orderStore.setPodBoxList({
// boxList: res.data,
......@@ -1104,6 +1117,28 @@ const printNormal = async () => {
ElMessage.success('操作成功')
window.open(filePath + res.message)
}
const reconnectWebSocket = async () => {
if (!userStore.user?.factory.id) return
try {
await socket.init(
{
account: userStore.user?.account.toString(),
factoryNo: userStore.user?.factory.id.toString(),
},
messageChange,
)
socket.send({
code: 'STARTORDER',
factoryNo: userStore.user?.factory.id,
warehouseId: warehouseId.value,
})
} catch (error) {
console.error('WebSocket 重连失败:', error)
ElMessage.error('WebSocket 重连失败,请稍后重试')
}
}
</script>
<style scoped lang="scss">
......
......@@ -242,6 +242,25 @@
>
</el-radio-group>
</ElFormItem>
<ElFormItem
label="标签"
v-if="status == 'TO_BE_REPLENISHMENT' || status == 'PICKING'"
>
<ElSelect
v-model="searchForm.outOfStock"
clearable
filterable
placeholder="请输入标签"
style="width: 150px"
>
<el-option
v-for="item in labelList"
:key="item.value"
:label="item.name"
:value="item.value"
></el-option>
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElPopover
placement="bottom"
......@@ -372,10 +391,10 @@
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="标签">
<ElFormItem label="ERP标签">
<ElSelect
v-model="searchForm.tagsIdArr"
placeholder="请选择标签"
placeholder="请选择ERP标签"
clearable
filterable
multiple
......@@ -558,40 +577,6 @@
</template>
</ElDropdown>
</ElFormItem>
<!-- <ElFormItem
v-if="
status === 'PICKING' ||
status === 'TO_BE_REPLENISHMENT' ||
status === 'IN_PRODUCTION'
"
>
<span class="item">
<ElButton
:loading="tifDownloadLoading"
type="warning"
@click="downloadTif('tiff')"
>
TIF排版
</ElButton>
</span>
</ElFormItem>
<ElFormItem
v-if="
status === 'PICKING' ||
status === 'TO_BE_REPLENISHMENT' ||
status === 'IN_PRODUCTION'
"
>
<span class="item">
<ElButton
:loading="pngDownloadLoading"
type="warning"
@click="downloadTif('png')"
>
PNG排版
</ElButton>
</span>
</ElFormItem> -->
<ElFormItem v-if="status === 'TO_BE_CONFIRMED'">
<span class="item">
<ElButton type="success" @click="confirmProduct">
......@@ -664,11 +649,11 @@
</ElButton>
</span>
</ElFormItem>
<ElFormItem v-if="status === 'PICKING'">
<!-- <ElFormItem v-if="status === 'PICKING'">
<span class="item">
<ElButton type="success" @click="toOutOfStock"> 转至缺货 </ElButton>
</span>
</ElFormItem>
</ElFormItem> -->
<ElFormItem v-if="status === 'TO_BE_CONFIRMED'">
<span class="item">
<ElButton type="warning" @click="changeExceptionOrder">
......@@ -942,6 +927,34 @@
</ElDropdown>
</span>
</ElFormItem>
<ElFormItem v-if="['PICKING', 'TO_BE_REPLENISHMENT'].includes(status)">
<span class="item">
<ElDropdown>
<el-button type="warning">
标签管理<el-icon class="el-icon--right"><ArrowDown /></el-icon>
</el-button>
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem
:disabled="
selection.length === 0 && cardSelection.length === 0
"
@click="labelFn(true)"
>添加缺货标签</ElDropdownItem
>
<ElDropdownItem
:disabled="
selection.length === 0 && cardSelection.length === 0
"
@click="labelFn(false)"
>移除缺货标签</ElDropdownItem
>
</ElDropdownMenu>
</template>
</ElDropdown>
</span>
</ElFormItem>
<ElFormItem
v-if="['WAIT_TRACK', 'COMPLETE', 'IN_TRANSIT'].includes(status)"
>
......@@ -1810,7 +1823,16 @@
</span>
</div> -->
<div
v-if="['TO_BE_CONFIRMED','EXCEPTION_ORDER', 'STOCK_OUT', 'CREATE_LOGISTICS', 'TO_BE_ARRANGE', 'WAIT_SHIPMENT'].includes(status)"
v-if="
[
'TO_BE_CONFIRMED',
'EXCEPTION_ORDER',
'STOCK_OUT',
'CREATE_LOGISTICS',
'TO_BE_ARRANGE',
'WAIT_SHIPMENT',
].includes(status)
"
class="order-detail-item"
>
<span class="order-detail-item-label">订单延期时间:</span>
......@@ -2196,6 +2218,26 @@
<template #top_left>
<el-tooltip
v-if="
cardItem.outOfStock &&
(status === 'PICKING' || status === 'TO_BE_REPLENISHMENT')
"
effect="light"
content="生产中缺货"
placement="bottom"
>
<div
style="
background-color: #bd3124;
color: #fff;
padding: 2px;
border-radius: 4px;
"
>
</div>
</el-tooltip>
<el-tooltip
v-if="
cardItem.interceptStatus == 0 ||
cardItem.interceptStatus == 2
"
......@@ -2372,7 +2414,7 @@
: cardItem?.notPassNum || 0
}}
<span title="订单延期时间" class="delayTime red-time">
{{ calculateDelayTime(cardItem) }}
{{ calculateDelayTime(cardItem) }}
</span>
</span>
</div>
......@@ -2391,8 +2433,18 @@
<span class="grid-item-label">补胚数量:</span>
<span class="grid-item-value">
{{ cardItem?.replenishmentNum || 0 }}
<span v-if="!['IN_PRODUCTION','PICKING','TO_BE_ARRANGE'].includes(status)" title="订单延期时间" class="delayTime red-time">
{{ calculateDelayTime(cardItem) }}
<span
v-if="
![
'IN_PRODUCTION',
'PICKING',
'TO_BE_ARRANGE',
].includes(status)
"
title="订单延期时间"
class="delayTime red-time"
>
{{ calculateDelayTime(cardItem) }}
</span>
</span>
</div>
......@@ -3149,7 +3201,7 @@ import {
// handleExceptionOrderApi,
applyForReplenishmentApi,
replenishmentSuccessApi,
toOutOfStockApi,
// toOutOfStockApi,
arrangeFinishApi,
getListCraftApi,
batchDownloadApi,
......@@ -3175,6 +3227,7 @@ import {
printNormalPickPdfApi,
updatePRNDownloadStatus,
getEmployeeListApi,
updateProductOutOfStockApi,
} from '@/api/podUsOrder'
import { BaseRespData } from '@/types/api'
......@@ -3431,6 +3484,11 @@ const sizeList = ref<{ name: string; value: number }[]>([
{ name: '正常码', value: 1 },
{ name: '大码', value: 2 },
])
// 标签类型表
const labelList = ref<{ name: string; value: boolean }[]>([
{ name: '生产中缺货', value: true },
{ name: '无标签', value: false },
])
const detailData = ref({})
const [searchForm, resetSearchForm] = useValue<SearchForm>({
......@@ -4508,23 +4566,28 @@ const downloadTif = async (type: string, templateWidth: number) => {
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const url =
status.value === 'TO_BE_REPLENISHMENT'
? 'factory/podJomallOrderUs/replenishmentComposingDesignImages'
: 'factory/podJomallOrderUs/composingDesignImages'
try {
const res = await composingDesignImages(
url,
cardSelection.value.map((el) => el.id),
type,
templateWidth,
)
const url =
const filePathUrl =
type === 'tiff'
? res.message?.startsWith('/temp')
? `https://factory.jomalls.com/upload/factory` + res.message
: `https://ps.jomalls.com/tiff/` + res.message
: filePath + res.message
if (type === 'tiff') {
window.open(url, '_blank')
window.open(filePathUrl, '_blank')
tifDownloadLoading.value = false
} else {
fetch(url)
fetch(filePathUrl)
.then((response) => {
// 确保响应是 OK
if (!response.ok) {
......@@ -4599,9 +4662,13 @@ const downloadSingleType = async (
templateWidth?: number,
) => {
try {
const res = await composingDesignImages([id], type, templateWidth)
const url =
status.value === 'TO_BE_REPLENISHMENT'
? 'factory/podJomallOrderUs/replenishmentComposingDesignImages'
: 'factory/podJomallOrderUS/composingDesignImages'
const res = await composingDesignImages(url, [id], type, templateWidth)
const isTiff = type === 'tiff'
const url = isTiff
const filePathUrl = isTiff
? res.message?.startsWith('/temp')
? `https://factory.jomalls.com/upload/factory` + res.message
: `https://ps.jomalls.com/tiff/` + res.message
......@@ -4609,10 +4676,10 @@ const downloadSingleType = async (
if (isTiff) {
// 对于tiff类型,直接在新窗口打开
window.open(url, '_blank')
window.open(filePathUrl, '_blank')
} else {
// 对于其他类型,使用下载方式
await downloadFile(url, res.message as string)
await downloadFile(filePathUrl, res.message as string)
}
} catch (error) {
console.error(`下载类型 ${type} 时出错:`, error)
......@@ -4686,95 +4753,6 @@ const handleMultiRadioGroupClick = (event: Event) => {
}
}
}
// const downloadTifItem = async () => {
// const row = { ...(typesettingRow.value as PodUsOrderListData) }
// const loading = ElLoading.service({
// fullscreen: true,
// text: '操作中...',
// background: 'rgba(0, 0, 0, 0.3)',
// })
// const { templateWidth, typeArr } = typesettingForm.value
// const type = (typeArr?.join(',') as string) || ''
// typesettingVisible.value = false
// try {
// if ((typeArr as string[]).length > 1) {
// typeArr?.forEach(async (el) => {
// const res = await composingDesignImages([row.id], el, templateWidth)
// const url =
// type === 'tiff'
// ? `https://ps.jomalls.com/tiff/` + res.message
// : filePath + res.message
// if (el === 'tiff') {
// window.open(url, '_blank')
// } else {
// fetch(url)
// .then((response) => {
// // 确保响应是 OK
// if (!response.ok) {
// throw new Error('网络响应错误')
// }
// // 返回图片的二进制数据(Blob)
// return response.blob()
// })
// .then((blob) => {
// const a = document.createElement('a')
// a.href = window.URL.createObjectURL(blob)
// a.target = '_blank'
// a.download = (res.message as string).split('/')[
// (res.message as string).split('/').length - 1
// ]
// a.click()
// pngDownloadLoading.value = false
// })
// .catch((error) => {
// console.error('下载图片时出错:', error)
// pngDownloadLoading.value = false
// })
// }
// })
// } else {
// const res = await composingDesignImages([row.id], type, templateWidth)
// const url =
// type === 'tiff'
// ? `https://ps.jomalls.com/tiff/` + res.message
// : filePath + res.message
// if (type === 'tiff') {
// window.open(url, '_blank')
// } else {
// fetch(url)
// .then((response) => {
// // 确保响应是 OK
// if (!response.ok) {
// throw new Error('网络响应错误')
// }
// // 返回图片的二进制数据(Blob)
// return response.blob()
// })
// .then((blob) => {
// const a = document.createElement('a')
// a.href = window.URL.createObjectURL(blob)
// a.target = '_blank'
// a.download = (res.message as string).split('/')[
// (res.message as string).split('/').length - 1
// ]
// a.click()
// pngDownloadLoading.value = false
// })
// .catch((error) => {
// console.error('下载图片时出错:', error)
// pngDownloadLoading.value = false
// })
// }
// }
// } catch (e) {
// console.log(e)
// } finally {
// typesettingRow.value = undefined
// loading.close()
// }
// }
const loadProductionClient = async () => {
try {
const res = await getProductionClientApi()
......@@ -5036,37 +5014,37 @@ const pickingComplete = async () => {
loading.close()
}
}
const toOutOfStock = async () => {
if (cardSelection.value.length === 0) {
return ElMessage.warning('请选择数据')
}
const orderIds = cardSelection.value.map((item) => item.podJomallOrderUsId)
try {
await ElMessageBox.confirm('确定转至缺货吗?', '提示', {
cancelButtonText: '取消',
confirmButtonText: '确认',
type: 'warning',
})
} catch {
return
}
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
const res = await toOutOfStockApi(orderIds)
if (res.code !== 200) return
search()
loadTabData()
cardSelection.value = []
} catch (e) {
console.error(e)
} finally {
loading.close()
}
}
// const toOutOfStock = async () => {
// if (cardSelection.value.length === 0) {
// return ElMessage.warning('请选择数据')
// }
// const orderIds = cardSelection.value.map((item) => item.podJomallOrderUsId)
// try {
// await ElMessageBox.confirm('确定转至缺货吗?', '提示', {
// cancelButtonText: '取消',
// confirmButtonText: '确认',
// type: 'warning',
// })
// } catch {
// return
// }
// const loading = ElLoading.service({
// fullscreen: true,
// text: '操作中...',
// background: 'rgba(0, 0, 0, 0.3)',
// })
// try {
// const res = await toOutOfStockApi(orderIds)
// if (res.code !== 200) return
// search()
// loadTabData()
// cardSelection.value = []
// } catch (e) {
// console.error(e)
// } finally {
// loading.close()
// }
// }
const exceptionTypes = [
{ value: '1', label: '客户' },
{ value: '2', label: '工厂' },
......@@ -6813,28 +6791,42 @@ const getEmployeeList = async () => {
employeeList.value = data
}
getPermission()
getLogisticsWay()
getEmployeeList()
const globalProperties =
getCurrentInstance()?.appContext.config.globalProperties // 获取全局挂载
const isPermissionBtn = globalProperties?.$isPermissionBtn
const labelFn = async (type: boolean) => {
try {
await ElMessageBox.confirm(
`确定${type ? '添加' : '移除'}“生产中缺货”标签?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
},
)
} catch {
return
}
const loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const getNewImageFn = (img: string) => {
try {
if (img.startsWith('http')) return img
if (img.startsWith('/')) return `https://img.jomalls.com/upload/erp${img}`
return `https://image.jomalls.com/${img}`
const params = {
productIds: cardSelection.value.map((item) => item.id),
orderFrom: 'US',
outOfStock: type,
}
await updateProductOutOfStockApi(params)
ElMessage.success('操作成功')
search()
loadTabData()
} catch (error) {
console.log(error)
} finally {
loading.close()
}
}
useRouter().beforeEach((to, from, next) => {
handleBeforeRouteLeave(to, from, next)
})
const printNormal = async () => {
await showConfirm('确定普货拣货吗?', {
confirmButtonText: '确认',
......@@ -6865,6 +6857,28 @@ const printNormal = async () => {
ElMessage.success('操作成功')
window.open(filePath + res.message)
}
getPermission()
getLogisticsWay()
getEmployeeList()
const globalProperties =
getCurrentInstance()?.appContext.config.globalProperties // 获取全局挂载
const isPermissionBtn = globalProperties?.$isPermissionBtn
const getNewImageFn = (img: string) => {
try {
if (img.startsWith('http')) return img
if (img.startsWith('/')) return `https://img.jomalls.com/upload/erp${img}`
return `https://image.jomalls.com/${img}`
} catch (error) {
console.log(error)
}
}
useRouter().beforeEach((to, from, next) => {
handleBeforeRouteLeave(to, from, next)
})
</script>
<style lang="scss" scoped>
.header-filter-form {
......@@ -6955,12 +6969,11 @@ const printNormal = async () => {
text-overflow: ellipsis;
white-space: nowrap;
}
}
.grid-item-value{
.grid-item-value {
position: relative;
}
.delayTime{
.delayTime {
position: absolute;
right: 0;
font-size: 14px;
......
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