2
0

feat:套餐办理界面中英适配

This commit is contained in:
zhongzm
2025-01-23 17:25:13 +08:00
parent 9dee7d17eb
commit 34cdce8a87
3 changed files with 79 additions and 38 deletions

View File

@@ -518,16 +518,28 @@ const local: any = {
}, },
}, },
setmeal:{ setmeal:{
changemeallable:'Change package discount|The traffic is unlimited, and you can choose from multiple grades!',
changablelevel:'Selectable gears', changablelevel:'Selectable gears',
highlyrecommended:'HOT',
mealmin:'min',
mealvip:'VIP*1',
mealdetail:'Course details', mealdetail:'Course details',
Limitedtimeoffer:'Limited time offer', packagename:'Package name',
GeneralPurposeTraffic:'General Purpose Traffic', client:'Client',
GeneralPurposeTraffic:'Traffic',
Expirationdate:'Expiration date',
rate:'Rate',
unlimit:'Unlimited',
uplimit:'Up rate',
downlimit:'Down rate',
useful:' validity',
device:'device',
upto:'Up to ',
canbe:' device can be online simultaneously',
hour:'Hour',
day:'Day',
month:'Month',
year:'Year',
unknow:'Unknow',
Effectivemethod:'Effective method', Effectivemethod:'Effective method',
Applynow:'Apply now', Applynow:'Apply now',
noPackages:'No packages'
}, },
carddata:{ carddata:{
email:'Email', email:'Email',

View File

@@ -520,16 +520,28 @@ const local:any = {
} }
}, },
setmeal:{ setmeal:{
changemeallable:'换套餐优惠|流量畅用,多个档次任你选!',
changablelevel:'可选档位', changablelevel:'可选档位',
highlyrecommended:'强烈推荐',
mealmin:'分钟',
mealvip:'会员',
mealdetail:'套餐详情', mealdetail:'套餐详情',
Limitedtimeoffer:'限时优惠', packagename:'套餐名称',
client:'设备数量',
GeneralPurposeTraffic:'通用流量', GeneralPurposeTraffic:'通用流量',
Expirationdate:'有效期限',
rate:'套餐速率',
unlimit:'无限制',
uplimit:'上行速率',
downlimit:'下行速率',
useful:'内有效',
device:'台设备',
upto:'最多',
canbe:'台设备允许同时在线',
hour:'小时',
day:'天',
month:'月',
year:'年',
unknow:'未知',
Effectivemethod:'生效方式', Effectivemethod:'生效方式',
Applynow:'立即办理', Applynow:'立即办理',
noPackages:'暂无套餐'
}, },
carddata:{ carddata:{
email:'邮箱地址', email:'邮箱地址',

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { ref, onMounted } from 'vue'; import { ref, onMounted, computed } from 'vue';
import { fetchPackageList, submitOrder } from '@/service/api/auth'; import { fetchPackageList, submitOrder } from '@/service/api/auth';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import OrderConfirmModal from '@/components/order-confirm/orderConfirmModal.vue'; import OrderConfirmModal from '@/components/order-confirm/orderConfirmModal.vue';
@@ -49,15 +49,15 @@ const PERIOD_TYPE = {
// 添加有效期单位映射 // 添加有效期单位映射
const PERIOD_UNIT = { const PERIOD_UNIT = {
0: '小时', 0: t('page.setmeal.hour'),
1: '天', 1: t('page.setmeal.day'),
2: '月', 2: t('page.setmeal.month'),
3: '年' 3: t('page.setmeal.year')
} as const; } as const;
// 格式化有效期显示 // 格式化有效期显示
const formatValidityPeriod = (num: number, type: number): string => { const formatValidityPeriod = (num: number, type: number): string => {
const unit = PERIOD_UNIT[type as keyof typeof PERIOD_UNIT] || '未知'; const unit = PERIOD_UNIT[type as keyof typeof PERIOD_UNIT] || t('page.setmeal.unknow');
return `${num}${unit}`; return `${num}${unit}`;
}; };
@@ -95,10 +95,10 @@ const formatTraffic = (bytes: number): string => {
// 添加速率格式化函数 // 添加速率格式化函数
const formatSpeed = (speed: number): string => { const formatSpeed = (speed: number): string => {
if (speed >= 1000000) { if (speed >= 1048576) {
return `${(speed / 1000000).toFixed(1)}Gbps`; return `${(speed / 1048576).toFixed(1)}Gbps`;
} else if (speed >= 1000) { } else if (speed >= 1024) {
return `${(speed / 1000).toFixed(1)}Mbps`; return `${(speed / 1024).toFixed(1)}Mbps`;
} }
return `${speed}Kbps`; return `${speed}Kbps`;
}; };
@@ -142,7 +142,12 @@ const currentOrderInfo = ref({
// 添加 appStore 实例 // 添加 appStore 实例
const appStore = useAppStore(); const appStore = useAppStore();
// 添加加载状态和数据状态的响应式引用
const isLoading = ref(false);
const hasPackages = computed(() => packageOptions.value.length > 0);
const fetchPackages = async () => { const fetchPackages = async () => {
isLoading.value = true;
try { try {
const response = await fetchPackageList(); const response = await fetchPackageList();
if (response.data && Array.isArray(response.data)) { if (response.data && Array.isArray(response.data)) {
@@ -154,7 +159,7 @@ const fetchPackages = async () => {
clientNumEnable: pkg.clientNumEnable, clientNumEnable: pkg.clientNumEnable,
traffic: Number(pkg.traffic), traffic: Number(pkg.traffic),
trafficEnable: pkg.trafficEnable, trafficEnable: pkg.trafficEnable,
trafficDisplay: pkg.trafficEnable ? formatTraffic(Number(pkg.traffic)) : '无限制', trafficDisplay: pkg.trafficEnable ? formatTraffic(Number(pkg.traffic)) : t('page.setmeal.unlimit'),
durationEnable: Boolean(pkg.periodNum && pkg.periodType !== undefined), durationEnable: Boolean(pkg.periodNum && pkg.periodType !== undefined),
isRecommended: pkg.isRecommended || false, isRecommended: pkg.isRecommended || false,
promotion: pkg.promotion || '', promotion: pkg.promotion || '',
@@ -162,7 +167,7 @@ const fetchPackages = async () => {
periodType: Number(pkg.periodType), periodType: Number(pkg.periodType),
validityPeriod: pkg.periodNum && pkg.periodType !== undefined validityPeriod: pkg.periodNum && pkg.periodType !== undefined
? formatValidityPeriod(Number(pkg.periodNum), Number(pkg.periodType)) ? formatValidityPeriod(Number(pkg.periodNum), Number(pkg.periodType))
: '无限制', : t('page.setmeal.unlimit'),
rateLimitEnable: pkg.rateLimitEnable, rateLimitEnable: pkg.rateLimitEnable,
rateLimits: { rateLimits: {
upLimitEnable: pkg.rateLimits?.upLimitEnable || false, upLimitEnable: pkg.rateLimits?.upLimitEnable || false,
@@ -178,6 +183,9 @@ const fetchPackages = async () => {
} }
} catch (error) { } catch (error) {
console.error('Failed to fetch packages:', error); console.error('Failed to fetch packages:', error);
message.error(t('page.setmeal.fetchFailed'));
} finally {
isLoading.value = false;
} }
}; };
@@ -251,7 +259,6 @@ onMounted(async () => {
<div class="price"> <div class="price">
<span class="currency">¥</span> <span class="currency">¥</span>
<span class="amount">{{ selectedPackage.price }}</span> <span class="amount">{{ selectedPackage.price }}</span>
<span class="period">/</span>
</div> </div>
<div class="subtitle">{{ selectedPackage.packageName }}</div> <div class="subtitle">{{ selectedPackage.packageName }}</div>
</div> </div>
@@ -277,9 +284,9 @@ onMounted(async () => {
</div> </div>
<div class="package-name">{{ option.packageName }}</div> <div class="package-name">{{ option.packageName }}</div>
<div class="price">¥{{ option.price }}</div> <div class="price">¥{{ option.price }}</div>
<div class="traffic">{{ option.trafficEnable ? option.trafficDisplay : '无限制' }}</div> <div class="traffic">{{ option.trafficEnable ? option.trafficDisplay : t('page.setmeal.unlimit') }}</div>
<div class="device-count"> <div class="device-count">
{{ option.clientNumEnable ? `${option.clientNum}台设备` : '无限制' }} {{ option.clientNumEnable ? `${option.clientNum} ${t('page.setmeal.device')}` : t('page.setmeal.unlimit') }}
</div> </div>
</div> </div>
</div> </div>
@@ -290,39 +297,39 @@ onMounted(async () => {
<h3 class="section-title">{{ t('page.setmeal.mealdetail') }}</h3> <h3 class="section-title">{{ t('page.setmeal.mealdetail') }}</h3>
<div class="details-list"> <div class="details-list">
<div class="detail-item"> <div class="detail-item">
<div class="label">套餐名称</div> <div class="label">{{ t('page.setmeal.packagename') }}</div>
<div class="value">{{ selectedPackage.packageName }}</div> <div class="value">{{ selectedPackage.packageName }}</div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="label">{{ t('page.setmeal.GeneralPurposeTraffic') }}</div> <div class="label">{{ t('page.setmeal.GeneralPurposeTraffic') }}</div>
<div class="value"> <div class="value">
{{ selectedPackage.trafficEnable ? selectedPackage.trafficDisplay : '无限制' }} {{ selectedPackage.trafficEnable ? selectedPackage.trafficDisplay : t('page.setmeal.unlimit') }}
</div> </div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="label">设备数量</div> <div class="label">{{ t('page.setmeal.client') }}</div>
<div class="value"> <div class="value">
{{ selectedPackage.clientNumEnable ? `最多${selectedPackage.clientNum}台设备同时在线` : '无限制' }} {{ selectedPackage.clientNumEnable ? `${t('page.setmeal.upto')} ${selectedPackage.clientNum} ${t('page.setmeal.canbe')}` : t('page.setmeal.unlimit') }}
</div> </div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="label">有效期限</div> <div class="label">{{ t('page.setmeal.Expirationdate') }}</div>
<div class="value"> <div class="value">
{{ selectedPackage.durationEnable ? selectedPackage.validityPeriod+'内有效' : '无限制' }} {{ selectedPackage.durationEnable ? selectedPackage.validityPeriod+t('page.setmeal.useful') : t('page.setmeal.unlimit') }}
</div> </div>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<div class="label">速率限制</div> <div class="label">{{ t('page.setmeal.rate') }}</div>
<div class="value"> <div class="value">
<template v-if="!selectedPackage.rateLimitEnable"> <template v-if="!selectedPackage.rateLimitEnable">
不限速 {{ t('page.setmeal.unlimit') }}
</template> </template>
<template v-else> <template v-else>
<div> <div>
上行{{ selectedPackage.rateLimits.upLimitEnable ? formatSpeed(selectedPackage.rateLimits.upLimit) : '-' }} {{ t('page.setmeal.uplimit') }}{{ selectedPackage.rateLimits.upLimitEnable ? formatSpeed(selectedPackage.rateLimits.upLimit) : '-' }}
</div> </div>
<div> <div>
下行{{ selectedPackage.rateLimits.downLimitEnable ? formatSpeed(selectedPackage.rateLimits.downLimit) : '-' }} {{ t('page.setmeal.downlimit') }}{{ selectedPackage.rateLimits.downLimitEnable ? formatSpeed(selectedPackage.rateLimits.downLimit) : '-' }}
</div> </div>
</template> </template>
</div> </div>
@@ -331,9 +338,12 @@ onMounted(async () => {
<button <button
class="btn-primary" class="btn-primary"
@click="handleSubmitOrder" @click="handleSubmitOrder"
:disabled="!selectedPackage.id" :disabled="isLoading || !hasPackages"
> >
{{ t('page.setmeal.Applynow') }} {{ isLoading ? t('page.common.loading') :
!hasPackages ? t('page.setmeal.noPackages') :
t('page.setmeal.Applynow')
}}
</button> </button>
</div> </div>
</div> </div>
@@ -491,6 +501,13 @@ onMounted(async () => {
font-size: 16px; font-size: 16px;
width: 90%; width: 90%;
max-width: 400px; max-width: 400px;
transition: all 0.3s;
}
.btn-primary:disabled {
background: #ccc;
cursor: not-allowed;
opacity: 0.7;
} }
.package-name { .package-name {