1.04 #5

Merged
zzh merged 2 commits from test into master 2026-10-10 19:34:34 +08:00
6 changed files with 195 additions and 0 deletions
Showing only changes of commit 631d113eea - Show all commits

View File

@ -369,6 +369,55 @@ export async function postOrderDownstreamForwardCreateOne(
}
}
/** getFile type:下游面单 / 末端面单 / POD */
export const DOWNSTREAM_GET_FILE_TYPES = [
{ value: 21, labelKey: 'order.myOrders.actions.getDownstreamFileType.downstreamLabel' },
{ value: 31, labelKey: 'order.myOrders.actions.getDownstreamFileType.lastMileLabel' },
{ value: 180, labelKey: 'order.myOrders.actions.getDownstreamFileType.pod' },
] as const
export type DownstreamGetFileType = (typeof DOWNSTREAM_GET_FILE_TYPES)[number]['value']
export interface OrderDownstreamGetFileResult {
success?: boolean
supplierCode?: string
type?: number
fileType?: string
url?: string
requestJson?: string
statusCode?: number
responseBody?: string
storedFileUrl?: string
downstreamServiceNo?: string
trackNo?: string
}
/** POST /order/downstream-forward-get-file → standardCode=getFile,转存 COS 并回写单号 */
export async function postOrderDownstreamGetFile(body: {
id: number | string
type: DownstreamGetFileType
}): Promise<OrderDownstreamGetFileResult> {
const res = await axiosInstance.post(orderUrl('/order/downstream-forward-get-file'), {
id: body.id,
type: body.type,
})
assertBusinessOk(res.data)
const d = res.data?.data ?? res.data?.Data ?? res.data ?? {}
return {
success: d.success ?? d.Success,
supplierCode: d.supplierCode ?? d.SupplierCode,
type: d.type ?? d.Type,
fileType: d.fileType ?? d.FileType,
url: d.url ?? d.Url,
requestJson: d.requestJson ?? d.RequestJson,
statusCode: d.statusCode ?? d.StatusCode,
responseBody: d.responseBody ?? d.ResponseBody,
storedFileUrl: d.storedFileUrl ?? d.StoredFileUrl,
downstreamServiceNo: d.downstreamServiceNo ?? d.DownstreamServiceNo,
trackNo: d.trackNo ?? d.TrackNo,
}
}
export interface OrderBatchActionFailure {
orderId?: number
OrderId?: number

View File

@ -82,6 +82,7 @@ export const PERMISSION_ACTION_LABELS: Record<string, string> = {
ChainPull: '串联拉取',
CreateTrack: '创建轨迹',
ForwardDownstream: '预报下游',
GetDownstreamFile: '获取下游文件',
MarkProblematic: '创建问题件',
MarkClaimed: '创建理赔件',
MarkProcessed: '标记已处理',
@ -555,6 +556,7 @@ const CORE_GROUPS: PageButtonGroup[] = [
{ code: 'PreDeclare', name: '预报' },
{ code: 'CreateTrack', name: '创建轨迹订单' },
{ code: 'ForwardDownstream', name: '预报下游订单' },
{ code: 'GetDownstreamFile', name: '获取下游文件' },
{ code: 'Print', name: '单个打印' },
{ code: 'BatchPrint', name: '批量打印' },
{ code: 'Intercept', name: '拦截' },

View File

@ -1743,7 +1743,14 @@ export default {
'order.myOrders.actions.predeclare': 'Re-predeclare',
'order.myOrders.actions.createTrackOrder': 'Create track order',
'order.myOrders.actions.forwardDownstreamCreate': 'Forward Downstream',
'order.myOrders.actions.getDownstreamFile': 'Get Downstream File',
'order.myOrders.actions.getDownstreamFileType.downstreamLabel': 'Get Downstream Label',
'order.myOrders.actions.getDownstreamFileType.lastMileLabel': 'Get Last-mile Label',
'order.myOrders.actions.getDownstreamFileType.pod': 'Get POD',
'order.myOrders.modal.downstreamForwardTitle': 'Downstream forward result',
'order.myOrders.modal.getDownstreamFileTitle': 'Get Downstream File Result',
'order.myOrders.message.getDownstreamFileNeedSelect': 'Please select orders first',
'order.myOrders.modal.payTitle': 'Payment confirmation',
'order.myOrders.modal.payOrderTotal': 'Amount due',
'order.myOrders.modal.payGrandTotal': 'Total due',

View File

@ -73,4 +73,18 @@ export async function initPreferredLocale(): Promise<void> {
i18n.global.locale.value = 'en-US';
}
/** 开发态:语言包热更新后立即灌入 i18n,避免按钮显示 key */
if (import.meta.hot) {
import.meta.hot.accept('./zh-CN', (mod) => {
if (!mod?.default) return;
i18n.global.setLocaleMessage('zh-CN', mod.default);
fullLocaleLoaded.add('zh-CN-full');
});
import.meta.hot.accept('./en-US', (mod) => {
if (!mod?.default) return;
i18n.global.setLocaleMessage('en-US', mod.default);
fullLocaleLoaded.add('en-US-full');
});
}
export default i18n;

View File

@ -1571,7 +1571,14 @@ export default {
'order.myOrders.actions.predeclare': '重新预报',
'order.myOrders.actions.createTrackOrder': '创建轨迹订单',
'order.myOrders.actions.forwardDownstreamCreate': '预报下游',
'order.myOrders.actions.getDownstreamFile': '获取下游文件',
'order.myOrders.actions.getDownstreamFileType.downstreamLabel': '获取下游面单',
'order.myOrders.actions.getDownstreamFileType.lastMileLabel': '获取末端面单',
'order.myOrders.actions.getDownstreamFileType.pod': '获取POD',
'order.myOrders.modal.downstreamForwardTitle': '下游预报结果',
'order.myOrders.modal.getDownstreamFileTitle': '获取下游文件结果',
'order.myOrders.message.getDownstreamFileNeedSelect': '请先选择订单',
'order.myOrders.modal.payTitle': '支付确认',
'order.myOrders.modal.payOrderTotal': '应付合计',
'order.myOrders.modal.payGrandTotal': '合计应付',

View File

@ -42,6 +42,8 @@
postOrderExport,
postOrderTrackUpsertSmallBag,
postOrderDownstreamForwardCreateOne,
postOrderDownstreamGetFile,
DOWNSTREAM_GET_FILE_TYPES,
postOrderBatchJob,
waitOrderBatchJob,
formatBatchJobTrackUpsertResultText,
@ -53,6 +55,8 @@
postOrderHandleStatusUpdate,
type OrderTrackUpsertResult,
type OrderDownstreamForwardResult,
type OrderDownstreamGetFileResult,
type DownstreamGetFileType,
} from '@/api/order';
import { notifyCustomerBalanceChanged } from '@/api/customer/accountFlow';
import { buildFailGuideFromReason } from '@/utils/parcelCreateFailGuide';
@ -937,6 +941,87 @@
}).catch(() => undefined);
};
const getDownstreamFileType = ref<DownstreamGetFileType>(21);
const getDownstreamFileModalVisible = ref(false);
const getDownstreamFileResultText = ref('');
function tx(key: string, fallback: string) {
return te(key) ? t(key) : fallback;
}
function getDownstreamFileTypeFallback(type: DownstreamGetFileType) {
if (type === 31) return '获取末端面单';
if (type === 180) return '获取POD';
return '获取下游面单';
}
const getDownstreamFileTypeLabel = computed(() => {
const hit = DOWNSTREAM_GET_FILE_TYPES.find((x) => x.value === getDownstreamFileType.value);
if (!hit) {
return tx(
'order.myOrders.actions.getDownstreamFileType.downstreamLabel',
'获取下游面单',
);
}
return tx(hit.labelKey, getDownstreamFileTypeFallback(hit.value));
});
function formatGetDownstreamFileResult(
waybillNo: string,
result: OrderDownstreamGetFileResult,
type: DownstreamGetFileType,
): string {
const lines = [
`【${waybillNo || '-'}】`,
result.success ? '成功' : '失败',
`standardCode:getFile`,
`type:${result.type ?? type}`,
];
if (result.supplierCode) {
lines.push(`supplierCode:${result.supplierCode}`);
}
if (result.downstreamServiceNo) {
lines.push(`服务商单号:${result.downstreamServiceNo}`);
}
if (result.trackNo) {
lines.push(`跟踪号:${result.trackNo}`);
}
if (result.storedFileUrl) {
lines.push(`已存文件:${result.storedFileUrl}`);
}
lines.push(`请求:${result.url || '-'}`);
if (result.requestJson) {
lines.push(`请求体:\n${result.requestJson}`);
}
lines.push(`HTTP:${result.statusCode ?? '-'}`);
if (result.responseBody) {
lines.push(`响应:\n${result.responseBody}`);
}
return lines.join('\n');
}
const handleGetDownstreamFile = async (type: DownstreamGetFileType) => {
const rows = requireSelectedRows();
if (!rows.length) return;
getDownstreamFileType.value = type;
await withOrderActionLoading('getDownstreamFile', async () => {
const resultBlocks: string[] = [];
for (const row of rows) {
const id = getOrderRowId(row)!;
const waybillNo = row.waybillNo || row.serviceNo || String(id);
try {
const result = await postOrderDownstreamGetFile({ id, type });
resultBlocks.push(formatGetDownstreamFileResult(waybillNo, result, type));
} catch (err: any) {
resultBlocks.push(`【${waybillNo}】失败:${err?.message || '请求异常'}`);
}
}
getDownstreamFileResultText.value = resultBlocks.join('\n\n');
getDownstreamFileModalVisible.value = true;
await refreshListAndTabCounts();
}).catch(() => undefined);
};
function getOrderRowId(row: any): number | string | undefined {
if (row == null) return undefined;
const id = row.id ?? row.Id;
@ -1986,6 +2071,28 @@
:disabled="selectedRowCount === 0 || isActionBusy('batchPrint')"
@click="handleBatchPrint"
>{{ t('order.myOrders.actions.batchPrint') }}</a-button>
<a-dropdown
trigger="click"
position="bl"
:disabled="selectedRowCount === 0 || !!actionLoadingKey"
>
<a-button
class="app-btn-toolbar btn-more"
:loading="isActionLoading('getDownstreamFile')"
:disabled="selectedRowCount === 0 || isActionBusy('getDownstreamFile')"
>
{{ getDownstreamFileTypeLabel }}
<icon-down class="btn-more-arrow" />
</a-button>
<template #content>
<a-doption
v-for="opt in DOWNSTREAM_GET_FILE_TYPES"
:key="opt.value"
:disabled="selectedRowCount === 0 || isActionBusy('getDownstreamFile')"
@click="handleGetDownstreamFile(opt.value)"
>{{ tx(opt.labelKey, getDownstreamFileTypeFallback(opt.value)) }}</a-doption>
</template>
</a-dropdown>
<a-dropdown trigger="click" position="bl" :disabled="!!actionLoadingKey">
<a-button
class="app-btn-toolbar btn-more"
@ -2186,6 +2293,15 @@
<pre class="track-upsert-result">{{ downstreamForwardResultText }}</pre>
</a-modal>
<a-modal
v-model:visible="getDownstreamFileModalVisible"
:title="tx('order.myOrders.modal.getDownstreamFileTitle', '获取下游文件结果')"
:width="800"
:footer="false"
>
<pre class="track-upsert-result">{{ getDownstreamFileResultText }}</pre>
</a-modal>
<MarkProblematicModal
v-if="problematicModalVisible"
v-model:visible="problematicModalVisible"