feat:套餐办理界面中英适配
This commit is contained in:
@@ -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',
|
||||||
|
|||||||
@@ -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:'邮箱地址',
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user