fix:支付方式对接
This commit is contained in:
155
src/components/order-confirm/orderConfirmModal.vue
Normal file
155
src/components/order-confirm/orderConfirmModal.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { AlipayOutlined, WechatOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
orderInfo: {
|
||||
orderId: string;
|
||||
orderType: number; // 0: 购买套餐, 1: 余额充值
|
||||
orderAmount: number;
|
||||
};
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits(['update:visible', 'confirm', 'cancel']);
|
||||
|
||||
const orderTypeMap = {
|
||||
0: t('page.order.packagePurchase'),
|
||||
1: t('page.order.balanceRecharge')
|
||||
} as const;
|
||||
|
||||
const handleConfirm = (paymentMethod: 'alipay' | 'wxpay') => {
|
||||
emit('confirm', paymentMethod);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
:title="t('page.order.confirmOrder')"
|
||||
:footer="null"
|
||||
@cancel="handleCancel"
|
||||
width="460px"
|
||||
:maskClosable="false"
|
||||
>
|
||||
<div class="order-info">
|
||||
<div class="info-item">
|
||||
<span class="label">{{ t('page.order.orderType') }}:</span>
|
||||
<span class="value">{{ orderTypeMap[orderInfo.orderType] }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">{{ t('page.order.orderAmount') }}:</span>
|
||||
<span class="value highlight">¥{{ orderInfo.orderAmount.toFixed(2) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">{{ t('page.order.orderId') }}:</span>
|
||||
<span class="value">{{ orderInfo.orderId }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="payment-methods">
|
||||
<h4>{{ t('page.order.selectPayment') }}</h4>
|
||||
<div class="methods-container">
|
||||
<div class="method-item" @click="handleConfirm('alipay')">
|
||||
<AlipayOutlined class="payment-icon alipay-icon" />
|
||||
<span>{{ t('page.order.alipay') }}</span>
|
||||
</div>
|
||||
<div class="method-item" @click="handleConfirm('wxpay')">
|
||||
<WechatOutlined class="payment-icon wxpay-icon" />
|
||||
<span>{{ t('page.order.wxpay') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.order-info {
|
||||
padding: 20px;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
margin-bottom: 16px;
|
||||
line-height: 24px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
width: 84px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.value.highlight {
|
||||
color: #ff4d4f;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.payment-methods {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.payment-methods h4 {
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.methods-container {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.method-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.method-item:hover {
|
||||
border-color: #1890ff;
|
||||
background: #f0f5ff;
|
||||
}
|
||||
|
||||
.payment-icon {
|
||||
font-size: 24px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.alipay-icon {
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
.wxpay-icon {
|
||||
color: #07c160;
|
||||
}
|
||||
</style>
|
||||
@@ -661,6 +661,17 @@ const local: any = {
|
||||
balanceRecharge:'Banlance Recharge',
|
||||
packageSubscription:'Package Subscription',
|
||||
},
|
||||
order:{
|
||||
confirmOrder:'Order Confirmation',
|
||||
orderType:'Order type',
|
||||
balanceRecharge:'Balance recharge',
|
||||
packagePurchase:'Package processing',
|
||||
orderAmount:'Amount',
|
||||
orderId:'ID',
|
||||
selectPayment:'Payment',
|
||||
alipay:'Alipay',
|
||||
wxpay:'WeChat Pay'
|
||||
}
|
||||
},
|
||||
form: {
|
||||
required: 'Cannot be empty',
|
||||
|
||||
@@ -663,6 +663,20 @@ const local:any = {
|
||||
balanceRecharge:'余额充值',
|
||||
packageSubscription:'套餐办理',
|
||||
},
|
||||
order:{
|
||||
confirmOrder:'订单确认',
|
||||
orderType:'订单类型',
|
||||
balanceRecharge:'余额充值',
|
||||
packagePurchase:'套餐办理',
|
||||
orderAmount:'订单金额',
|
||||
orderId:'订单ID',
|
||||
selectPayment:'支付方式',
|
||||
alipay:'支付宝支付',
|
||||
wxpay:'微信支付'
|
||||
},
|
||||
package:{
|
||||
|
||||
}
|
||||
},
|
||||
form: {
|
||||
required: '不能为空',
|
||||
|
||||
3
src/typings/auto-imports.d.ts
vendored
3
src/typings/auto-imports.d.ts
vendored
@@ -14,6 +14,7 @@ declare global {
|
||||
const afterAll: typeof import('vitest')['afterAll']
|
||||
const afterEach: typeof import('vitest')['afterEach']
|
||||
const aliPayPcPay: typeof import('../service/api/payment')['aliPayPcPay']
|
||||
const aliPayWapPay: typeof import('../service/api/payment')['aliPayWapPay']
|
||||
const assert: typeof import('vitest')['assert']
|
||||
const assign: typeof import('lodash-es')['assign']
|
||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
@@ -74,6 +75,7 @@ declare global {
|
||||
const doGetDictList: typeof import('../service/api/dict')['doGetDictList']
|
||||
const doGetMenuDetail: typeof import('../service/api/menu')['doGetMenuDetail']
|
||||
const doGetMenuList: typeof import('../service/api/menu')['doGetMenuList']
|
||||
const doGetOrderInfo: typeof import('../service/api/order')['doGetOrderInfo']
|
||||
const doGetPostDetail: typeof import('../service/api/post')['doGetPostDetail']
|
||||
const doGetPostList: typeof import('../service/api/post')['doGetPostList']
|
||||
const doGetRoleList: typeof import('../service/api/role')['doGetRoleList']
|
||||
@@ -433,6 +435,7 @@ declare global {
|
||||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
||||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
||||
const whenever: typeof import('@vueuse/core')['whenever']
|
||||
const wxPayScanCode: typeof import('../service/api/payment')['wxPayScanCode']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
|
||||
1
src/typings/components.d.ts
vendored
1
src/typings/components.d.ts
vendored
@@ -77,6 +77,7 @@ declare module 'vue' {
|
||||
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
||||
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
||||
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
||||
OrderConfirmModal: typeof import('./../components/order-confirm/orderConfirmModal.vue')['default']
|
||||
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
|
||||
ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
||||
@@ -7,6 +7,7 @@ import { message } from 'ant-design-vue';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import type { Ref } from 'vue';
|
||||
import OrderConfirmModal from '@/components/order-confirm/orderConfirmModal.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'BalanceRecharge'
|
||||
@@ -82,6 +83,14 @@ onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
});
|
||||
|
||||
// 添加订单确认弹窗相关状态
|
||||
const showOrderModal = ref(false);
|
||||
const currentOrderInfo = ref({
|
||||
orderId: '',
|
||||
orderType: 1, // 1 表示余额充值
|
||||
orderAmount: 0
|
||||
});
|
||||
|
||||
// 修改充值处理方法
|
||||
const handleRecharge = async () => {
|
||||
// 验证金额
|
||||
@@ -90,55 +99,54 @@ const handleRecharge = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await submitOrder({
|
||||
type: 1,
|
||||
orderAmount: paymentAmount.value
|
||||
});
|
||||
message.success('充值订单提交成功!');
|
||||
} catch (error) {
|
||||
message.error('充值失败,请重试!');
|
||||
console.error('Failed to submit recharge order:', error);
|
||||
}
|
||||
};
|
||||
// 测试:支付宝支付
|
||||
const handleAliPay = async () => {
|
||||
try {
|
||||
const orderRes = await submitOrder({
|
||||
type: 1,
|
||||
orderAmount: paymentAmount.value
|
||||
});
|
||||
// 区分手机端和pc端支付
|
||||
let res;
|
||||
if(appStore.isMobile) {
|
||||
res = await aliPayWapPay({orderId: orderRes.data});
|
||||
|
||||
// 更新订单信息并显示弹窗
|
||||
currentOrderInfo.value = {
|
||||
orderId: orderRes.data,
|
||||
orderType: 1,
|
||||
orderAmount: paymentAmount.value
|
||||
};
|
||||
showOrderModal.value = true;
|
||||
} catch (error) {
|
||||
message.error('创建订单失败,请重试!');
|
||||
console.error('Failed to create order:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理支付方式选择
|
||||
const handlePaymentConfirm = async (paymentMethod: 'alipay' | 'wxpay') => {
|
||||
try {
|
||||
if (paymentMethod === 'alipay') {
|
||||
// 区分手机端和pc端支付
|
||||
let res;
|
||||
if (appStore.isMobile) {
|
||||
res = await aliPayWapPay({ orderId: currentOrderInfo.value.orderId });
|
||||
} else {
|
||||
res = await aliPayPcPay({ orderId: currentOrderInfo.value.orderId });
|
||||
}
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = res;
|
||||
document.body.appendChild(div);
|
||||
document.forms['punchout_form'].submit();
|
||||
} else {
|
||||
res = await aliPayPcPay({orderId: orderRes.data});
|
||||
const res = await wxPayScanCode({ orderId: currentOrderInfo.value.orderId });
|
||||
routerPushByKey('billing_wxpay', {
|
||||
query: {
|
||||
url: res.data,
|
||||
orderId: currentOrderInfo.value.orderId
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log(res);
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = res; // html code
|
||||
document.body.appendChild(div);
|
||||
document.forms['punchout_form'].submit();
|
||||
|
||||
} catch (error) {
|
||||
message.error('充值失败,请重试!');
|
||||
console.error('Failed to submit recharge order:', error);
|
||||
}
|
||||
};
|
||||
// 微信支付
|
||||
const handleWxPay = async () => {
|
||||
try {
|
||||
const orderRes = await submitOrder({
|
||||
type: 1,
|
||||
orderAmount: paymentAmount.value
|
||||
});
|
||||
const res = await wxPayScanCode({orderId: orderRes.data});
|
||||
routerPushByKey('billing_wxpay', { query: { url: res.data, orderId: orderRes.data } })
|
||||
|
||||
} catch (error) {
|
||||
message.error('充值失败,请重试!');
|
||||
console.error('Failed to submit recharge order:', error);
|
||||
message.error(t('page.order.paymentFailed'));
|
||||
console.error('Payment failed:', error);
|
||||
} finally {
|
||||
showOrderModal.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -193,27 +201,14 @@ const handleWxPay = async () => {
|
||||
>
|
||||
¥{{ paymentAmount.toFixed(2) }} {{ t('page.carddata.pay') }}
|
||||
</AButton>
|
||||
<!-- 测试:支付宝支付 -->
|
||||
<AButton
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
:disabled="!paymentAmount || paymentAmount <= 0"
|
||||
@click="handleAliPay"
|
||||
>
|
||||
AliPay
|
||||
</AButton>
|
||||
<!-- 测试:微信支付 -->
|
||||
<AButton
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
:disabled="!paymentAmount || paymentAmount <= 0"
|
||||
@click="handleWxPay"
|
||||
>
|
||||
WxPay
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<!-- 订单确认弹窗 -->
|
||||
<OrderConfirmModal
|
||||
v-model:visible="showOrderModal"
|
||||
:order-info="currentOrderInfo"
|
||||
@confirm="handlePaymentConfirm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -3,12 +3,22 @@ import { useI18n } from 'vue-i18n';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { fetchPackageList, submitOrder } from '@/service/api/auth';
|
||||
import { message } from 'ant-design-vue';
|
||||
import OrderConfirmModal from '@/components/order-confirm/orderConfirmModal.vue';
|
||||
import { aliPayPcPay, wxPayScanCode } from '@/service/api/payment';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
|
||||
defineOptions({
|
||||
name: 'PackageSubscription'
|
||||
});
|
||||
const { t } = useI18n();
|
||||
|
||||
interface RateLimit {
|
||||
upLimitEnable: boolean;
|
||||
downLimitEnable: boolean;
|
||||
upLimit: number;
|
||||
downLimit: number;
|
||||
}
|
||||
|
||||
interface PackageOption {
|
||||
id: string;
|
||||
packageName: string;
|
||||
@@ -24,6 +34,8 @@ interface PackageOption {
|
||||
periodNum: number;
|
||||
periodType: number;
|
||||
validityPeriod: string;
|
||||
rateLimitEnable: boolean;
|
||||
rateLimits: RateLimit;
|
||||
}
|
||||
|
||||
// 添加有效期类型枚举
|
||||
@@ -86,6 +98,16 @@ const formatTrafficValidity = (num: number, type: number): string => {
|
||||
return `${num}${unit}`;
|
||||
};
|
||||
|
||||
// 添加速率格式化函数
|
||||
const formatSpeed = (speed: number): string => {
|
||||
if (speed >= 1000000) {
|
||||
return `${(speed / 1000000).toFixed(1)}Gbps`;
|
||||
} else if (speed >= 1000) {
|
||||
return `${(speed / 1000).toFixed(1)}Mbps`;
|
||||
}
|
||||
return `${speed}Kbps`;
|
||||
};
|
||||
|
||||
const packageOptions = ref<PackageOption[]>([]);
|
||||
const selectedPackage = ref<PackageOption>({
|
||||
id: '1',
|
||||
@@ -101,7 +123,25 @@ const selectedPackage = ref<PackageOption>({
|
||||
promotion: '',
|
||||
periodNum: 0,
|
||||
periodType: PERIOD_TYPE.MONTH,
|
||||
validityPeriod: '0月'
|
||||
validityPeriod: '0月',
|
||||
rateLimitEnable: false,
|
||||
rateLimits: {
|
||||
upLimitEnable: false,
|
||||
downLimitEnable: false,
|
||||
upLimit: 0,
|
||||
downLimit: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 添加路由跳转方法
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
|
||||
// 添加订单确认弹窗相关状态
|
||||
const showOrderModal = ref(false);
|
||||
const currentOrderInfo = ref({
|
||||
orderId: '',
|
||||
orderType: 0, // 0 表示购买套餐
|
||||
orderAmount: 0
|
||||
});
|
||||
|
||||
const fetchPackages = async () => {
|
||||
@@ -116,13 +156,22 @@ const fetchPackages = async () => {
|
||||
clientNumEnable: pkg.clientNumEnable,
|
||||
traffic: Number(pkg.traffic),
|
||||
trafficEnable: pkg.trafficEnable,
|
||||
trafficDisplay: pkg.trafficEnable ? `${formatTraffic(Number(pkg.traffic))},${formatTrafficValidity(Number(pkg.periodNum), Number(pkg.periodType))}内有效` : '无限制',
|
||||
durationEnable: pkg.durationEnable,
|
||||
trafficDisplay: pkg.trafficEnable ? formatTraffic(Number(pkg.traffic)) : '无限制',
|
||||
durationEnable: Boolean(pkg.periodNum && pkg.periodType !== undefined),
|
||||
isRecommended: pkg.isRecommended || false,
|
||||
promotion: pkg.promotion || '',
|
||||
periodNum: Number(pkg.periodNum),
|
||||
periodType: Number(pkg.periodType),
|
||||
validityPeriod: pkg.durationEnable ? formatValidityPeriod(Number(pkg.periodNum), Number(pkg.periodType)) : '无限制'
|
||||
validityPeriod: pkg.periodNum && pkg.periodType !== undefined
|
||||
? formatValidityPeriod(Number(pkg.periodNum), Number(pkg.periodType))+'内有效'
|
||||
: '无限制',
|
||||
rateLimitEnable: pkg.rateLimitEnable,
|
||||
rateLimits: {
|
||||
upLimitEnable: pkg.rateLimits?.upLimitEnable || false,
|
||||
downLimitEnable: pkg.rateLimits?.downLimitEnable || false,
|
||||
upLimit: Number(pkg.rateLimits?.upLimit) || 0,
|
||||
downLimit: Number(pkg.rateLimits?.downLimit) || 0
|
||||
}
|
||||
}));
|
||||
|
||||
if (packageOptions.value.length > 0) {
|
||||
@@ -138,17 +187,50 @@ const selectPackage = (option: PackageOption) => {
|
||||
selectedPackage.value = option;
|
||||
};
|
||||
|
||||
// 套餐办理方法
|
||||
// 修改套餐办理方法
|
||||
const handleSubmitOrder = async () => {
|
||||
try {
|
||||
await submitOrder({
|
||||
const orderRes = await submitOrder({
|
||||
type: 0,
|
||||
packageId: selectedPackage.value.id
|
||||
});
|
||||
message.success('套餐办理成功!');
|
||||
|
||||
// 更新订单信息并显示弹窗
|
||||
currentOrderInfo.value = {
|
||||
orderId: orderRes.data,
|
||||
orderType: 0,
|
||||
orderAmount: selectedPackage.value.price
|
||||
};
|
||||
showOrderModal.value = true;
|
||||
} catch (error) {
|
||||
message.error('套餐办理失败,请重试!');
|
||||
console.error('Failed to submit order:', error);
|
||||
message.error(t('page.order.createOrderFailed'));
|
||||
console.error('Failed to create order:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理支付方式选择
|
||||
const handlePaymentConfirm = async (paymentMethod: 'alipay' | 'wxpay') => {
|
||||
try {
|
||||
if (paymentMethod === 'alipay') {
|
||||
const res = await aliPayPcPay({ orderId: currentOrderInfo.value.orderId });
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = res;
|
||||
document.body.appendChild(div);
|
||||
document.forms['punchout_form'].submit();
|
||||
} else {
|
||||
const res = await wxPayScanCode({ orderId: currentOrderInfo.value.orderId });
|
||||
routerPushByKey('billing_wxpay', {
|
||||
query: {
|
||||
url: res.data,
|
||||
orderId: currentOrderInfo.value.orderId
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(t('page.order.paymentFailed'));
|
||||
console.error('Payment failed:', error);
|
||||
} finally {
|
||||
showOrderModal.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -224,6 +306,22 @@ onMounted(async () => {
|
||||
{{ selectedPackage.durationEnable ? selectedPackage.validityPeriod : '无限制' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="label">速率限制</div>
|
||||
<div class="value">
|
||||
<template v-if="!selectedPackage.rateLimitEnable">
|
||||
不限速
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>
|
||||
上行:{{ selectedPackage.rateLimits.upLimitEnable ? formatSpeed(selectedPackage.rateLimits.upLimit) : '-' }}
|
||||
</div>
|
||||
<div>
|
||||
下行:{{ selectedPackage.rateLimits.downLimitEnable ? formatSpeed(selectedPackage.rateLimits.downLimit) : '-' }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-bar">
|
||||
<button
|
||||
class="btn-primary"
|
||||
@@ -235,6 +333,13 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单确认弹窗 -->
|
||||
<OrderConfirmModal
|
||||
v-model:visible="showOrderModal"
|
||||
:order-info="currentOrderInfo"
|
||||
@confirm="handlePaymentConfirm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -401,4 +506,18 @@ onMounted(async () => {
|
||||
color: #666;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.speed-limit {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.value > div {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.value > div:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user