2
0

fix:套餐管理界面中英适配

This commit is contained in:
zhongzm
2025-02-08 19:24:23 +08:00
parent 66b705ab17
commit dd390a8a0f
3 changed files with 174 additions and 80 deletions

View File

@@ -857,6 +857,55 @@ const local: any = {
operate:'Operate', operate:'Operate',
changed:'Revise', changed:'Revise',
delete:'Delete', delete:'Delete',
},
package: {
title: 'Package Management',
add: 'Add Package',
packagename: 'Package Name',
plepackagename: 'Please enter package name',
period: 'Billing Cycle',
pleperiod: 'Please enter cycle number',
pleunit:'Please enter the billing period unit',
price: 'Price',
pleprice: 'Please enter price',
traffic: 'Traffic Limit',
pletraffic: 'Please enter traffic',
limit: 'Bandwidth Limit',
plelimit: 'Please select bandwidth limit configuration',
duration: 'Duration Limit',
pleduration: 'Please enter duration',
client: 'Device Limit',
pleclient: 'Please enter number of devices',
unit: 'Units',
usepackage: 'Package Status',
day: 'Day',
month: 'Month',
year: 'Year',
unlimit: 'Unlimited',
up: 'Upload',
down: 'Download',
status:'Status',
use: 'Enable',
unuse: 'Disable',
operate: 'Operation',
edit: 'Edit',
delete: 'Delete',
hour: 'Hour',
second:'s',
rejtraffic: 'Please enter a traffic value greater than 0',
rejduration: 'Please enter a duration value greater than 0',
rejclient: 'Please enter a device number greater than 0',
idnull: 'Edit ID cannot be empty',
editsuc: 'Modified successfully',
addsuc: 'Added successfully',
editerr: 'Modification failed',
adderr: 'Add failed',
confirmdelete: 'Confirm Delete',
deletecontent: 'Are you sure to delete this package?',
confirm: 'Confirm',
close: 'Cancel',
deletesuc: 'Deleted successfully',
deleteerr: 'Delete failed',
} }
}, },
form: { form: {

View File

@@ -857,7 +857,56 @@ const local:any = {
operate:'操作', operate:'操作',
changed:'修改', changed:'修改',
delete:'删除', delete:'删除',
} },
package:{
title:'套餐管理',
add:'新增套餐',
packagename:'套餐名称',
plepackagename:'请输入套餐名称',
period:'计费周期',
pleperiod:'请输入周期数',
pleunit:'请输入计费周期单位',
price:'价格',
pleprice:'请输入价格',
traffic:'流量限制',
pletraffic:'请输入流量',
limit:'带宽限制',
plelimit:'请选择带宽限速配置',
duration:'时长限制',
pleduration:'请输入时长',
client:'设备数限制',
pleclient:'请输入设备数',
unit:'台',
usepackage:'套餐启用',
day:'天',
month:'月',
year:'年',
unlimit:'无限制',
up:'上行',
down:'下行',
status:'套餐状态',
use:'启用',
unuse:'禁用',
operate:'操作',
edit:'编辑',
delete:'删除',
hour:'小时',
second:'秒',
rejtraffic:'请输入大于0的流量值',
rejduration:'请输入大于0的时长值',
rejclient:'请输入大于0的设备数',
idnull:'编辑ID不能为空',
editsuc:'修改成功',
addsuc:'添加成功',
editerr:'修改失败',
adderr:'添加失败',
confirmdelete:'确认删除',
deletecontent:'是否确认删除该套餐?',
confirm:'确认',
close:'取消',
deletesuc:'删除成功',
deleteerr:'删除失败',
},
}, },
form: { form: {
required: '不能为空', required: '不能为空',

View File

@@ -3,24 +3,18 @@
<SimpleScrollbar> <SimpleScrollbar>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto"> <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<ACard <ACard
title="套餐管理" :title="t('page.package.title')"
:bordered="false" :bordered="false"
:body-style="{ flex: 1, overflow: 'hidden' }" :body-style="{ flex: 1, overflow: 'hidden' }"
class="flex-col-stretch sm:flex-1-hidden card-wrapper" class="flex-col-stretch sm:flex-1-hidden card-wrapper"
> >
<template #extra> <template #extra>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<AButton type="primary" @click="handleAdd">
<template #icon>
<PlusOutlined />
</template>
新增
</AButton>
<TableHeaderOperation <TableHeaderOperation
v-model:columns="columnChecks" v-model:columns="columnChecks"
:loading="loading" :loading="loading"
:show-delete="false" :show-delete="false"
:notShowAdd="true" @add="handleAdd"
@refresh="getData" @refresh="getData"
/> />
</div> </div>
@@ -43,7 +37,7 @@
<!-- 新增套餐弹窗 --> <!-- 新增套餐弹窗 -->
<AModal <AModal
v-model:open="showModal" v-model:open="showModal"
title="新增套餐" :title="t('page.package.add')"
@ok="handleOk" @ok="handleOk"
@cancel="handleCancel" @cancel="handleCancel"
width="600px" width="600px"
@@ -55,16 +49,16 @@
:label-col="{ span: 6 }" :label-col="{ span: 6 }"
:wrapper-col="{ span: 16 }" :wrapper-col="{ span: 16 }"
> >
<AFormItem label="套餐名称" name="packageName"> <AFormItem :label="t('page.package.packagename')" name="packageName">
<AInput v-model:value="formState.packageName" placeholder="请输入套餐名称" /> <AInput v-model:value="formState.packageName" :placeholder="t('page.package.plepackagename')" />
</AFormItem> </AFormItem>
<AFormItem label="计费周期" required> <AFormItem :label="t('page.package.period')" required>
<div class="flex gap-2"> <div class="flex gap-2">
<AFormItem name="periodNum" class="mb-0 flex-1"> <AFormItem name="periodNum" class="mb-0 flex-1">
<AInputNumber <AInputNumber
v-model:value="formState.periodNum" v-model:value="formState.periodNum"
placeholder="请输入周期数" :placeholder="t('page.package.pleperiod')"
:min="1" :min="1"
style="width: 100%" style="width: 100%"
/> />
@@ -75,10 +69,10 @@
</div> </div>
</AFormItem> </AFormItem>
<AFormItem label="价格" name="price" :rules="[{ required: true, message: '请输入价格' }]"> <AFormItem :label="t('page.package.price')" name="price" :rules="[{ required: true, message: t('page.package.pleprice') }]">
<AInputNumber <AInputNumber
v-model:value="formState.price" v-model:value="formState.price"
placeholder="请输入价格" :placeholder="t('page.package.pleprice')"
:min="0" :min="0"
:precision="2" :precision="2"
style="width: 100%" style="width: 100%"
@@ -87,13 +81,13 @@
/> />
</AFormItem> </AFormItem>
<AFormItem label="流量限制" name="traffic"> <AFormItem :label="t('page.package.traffic')" name="traffic">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<ASwitch v-model:checked="formState.trafficEnable" /> <ASwitch v-model:checked="formState.trafficEnable" />
<div v-if="formState.trafficEnable" class="flex gap-2 flex-1"> <div v-if="formState.trafficEnable" class="flex gap-2 flex-1">
<AInputNumber <AInputNumber
v-model:value="formState.traffic" v-model:value="formState.traffic"
placeholder="请输入流量" :placeholder="t('page.package.pletraffic')"
:min="1" :min="1"
:precision="0" :precision="0"
style="width: 100%" style="width: 100%"
@@ -107,13 +101,13 @@
</div> </div>
</AFormItem> </AFormItem>
<AFormItem label="带宽限制" name="rateLimitId"> <AFormItem :label="t('page.package.limit')" name="rateLimitId">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<ASwitch v-model:checked="formState.rateLimitEnable" /> <ASwitch v-model:checked="formState.rateLimitEnable" />
<ASelect <ASelect
v-if="formState.rateLimitEnable" v-if="formState.rateLimitEnable"
v-model:value="formState.rateLimitId" v-model:value="formState.rateLimitId"
placeholder="请选择带宽限速配置" :placeholder="t('page.package.plelimit')"
:options="rateLimitOptions" :options="rateLimitOptions"
:loading="!rateLimitOptions.length" :loading="!rateLimitOptions.length"
style="width: 100%" style="width: 100%"
@@ -121,13 +115,13 @@
</div> </div>
</AFormItem> </AFormItem>
<AFormItem label="时长限制" name="duration"> <AFormItem :label="t('page.package.duration')" name="duration">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<ASwitch v-model:checked="formState.durationEnable" /> <ASwitch v-model:checked="formState.durationEnable" />
<div v-if="formState.durationEnable" class="flex gap-2 flex-1"> <div v-if="formState.durationEnable" class="flex gap-2 flex-1">
<AInputNumber <AInputNumber
v-model:value="formState.duration" v-model:value="formState.duration"
placeholder="请输入时长" :placeholder="t('page.package.pleduration')"
:min="1" :min="1"
style="width: 100%" style="width: 100%"
/> />
@@ -140,21 +134,21 @@
</div> </div>
</AFormItem> </AFormItem>
<AFormItem label="设备数限制" name="clientNum"> <AFormItem :label="t('page.package.client')" name="clientNum">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<ASwitch v-model:checked="formState.clientNumEnable" /> <ASwitch v-model:checked="formState.clientNumEnable" />
<AInputNumber <AInputNumber
v-if="formState.clientNumEnable" v-if="formState.clientNumEnable"
v-model:value="formState.clientNum" v-model:value="formState.clientNum"
placeholder="请输入设备数" :placeholder="t('page.package.pleclient')"
:min="1" :min="1"
addon-after="" :addon-after="t('page.package.unit')"
style="width: 100%" style="width: 100%"
/> />
</div> </div>
</AFormItem> </AFormItem>
<AFormItem label="套餐启用"> <AFormItem :label="t('page.package.usepackage')">
<ASwitch v-model:checked="formState.packageEnable" /> <ASwitch v-model:checked="formState.packageEnable" />
</AFormItem> </AFormItem>
</AForm> </AForm>
@@ -182,6 +176,8 @@ import {
type StorageUnit, type StorageUnit,
type TimeUnit type TimeUnit
} from '@/utils/units'; } from '@/utils/units';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const wrapperEl = shallowRef<HTMLElement | null>(null); const wrapperEl = shallowRef<HTMLElement | null>(null);
const { height: wrapperElHeight } = useElementSize(wrapperEl); const { height: wrapperElHeight } = useElementSize(wrapperEl);
@@ -194,9 +190,9 @@ const scrollConfig = computed(() => {
}); });
const periodMap: Record<number, string> = { const periodMap: Record<number, string> = {
1: '天', 1: t('page.package.day'),
2: '月', 2: t('page.package.month'),
3: '年' 3: t('page.package.year')
}; };
const { columns, columnChecks, data, loading, getData, mobilePagination } = useTable({ const { columns, columnChecks, data, loading, getData, mobilePagination } = useTable({
@@ -224,13 +220,13 @@ const { columns, columnChecks, data, loading, getData, mobilePagination } = useT
{ {
key: 'packageName', key: 'packageName',
dataIndex: 'packageName', dataIndex: 'packageName',
title: '套餐名称', title: t('page.package.packagename'),
align: 'center' align: 'center'
}, },
{ {
key: 'periodNum', key: 'periodNum',
dataIndex: 'periodNum', dataIndex: 'periodNum',
title: '计费周期', title: t('page.package.period'),
align: 'center', align: 'center',
customRender: ({ record }) => { customRender: ({ record }) => {
const { periodNum, periodType } = record; const { periodNum, periodType } = record;
@@ -241,17 +237,17 @@ const { columns, columnChecks, data, loading, getData, mobilePagination } = useT
{ {
key: 'price', key: 'price',
dataIndex: 'price', dataIndex: 'price',
title: '价格', title: t('page.package.price'),
align: 'center', align: 'center',
customRender: ({ text }) => `${Number(text).toFixed(2)}` customRender: ({ text }) => `${Number(text).toFixed(2)}`
}, },
{ {
key: 'traffic', key: 'traffic',
dataIndex: 'traffic', dataIndex: 'traffic',
title: '流量限制', title: t('page.package.traffic'),
align: 'center', align: 'center',
customRender: ({ text, record }) => { customRender: ({ text, record }) => {
if (!record.trafficEnable) return '无限制'; if (!record.trafficEnable) return t('page.package.unlimit');
const { value, unit } = formatStorage(text); const { value, unit } = formatStorage(text);
return `${value} ${unit}`; return `${value} ${unit}`;
} }
@@ -259,28 +255,28 @@ const { columns, columnChecks, data, loading, getData, mobilePagination } = useT
{ {
key: 'rateLimitId', key: 'rateLimitId',
dataIndex: 'rateLimitId', dataIndex: 'rateLimitId',
title: '带宽限制', title: t('page.package.limit'),
align: 'center', align: 'center',
customRender: ({ record }) => { customRender: ({ record }) => {
if (!record.rateLimitEnable) return '无限制'; if (!record.rateLimitEnable) return t('page.package.unlimit');
const rateLimit = rateLimitData.value.find(item => item.id === record.rateLimitId); const rateLimit = rateLimitData.value.find(item => item.id === record.rateLimitId);
if (!rateLimit) return '-'; if (!rateLimit) return '-';
const upLimitText = rateLimit.upLimitEnable const upLimitText = rateLimit.upLimitEnable
? `上行:${formatBandwidth(rateLimit.upLimit).value} ${formatBandwidth(rateLimit.upLimit).unit}` ? `${t('page.package.up')}:${formatBandwidth(rateLimit.upLimit).value} ${formatBandwidth(rateLimit.upLimit).unit}`
: '上行:无限制'; : `${t('page.package.up')}:${t('page.package.unlimit')}`;
const downLimitText = rateLimit.downLimitEnable const downLimitText = rateLimit.downLimitEnable
? `下行:${formatBandwidth(rateLimit.downLimit).value} ${formatBandwidth(rateLimit.downLimit).unit}` ? `${t('page.package.down')}:${formatBandwidth(rateLimit.downLimit).value} ${formatBandwidth(rateLimit.downLimit).unit}`
: '下行:无限制'; : `${t('page.package.down')}:${t('page.package.unlimit')}`;
return `${rateLimit.rateLimitName} (${upLimitText}/${downLimitText})`; return `${rateLimit.rateLimitName} (${upLimitText}/${downLimitText})`;
} }
}, },
{ {
key: 'duration', key: 'duration',
dataIndex: 'duration', dataIndex: 'duration',
title: '时长限制', title: t('page.package.duration'),
align: 'center', align: 'center',
customRender: ({ text, record }) => { customRender: ({ text, record }) => {
if (!record.durationEnable) return '无限制'; if (!record.durationEnable) return t('page.package.unlimit');
const { value, unit } = formatTime(text); const { value, unit } = formatTime(text);
return `${value} ${unit}`; return `${value} ${unit}`;
} }
@@ -288,36 +284,36 @@ const { columns, columnChecks, data, loading, getData, mobilePagination } = useT
{ {
key: 'clientNum', key: 'clientNum',
dataIndex: 'clientNum', dataIndex: 'clientNum',
title: '设备数限制', title: t('page.package.client'),
align: 'center', align: 'center',
customRender: ({ text, record }) => { customRender: ({ text, record }) => {
if (!record.clientNumEnable) return '无限制'; if (!record.clientNumEnable) return t('page.package.unlimit');
return text; return text;
} }
}, },
{ {
key: 'packageEnable', key: 'packageEnable',
dataIndex: 'packageEnable', dataIndex: 'packageEnable',
title: '套餐状态', title: t('page.package.status'),
align: 'center', align: 'center',
customRender: ({ text }) => ( customRender: ({ text }) => (
<ATag color={text ? 'success' : 'error'}> <ATag color={text ? 'success' : 'error'}>
{text ? '启用' : '禁用'} {text ? t('page.package.use') : t('page.package.unuse')}
</ATag> </ATag>
) )
}, },
{ {
key: 'operate', key: 'operate',
title: '操作', title: t('page.package.operate'),
align: 'center', align: 'center',
width: 200, width: 200,
customRender: ({ record }) => ( customRender: ({ record }) => (
<div class="flex justify-center gap-2"> <div class="flex justify-center gap-2">
<AButton type="link" onClick={() => handleEdit(record)}> <AButton type="link" onClick={() => handleEdit(record)}>
编辑 {t('page.package.edit')}
</AButton> </AButton>
<AButton type="link" danger onClick={() => handleDelete(record)}> <AButton type="link" danger onClick={() => handleDelete(record)}>
删除 {t('page.package.delete')}
</AButton> </AButton>
</div> </div>
) )
@@ -359,22 +355,22 @@ const formState = ref<PackageForm>({
rateLimitId: undefined, rateLimitId: undefined,
durationEnable: false, durationEnable: false,
duration: 0, duration: 0,
durationUnit: '小时', durationUnit: t('page.package.hour'),
clientNumEnable: false, clientNumEnable: false,
clientNum: 0, clientNum: 0,
packageEnable: true packageEnable: true
}); });
const rules: Record<string, Rule[]> = { const rules: Record<string, Rule[]> = {
packageName: [{ required: true, message: '请输入套餐名称', trigger: 'blur' }], packageName: [{ required: true, message: t('page.package.plepackagename'), trigger: 'blur' }],
periodNum: [{ required: true, message: '请输入计费周期数', trigger: 'blur' }], periodNum: [{ required: true, message: t('page.package.pleperiod'), trigger: 'blur' }],
periodType: [{ required: true, message: '请选择计费周期单位', trigger: 'change' }], periodType: [{ required: true, message: t('page.package.pleunit'), trigger: 'change' }],
price: [{ required: true, message: '请输入价格', trigger: 'blur' }], price: [{ required: true, message: t('page.package.pleprice'), trigger: 'blur' }],
traffic: [ traffic: [
{ {
validator: (_rule: Rule, value: number) => { validator: (_rule: Rule, value: number) => {
if (!formState.value.trafficEnable) return Promise.resolve(); if (!formState.value.trafficEnable) return Promise.resolve();
if (!value || value <= 0) return Promise.reject('请输入大于0的流量值'); if (!value || value <= 0) return Promise.reject(t('page.package.rejtraffic'));
return Promise.resolve(); return Promise.resolve();
}, },
trigger: 'blur' trigger: 'blur'
@@ -384,7 +380,7 @@ const rules: Record<string, Rule[]> = {
{ {
validator: (_rule: Rule, value: number) => { validator: (_rule: Rule, value: number) => {
if (!formState.value.rateLimitEnable) return Promise.resolve(); if (!formState.value.rateLimitEnable) return Promise.resolve();
if (!value) return Promise.reject('请选择带宽限速配置'); if (!value) return Promise.reject(t('page.package.plelimit'));
return Promise.resolve(); return Promise.resolve();
}, },
trigger: 'change' trigger: 'change'
@@ -394,7 +390,7 @@ const rules: Record<string, Rule[]> = {
{ {
validator: (_rule: Rule, value: number) => { validator: (_rule: Rule, value: number) => {
if (!formState.value.durationEnable) return Promise.resolve(); if (!formState.value.durationEnable) return Promise.resolve();
if (!value || value <= 0) return Promise.reject('请输入大于0的时长值'); if (!value || value <= 0) return Promise.reject(t('page.package.rejduration'));
return Promise.resolve(); return Promise.resolve();
}, },
trigger: 'blur' trigger: 'blur'
@@ -404,7 +400,7 @@ const rules: Record<string, Rule[]> = {
{ {
validator: (_rule: Rule, value: number) => { validator: (_rule: Rule, value: number) => {
if (!formState.value.clientNumEnable) return Promise.resolve(); if (!formState.value.clientNumEnable) return Promise.resolve();
if (!value || value <= 0) return Promise.reject('请输入大于0的设备数'); if (!value || value <= 0) return Promise.reject(t('page.package.rejclient'));
return Promise.resolve(); return Promise.resolve();
}, },
trigger: 'blur' trigger: 'blur'
@@ -412,12 +408,12 @@ const rules: Record<string, Rule[]> = {
] ]
}; };
const periodOptions = [ const periodOptions =computed(()=> [
{ label: '小时', value: 0 }, { label: t('page.package.hour'), value: 0 },
{ label: '天', value: 1 }, { label: t('page.package.day'), value: 1 },
{ label: '月', value: 2 }, { label: t('page.package.month'), value: 2 },
{ label: '年', value: 3 } { label: t('page.package.year'), value: 3 }
]; ]);
const rateLimitOptions = ref<{ label: string; value: number }[]>([]); const rateLimitOptions = ref<{ label: string; value: number }[]>([]);
@@ -429,11 +425,11 @@ const getRateLimitData = async () => {
rateLimitData.value = response.data || []; rateLimitData.value = response.data || [];
rateLimitOptions.value = rateLimitData.value.map(item => { rateLimitOptions.value = rateLimitData.value.map(item => {
const upLimitText = item.upLimitEnable const upLimitText = item.upLimitEnable
? `上行:${formatBandwidth(item.upLimit).value} ${formatBandwidth(item.upLimit).unit}` ? `${t('page.package.up')}:${formatBandwidth(item.upLimit).value} ${formatBandwidth(item.upLimit).unit}`
: '上行:无限制'; : `${t('page.package.up')}:${t('page.package.unlimit')}`;
const downLimitText = item.downLimitEnable const downLimitText = item.downLimitEnable
? `下行:${formatBandwidth(item.downLimit).value} ${formatBandwidth(item.downLimit).unit}` ? `${t('page.package.down')}:${formatBandwidth(item.downLimit).value} ${formatBandwidth(item.downLimit).unit}`
: '下行:无限制'; : `${t('page.package.down')}:${t('page.package.unlimit')}`;
return { return {
label: `${item.rateLimitName} (${upLimitText}/${downLimitText})`, label: `${item.rateLimitName} (${upLimitText}/${downLimitText})`,
@@ -441,7 +437,7 @@ const getRateLimitData = async () => {
}; };
}); });
} catch (error) { } catch (error) {
console.error('获取带宽限速配置失败:', error); console.error('error:', error);
} }
}; };
@@ -472,7 +468,7 @@ const handleCancel = () => {
rateLimitId: undefined, rateLimitId: undefined,
durationEnable: false, durationEnable: false,
duration: 0, duration: 0,
durationUnit: '小时', durationUnit:`${t('page.package.hour')}`,
clientNumEnable: false, clientNumEnable: false,
clientNum: 0, clientNum: 0,
packageEnable: true packageEnable: true
@@ -508,7 +504,7 @@ const handleOk = async () => {
if (isEdit.value) { if (isEdit.value) {
if (!editId.value) { if (!editId.value) {
message.error('编辑ID不能为空'); message.error(t('page.package.isnull'));
return; return;
} }
// 编辑模式 // 编辑模式
@@ -518,7 +514,7 @@ const handleOk = async () => {
traffic, traffic,
duration duration
}); });
message.success('修改成功'); message.success(t('page.package.editsuc'));
} else { } else {
// 新增模式 // 新增模式
await addPackage({ await addPackage({
@@ -526,12 +522,12 @@ const handleOk = async () => {
traffic, traffic,
duration duration
}); });
message.success('添加成功'); message.success(t('page.package.addsuc'));
} }
handleCancel(); handleCancel();
getData(); getData();
} catch (error) { } catch (error) {
message.error(isEdit.value ? '修改失败' : '添加失败'); message.error(isEdit.value ? t('page.package.editerr') : t('page.package.adderr'));
} }
}; };
@@ -565,18 +561,18 @@ const handleEdit = async (record: Api.Auth.Package) => {
const handleDelete = (record: Api.Auth.Package) => { const handleDelete = (record: Api.Auth.Package) => {
Modal.confirm({ Modal.confirm({
title: '确认删除', title: t('page.package.confirmdelete'),
content: '是否确认删除该套餐?', content: t('page.package.deletecontent'),
okText: '确认', okText: t('page.package.confirm'),
cancelText: '取消', cancelText: t('page.package.close'),
okType: 'danger', okType: 'danger',
async onOk() { async onOk() {
try { try {
await deletePackage(record.id); await deletePackage(record.id);
message.success('删除成功'); message.success(t('page.package.deletesuc'));
getData(); getData();
} catch (error) { } catch (error) {
message.error('删除失败'); message.error(t('page.package.deleteerr'));
} }
} }
}); });