Commit 9687e81f by qinjianhui

Merge branch 'dev' into 'master'

Dev

See merge request !149
parents 5a71e66e de4b50da
......@@ -55,6 +55,7 @@ export interface SearchForm {
employeeId?: number
blocking?: boolean
outOfStock?: boolean
receiverCountry?: string
}
export interface PodCnOrderListData {
id: number
......@@ -215,6 +216,7 @@ export interface LogisticsData {
export interface AddressInfo {
id?: string
receiverName: string
rfcNumber: string
receiverPhone: string
receiverCountry: string
receiverProvince: string
......
......@@ -27,11 +27,17 @@ export interface statisticData {
outOfStockSkuNum: number
outOfStockProductNum: number
yesterdayOverTimeShipmentOrderNum: number
notShipmentProductNum: number
overTimeNotShipmentProductNum: number
yesterdayShipmentProductNum: number
}
export interface trendType {
confirmNum: number // 接单数
produceNum: number // 生产数
shipmentNum: number // 发货数
confirmProductNum?: number // 新接数(件)
produceProductNum?: number // 生产数(件)
shipmentProductNum?: number // 发货数(件)
shipmentRateOf24Hour: number // 24小时发货率
shipmentRateOf48Hour: number // 48小时发货率
overtimeShipmentRate: number // 超48小时发货率
......
......@@ -50,11 +50,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>
......@@ -62,17 +62,21 @@
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.notShipmentOrderNum ?? '-' }}
{{
(statisticData?.notShipmentProductNum ?? '-') +
'/' +
(statisticData?.notShipmentOrderNum ?? '-')
}}
</div>
</div>
</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="目前确认生产后超过48H还未转为已发货状态的总订单数"
content="目前确认生产后超过48H还未转为已发货状态的总件数/总订单数"
placement="bottom"
>
<div class="card-icon"></div>
......@@ -80,7 +84,11 @@
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-red">
{{ statisticData?.overTimeNotShipmentOrderNum ?? '-' }}
{{
(statisticData?.overTimeNotShipmentProductNum ?? '-') +
'/' +
(statisticData?.overTimeNotShipmentOrderNum ?? '-')
}}
</div>
</div>
</div>
......@@ -97,11 +105,11 @@
</template>
<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="`昨日转为已发货状态的总订单数(${yesterday}北京时间 0-24点数据)`"
:content="`昨日转为已发货状态的总件数/总订单数(${yesterday}北京时间 0-24点数据)`"
placement="bottom"
>
<div class="card-icon"></div>
......@@ -109,7 +117,11 @@
</div>
<div class="card-item-content-box">
<div v-auto-fit-text class="card-item-content text-blue">
{{ statisticData?.yesterdayShipmentOrderNum ?? '-' }}
{{
(statisticData?.yesterdayShipmentProductNum ?? '-') +
'/' +
(statisticData?.yesterdayShipmentOrderNum ?? '-')
}}
</div>
<div class="card-item-content-text">
较前天
......@@ -121,7 +133,11 @@
style="display: flex; margin-left: 10px"
>
<div class="text-green">
{{ statisticData?.compareYesterdayShipmentOrderNum }}
{{
(statisticData?.compareYesterdayShipmentOrderNum).toFixed(
0,
) + '单'
}}
</div>
<div class="up-icon-green"></div>
</div>
......@@ -130,7 +146,7 @@
{{
Math.abs(
statisticData?.compareYesterdayShipmentOrderNum || 0,
)
).toFixed(0) + '单'
}}
</div>
<div class="down-icon-red"></div>
......@@ -541,27 +557,51 @@
</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"
<div class="charts-row" style="width: 100%">
<div class="chart-wrapper chart-half">
<el-radio-group
v-model="chartTimes4"
size="small"
class="chart-controls"
@change="getchartTimes($event, 'PRODUCT_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="orderChart4"
v-loading="orderChart4Loading"
class="chart-container"
style="width: 100%"
/>
</div>
<div class="chart-wrapper chart-half">
<el-radio-group
v-model="chartTimes1"
size="small"
class="chart-controls"
@change="getchartTimes($event, 'ORDER_TREND')"
>
</el-radio-button>
</el-radio-group>
<div
ref="orderChart1"
v-loading="orderChart1Loading"
class="chart-container"
style="width: 100%"
/>
<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>
<div class="charts-row">
<div class="chart-wrapper chart-half">
......@@ -662,6 +702,7 @@ const statisticData = ref<StatisticData | null>(null)
const orderChart1Loading = ref<boolean>(true)
const orderChart2Loading = ref<boolean>(true)
const orderChart3Loading = ref<boolean>(true)
const orderChart4Loading = ref<boolean>(true)
const timeOptions = ref<{ type: string; name: string }[]>([
{ type: '0', name: '日数据' },
......@@ -672,14 +713,16 @@ const timeOptions = ref<{ type: string; name: string }[]>([
const chartTimes1 = ref<string>('0')
const chartTimes2 = ref<string>('0')
const chartTimes3 = ref<string>('0')
const chartTimes4 = ref<string>('0')
// 图表容器引用
const orderChart1 = ref<HTMLDivElement | null>(null)
const orderChart2 = ref<HTMLDivElement | null>(null)
const orderChart3 = ref<HTMLDivElement | null>(null)
const orderChart4 = ref<HTMLDivElement | null>(null)
// 图表实例数组
const chartInstances: (echarts.ECharts | null)[] = [null, null, null]
const chartInstances: (echarts.ECharts | null)[] = [null, null, null, null]
type ChartSeriesItem = {
name: string
......@@ -750,6 +793,29 @@ const chartConfig3 = ref<ChartConfig>({
],
})
const chartConfig4 = ref<ChartConfig>({
title: '订单趋势统计(件)',
legend: ['新接数', '生产数', '发货数'],
xAxisData: [''],
series: [
{
name: '新接数',
data: [0],
color: '#30d2cb',
},
{
name: '生产数',
data: [0],
color: '#9e95ff',
},
{
name: '发货数',
data: [0],
color: '#6bb3fd',
},
],
})
const overtimeTooltipFormatter = (params: TooltipParam[]) =>
params
.map((item) => {
......@@ -1045,11 +1111,35 @@ const getStatisticDataApi = async () => {
.catch((error) => {
console.error('获取超时发货趋势数据失败:', error)
})
// 订单趋势统计(件)
trendApi({
timeUnit: 0,
trendType: 'PRODUCT_TREND',
})
.then((res) => {
if (res.code === 200) {
const isEmpty = checkProductNumTrendDataEmpty(res.data)
// 无论数据是否为空,都要更新 x 轴数据
updateProductNumTrendChart(res.data, 0)
updateChart(
chartInstances[3],
chartConfig4,
isEmpty,
false,
chartTimes4.value,
)
orderChart4Loading.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))
......@@ -1066,6 +1156,11 @@ onMounted(async () => {
createChartOption(chartConfig3, true, overtimeTooltipFormatter),
)
}
// 订单趋势统计(件)
if (orderChart4.value) {
chartInstances[3] = echarts.init(orderChart4.value)
chartInstances[3]?.setOption(createChartOption(chartConfig4))
}
// 请求成功后立即更新对应的图表
getStatisticDataApi()
// 监听窗口大小变化,自动调整图表大小
......@@ -1081,6 +1176,8 @@ const getchartTimes = async (v: string, type: string) => {
orderChart2Loading.value = true
} else if (type === 'OVERTIME_SHIPMENT_TREND') {
orderChart3Loading.value = true
} else if (type === 'PRODUCT_TREND') {
orderChart4Loading.value = true
}
const { data } = await trendApi({
......@@ -1111,6 +1208,18 @@ const getchartTimes = async (v: string, type: string) => {
chartTimes2.value,
)
orderChart2Loading.value = !(data && data.length > 0)
} else if (type == 'PRODUCT_TREND') {
const isEmpty = checkProductNumTrendDataEmpty(data)
// 无论数据是否为空,都要更新 x 轴数据
updateProductNumTrendChart(data, v)
updateChart(
chartInstances[3],
chartConfig4,
isEmpty,
false,
chartTimes4.value,
)
orderChart4Loading.value = !(data && data.length > 0)
} else {
const isEmpty = checkOvertimeTrendDataEmpty(data)
// 无论数据是否为空,都要更新 x 轴数据
......@@ -1416,6 +1525,40 @@ const updateOvertimeTrendChart = (data: trendType[], type: number | string) => {
)
}
// 检查订单趋势(件)数据是否为空
const checkProductNumTrendDataEmpty = (data: trendType[]): boolean => {
const confirmProductNums = data.map((el) => el.confirmProductNum ?? 0)
const producedProductNums = data.map((el) => el.produceProductNum ?? 0)
const shipmentProductNums = data.map((el) => el.shipmentProductNum ?? 0)
const hasData =
confirmProductNums.some((item) => item !== 0) ||
producedProductNums.some((item) => item !== 0) ||
shipmentProductNums.some((item) => item !== 0)
return !hasData
}
// 更新订单趋势(件)图表数据
const updateProductNumTrendChart = (
data: trendType[],
type: number | string,
) => {
const confirmProductNums = data.map((el) => el.confirmProductNum ?? 0)
const producedProductNums = data.map((el) => el.produceProductNum ?? 0)
const shipmentProductNums = data.map((el) => el.shipmentProductNum ?? 0)
const startTimes = data.map((el) => el.startTime)
const timerange = data.map((el) => `${el.startTime}——${el.endTime}`)
if (type == 0) {
chartConfig4.value.xAxisData = startTimes
} else {
chartConfig4.value.xAxisData = timerange
}
chartConfig4.value.series[0].data = confirmProductNums
chartConfig4.value.series[1].data = producedProductNums
chartConfig4.value.series[2].data = shipmentProductNums
}
const handleResize = () => {
chartInstances.forEach((instance) => {
instance?.resize()
......
......@@ -398,6 +398,34 @@ const formConfig = computed<IFormConfig[]>(() => [
message: '请输入物流编码',
},
],
},{
prop: 'vat',
type: 'input',
label: 'vat编号',
fixed: 'last',
attrs: {
placeholder: '请输入vat编号',
},
rules: [
{
required: false,
message: '请输入vat编号',
},
],
},{
prop: 'ioss',
type: 'input',
label: 'IOSS编号',
fixed: 'last',
attrs: {
placeholder: '请输入IOSS编号',
},
rules: [
{
required: false,
message: '请输入IOSS编号',
},
],
},
{
prop: 'status',
......@@ -605,6 +633,16 @@ const tableConfig = ref<TableColumn[]>([
},
},
{
prop: 'vat',
label: 'vat编号',
},
{
prop: 'ioss',
label: 'IOSS编号',
},
{
prop: 'opeare',
label: '操作',
attrs: {
......
......@@ -757,19 +757,6 @@ const handleSelectionChange = (val: PodUsOrderListData[]) => {
selection.value = val
}
// 修改行样式方法
const getRowStyle = ({ row }: { row: PodUsOrderListData }) => {
// 如果行被选中,设置背景色为 #fdf6ec
if (selection.value.some((item) => item.id === row.id)) {
return {
backgroundColor: '#fdf6ec',
}
}
return {
backgroundColor: '',
}
}
// 获取行类名方法
const getRowClassName = ({ row }: { row: PodUsOrderListData }) => {
return selection.value.some((item) => item.id === row.id)
......@@ -1156,7 +1143,6 @@ onMounted(() => {
:serial-numberable="true"
:selectionable="true"
:paginated-data="tableData"
:row-style="getRowStyle"
:row-class-name="getRowClassName"
@row-click="rowClick"
@selection-change="handleSelectionChange"
......@@ -1385,11 +1371,22 @@ onMounted(() => {
}
}
// 确保选中行的背景色在 hover 时也保持
// 设置选中行的背景色
:deep(.el-table__body) {
.el-table__row:hover {
td {
background-color: #e1ebf5 !important;
}
}
.el-table__row.row-selected {
td {
background-color: #faecd8 !important;
}
}
// 确保选中行的背景色在 hover 时也保持
.el-table__row.row-selected:hover {
td {
background-color: #fdf6ec !important;
background-color: #faecd8 !important;
}
}
}
......
......@@ -772,20 +772,6 @@ const handleSelectionChange = (val: PodCnOrderListData[]) => {
selection.value = val
}
// 修改行样式方法
const getRowStyle = ({ row }: { row: PodCnOrderListData }) => {
// 如果行被选中,设置背景色为 #fdf6ec
if (selection.value.some((item) => item.id === row.id)) {
return {
backgroundColor: '#fdf6ec',
}
}
return {
backgroundColor: '',
}
}
// 获取行类名方法
const getRowClassName = ({ row }: { row: PodCnOrderListData }) => {
return selection.value.some((item) => item.id === row.id)
......@@ -1246,7 +1232,6 @@ onMounted(() => {
:serial-numberable="true"
:selectionable="true"
:paginated-data="tableData"
:row-style="getRowStyle"
:row-class-name="getRowClassName"
@row-click="rowClick"
@selection-change="handleSelectionChange"
......@@ -1482,11 +1467,22 @@ onMounted(() => {
}
}
// 确保选中行的背景色在 hover 时也保持
// 设置选中行的背景色
:deep(.el-table__body) {
.el-table__row:hover {
td {
background-color: #e1ebf5 !important;
}
}
.el-table__row.row-selected {
td {
background-color: #faecd8 !important;
}
}
// 确保选中行的背景色在 hover 时也保持
.el-table__row.row-selected:hover {
td {
background-color: #fdf6ec !important;
background-color: #faecd8 !important;
}
}
}
......
......@@ -11,6 +11,7 @@ const visible = defineModel<boolean>('visible')
const form = defineModel<AddressInfo>('form', {
default: {
receiverName: '',
rfcNumber: '',
receiverPhone: '',
receiverCountry: '',
receiverProvince: '',
......@@ -133,6 +134,13 @@ const submitForm = async () => {
placeholder="请输入邮政编码"
/>
</el-form-item>
<el-form-item label="RFC税号" prop="rfcNumber">
<el-input
v-model="form.rfcNumber"
clearable
placeholder="请输入RFC税号"
/>
</el-form-item>
</el-form>
<template #footer>
......
......@@ -379,6 +379,34 @@
style="width: 150px"
></ElInput>
</ElFormItem>
<ElFormItem
v-if="
![
'TO_BE_ARRANGE',
'PICKING',
'TO_BE_REPLENISHMENT',
'IN_PRODUCTION',
].includes(status)
"
label="收件国家"
>
<ElSelect
v-model="searchForm.receiverCountry"
placeholder="收件国家"
clearable
:teleported="false"
style="width: 150px"
filterable
@change="changeReplaceShipment"
>
<ElOption
v-for="item in receiverCountryList"
:key="item.countryCode"
:value="item.countryCode"
:label="item.nameCn + '(' + item.countryCode + ')'"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="是否代发">
<ElSelect
v-model="searchForm.replaceShipment"
......@@ -1458,6 +1486,43 @@
</el-button>
</div>
</div>
<div class="goods-item-info">
<div class="goods-item-info-item">
<span class="goods-item-info-item-label"
>英文报关名称:</span
>
<span :title="item.customsNameEnglish" class="goods-item-info-item-value">
{{ item.customsNameEnglish }}
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label"
>中文报关名称:</span
>
<span :title="item.customsNameChinese" class="goods-item-info-item-value">
{{ item.customsNameChinese }}
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label"
>申报重量(g):</span
>
<span :title="item.customsWeight" class="goods-item-info-item-value">
{{ item.customsWeight }}
</span>
</div>
<div class="goods-item-info-item">
<span class="goods-item-info-item-label"
>申报价值($):</span
>
<span :title="item.customsValue" class="goods-item-info-item-value">
{{ item.customsValue }}
</span>
</div>
</div>
</div>
</div>
</div>
......@@ -2985,6 +3050,7 @@ const totalAmountPrice = (item: PodCnOrderListData): string => {
const countryList = ref([])
const currentRow = ref<AddressInfo>({
receiverName: '',
rfcNumber: '',
receiverPhone: '',
receiverCountry: '',
receiverProvince: '',
......@@ -3132,6 +3198,7 @@ const [searchForm, resetSearchForm] = useValue<SearchForm>({
batchArrangeNumber: '',
craftCode: [],
thirdStockSku: '',
receiverCountry: '',
})
const shipmentArea = ref(0)
const userMarkList = ref<string[]>([])
......@@ -3873,7 +3940,7 @@ const tableColumns = computed(() => {
{
label: '操作',
slot: 'operate',
width: 260,
width: 120,
align: 'center',
fixed: 'right',
prop: 'operate',
......@@ -3892,7 +3959,7 @@ const tableColumns = computed(() => {
label: '商品',
prop: 'goods',
slot: 'goods',
minWidth: 920,
minWidth: 1100,
},
{
label: '订单详情',
......@@ -3917,7 +3984,7 @@ const tableColumns = computed(() => {
{
label: '操作',
slot: 'operate',
width: 180,
width: 100,
align: 'center',
fixed: 'right',
prop: 'operate',
......@@ -5505,15 +5572,8 @@ const getRowStyle = ({ row }: { row: PodCnOrderListData }) => {
color: '#67c23a',
}
}
// 如果行被选中,设置背景色为 #fdf6ec
if (selection.value.some((item) => item.id === row.id)) {
return {
backgroundColor: '#fdf6ec',
}
}
return {
backgroundColor: '',
}
// 选中状态通过 CSS 类名控制,这里不再处理
return {}
}
// 获取行类名方法
......@@ -5608,6 +5668,17 @@ const getlogisticsCompanyAllCodelist = async () => {
}
}
const receiverCountryList = ref<{ countryCode: string; nameCn: string }[]>([])
const getReceiverCountryList = async () => {
try {
const res = await getAllCountryApi()
if (res.code !== 200) return
receiverCountryList.value = res.data
} catch (e) {
console.error(e)
}
}
function tooltipContent(arr: { name: string }[]) {
return arr.map((tag) => tag.name).join('、')
}
......@@ -5708,6 +5779,7 @@ onMounted(() => {
getCustomTagList()
loadCraftList()
getlogisticsCompanyAllCodelist()
getReceiverCountryList()
// 每60秒更新一次当前时间
timer = window.setInterval(() => {
currentTime.value = new Date()
......@@ -6150,7 +6222,8 @@ const onUpdateCustomsDeclarationInfo = () => {
.goods-item {
display: grid;
grid-template-columns: 100px 1fr minmax(150px, 1fr) 150px;
// grid-template-columns: 100px 1fr minmax(150px, 1fr) 150px;
grid-template-columns: 100px 254px 1fr minmax(150px, 1fr) 150px 200px;
gap: 15px;
.goods-item-img {
......@@ -6510,11 +6583,22 @@ const onUpdateCustomsDeclarationInfo = () => {
}
}
// 确保选中行的背景色在 hover 时也保持
// 设置选中行的背景色
:deep(.el-table__body) {
.el-table__row:hover {
td {
background-color: #e1ebf5 !important;
}
}
.el-table__row.row-selected {
td {
background-color: #faecd8 !important;
}
}
// 确保选中行的背景色在 hover 时也保持
.el-table__row.row-selected:hover {
td {
background-color: #fdf6ec !important;
background-color: #faecd8 !important;
}
}
}
......
......@@ -650,6 +650,7 @@ const getPackingData = async (code: string) => {
background: 'rgba(0, 0, 0, 0.3)',
})
currentCode = code
try {
const factoryNo = userStore.user?.factory.id
if (!factoryNo) {
......
......@@ -6176,15 +6176,8 @@ const getRowStyle = ({ row }: { row: PodUsOrderListData }) => {
color: '#67c23a',
}
}
// 如果行被选中,设置背景色为 #fdf6ec
if (selection.value.some((item) => item.id === row.id)) {
return {
backgroundColor: '#fdf6ec',
}
}
return {
backgroundColor: '',
}
// 选中状态通过 CSS 类名控制,这里不再处理
return {}
}
// 获取行类名方法
......@@ -7327,11 +7320,22 @@ useRouter().beforeEach((to, from, next) => {
}
}
// 确保选中行的背景色在 hover 时也保持
// 设置选中行的背景色
:deep(.el-table__body) {
.el-table__row:hover {
td {
background-color: #e1ebf5 !important;
}
}
.el-table__row.row-selected {
td {
background-color: #faecd8 !important;
}
}
// 确保选中行的背景色在 hover 时也保持
.el-table__row.row-selected:hover {
td {
background-color: #fdf6ec !important;
background-color: #faecd8 !important;
}
}
}
......
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