Files
dukang/apps/mini-user/src/lib/order-logistics-utils.ts
T

115 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { OrderTrackDto } from '@dukang/shared-types';
import { isXfxProviderCode } from '@dukang/shared-types';
import { formatShanghaiDateTime } from './datetime';
export type OrderDelivery = {
provider?: string;
trackingNo?: string;
logisticsCompany?: string;
manualQueryUrl?: string;
};
export type OrderTrackNode = {
trackInfo?: string;
createTime?: string;
createdAt?: string;
statusName?: string;
};
export type OrderTrackEstimatedArrival = {
arriveTime: string;
siteName?: string;
};
export type OrderTrackResponse = OrderTrackDto;
/** 订单详情页展示物流摘要的状态(配送中) */
export const ORDER_LOGISTICS_PREVIEW_STATUSES = ['SHIPPING', 'SHIPPED'] as const;
const PHONE_PATTERN = /(1[3-9]\d{9}|\d{3,4}-\d{7,8})/g;
function compareTrackNodeTime(a: OrderTrackNode, b: OrderTrackNode) {
const ta = new Date(a.createTime || a.createdAt || 0).getTime();
const tb = new Date(b.createTime || b.createdAt || 0).getTime();
if (Number.isNaN(ta) && Number.isNaN(tb)) return 0;
if (Number.isNaN(ta)) return 1;
if (Number.isNaN(tb)) return -1;
return ta - tb;
}
export function deliveryProviderLabel(provider?: string, company?: string) {
if (company) return company;
if (!provider || provider === 'MOCK' || isXfxProviderCode(provider)) {
return '小飞侠配送';
}
if (provider === 'LOGISTICS') return '快递配送';
return provider;
}
export function shouldLoadOrderTrack(delivery?: OrderDelivery | null) {
if (!delivery) return false;
if (delivery.trackingNo) return true;
return isXfxProviderCode(delivery.provider || '');
}
export function formatTrackNodeTime(node: OrderTrackNode) {
return formatShanghaiDateTime(node.createTime || node.createdAt);
}
export function sortTrackNodesNewestFirst(nodes: OrderTrackNode[]): OrderTrackNode[] {
return [...nodes].sort((a, b) => -compareTrackNodeTime(a, b));
}
export function sortTrackNodesOldestFirst(nodes: OrderTrackNode[]): OrderTrackNode[] {
return [...nodes].sort(compareTrackNodeTime);
}
export function latestTrackNode(nodes: OrderTrackNode[]) {
if (!nodes.length) return null;
let latest = nodes[0];
for (let i = 1; i < nodes.length; i += 1) {
if (compareTrackNodeTime(nodes[i], latest) > 0) {
latest = nodes[i];
}
}
return latest;
}
export function isLogisticsNotArrived(nodes: OrderTrackNode[], orderStatus?: string) {
if (['PENDING_RECEIVE', 'DELIVERED', 'COMPLETED'].includes(orderStatus || '')) {
return false;
}
if (nodes.length === 0) return true;
return !nodes.some(
(node) => node.statusName?.includes('签收') || node.trackInfo?.includes('签收'),
);
}
export function formatEstimatedArrival(eta?: OrderTrackEstimatedArrival | null) {
if (!eta?.arriveTime) return '';
const time = formatShanghaiDateTime(eta.arriveTime);
if (eta.siteName) return `预计送达:${time}${eta.siteName}`;
return `预计送达:${time}`;
}
export type LogisticsTextSegment = { type: 'text' | 'phone'; value: string };
export function splitLogisticsText(text: string): LogisticsTextSegment[] {
if (!text) return [];
const segments: LogisticsTextSegment[] = [];
let lastIndex = 0;
const regex = new RegExp(PHONE_PATTERN.source, 'g');
let match: RegExpExecArray | null;
while ((match = regex.exec(text)) !== null) {
if (match.index > lastIndex) {
segments.push({ type: 'text', value: text.slice(lastIndex, match.index) });
}
segments.push({ type: 'phone', value: match[0] });
lastIndex = match.index + match[0].length;
}
if (lastIndex < text.length) {
segments.push({ type: 'text', value: text.slice(lastIndex) });
}
return segments.length ? segments : [{ type: 'text', value: text }];
}