This commit is contained in:
@@ -9,8 +9,8 @@
|
||||
<view class="card package-card" v-for="item in packageList" :key="item.package_id">
|
||||
<view class="package-header">
|
||||
<view class="package-name">{{ item.package_name }}</view>
|
||||
<view class="tag-apple" :class="item.is_addon ? 'tag-warning' : 'tag-primary'">
|
||||
{{ item.is_addon ? '加油包' : '正式套餐' }}
|
||||
<view class="tag-apple" :class="item.is_renewal ? 'tag-warning' : (item.is_addon ? 'tag-warning' : 'tag-primary')">
|
||||
{{ item.is_renewal ? '续费套餐' : (item.is_addon ? '加油包' : '正式套餐') }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="package-main">
|
||||
@@ -27,7 +27,7 @@
|
||||
<view class="package-footer">
|
||||
<view class="price-block">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="package-price">{{ formatMoney(item.retail_price) }}</text>
|
||||
<text class="package-price">{{ formatPackagePrice(item.retail_price) }}</text>
|
||||
</view>
|
||||
<view class="btn">
|
||||
<up-button type="primary" @click="buyPackage(item)">立即订购</up-button>
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<view class="package-summary">
|
||||
<view class="summary-name">{{ currentPackage?.package_name }}</view>
|
||||
<view class="summary-price">¥{{ formatMoney(currentPackage?.retail_price) }}</view>
|
||||
<view class="summary-price">¥{{ formatPackagePrice(currentPackage?.retail_price) }}</view>
|
||||
<view class="summary-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">套餐流量</text>
|
||||
@@ -59,21 +59,17 @@
|
||||
</view>
|
||||
|
||||
<view class="payment-methods">
|
||||
<view class="method-item" :class="{ active: paymentMethod === 'alipay' }" @tap="selectPaymentMethod('alipay')">
|
||||
<view v-for="method in paymentMethodOptions" :key="method.value" class="method-item"
|
||||
:class="{ active: paymentMethod === method.value }" @tap="selectPaymentMethod(method.value)">
|
||||
<view class="method-left">
|
||||
<view class="method-icon method-badge method-badge-alipay">支</view>
|
||||
<text class="method-name">支付宝支付</text>
|
||||
<view v-if="method.value === 'alipay'" class="method-icon method-badge method-badge-alipay">支</view>
|
||||
<image v-else-if="method.value === 'wallet'" class="method-icon" src="/static/wallet.png" mode="aspectFit"></image>
|
||||
<view v-else class="method-icon method-badge">微</view>
|
||||
<text class="method-name">{{ method.label }}<template v-if="method.value === 'wallet'">(¥{{ formatMoney(walletBalance) }})</template></text>
|
||||
</view>
|
||||
<view class="method-radio" :class="{ checked: paymentMethod === 'alipay' }"></view>
|
||||
</view>
|
||||
|
||||
<view class="method-item" :class="{ active: paymentMethod === 'wallet' }" @tap="selectPaymentMethod('wallet')">
|
||||
<view class="method-left">
|
||||
<image class="method-icon" src="/static/wallet.png" mode="aspectFit"></image>
|
||||
<text class="method-name">账户余额(¥{{ formatMoney(walletBalance) }})</text>
|
||||
</view>
|
||||
<view class="method-radio" :class="{ checked: paymentMethod === 'wallet' }"></view>
|
||||
<view class="method-radio" :class="{ checked: paymentMethod === method.value }"></view>
|
||||
</view>
|
||||
<view v-if="paymentMethodOptions.length === 0" class="method-empty">暂无可用支付方式</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-footer">
|
||||
@@ -88,8 +84,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import { ref, reactive, onMounted, computed } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { assetApi, orderApi, walletApi } from '@/api/index.js';
|
||||
import { useUserStore } from '@/store/index.js';
|
||||
import {
|
||||
@@ -102,6 +98,8 @@
|
||||
showPaymentToast,
|
||||
wechatH5Pay
|
||||
} from '@/utils/payment.js';
|
||||
import { formatMoney } from '@/utils/display.js';
|
||||
import { getDefaultPaymentMethod, getPaymentMethodOptions, normalizePaymentMethods } from '@/utils/payment-methods.js';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -112,13 +110,12 @@
|
||||
const paymentMethod = ref('alipay');
|
||||
const walletBalance = ref(0);
|
||||
const paySubmitting = ref(false);
|
||||
const isDeviceAsset = ref(true);
|
||||
const assetInfo = ref({});
|
||||
const allowedPaymentMethods = ref([]);
|
||||
const renewalPackageIds = ref([]);
|
||||
const renewalPackageNames = ref([]);
|
||||
let assetTypePromise = null;
|
||||
|
||||
const formatMoney = (amount) => {
|
||||
if (!amount && amount !== 0) return '0.00';
|
||||
return (amount / 100).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
};
|
||||
const paymentMethodOptions = computed(() => getPaymentMethodOptions(allowedPaymentMethods.value));
|
||||
|
||||
const formatData = (allowance, unit) => {
|
||||
if (unit === 'MB') {
|
||||
@@ -127,18 +124,15 @@
|
||||
return `${allowance} ${unit}`;
|
||||
};
|
||||
|
||||
const getDefaultPaymentMethod = () => 'alipay';
|
||||
const formatPackagePrice = (amount) => amount === null || amount === undefined ? '-' : formatMoney(amount);
|
||||
|
||||
const isPaymentMethodAvailable = (method) => {
|
||||
if (method === 'wallet') return true;
|
||||
if (method === 'wechat') return false;
|
||||
if (method === 'alipay') return true;
|
||||
return false;
|
||||
return paymentMethodOptions.value.some((item) => item.value === method);
|
||||
};
|
||||
|
||||
const normalizePaymentMethod = () => {
|
||||
if (!isPaymentMethodAvailable(paymentMethod.value)) {
|
||||
paymentMethod.value = getDefaultPaymentMethod();
|
||||
paymentMethod.value = getDefaultPaymentMethod(allowedPaymentMethods.value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -148,7 +142,8 @@
|
||||
|
||||
assetTypePromise = assetApi.getInfo(userStore.state.identifier)
|
||||
.then((data) => {
|
||||
isDeviceAsset.value = data.asset_type === 'device';
|
||||
assetInfo.value = data;
|
||||
allowedPaymentMethods.value = normalizePaymentMethods(data.allowed_payment_methods);
|
||||
normalizePaymentMethod();
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -165,7 +160,31 @@
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = await assetApi.getPackages(userStore.state.identifier);
|
||||
packageList.splice(0, packageList.length, ...(data.packages || []));
|
||||
const currentPackageId = Number(assetInfo.value.current_package_id || 0);
|
||||
const packages = (data.packages || []).filter((item) => {
|
||||
const status = String(item.status || '').toLowerCase();
|
||||
const discontinued = item.is_on_sale === false || item.on_sale === false ||
|
||||
['off_shelf', 'offline', 'discontinued', '下架'].includes(status);
|
||||
return !discontinued || Number(item.package_id) === currentPackageId;
|
||||
}).map((item) => ({
|
||||
...item,
|
||||
is_renewal: Number(item.package_id) === currentPackageId &&
|
||||
(item.is_on_sale === false || item.on_sale === false ||
|
||||
['off_shelf', 'offline', 'discontinued', '下架'].includes(String(item.status || '').toLowerCase()))
|
||||
}));
|
||||
const packageIdsInList = new Set(packages.map((item) => Number(item.package_id)));
|
||||
const renewalOnlyPackages = renewalPackageIds.value
|
||||
.filter((packageId) => !packageIdsInList.has(Number(packageId)))
|
||||
.map((packageId, index) => ({
|
||||
package_id: Number(packageId),
|
||||
package_name: renewalPackageNames.value[index] || `历史套餐 ${packageId}`,
|
||||
retail_price: null,
|
||||
data_allowance: 0,
|
||||
data_unit: 'MB',
|
||||
validity_days: '-',
|
||||
is_renewal: true
|
||||
}));
|
||||
packageList.splice(0, packageList.length, ...packages, ...renewalOnlyPackages);
|
||||
} catch (error) {
|
||||
console.error('加载套餐列表失败', error);
|
||||
}
|
||||
@@ -181,16 +200,32 @@
|
||||
}
|
||||
};
|
||||
|
||||
const syncPackagePageState = () => {
|
||||
loadAssetType();
|
||||
loadPackages();
|
||||
loadWalletBalance();
|
||||
const syncPackagePageState = async () => {
|
||||
await loadAssetType();
|
||||
await Promise.all([loadPackages(), loadWalletBalance()]);
|
||||
};
|
||||
|
||||
const buyPackage = async (item) => {
|
||||
await loadAssetType();
|
||||
if (assetInfo.value.effective_realname_policy === 'before_order' &&
|
||||
assetInfo.value.realname_required && Number(assetInfo.value.real_name_status) !== 1) {
|
||||
uni.showModal({
|
||||
title: '需要实名认证',
|
||||
content: '当前资产下单前需要完成实名认证',
|
||||
confirmText: '去实名',
|
||||
cancelText: '取消',
|
||||
success: ({ confirm }) => {
|
||||
if (confirm) uni.navigateTo({ url: '/pages/auth/auth' });
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!paymentMethodOptions.value.length) {
|
||||
uni.showToast({ title: '暂无可用支付方式', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
currentPackage.value = item;
|
||||
paymentMethod.value = getDefaultPaymentMethod();
|
||||
paymentMethod.value = getDefaultPaymentMethod(allowedPaymentMethods.value);
|
||||
showModal.value = true;
|
||||
};
|
||||
|
||||
@@ -204,10 +239,16 @@
|
||||
isValidAlipayPaymentLink(paymentData?.payment_link);
|
||||
};
|
||||
|
||||
const handleWechatPay = async (payConfig, isForceRecharge = false) => {
|
||||
const handleWechatPay = async (payConfig, isForceRecharge = false, orderId = null) => {
|
||||
try {
|
||||
await wechatH5Pay(payConfig);
|
||||
showPaymentToast(true, isForceRecharge ? '充值成功,套餐将自动购买' : '支付成功');
|
||||
if (orderId) {
|
||||
const detail = await orderApi.getDetail(orderId);
|
||||
const status = detail?.payment_status ?? detail?.order?.payment_status;
|
||||
showPaymentToast(status === 2, status === 2 ? '支付成功' : '支付结果确认中');
|
||||
} else {
|
||||
showPaymentToast(true, isForceRecharge ? '充值成功,套餐将自动购买' : '支付成功');
|
||||
}
|
||||
setTimeout(() => {
|
||||
loadWalletBalance();
|
||||
}, 1500);
|
||||
@@ -216,9 +257,9 @@
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreparedPayment = async (paymentData, isForceRecharge = false) => {
|
||||
const handlePreparedPayment = async (paymentData, isForceRecharge = false, orderId = null) => {
|
||||
if (isValidWechatPayConfig(paymentData?.pay_config)) {
|
||||
await handleWechatPay(paymentData.pay_config, isForceRecharge);
|
||||
await handleWechatPay(paymentData.pay_config, isForceRecharge, orderId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,11 +275,13 @@
|
||||
};
|
||||
|
||||
const getCreateOrderPaymentMethod = () => {
|
||||
if (paymentMethod.value === 'alipay') return 'alipay';
|
||||
if (paymentMethod.value === 'wallet') return 'alipay';
|
||||
return undefined;
|
||||
return paymentMethod.value;
|
||||
};
|
||||
|
||||
const getCreateOrderPackageIds = () => renewalPackageIds.value.length
|
||||
? renewalPackageIds.value
|
||||
: [currentPackage.value.package_id];
|
||||
|
||||
const confirmPay = async () => {
|
||||
if (paySubmitting.value || !currentPackage.value) return;
|
||||
|
||||
@@ -253,7 +296,7 @@
|
||||
try {
|
||||
const orderResult = await orderApi.create(
|
||||
userStore.state.identifier,
|
||||
[currentPackage.value.package_id],
|
||||
getCreateOrderPackageIds(),
|
||||
getCreateOrderPaymentMethod()
|
||||
);
|
||||
|
||||
@@ -348,17 +391,20 @@
|
||||
showModal.value = false;
|
||||
|
||||
if (paymentMethod.value === 'wallet') {
|
||||
uni.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success'
|
||||
});
|
||||
try {
|
||||
const detail = await orderApi.getDetail(orderResult.order.order_id);
|
||||
const status = detail?.payment_status ?? detail?.order?.payment_status;
|
||||
showPaymentToast(status === 2, status === 2 ? '支付成功' : '支付结果确认中');
|
||||
} catch (error) {
|
||||
showPaymentToast(false, '支付结果确认失败,请稍后查看订单');
|
||||
}
|
||||
setTimeout(() => {
|
||||
loadWalletBalance();
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
|
||||
await handlePreparedPayment(payResult);
|
||||
await handlePreparedPayment(payResult, false, orderResult.order.order_id);
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
showModal.value = false;
|
||||
@@ -408,6 +454,21 @@
|
||||
});
|
||||
});
|
||||
|
||||
onLoad((query = {}) => {
|
||||
const ids = String(query.renewal_package_ids || '')
|
||||
.split(',')
|
||||
.map((value) => Number(value))
|
||||
.filter((value) => Number.isInteger(value) && value > 0);
|
||||
renewalPackageIds.value = [...new Set(ids)];
|
||||
try {
|
||||
renewalPackageNames.value = decodeURIComponent(String(query.renewal_package_names || ''))
|
||||
.split('|')
|
||||
.filter(Boolean);
|
||||
} catch (error) {
|
||||
renewalPackageNames.value = [];
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
syncPackagePageState();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user