This commit is contained in:
@@ -7,8 +7,8 @@
|
||||
</view>
|
||||
|
||||
<view class="package-summary">
|
||||
<view class="summary-label">{{ summaryLabel }}</view>
|
||||
<view class="summary-name">{{ summaryName }}</view>
|
||||
<view v-if="summaryPrice" class="summary-price">¥{{ summaryPrice }}</view>
|
||||
</view>
|
||||
|
||||
<view class="payment-methods">
|
||||
@@ -65,6 +65,7 @@
|
||||
const submitting = ref(false);
|
||||
const packageIds = ref([]);
|
||||
const packageNames = ref([]);
|
||||
const renewalPrice = ref(null);
|
||||
const paymentMethod = ref('alipay');
|
||||
const allowedPaymentMethods = ref([]);
|
||||
const assetInfo = ref({});
|
||||
@@ -73,10 +74,12 @@
|
||||
const paymentMethodOptions = computed(() => getPaymentMethodOptions(allowedPaymentMethods.value));
|
||||
const packageNamesText = computed(() => packageNames.value.filter(Boolean).join('、') || '当前套餐');
|
||||
const popupTitle = computed(() => operationMode.value === 'order-payment' ? '立即支付' : '立即续费');
|
||||
const summaryLabel = computed(() => operationMode.value === 'order-payment' ? '支付订单' : '续费套餐');
|
||||
const summaryName = computed(() => operationMode.value === 'order-payment'
|
||||
? packageNamesText.value.replace(/^当前套餐$/, '当前订单')
|
||||
: packageNamesText.value);
|
||||
const summaryPrice = computed(() => renewalPrice.value === null || renewalPrice.value === undefined || renewalPrice.value === ''
|
||||
? ''
|
||||
: formatMoney(renewalPrice.value));
|
||||
const confirmText = computed(() => operationMode.value === 'order-payment' ? '确认支付' : '确认续费');
|
||||
|
||||
const hasPreparedPaymentData = (paymentData) => {
|
||||
@@ -94,9 +97,10 @@
|
||||
paymentMethod.value = getDefaultPaymentMethod(allowedPaymentMethods.value);
|
||||
};
|
||||
|
||||
const open = async (ids, names = []) => {
|
||||
const open = async (ids, names = [], price = null) => {
|
||||
operationMode.value = 'renewal';
|
||||
orderPaymentId.value = null;
|
||||
renewalPrice.value = price;
|
||||
const validIds = [...new Set((Array.isArray(ids) ? ids : [ids])
|
||||
.map((value) => Number(value))
|
||||
.filter((value) => Number.isInteger(value) && value > 0))];
|
||||
@@ -149,6 +153,7 @@
|
||||
|
||||
operationMode.value = 'order-payment';
|
||||
orderPaymentId.value = orderId;
|
||||
renewalPrice.value = null;
|
||||
packageIds.value = [];
|
||||
packageNames.value = Array.isArray(names) ? names.filter(Boolean) : [];
|
||||
try {
|
||||
@@ -397,25 +402,27 @@
|
||||
}
|
||||
|
||||
.package-summary {
|
||||
padding: 40rpx 30rpx 30rpx;
|
||||
background: linear-gradient(135deg, rgba(85, 171, 92, 0.05) 0%, rgba(85, 171, 92, 0.02) 100%);
|
||||
border-bottom: 1rpx solid var(--border-light);
|
||||
padding: 32rpx 30rpx 24rpx;
|
||||
background: transparent;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.summary-name {
|
||||
margin: 20rpx 0 0;
|
||||
margin: 0;
|
||||
color: var(--text-primary);
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.summary-price {
|
||||
margin-top: 14rpx;
|
||||
color: var(--primary);
|
||||
font-size: 48rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.payment-methods {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
<view class="card carrier-card" v-for="item in list" :key="item.iccid">
|
||||
<view class="carrier-main">
|
||||
<view v-if="item.isDevice" class="slot-logo">
|
||||
<image class="slot-visual" :src="getSlotIcon(item.slot_position)" mode="aspectFit"></image>
|
||||
<view class="logo-stack">
|
||||
<image class="carrier-logo" :src="getCarrier(item.carrier_type).logo" mode="aspectFit"></image>
|
||||
<image v-if="item.isDevice" class="slot-badge" :src="getSlotIcon(item.slot_position)" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="carrier-details">
|
||||
<view class="carrier-name">{{ getCarrier(item.carrier_type).name }}</view>
|
||||
@@ -48,6 +49,10 @@
|
||||
import slot1Icon from '@/static/卡槽1.png';
|
||||
import slot2Icon from '@/static/卡槽2.png';
|
||||
import slot3Icon from '@/static/卡槽3.png';
|
||||
import cmccLogo from '@/static/中国移动.png';
|
||||
import cuccLogo from '@/static/中国联通.png';
|
||||
import ctccLogo from '@/static/中国电信.png';
|
||||
import cbnLogo from '@/static/中国广电.png';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -58,10 +63,10 @@
|
||||
let currentCard = ref(null);
|
||||
|
||||
const carrierMap = {
|
||||
CMCC: '中国移动',
|
||||
CUCC: '中国联通',
|
||||
CTCC: '中国电信',
|
||||
CBN: '中国广电'
|
||||
CMCC: { name: '中国移动', logo: cmccLogo },
|
||||
CUCC: { name: '中国联通', logo: cuccLogo },
|
||||
CTCC: { name: '中国电信', logo: ctccLogo },
|
||||
CBN: { name: '中国广电', logo: cbnLogo }
|
||||
};
|
||||
|
||||
const slotIconMap = {
|
||||
@@ -71,7 +76,7 @@
|
||||
};
|
||||
|
||||
const getCarrier = (carrierType) => {
|
||||
return { name: carrierMap[carrierType] || '-' };
|
||||
return carrierMap[carrierType] || { name: '-', logo: '' };
|
||||
};
|
||||
|
||||
const getSlotIcon = (slotPosition) => slotIconMap[Number(slotPosition)] || slotIconMap[1];
|
||||
@@ -173,20 +178,28 @@
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.slot-logo {
|
||||
.logo-stack {
|
||||
position: relative;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
flex-shrink: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.slot-visual {
|
||||
.carrier-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.slot-badge {
|
||||
position: absolute;
|
||||
right: -6rpx;
|
||||
bottom: -6rpx;
|
||||
z-index: 2;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
|
||||
.carrier-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
status: 1,
|
||||
packageName: '-',
|
||||
currentPackageId: 0,
|
||||
renewalPrice: null,
|
||||
expireDate: '-',
|
||||
isExpiring: false,
|
||||
expiryDays: null,
|
||||
@@ -263,6 +264,7 @@
|
||||
deviceInfo.bound_phone = data.bound_phone || '';
|
||||
deviceInfo.packageName = data.current_package || '-';
|
||||
deviceInfo.currentPackageId = Number(data.current_package_id || 0);
|
||||
deviceInfo.renewalPrice = data.renewal_price ?? null;
|
||||
deviceInfo.expireDate = formatDate(data.estimated_final_expires_at);
|
||||
deviceInfo.isExpiring = data.is_expiring === true;
|
||||
deviceInfo.expiryDays = data.days_until_final_expiry ?? null;
|
||||
@@ -364,7 +366,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
renewalPopupRef.value?.open([packageId], [packageName]);
|
||||
renewalPopupRef.value?.open([packageId], [packageName], deviceInfo.renewalPrice);
|
||||
};
|
||||
|
||||
const modifyWifi = () => {
|
||||
|
||||
@@ -181,15 +181,8 @@
|
||||
</view>
|
||||
|
||||
<view class="package-summary">
|
||||
<view class="summary-label">充值订单</view>
|
||||
<view class="summary-name">{{ selectedRechargeOrder?.recharge_order_no || selectedRechargeOrder?.recharge_no || '充值订单' }}</view>
|
||||
<view class="summary-name">{{ selectedRechargeOrder?.recharge_order_no || selectedRechargeOrder?.recharge_no || '-' }}</view>
|
||||
<view class="summary-price">¥{{ formatMoney(selectedRechargeOrder?.amount) }}</view>
|
||||
<view class="summary-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">充值金额</text>
|
||||
<text class="detail-value">¥{{ formatMoney(selectedRechargeOrder?.amount) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="payment-methods">
|
||||
@@ -1204,17 +1197,11 @@
|
||||
.recharge-order-payment-popup {
|
||||
.package-summary {
|
||||
padding: 40rpx 30rpx 30rpx;
|
||||
background: linear-gradient(135deg, rgba(85, 171, 92, 0.05) 0%, rgba(85, 171, 92, 0.02) 100%);
|
||||
border-bottom: 1rpx solid var(--border-light);
|
||||
text-align: center;
|
||||
|
||||
.summary-label {
|
||||
font-size: 22rpx;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
background: transparent;
|
||||
|
||||
.summary-name {
|
||||
margin: 20rpx 0 0;
|
||||
margin: 0 0 20rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
@@ -1222,38 +1209,12 @@
|
||||
}
|
||||
|
||||
.summary-price {
|
||||
margin: 20rpx 0 24rpx;
|
||||
margin: 0;
|
||||
font-size: 56rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: -1rpx;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.summary-details {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid rgba(85, 171, 92, 0.1);
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.detail-label {
|
||||
font-size: 22rpx;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payment-methods {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
@change="onFilterSwiperChange"
|
||||
>
|
||||
<swiper-item v-for="(item, index) in filterOptions" :key="item.value ?? 'all'" class="order-swiper-item">
|
||||
<scroll-view v-if="filterIndex === index" scroll-y class="scroll-container" :style="scrollViewStyle" @scrolltolower="loadMore">
|
||||
<scroll-view v-if="filterIndex === index" scroll-y class="scroll-container" @scrolltolower="loadMore">
|
||||
<view v-if="orderList.length === 0 && !loading" class="empty-state">
|
||||
<image class="empty-icon" src="/static/order.png" mode="aspectFit" alt="我的订单"></image>
|
||||
<view class="empty-title">暂无订单</view>
|
||||
@@ -84,7 +84,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, nextTick, onMounted } from 'vue';
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import { orderApi } from '@/api/index.js';
|
||||
import RenewalPaymentPopup from '@/components/RenewalPaymentPopup.vue';
|
||||
@@ -102,7 +102,6 @@
|
||||
const noMore = ref(false);
|
||||
const page = ref(1);
|
||||
const renewalPopupRef = ref(null);
|
||||
const scrollViewHeight = ref(0);
|
||||
const pageSize = 10;
|
||||
const filterIndex = ref(0);
|
||||
const filterOptions = [
|
||||
@@ -113,29 +112,10 @@
|
||||
{ label: '已退款', value: 4 }
|
||||
];
|
||||
|
||||
const scrollViewStyle = computed(() => scrollViewHeight.value > 0
|
||||
? { height: `${scrollViewHeight.value}px`, flex: 'none' }
|
||||
: {});
|
||||
const filterIndicatorStyle = computed(() => ({
|
||||
left: `calc(${filterIndex.value * 20}% + 8rpx)`
|
||||
}));
|
||||
|
||||
const updateScrollViewHeight = () => {
|
||||
const windowInfo = typeof uni.getWindowInfo === 'function'
|
||||
? uni.getWindowInfo()
|
||||
: uni.getSystemInfoSync();
|
||||
const windowHeight = Number(windowInfo?.windowHeight || 0);
|
||||
if (!windowHeight) return;
|
||||
|
||||
uni.createSelectorQuery()
|
||||
.select('.filter-tabs')
|
||||
.boundingClientRect((rect) => {
|
||||
if (!rect) return;
|
||||
scrollViewHeight.value = Math.max(Math.floor(windowHeight - rect.bottom), 1);
|
||||
})
|
||||
.exec();
|
||||
};
|
||||
|
||||
const getStatusClass = (status) => {
|
||||
const classMap = {
|
||||
1: 'tag-warning',
|
||||
@@ -276,7 +256,6 @@
|
||||
|
||||
onMounted(() => {
|
||||
loadOrderList();
|
||||
nextTick(updateScrollViewHeight);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -516,6 +495,9 @@
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
padding-top: 0;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
@@ -602,8 +584,9 @@
|
||||
}
|
||||
|
||||
.order-swiper {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
flex: 1 1 0;
|
||||
height: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.order-swiper-item {
|
||||
@@ -611,8 +594,8 @@
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
flex: 1 1 0;
|
||||
height: auto;
|
||||
flex: none;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="package-tabs">
|
||||
<view class="package-tab-indicator" :style="{ left: packageTypeIndex === 0 ? '8rpx' : '50%' }"></view>
|
||||
<view class="tab-section">
|
||||
<view class="tab-header">
|
||||
<view class="tab-indicator" :style="{ left: packageTypeIndex === 0 ? '8rpx' : '50%' }"></view>
|
||||
<view
|
||||
v-for="tab in packageTypeTabs"
|
||||
:key="tab.value"
|
||||
class="package-tab"
|
||||
class="tab-item"
|
||||
:class="{ active: activePackageType === tab.value }"
|
||||
@tap="switchPackageType(tab.value)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<swiper
|
||||
class="package-swiper"
|
||||
class="tab-swiper package-swiper"
|
||||
:current="packageTypeIndex"
|
||||
:circular="false"
|
||||
:acceleration="true"
|
||||
@@ -53,6 +54,7 @@
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<up-popup :show="showModal" mode="center" @close="showModal = false">
|
||||
<view class="payment-popup">
|
||||
@@ -717,6 +719,59 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-section {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 8rpx;
|
||||
}
|
||||
|
||||
.tab-indicator {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
width: calc(50% - 16rpx);
|
||||
height: calc(100% - 16rpx);
|
||||
background: var(--primary);
|
||||
border-radius: 12rpx;
|
||||
transition: left 0.3s ease;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20rpx 0;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: var(--text-tertiary);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
transition: color 0.3s;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-swiper {
|
||||
margin-top: 20rpx;
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.container .package-tabs {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
<view class="card carrier-card" v-for="item in mchList" :key="item.iccid">
|
||||
<view class="carrier-main">
|
||||
<view class="slot-logo">
|
||||
<image class="slot-visual" :src="getSlotIcon(item.slot_position)" mode="aspectFit"></image>
|
||||
<view class="logo-stack">
|
||||
<image class="carrier-logo" :src="getCarrier(item.carrier_type).logo" mode="aspectFit"></image>
|
||||
<image class="slot-badge" :src="getSlotIcon(item.slot_position)" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="carrier-details">
|
||||
<view class="carrier-heading">
|
||||
@@ -61,6 +62,10 @@
|
||||
import slot1Icon from '@/static/卡槽1.png';
|
||||
import slot2Icon from '@/static/卡槽2.png';
|
||||
import slot3Icon from '@/static/卡槽3.png';
|
||||
import cmccLogo from '@/static/中国移动.png';
|
||||
import cuccLogo from '@/static/中国联通.png';
|
||||
import ctccLogo from '@/static/中国电信.png';
|
||||
import cbnLogo from '@/static/中国广电.png';
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -71,10 +76,10 @@
|
||||
let currentModalIccid = ref('');
|
||||
|
||||
const carrierMap = {
|
||||
CMCC: '中国移动',
|
||||
CUCC: '中国联通',
|
||||
CTCC: '中国电信',
|
||||
CBN: '中国广电'
|
||||
CMCC: { name: '中国移动', logo: cmccLogo },
|
||||
CUCC: { name: '中国联通', logo: cuccLogo },
|
||||
CTCC: { name: '中国电信', logo: ctccLogo },
|
||||
CBN: { name: '中国广电', logo: cbnLogo }
|
||||
};
|
||||
|
||||
const slotIconMap = {
|
||||
@@ -84,7 +89,7 @@
|
||||
};
|
||||
|
||||
const getCarrier = (carrierType) => {
|
||||
return { name: carrierMap[carrierType] || '-' };
|
||||
return carrierMap[carrierType] || { name: '-', logo: '' };
|
||||
};
|
||||
|
||||
const getSlotIcon = (slotPosition) => slotIconMap[Number(slotPosition)] || slotIconMap[1];
|
||||
@@ -221,20 +226,28 @@
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.slot-logo {
|
||||
.logo-stack {
|
||||
position: relative;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
flex-shrink: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.slot-visual {
|
||||
.carrier-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.slot-badge {
|
||||
position: absolute;
|
||||
right: -6rpx;
|
||||
bottom: -6rpx;
|
||||
z-index: 2;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
|
||||
.carrier-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
Reference in New Issue
Block a user