开始增加支付-1

This commit is contained in:
yml
2026-06-03 12:21:23 +08:00
parent 6dcea2d56c
commit ae8928f458
22 changed files with 2098 additions and 33 deletions
+27 -1
View File
@@ -70,6 +70,27 @@ export interface HandoffRecord {
created_at: string
}
export interface PaymentOrder {
id: number
payment_no: string
order_id: number
order_no: string
provider: string
third_order_id: string
provider_order_id: string
pay_way: string
jspay_flag: string
amount_cent: number
status: string
td_code?: string
jspay_url?: string
jspay_info?: string
paid: boolean
paid_at?: string
created_at: string
updated_at: string
}
export interface SubmitCheckoutPayload {
content: string
consumable_amount: number
@@ -95,7 +116,12 @@ export async function createOrder(listingId: number) {
}
export async function payOrder(id: number) {
const { data } = await apiClient.post<ApiResponse<{ paid: boolean }>>(`/orders/${id}/pay`)
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(`/orders/${id}/pay`)
return data.data
}
export async function queryOrderPayment(id: number) {
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(`/orders/${id}/pay/query`)
return data.data
}
+11
View File
@@ -2,6 +2,7 @@ import { apiClient } from './client'
import type { ApiResponse, PaginatedResult } from './types'
import type { BalanceType, LedgerDirection, WalletStatus } from '@/types/status'
import type { PaymentOrder } from './orders'
export interface WalletAccount {
user_id: number
@@ -41,3 +42,13 @@ export async function rechargeWallet(amount: number) {
const { data } = await apiClient.post<ApiResponse<WalletAccount>>('/wallet/recharge', { amount })
return data.data
}
export async function startWalletRechargePayment(amount: number) {
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>('/wallet/recharge/pay', { amount })
return data.data
}
export async function queryWalletRechargePayment(id: number) {
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(`/wallet/recharge/pay/${id}/query`)
return data.data
}
+63 -6
View File
@@ -1,8 +1,16 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fetchWalletBalance, fetchWalletLedger, rechargeWallet, type WalletAccount, type WalletLedger } from '@/api/wallet'
import {
fetchWalletBalance,
fetchWalletLedger,
queryWalletRechargePayment,
startWalletRechargePayment,
type WalletAccount,
type WalletLedger,
} from '@/api/wallet'
import type { PaymentOrder } from '@/api/orders'
import { balanceTypeLabel, ledgerDirectionLabel, walletStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
@@ -41,8 +49,12 @@ function loadLedgerPage() {
async function handleRecharge() {
recharging.value = true
try {
account.value = await rechargeWallet(rechargeAmount.value)
ElMessage.success('充值成功')
const payment = await startWalletRechargePayment(rechargeAmount.value)
if (payment.paid) {
ElMessage.success('充值成功')
} else {
await showRechargePaymentDialog(payment)
}
await loadWallet()
} catch (error) {
ElMessage.error(readError(error, '充值失败'))
@@ -51,6 +63,51 @@ async function handleRecharge() {
}
}
async function showRechargePaymentDialog(payment: PaymentOrder) {
const payURL = payment.jspay_url || payment.td_code || payment.jspay_info || ''
const message = payURL
? `充值支付单已创建,金额 ¥${(payment.amount_cent / 100).toFixed(2)}\n\n${payURL}`
: '充值支付单已创建,请完成付款后刷新状态。'
await ElMessageBox.confirm(message, '支付充值', {
confirmButtonText: payURL ? '打开/复制' : '刷新状态',
cancelButtonText: '刷新状态',
distinguishCancelAndClose: true,
})
.then(async () => {
if (payURL) {
await openOrCopyPayURL(payURL)
}
await refreshRechargePayment(payment.id)
})
.catch(async (action) => {
if (action === 'cancel') {
await refreshRechargePayment(payment.id)
}
})
}
async function openOrCopyPayURL(payURL: string) {
if (/^https?:\/\//.test(payURL)) {
window.open(payURL, '_blank')
return
}
try {
await navigator.clipboard?.writeText(payURL)
ElMessage.success('支付链接已复制')
} catch {
ElMessage.warning('请手动复制支付链接')
}
}
async function refreshRechargePayment(paymentID: number) {
const payment = await queryWalletRechargePayment(paymentID)
if (payment.paid) {
ElMessage.success('充值成功')
} else {
ElMessage.info('支付未完成')
}
}
function readError(error: unknown, fallback: string) {
if (typeof error === 'object' && error && 'response' in error) {
const response = (error as { response?: { data?: { message?: string } } }).response
@@ -84,9 +141,9 @@ function readError(error: unknown, fallback: string) {
</div>
<div class="table-panel recharge-panel">
<h2>开发充值</h2>
<h2>支付充值</h2>
<el-input-number v-model="rechargeAmount" :min="1" :precision="0" controls-position="right" />
<el-button type="primary" :loading="recharging" @click="handleRecharge">充值</el-button>
<el-button type="primary" :loading="recharging" @click="handleRecharge">发起充值</el-button>
</div>
<el-table class="table-panel" :data="ledger">
+53 -4
View File
@@ -1,10 +1,10 @@
<script setup lang="ts">
import { onMounted, ref, computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import { showToast } from "vant";
import { showDialog, showToast } from "vant";
import MobileBottomNav from "@/components/MobileBottomNav.vue";
import { fetchOrders, payOrder, type Order } from "@/api/orders";
import { fetchOrders, payOrder, queryOrderPayment, type Order, type PaymentOrder } from "@/api/orders";
import { useSessionStore } from "@/stores/session";
import { formatDateMinute } from "@/utils/time";
@@ -75,8 +75,12 @@ function goDetail(id: number) {
async function handlePay(order: Order) {
payingOrderId.value = order.id;
try {
await payOrder(order.id);
showToast({ message: "支付成功", icon: "passed" });
const payment = await payOrder(order.id);
if (payment.paid) {
showToast({ message: "支付成功", icon: "passed" });
} else {
await showPaymentDialog(order, payment);
}
await loadOrders();
} catch (error) {
showToast({ message: readError(error, "支付失败"), icon: "cross" });
@@ -85,6 +89,51 @@ async function handlePay(order: Order) {
}
}
async function showPaymentDialog(order: Order, payment: PaymentOrder) {
const payURL = payment.jspay_url || payment.td_code || payment.jspay_info || "";
const message = payURL
? `支付单已创建,金额 ¥${(payment.amount_cent / 100).toFixed(2)}。请复制或打开支付链接完成付款,付款后可刷新订单状态。\n\n${payURL}`
: "支付单已创建,请完成付款后刷新订单状态。";
await showDialog({
title: "去支付",
message,
confirmButtonText: payURL ? "打开/复制" : "刷新状态",
cancelButtonText: "刷新状态",
showCancelButton: true,
})
.then(async () => {
if (payURL) {
await openOrCopyPayURL(payURL);
}
await refreshPayment(order.id);
})
.catch(async () => {
await refreshPayment(order.id);
});
}
async function openOrCopyPayURL(payURL: string) {
if (/^https?:\/\//.test(payURL)) {
window.open(payURL, "_blank");
return;
}
try {
await navigator.clipboard?.writeText(payURL);
showToast({ message: "支付链接已复制", icon: "passed" });
} catch {
showToast({ message: "请手动复制支付链接", icon: "warning-o" });
}
}
async function refreshPayment(orderId: number) {
const payment = await queryOrderPayment(orderId);
if (payment.paid) {
showToast({ message: "支付成功", icon: "passed" });
} else {
showToast({ message: "支付未完成", icon: "clock-o" });
}
}
function readError(error: unknown, fallback: string) {
if (typeof error === "object" && error && "response" in error) {
const response = (error as { response?: { data?: { message?: string } } })