Compare commits
No commits in common. "25bc5efd3082311c4be0d3f25e3c435453eb37d6" and "ffadbcd92f7c02bbdf3f5de1aed0ef6e0670077b" have entirely different histories.
25bc5efd30
...
ffadbcd92f
@ -106,19 +106,13 @@ const useTabBarStore = defineStore('tabBar', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/** LRU:访问时挪到末尾,并裁剪超量缓存 */
|
||||||
* LRU:访问时挪到末尾,并裁剪超量缓存。
|
|
||||||
* 必须一次性重赋值 Set,禁止先 delete 再 add:
|
|
||||||
* keep-alive 会监听 include,名字从列表里消失会立刻 prune 掉缓存实例,
|
|
||||||
* 表现为「切换标签就整页刷新」。
|
|
||||||
*/
|
|
||||||
touchCache(name: string) {
|
touchCache(name: string) {
|
||||||
if (!isString(name) || name === '') return;
|
if (!isString(name) || name === '') return;
|
||||||
const next = new Set(
|
if (this.cacheTabList.has(name)) {
|
||||||
[...this.cacheTabList].filter((item) => item !== name),
|
this.cacheTabList.delete(name);
|
||||||
);
|
}
|
||||||
next.add(name);
|
this.cacheTabList.add(name);
|
||||||
this.cacheTabList = next;
|
|
||||||
this.pruneCache(name);
|
this.pruneCache(name);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@ function escapeAttr(text: string): string {
|
|||||||
.replace(/"/g, '"')
|
.replace(/"/g, '"')
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Vue / a-tag 内联样式(软底圆角,无硬框、无左侧色条) */
|
/** Vue / a-tag 内联样式(软底 + 左侧色条,无硬框) */
|
||||||
export function getStatusTagStyle(
|
export function getStatusTagStyle(
|
||||||
toneOrColors: StatusTagTone | StatusTagColors | null | undefined,
|
toneOrColors: StatusTagTone | StatusTagColors | null | undefined,
|
||||||
variant: StatusTagVariant = 'solid',
|
variant: StatusTagVariant = 'solid',
|
||||||
@ -102,10 +102,11 @@ export function getStatusTagStyle(
|
|||||||
background: colors.tagBgColor,
|
background: colors.tagBgColor,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
|
boxShadow: `inset 3px 0 0 ${colors.tagColor}`,
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
lineHeight: '22px',
|
lineHeight: '22px',
|
||||||
padding: '0 10px',
|
padding: '0 10px 0 12px',
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
letterSpacing: '0.02em',
|
letterSpacing: '0.02em',
|
||||||
|
|||||||
@ -10,8 +10,7 @@ import AdminWorkplace from './components/AdminWorkplace.vue'
|
|||||||
import CustomerWorkplace from './components/CustomerWorkplace.vue'
|
import CustomerWorkplace from './components/CustomerWorkplace.vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
// 必须与路由 name `Workplace` 一致,否则 keep-alive include 对不上,切标签会整页重挂
|
name: 'Home',
|
||||||
name: 'Workplace',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const rbacUserStore = useRbacUserStore()
|
const rbacUserStore = useRbacUserStore()
|
||||||
|
|||||||
@ -5,50 +5,6 @@ export interface OrderDetailFieldDef {
|
|||||||
labelKey: string;
|
labelKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 订单详情基本信息中按「是/否」展示的布尔字段 */
|
|
||||||
export const ORDER_DETAIL_BOOLEAN_FIELD_KEYS = [
|
|
||||||
'isCod',
|
|
||||||
'isIntercept',
|
|
||||||
'isRemote',
|
|
||||||
'isPaid',
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export type OrderDetailBooleanFieldKey = (typeof ORDER_DETAIL_BOOLEAN_FIELD_KEYS)[number];
|
|
||||||
|
|
||||||
export function isOrderDetailBooleanField(key: string): boolean {
|
|
||||||
return (ORDER_DETAIL_BOOLEAN_FIELD_KEYS as readonly string[]).includes(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 兼容 true/false、0/1、是/否 等后端写法 */
|
|
||||||
export function coerceOrderDetailBoolean(raw: unknown): boolean | null {
|
|
||||||
if (raw === true || raw === 1 || raw === '1') return true;
|
|
||||||
if (raw === false || raw === 0 || raw === '0') return false;
|
|
||||||
if (raw == null || raw === '') return null;
|
|
||||||
const s = String(raw).trim().toLowerCase();
|
|
||||||
if (!s || s === '--') return null;
|
|
||||||
if (['true', 'yes', 'y', '是'].includes(s)) return true;
|
|
||||||
if (['false', 'no', 'n', '否'].includes(s)) return false;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatOrderDetailBooleanLabel(
|
|
||||||
raw: unknown,
|
|
||||||
t: (key: string, ...args: any[]) => string,
|
|
||||||
): string {
|
|
||||||
const flag = coerceOrderDetailBoolean(raw);
|
|
||||||
// 缺省按「否」,避免详情里出现裸文本/「--」与同组 tag 不一致
|
|
||||||
return flag ? t('order.myOrders.drawer.yes') : t('order.myOrders.drawer.no');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOrderDetailYesNoLabel(
|
|
||||||
text: string,
|
|
||||||
t: (key: string, ...args: any[]) => string,
|
|
||||||
): boolean {
|
|
||||||
return (
|
|
||||||
text === t('order.myOrders.drawer.yes') || text === t('order.myOrders.drawer.no')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ORDER_DETAIL_EXTRA_BASIC_FIELDS: OrderDetailFieldDef[] = [
|
export const ORDER_DETAIL_EXTRA_BASIC_FIELDS: OrderDetailFieldDef[] = [
|
||||||
{ key: 'quantity', labelKey: 'order.myOrders.drawer.quantity' },
|
{ key: 'quantity', labelKey: 'order.myOrders.drawer.quantity' },
|
||||||
{ key: 'exportCustomsMode', labelKey: 'order.myOrders.drawer.exportCustomsMode' },
|
{ key: 'exportCustomsMode', labelKey: 'order.myOrders.drawer.exportCustomsMode' },
|
||||||
@ -78,30 +34,8 @@ export const ORDER_DETAIL_VALUE_FIELD_MAP: Record<string, string[]> = {
|
|||||||
additionalServices: ['additionalServices', 'AdditionalServices'],
|
additionalServices: ['additionalServices', 'AdditionalServices'],
|
||||||
downstreamSupplierName: ['downstreamSupplierName', 'DownstreamSupplierName'],
|
downstreamSupplierName: ['downstreamSupplierName', 'DownstreamSupplierName'],
|
||||||
downstreamSupplierCode: ['downstreamSupplierCode', 'DownstreamSupplierCode'],
|
downstreamSupplierCode: ['downstreamSupplierCode', 'DownstreamSupplierCode'],
|
||||||
isPaid: ['isPaid', 'IsPaid'],
|
|
||||||
isCod: ['isCod', 'IsCod'],
|
|
||||||
isIntercept: ['isIntercept', 'IsIntercept'],
|
|
||||||
isRemote: ['isRemote', 'IsRemote'],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 读取布尔字段原始值(保留 false/0,不因 falsy 被跳过) */
|
|
||||||
export function pickOrderDetailBooleanRaw(
|
|
||||||
order: Record<string, any> | null | undefined,
|
|
||||||
key: string,
|
|
||||||
): unknown {
|
|
||||||
if (!order) return undefined;
|
|
||||||
const keys = ORDER_DETAIL_VALUE_FIELD_MAP[key] || [key];
|
|
||||||
for (const k of keys) {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(order, k) && order[k] === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const v = order[k];
|
|
||||||
if (v === undefined) continue;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OrderDetailFieldGroup {
|
export interface OrderDetailFieldGroup {
|
||||||
key: string;
|
key: string;
|
||||||
labelKey: string;
|
labelKey: string;
|
||||||
@ -163,80 +97,6 @@ export function pickOrderDetailRawValue(order: Record<string, any> | null | unde
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 兼容 camelCase / PascalCase 嵌套字段(列表轻量映射会留下空 items/weightList) */
|
|
||||||
export function pickOrderDetailNested<T = unknown>(
|
|
||||||
order: Record<string, any> | null | undefined,
|
|
||||||
...keys: string[]
|
|
||||||
): T | undefined {
|
|
||||||
if (!order) return undefined;
|
|
||||||
for (const key of keys) {
|
|
||||||
if (order[key] !== undefined && order[key] !== null) {
|
|
||||||
return order[key] as T;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 多个候选数组里取「有内容」的那个,避免列表空数组盖住详情 */
|
|
||||||
export function pickOrderDetailArray<T = any>(
|
|
||||||
order: Record<string, any> | null | undefined,
|
|
||||||
...keys: string[]
|
|
||||||
): T[] {
|
|
||||||
if (!order) return [];
|
|
||||||
let fallback: T[] = [];
|
|
||||||
for (const key of keys) {
|
|
||||||
const raw = order[key];
|
|
||||||
if (!Array.isArray(raw)) continue;
|
|
||||||
if (raw.length > 0) return raw as T[];
|
|
||||||
fallback = raw as T[];
|
|
||||||
}
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开详情时合并列表行 + /order/detail:
|
|
||||||
* 列表故意 Items/WeightList/FeeList=[],不能让空数组盖住详情里的完整嵌套数据。
|
|
||||||
*/
|
|
||||||
export function mergeOrderListRowWithDetail(listRow: any, detail: any) {
|
|
||||||
const base = listRow && typeof listRow === 'object' ? listRow : {};
|
|
||||||
const d = detail && typeof detail === 'object' ? detail : {};
|
|
||||||
const merged = { ...base, ...d };
|
|
||||||
|
|
||||||
const sender = pickOrderDetailNested(d, 'sender', 'Sender')
|
|
||||||
?? pickOrderDetailNested(base, 'sender', 'Sender');
|
|
||||||
const receiver = pickOrderDetailNested(d, 'receiver', 'Receiver')
|
|
||||||
?? pickOrderDetailNested(base, 'receiver', 'Receiver');
|
|
||||||
const items = pickOrderDetailArray(d, 'items', 'Items');
|
|
||||||
const itemsResolved = items.length
|
|
||||||
? items
|
|
||||||
: pickOrderDetailArray(base, 'items', 'Items');
|
|
||||||
const weightList = pickOrderDetailArray(d, 'weightList', 'WeightList');
|
|
||||||
const weightResolved = weightList.length
|
|
||||||
? weightList
|
|
||||||
: pickOrderDetailArray(base, 'weightList', 'WeightList');
|
|
||||||
const feeList = pickOrderDetailArray(
|
|
||||||
d,
|
|
||||||
'feeList',
|
|
||||||
'FeeList',
|
|
||||||
'orderFees',
|
|
||||||
'fees',
|
|
||||||
);
|
|
||||||
const feeResolved = feeList.length
|
|
||||||
? feeList
|
|
||||||
: pickOrderDetailArray(base, 'feeList', 'FeeList', 'orderFees', 'fees');
|
|
||||||
|
|
||||||
if (sender && typeof sender === 'object') {
|
|
||||||
merged.sender = sender;
|
|
||||||
}
|
|
||||||
if (receiver && typeof receiver === 'object') {
|
|
||||||
merged.receiver = receiver;
|
|
||||||
}
|
|
||||||
merged.items = itemsResolved;
|
|
||||||
merged.weightList = weightResolved;
|
|
||||||
merged.feeList = feeResolved;
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DictRowLike {
|
export interface DictRowLike {
|
||||||
dictCode?: string | null;
|
dictCode?: string | null;
|
||||||
dictName?: string | null;
|
dictName?: string | null;
|
||||||
|
|||||||
@ -216,10 +216,10 @@
|
|||||||
{{ getOrderValue(fieldKey) }}
|
{{ getOrderValue(fieldKey) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="shouldRenderOrderBooleanTag(fieldKey)">
|
<template v-else-if="isOrderBooleanField(fieldKey)">
|
||||||
<a-tag
|
<a-tag
|
||||||
size="small"
|
size="small"
|
||||||
:style="getBooleanTagStyle(getOrderValue(fieldKey) === $t('order.myOrders.drawer.yes'))"
|
:style="getOrderBooleanTagStyle(fieldKey)"
|
||||||
>
|
>
|
||||||
{{ getOrderValue(fieldKey) }}
|
{{ getOrderValue(fieldKey) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
@ -761,16 +761,10 @@ import {
|
|||||||
ORDER_DETAIL_VALUE_FIELD_MAP,
|
ORDER_DETAIL_VALUE_FIELD_MAP,
|
||||||
buildDeclarationPayloadFromRows,
|
buildDeclarationPayloadFromRows,
|
||||||
cloneDeclarationItemRows,
|
cloneDeclarationItemRows,
|
||||||
formatOrderDetailBooleanLabel,
|
|
||||||
formatOrderDetailExtendedValue,
|
formatOrderDetailExtendedValue,
|
||||||
isOrderDetailBooleanField,
|
|
||||||
isOrderDetailYesNoLabel,
|
|
||||||
mergeOrderBasicFields,
|
mergeOrderBasicFields,
|
||||||
parseAdditionalServiceCodes,
|
parseAdditionalServiceCodes,
|
||||||
patchOrderBasicFieldGroups,
|
patchOrderBasicFieldGroups,
|
||||||
pickOrderDetailArray,
|
|
||||||
pickOrderDetailBooleanRaw,
|
|
||||||
pickOrderDetailNested,
|
|
||||||
} from '../../components/orderDetailFieldConfig';
|
} from '../../components/orderDetailFieldConfig';
|
||||||
import {
|
import {
|
||||||
filterMyOrdersColumns,
|
filterMyOrdersColumns,
|
||||||
@ -1126,9 +1120,14 @@ function getOrderFieldLabelKey(fieldKey: string) {
|
|||||||
return orderBasicFields.find((field) => field.key === fieldKey)?.labelKey ?? fieldKey;
|
return orderBasicFields.find((field) => field.key === fieldKey)?.labelKey ?? fieldKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldRenderOrderBooleanTag(fieldKey: string) {
|
function isOrderBooleanField(fieldKey: string) {
|
||||||
if (isOrderDetailBooleanField(fieldKey)) return true;
|
return ['isCod', 'isIntercept', 'isRemote', 'isPaid'].includes(fieldKey);
|
||||||
return isOrderDetailYesNoLabel(getOrderValue(fieldKey), t);
|
}
|
||||||
|
|
||||||
|
function getOrderBooleanTagStyle(fieldKey: string) {
|
||||||
|
const val = getOrderValue(fieldKey);
|
||||||
|
const yes = t('order.myOrders.drawer.yes');
|
||||||
|
return getBooleanTagStyle(val === yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const declarationSkuPreviewVisible = ref(false);
|
const declarationSkuPreviewVisible = ref(false);
|
||||||
@ -1587,15 +1586,18 @@ function getOrderValue(key: string) {
|
|||||||
shipTime: ['shipTime'],
|
shipTime: ['shipTime'],
|
||||||
payTime: ['payTime'],
|
payTime: ['payTime'],
|
||||||
signTime: ['signTime'],
|
signTime: ['signTime'],
|
||||||
|
isPaid: ['isPaid', 'IsPaid'],
|
||||||
|
isCod: ['isCod'],
|
||||||
|
codCurrency: ['codCurrency'],
|
||||||
|
codSum: ['codSum'],
|
||||||
|
isIntercept: ['isIntercept'],
|
||||||
|
isRemote: ['isRemote'],
|
||||||
createTime: ['createTime'],
|
createTime: ['createTime'],
|
||||||
createBy: ['createBy'],
|
createBy: ['createBy'],
|
||||||
updateTime: ['updateTime'],
|
updateTime: ['updateTime'],
|
||||||
updateBy: ['updateBy'],
|
updateBy: ['updateBy'],
|
||||||
...ORDER_DETAIL_VALUE_FIELD_MAP,
|
...ORDER_DETAIL_VALUE_FIELD_MAP,
|
||||||
};
|
};
|
||||||
if (isOrderDetailBooleanField(key)) {
|
|
||||||
return formatOrderDetailBooleanLabel(pickOrderDetailBooleanRaw(o, key), t);
|
|
||||||
}
|
|
||||||
const keys = fieldMap[key] || [key];
|
const keys = fieldMap[key] || [key];
|
||||||
let val: any;
|
let val: any;
|
||||||
for (const k of keys) {
|
for (const k of keys) {
|
||||||
@ -1605,6 +1607,9 @@ function getOrderValue(key: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (val == null || val === '') return '--';
|
if (val == null || val === '') return '--';
|
||||||
|
if (key === 'isCod' || key === 'isIntercept' || key === 'isRemote' || key === 'isPaid') {
|
||||||
|
return val ? t('order.myOrders.drawer.yes') : t('order.myOrders.drawer.no');
|
||||||
|
}
|
||||||
if (key === 'orderStatus') {
|
if (key === 'orderStatus') {
|
||||||
const code = resolveOrderStatusCode(o);
|
const code = resolveOrderStatusCode(o);
|
||||||
const meta = getOrderStatusMeta(code);
|
const meta = getOrderStatusMeta(code);
|
||||||
@ -1629,7 +1634,7 @@ function getSenderValue(key: string) {
|
|||||||
}
|
}
|
||||||
const val = sender.value[key];
|
const val = sender.value[key];
|
||||||
if (key === 'isDefault') {
|
if (key === 'isDefault') {
|
||||||
return formatOrderDetailBooleanLabel(val, t);
|
return val == null ? '--' : (val ? t('order.myOrders.drawer.yes') : t('order.myOrders.drawer.no'));
|
||||||
}
|
}
|
||||||
return val ?? '--';
|
return val ?? '--';
|
||||||
}
|
}
|
||||||
@ -1962,27 +1967,21 @@ async function loadTrackTimeline() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载详情数据(兼容 camel/Pascal;列表空 items/weightList 不能盖住详情)
|
// 加载详情数据(优先使用 list 接口返回的 sender/receiver/items/weightList,与 parcel/create 对应)
|
||||||
function loadDetailData() {
|
function loadDetailData() {
|
||||||
const o = detail.value;
|
const o = detail.value;
|
||||||
if (!o) return;
|
if (!o) return;
|
||||||
|
|
||||||
const senderRaw = pickOrderDetailNested<Record<string, any>>(o, 'sender', 'Sender');
|
// 发件人
|
||||||
if (senderRaw && typeof senderRaw === 'object') {
|
if (o.sender && typeof o.sender === 'object') {
|
||||||
sender.value = {
|
sender.value = { ...o.sender, country: o.sender.country ?? o.sender.countryCode };
|
||||||
...senderRaw,
|
|
||||||
country: senderRaw.country ?? senderRaw.countryCode ?? senderRaw.CountryCode,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
sender.value = {};
|
sender.value = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const receiverRaw = pickOrderDetailNested<Record<string, any>>(o, 'receiver', 'Receiver');
|
// 收件人:优先使用 list 返回的 receiver
|
||||||
if (receiverRaw && typeof receiverRaw === 'object') {
|
if (o.receiver && typeof o.receiver === 'object') {
|
||||||
recipient.value = {
|
recipient.value = { ...o.receiver, country: o.receiver.country ?? o.receiver.countryCode };
|
||||||
...receiverRaw,
|
|
||||||
country: receiverRaw.country ?? receiverRaw.countryCode ?? receiverRaw.CountryCode,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
recipient.value = {
|
recipient.value = {
|
||||||
recipientsName: o.consignee || '',
|
recipientsName: o.consignee || '',
|
||||||
@ -2007,12 +2006,17 @@ function loadDetailData() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemsRaw = pickOrderDetailArray(o, 'items', 'Items');
|
// 申报信息
|
||||||
declarationList.value = itemsRaw.length > 0 ? cloneDeclarationItemRows(itemsRaw) : [];
|
declarationList.value = Array.isArray(o.items) && o.items.length > 0
|
||||||
|
? cloneDeclarationItemRows(o.items)
|
||||||
|
: [];
|
||||||
|
|
||||||
weightList.value = pickOrderDetailArray(o, 'weightList', 'WeightList');
|
// 件重尺
|
||||||
|
weightList.value = Array.isArray(o.weightList) && o.weightList.length > 0 ? o.weightList : [];
|
||||||
|
|
||||||
feeList.value = pickOrderDetailArray(o, 'feeList', 'FeeList', 'orderFees', 'fees');
|
// 费用:接口字段可为 feeList / orderFees / FeeList
|
||||||
|
const fees = o.feeList ?? o.FeeList ?? o.orderFees ?? o.fees;
|
||||||
|
feeList.value = Array.isArray(fees) ? fees : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyDetailFromApi(raw: any) {
|
function applyDetailFromApi(raw: any) {
|
||||||
|
|||||||
@ -62,7 +62,6 @@
|
|||||||
type ColumnScheme,
|
type ColumnScheme,
|
||||||
} from './columnConfig';
|
} from './columnConfig';
|
||||||
import { filterMyOrdersColumns, filterMyOrdersFieldKeys } from './customerFieldMask';
|
import { filterMyOrdersColumns, filterMyOrdersFieldKeys } from './customerFieldMask';
|
||||||
import { mergeOrderListRowWithDetail } from '../components/orderDetailFieldConfig';
|
|
||||||
import { useHiprintClientState } from '@/utils/hiprint/hiprintClientState';
|
import { useHiprintClientState } from '@/utils/hiprint/hiprintClientState';
|
||||||
import { fetchPrintUrlsForOrders, getCachedPrintUrl } from '@/utils/printSessionCache';
|
import { fetchPrintUrlsForOrders, getCachedPrintUrl } from '@/utils/printSessionCache';
|
||||||
|
|
||||||
@ -275,7 +274,7 @@
|
|||||||
if (id != null && id !== '') {
|
if (id != null && id !== '') {
|
||||||
try {
|
try {
|
||||||
const detail = await getOrderDetail(id);
|
const detail = await getOrderDetail(id);
|
||||||
nextRow = normalizeOrderRow(mergeOrderListRowWithDetail(row, detail));
|
nextRow = normalizeOrderRow({ ...row, ...detail });
|
||||||
} catch {
|
} catch {
|
||||||
/* 保留列表行数*/
|
/* 保留列表行数*/
|
||||||
}
|
}
|
||||||
@ -1529,7 +1528,7 @@
|
|||||||
if (rows.length === 1 && id != null) {
|
if (rows.length === 1 && id != null) {
|
||||||
try {
|
try {
|
||||||
const detail = await getOrderDetail(id);
|
const detail = await getOrderDetail(id);
|
||||||
ctxRow = normalizeOrderRow(mergeOrderListRowWithDetail(ctxRow, detail));
|
ctxRow = normalizeOrderRow({ ...ctxRow, ...detail });
|
||||||
} catch {
|
} catch {
|
||||||
/* keep list row */
|
/* keep list row */
|
||||||
}
|
}
|
||||||
|
|||||||
@ -207,10 +207,10 @@
|
|||||||
{{ getOrderValue(fieldKey) }}
|
{{ getOrderValue(fieldKey) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="shouldRenderOrderBooleanTag(fieldKey)">
|
<template v-else-if="isOrderBooleanField(fieldKey)">
|
||||||
<a-tag
|
<a-tag
|
||||||
size="small"
|
size="small"
|
||||||
:style="getBooleanTagStyle(getOrderValue(fieldKey) === $t('order.myOrders.drawer.yes'))"
|
:style="getOrderBooleanTagStyle(fieldKey)"
|
||||||
>
|
>
|
||||||
{{ getOrderValue(fieldKey) }}
|
{{ getOrderValue(fieldKey) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
@ -1037,16 +1037,10 @@ import {
|
|||||||
ORDER_DETAIL_VALUE_FIELD_MAP,
|
ORDER_DETAIL_VALUE_FIELD_MAP,
|
||||||
buildDeclarationPayloadFromRows,
|
buildDeclarationPayloadFromRows,
|
||||||
cloneDeclarationItemRows,
|
cloneDeclarationItemRows,
|
||||||
formatOrderDetailBooleanLabel,
|
|
||||||
formatOrderDetailExtendedValue,
|
formatOrderDetailExtendedValue,
|
||||||
isOrderDetailBooleanField,
|
|
||||||
isOrderDetailYesNoLabel,
|
|
||||||
mergeOrderBasicFields,
|
mergeOrderBasicFields,
|
||||||
parseAdditionalServiceCodes,
|
parseAdditionalServiceCodes,
|
||||||
patchOrderBasicFieldGroups,
|
patchOrderBasicFieldGroups,
|
||||||
pickOrderDetailArray,
|
|
||||||
pickOrderDetailBooleanRaw,
|
|
||||||
pickOrderDetailNested,
|
|
||||||
} from '../../components/orderDetailFieldConfig';
|
} from '../../components/orderDetailFieldConfig';
|
||||||
import { openAskAdvisor } from '@/composables/useAskAdvisor';
|
import { openAskAdvisor } from '@/composables/useAskAdvisor';
|
||||||
import { buildFailGuideFromReason } from '@/utils/parcelCreateFailGuide';
|
import { buildFailGuideFromReason } from '@/utils/parcelCreateFailGuide';
|
||||||
@ -1399,9 +1393,14 @@ function getOrderFieldLabelKey(fieldKey: string) {
|
|||||||
return orderBasicFields.find((field) => field.key === fieldKey)?.labelKey ?? fieldKey;
|
return orderBasicFields.find((field) => field.key === fieldKey)?.labelKey ?? fieldKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldRenderOrderBooleanTag(fieldKey: string) {
|
function isOrderBooleanField(fieldKey: string) {
|
||||||
if (isOrderDetailBooleanField(fieldKey)) return true;
|
return ['isCod', 'isIntercept', 'isRemote', 'isPaid'].includes(fieldKey);
|
||||||
return isOrderDetailYesNoLabel(getOrderValue(fieldKey), t);
|
}
|
||||||
|
|
||||||
|
function getOrderBooleanTagStyle(fieldKey: string) {
|
||||||
|
const val = getOrderValue(fieldKey);
|
||||||
|
const yes = t('order.myOrders.drawer.yes');
|
||||||
|
return getBooleanTagStyle(val === yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const declarationSkuPreviewVisible = ref(false);
|
const declarationSkuPreviewVisible = ref(false);
|
||||||
@ -1820,15 +1819,18 @@ function getOrderValue(key: string) {
|
|||||||
shipTime: ['shipTime'],
|
shipTime: ['shipTime'],
|
||||||
payTime: ['payTime'],
|
payTime: ['payTime'],
|
||||||
signTime: ['signTime'],
|
signTime: ['signTime'],
|
||||||
|
isPaid: ['isPaid', 'IsPaid'],
|
||||||
|
isCod: ['isCod'],
|
||||||
|
codCurrency: ['codCurrency'],
|
||||||
|
codSum: ['codSum'],
|
||||||
|
isIntercept: ['isIntercept'],
|
||||||
|
isRemote: ['isRemote'],
|
||||||
createTime: ['createTime'],
|
createTime: ['createTime'],
|
||||||
createBy: ['createBy'],
|
createBy: ['createBy'],
|
||||||
updateTime: ['updateTime'],
|
updateTime: ['updateTime'],
|
||||||
updateBy: ['updateBy'],
|
updateBy: ['updateBy'],
|
||||||
...ORDER_DETAIL_VALUE_FIELD_MAP,
|
...ORDER_DETAIL_VALUE_FIELD_MAP,
|
||||||
};
|
};
|
||||||
if (isOrderDetailBooleanField(key)) {
|
|
||||||
return formatOrderDetailBooleanLabel(pickOrderDetailBooleanRaw(o, key), t);
|
|
||||||
}
|
|
||||||
const keys = fieldMap[key] || [key];
|
const keys = fieldMap[key] || [key];
|
||||||
let val: any;
|
let val: any;
|
||||||
for (const k of keys) {
|
for (const k of keys) {
|
||||||
@ -1838,6 +1840,9 @@ function getOrderValue(key: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (val == null || val === '') return '--';
|
if (val == null || val === '') return '--';
|
||||||
|
if (key === 'isCod' || key === 'isIntercept' || key === 'isRemote' || key === 'isPaid') {
|
||||||
|
return val ? t('order.myOrders.drawer.yes') : t('order.myOrders.drawer.no');
|
||||||
|
}
|
||||||
if (key === 'orderStatus') {
|
if (key === 'orderStatus') {
|
||||||
const code = resolveOrderStatusCode(o);
|
const code = resolveOrderStatusCode(o);
|
||||||
const meta = getOrderStatusMeta(code);
|
const meta = getOrderStatusMeta(code);
|
||||||
@ -1862,7 +1867,7 @@ function getSenderValue(key: string) {
|
|||||||
}
|
}
|
||||||
const val = sender.value[key];
|
const val = sender.value[key];
|
||||||
if (key === 'isDefault') {
|
if (key === 'isDefault') {
|
||||||
return formatOrderDetailBooleanLabel(val, t);
|
return val == null ? '--' : (val ? t('order.myOrders.drawer.yes') : t('order.myOrders.drawer.no'));
|
||||||
}
|
}
|
||||||
return val ?? '--';
|
return val ?? '--';
|
||||||
}
|
}
|
||||||
@ -2457,22 +2462,16 @@ function loadDetailData() {
|
|||||||
const o = detail.value;
|
const o = detail.value;
|
||||||
if (!o) return;
|
if (!o) return;
|
||||||
|
|
||||||
const senderRaw = pickOrderDetailNested<Record<string, any>>(o, 'sender', 'Sender');
|
// 发件人
|
||||||
if (senderRaw && typeof senderRaw === 'object') {
|
if (o.sender && typeof o.sender === 'object') {
|
||||||
sender.value = {
|
sender.value = { ...o.sender, country: o.sender.country ?? o.sender.countryCode };
|
||||||
...senderRaw,
|
|
||||||
country: senderRaw.country ?? senderRaw.countryCode ?? senderRaw.CountryCode,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
sender.value = {};
|
sender.value = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const receiverRaw = pickOrderDetailNested<Record<string, any>>(o, 'receiver', 'Receiver');
|
// 收件人:优先使用 list 返回的 receiver
|
||||||
if (receiverRaw && typeof receiverRaw === 'object') {
|
if (o.receiver && typeof o.receiver === 'object') {
|
||||||
recipient.value = {
|
recipient.value = { ...o.receiver, country: o.receiver.country ?? o.receiver.countryCode };
|
||||||
...receiverRaw,
|
|
||||||
country: receiverRaw.country ?? receiverRaw.countryCode ?? receiverRaw.CountryCode,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
recipient.value = {
|
recipient.value = {
|
||||||
recipientsName: o.consignee || '',
|
recipientsName: o.consignee || '',
|
||||||
@ -2497,12 +2496,17 @@ function loadDetailData() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemsRaw = pickOrderDetailArray(o, 'items', 'Items');
|
// 申报信息
|
||||||
declarationList.value = itemsRaw.length > 0 ? cloneDeclarationItemRows(itemsRaw) : [];
|
declarationList.value = Array.isArray(o.items) && o.items.length > 0
|
||||||
|
? cloneDeclarationItemRows(o.items)
|
||||||
|
: [];
|
||||||
|
|
||||||
weightList.value = pickOrderDetailArray(o, 'weightList', 'WeightList');
|
// 件重尺
|
||||||
|
weightList.value = Array.isArray(o.weightList) && o.weightList.length > 0 ? o.weightList : [];
|
||||||
|
|
||||||
feeList.value = pickOrderDetailArray(o, 'feeList', 'FeeList', 'orderFees', 'fees');
|
// 费用:接口字段可为 feeList / orderFees / FeeList
|
||||||
|
const fees = o.feeList ?? o.FeeList ?? o.orderFees ?? o.fees;
|
||||||
|
feeList.value = Array.isArray(fees) ? fees : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyDetailFromApi(raw: any) {
|
function applyDetailFromApi(raw: any) {
|
||||||
|
|||||||
@ -74,7 +74,6 @@
|
|||||||
WAYBILL_MANAGE_DEFAULT_KEYS,
|
WAYBILL_MANAGE_DEFAULT_KEYS,
|
||||||
getWaybillBaseCatalog,
|
getWaybillBaseCatalog,
|
||||||
} from './columnConfig';
|
} from './columnConfig';
|
||||||
import { mergeOrderListRowWithDetail } from '../components/orderDetailFieldConfig';
|
|
||||||
import {
|
import {
|
||||||
fetchPrintUrlForOrder,
|
fetchPrintUrlForOrder,
|
||||||
fetchPrintUrlsForOrders,
|
fetchPrintUrlsForOrders,
|
||||||
@ -210,17 +209,11 @@
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 列表行与表格列对齐:只保留标量/展平字段,不保留嵌套树(Items/FeeList 等) */
|
||||||
* 列表行与表格列对齐:展平寄收件人等列字段;
|
|
||||||
* 同时保留 sender/receiver/items/weightList/feeList,供详情抽屉使用
|
|
||||||
*(勿再整棵丢掉,否则 /order/detail 嵌套数据会被 normalize 冲掉)。
|
|
||||||
*/
|
|
||||||
function normalizeOrderRow(raw: any, customerLabelMap?: Map<number, string>) {
|
function normalizeOrderRow(raw: any, customerLabelMap?: Map<number, string>) {
|
||||||
const r = raw?.receiver || raw?.Receiver || {};
|
const r = raw?.receiver || raw?.Receiver || {};
|
||||||
const s = raw?.sender || raw?.Sender || {};
|
const s = raw?.sender || raw?.Sender || {};
|
||||||
const wl = raw?.weightList || raw?.WeightList;
|
const wl = raw?.weightList || raw?.WeightList;
|
||||||
const itemsRaw = raw?.items || raw?.Items;
|
|
||||||
const feeRaw = raw?.feeList || raw?.FeeList || raw?.orderFees || raw?.fees;
|
|
||||||
const lastW =
|
const lastW =
|
||||||
Array.isArray(wl) && wl.length ? wl[wl.length - 1] : undefined;
|
Array.isArray(wl) && wl.length ? wl[wl.length - 1] : undefined;
|
||||||
|
|
||||||
@ -473,12 +466,6 @@
|
|||||||
consigneeCountry && consigneeCountryName
|
consigneeCountry && consigneeCountryName
|
||||||
? `${consigneeCountry} ${consigneeCountryName}`
|
? `${consigneeCountry} ${consigneeCountryName}`
|
||||||
: consigneeCountryName || consigneeCountry || null,
|
: consigneeCountryName || consigneeCountry || null,
|
||||||
// 详情抽屉依赖嵌套对象;列表接口 items/weightList 常为空数组,有内容时以 raw 为准
|
|
||||||
sender: s && typeof s === 'object' && Object.keys(s).length ? s : undefined,
|
|
||||||
receiver: r && typeof r === 'object' && Object.keys(r).length ? r : undefined,
|
|
||||||
items: Array.isArray(itemsRaw) ? itemsRaw : [],
|
|
||||||
weightList: Array.isArray(wl) ? wl : [],
|
|
||||||
feeList: Array.isArray(feeRaw) ? feeRaw : [],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,10 +478,7 @@
|
|||||||
if (id != null && id !== '') {
|
if (id != null && id !== '') {
|
||||||
try {
|
try {
|
||||||
const detail = await getOrderDetail(id);
|
const detail = await getOrderDetail(id);
|
||||||
nextRow = normalizeOrderRow(
|
nextRow = normalizeOrderRow({ ...row, ...detail }, buildCustomerLabelMap());
|
||||||
mergeOrderListRowWithDetail(row, detail),
|
|
||||||
buildCustomerLabelMap(),
|
|
||||||
);
|
|
||||||
} catch {
|
} catch {
|
||||||
/* 保留列表行数据 */
|
/* 保留列表行数据 */
|
||||||
}
|
}
|
||||||
@ -1751,10 +1735,7 @@
|
|||||||
if (rows.length === 1 && id != null) {
|
if (rows.length === 1 && id != null) {
|
||||||
try {
|
try {
|
||||||
const detail = await getOrderDetail(id);
|
const detail = await getOrderDetail(id);
|
||||||
ctxRow = normalizeOrderRow(
|
ctxRow = normalizeOrderRow({ ...ctxRow, ...detail });
|
||||||
mergeOrderListRowWithDetail(ctxRow, detail),
|
|
||||||
buildCustomerLabelMap(),
|
|
||||||
);
|
|
||||||
} catch {
|
} catch {
|
||||||
/* keep list row */
|
/* keep list row */
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,11 +68,6 @@ import {
|
|||||||
} from './providerCatalog';
|
} from './providerCatalog';
|
||||||
import { buildAiViewTree, type AiViewKey } from './viewsCatalog';
|
import { buildAiViewTree, type AiViewKey } from './viewsCatalog';
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
// 与路由 name 对齐;index.vue 默认推断为 index,会导致切标签无法缓存
|
|
||||||
name: 'SystemAiAssistant',
|
|
||||||
});
|
|
||||||
|
|
||||||
const DEFAULT_VIEW: AiViewKey = 'providers';
|
const DEFAULT_VIEW: AiViewKey = 'providers';
|
||||||
|
|
||||||
const selectedViewKeys = ref<string[]>([DEFAULT_VIEW]);
|
const selectedViewKeys = ref<string[]>([DEFAULT_VIEW]);
|
||||||
|
|||||||
@ -147,11 +147,6 @@ import {
|
|||||||
type AiProviderItem,
|
type AiProviderItem,
|
||||||
} from '@/views/system/aiAssistant/providerCatalog';
|
} from '@/views/system/aiAssistant/providerCatalog';
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
// 与路由 name 对齐;index.vue 默认推断为 index,会导致切标签无法缓存
|
|
||||||
name: 'SystemMcpTools',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user