完善下单逻辑及其ui展示,修复支付倒计时显示错误bug

This commit is contained in:
2026-05-25 15:35:41 +08:00
parent d25f80ccdd
commit cecb51a8e2
40 changed files with 13040 additions and 3217 deletions

172
utils/orderStatus.uts Normal file
View File

@@ -0,0 +1,172 @@
export type UnifiedOrderSource = 'goods' | 'service'
export type OrderStatusSource = {
source?: UnifiedOrderSource | string
order_status: number
payment_status: number
pay_expire_at: string
created_at: string
cancel_reason: string
}
export const ORDER_STATUS_PENDING = 1
export const ORDER_STATUS_PAID_OR_SHIPPING = 2
export const ORDER_STATUS_RECEIVING = 3
export const ORDER_STATUS_COMPLETED = 4
export const ORDER_STATUS_CANCELLED = 5
export const ORDER_STATUS_REFUNDING = 6
export const ORDER_STATUS_REFUNDED = 7
export const ORDER_STATUS_TIMEOUT_LEGACY = 8
export const PAYMENT_STATUS_UNPAID = 1
export const PAYMENT_STATUS_PAID = 2
export const PAYMENT_STATUS_PARTIAL_REFUND = 3
export const PAYMENT_STATUS_REFUNDED = 4
export const PAYMENT_STATUS_TIMEOUT = 5
export const ORDER_PAY_TIMEOUT_SECONDS = 10 * 60
export const ORDER_TIMEOUT_CANCEL_REASON = '支付超时自动取消'
function parseDateMs(value: string): number {
if (value == '') {
return 0
}
const date = new Date(value)
if (isNaN(date.getTime())) {
return 0
}
return date.getTime()
}
function containsTimeoutReason(cancelReason: string): boolean {
return cancelReason.indexOf('超时') >= 0
}
function getNormalizedSource(order: OrderStatusSource): UnifiedOrderSource {
if (order.source == 'service') {
return 'service'
}
return 'goods'
}
function isPendingSourceOrder(order: OrderStatusSource): boolean {
return order.order_status == ORDER_STATUS_PENDING && order.payment_status == PAYMENT_STATUS_UNPAID
}
export function getOrderDeadlineMs(order: OrderStatusSource): number {
const payExpireAtMs = parseDateMs(order.pay_expire_at)
if (payExpireAtMs > 0) {
return payExpireAtMs
}
const createdAtMs = parseDateMs(order.created_at)
if (createdAtMs > 0) {
return createdAtMs + ORDER_PAY_TIMEOUT_SECONDS * 1000
}
return 0
}
export function getRemainingSeconds(order: OrderStatusSource): number {
const deadlineMs = getOrderDeadlineMs(order)
if (deadlineMs <= 0) {
return 0
}
const diff = Math.floor((deadlineMs - Date.now()) / 1000)
return diff > 0 ? diff : 0
}
export function getUnifiedDisplayState(order: OrderStatusSource): string {
const source = getNormalizedSource(order)
const deadlineMs = getOrderDeadlineMs(order)
const hasExpiredByDeadline = order.order_status == ORDER_STATUS_PENDING && deadlineMs > 0 && deadlineMs <= Date.now()
if (source == 'service') {
if (order.order_status == ORDER_STATUS_PENDING && order.payment_status == PAYMENT_STATUS_UNPAID && !hasExpiredByDeadline && !containsTimeoutReason(order.cancel_reason)) {
return 'pending_pay'
}
if (order.order_status == ORDER_STATUS_TIMEOUT_LEGACY || order.payment_status == PAYMENT_STATUS_TIMEOUT || containsTimeoutReason(order.cancel_reason)) {
return 'cancelled'
}
if (hasExpiredByDeadline) {
return 'expired'
}
if (order.order_status == 2 || order.order_status == 3 || order.order_status == 4) {
return 'processing'
}
if (order.order_status == ORDER_STATUS_COMPLETED) {
return 'completed'
}
if (order.order_status == ORDER_STATUS_REFUNDING || order.order_status == ORDER_STATUS_REFUNDED) {
return 'refund'
}
return 'unknown'
}
if (order.order_status == ORDER_STATUS_PENDING && order.payment_status == PAYMENT_STATUS_UNPAID && !hasExpiredByDeadline && !containsTimeoutReason(order.cancel_reason)) {
return 'pending_pay'
}
if (order.order_status == ORDER_STATUS_CANCELLED || order.order_status == ORDER_STATUS_TIMEOUT_LEGACY || order.payment_status == PAYMENT_STATUS_TIMEOUT || containsTimeoutReason(order.cancel_reason)) {
return 'cancelled'
}
if (hasExpiredByDeadline) {
return 'expired'
}
if (order.order_status == ORDER_STATUS_PAID_OR_SHIPPING || order.order_status == ORDER_STATUS_RECEIVING) {
return 'processing'
}
if (order.order_status == ORDER_STATUS_COMPLETED) {
return 'completed'
}
if (order.order_status == ORDER_STATUS_REFUNDING || order.order_status == ORDER_STATUS_REFUNDED) {
return 'refund'
}
return 'unknown'
}
export function isOrderPayExpired(order: OrderStatusSource): boolean {
const displayState = getUnifiedDisplayState(order)
return displayState == 'cancelled' || displayState == 'expired'
}
export function isPendingPayOrder(order: OrderStatusSource): boolean {
return getUnifiedDisplayState(order) == 'pending_pay' && isPendingSourceOrder(order)
}
export function getOrderDisplayStatus(order: OrderStatusSource): string {
const displayState = getUnifiedDisplayState(order)
if (displayState == 'pending_pay') {
return 'pending'
}
if (displayState == 'cancelled' || displayState == 'expired') {
return 'cancelled'
}
if (displayState == 'processing') {
return 'shipping'
}
if (displayState == 'completed') {
return 'completed'
}
if (displayState == 'refund') {
return 'refund'
}
return 'unknown'
}
function pad2(value: number): string {
return value < 10 ? '0' + value : '' + value
}
export function formatCountdownHM(seconds: number): string {
const safeSeconds = seconds > 0 ? seconds : 0
const totalMinutes = Math.floor(safeSeconds / 60)
const hours = Math.floor(totalMinutes / 60)
const minutes = totalMinutes % 60
return pad2(hours) + '时' + pad2(minutes) + '分钟'
}
export function formatCountdownHMS(seconds: number): string {
const safeSeconds = seconds > 0 ? seconds : 0
const hours = Math.floor(safeSeconds / 3600)
const minutes = Math.floor((safeSeconds % 3600) / 60)
const remainSeconds = safeSeconds % 60
return pad2(hours) + ':' + pad2(minutes) + ':' + pad2(remainSeconds)
}

File diff suppressed because it is too large Load Diff