256 lines
6.1 KiB
Vue
256 lines
6.1 KiB
Vue
<template>
|
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
<ACard
|
|
:title="t('page.rule.title')"
|
|
:bordered="false"
|
|
:body-style="{ flex: 1, overflow: 'hidden' }"
|
|
class="flex-col-stretch sm:flex-1-hidden"
|
|
>
|
|
<ATable
|
|
:columns="columns"
|
|
:data-source="data"
|
|
:loading="loading"
|
|
row-key="id"
|
|
size="small"
|
|
:pagination="false"
|
|
>
|
|
<template #bodyCell="{ column, record }">
|
|
<template v-if="column.key === 'action'">
|
|
<ASpace>
|
|
<AButton type="primary" ghost @click="handleEdit(record)">{{ t('page.rule.edit') }}</AButton>
|
|
</ASpace>
|
|
</template>
|
|
</template>
|
|
</ATable>
|
|
</ACard>
|
|
|
|
<!-- 编辑抽屉 -->
|
|
<ADrawer
|
|
v-model:visible="drawerVisible"
|
|
:title="drawerTitle"
|
|
placement="right"
|
|
width="500px"
|
|
@close="closeDrawer"
|
|
>
|
|
<AForm
|
|
v-if="currentRule"
|
|
ref="formRef"
|
|
:model="currentRule"
|
|
:rules="rules"
|
|
layout="vertical"
|
|
>
|
|
<AFormItem :label="t('page.rule.traffic')" name="traffic">
|
|
<AInputNumber
|
|
v-model:value="currentRule.traffic"
|
|
:min="1"
|
|
:precision="0"
|
|
style="width: 100%"
|
|
:placeholder="t('page.rule.pletraffic')"
|
|
/>
|
|
</AFormItem>
|
|
<AFormItem :label="t('page.rule.price')" name="price">
|
|
<AInputNumber
|
|
v-model:value="currentRule.price"
|
|
:min="0"
|
|
:precision="2"
|
|
style="width: 100%"
|
|
:placeholder="t('page.rule.pleprice')"
|
|
/>
|
|
</AFormItem>
|
|
<AFormItem :label="t('page.rule.unit')" name="unit">
|
|
<ASelect
|
|
v-model:value="currentRule.unit"
|
|
style="width: 100%"
|
|
:placeholder="t('page.rule.pleunit')"
|
|
>
|
|
<ASelect.Option
|
|
v-for="option in unitOptions"
|
|
:key="option.value"
|
|
:value="option.value"
|
|
>
|
|
{{ option.label }}
|
|
</ASelect.Option>
|
|
</ASelect>
|
|
</AFormItem>
|
|
<AFormItem :label="t('page.rule.status')" name="enable">
|
|
<ASwitch v-model:checked="currentRule.enable" />
|
|
</AFormItem>
|
|
</AForm>
|
|
|
|
<template #footer>
|
|
<ASpace>
|
|
<AButton @click="closeDrawer">{{ t('page.rule.close') }}</AButton>
|
|
<AButton type="primary" :loading="submitLoading" @click="handleSubmit">{{ t('page.rule.confirm') }}</AButton>
|
|
</ASpace>
|
|
</template>
|
|
</ADrawer>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onMounted, ref } from 'vue';
|
|
import { fetchBillRuleList, updateBillRule } from '@/service/api/auth';
|
|
import {
|
|
Card as ACard,
|
|
Table as ATable,
|
|
Space as ASpace,
|
|
Switch as ASwitch,
|
|
Button as AButton,
|
|
Drawer as ADrawer,
|
|
Form as AForm,
|
|
FormItem as AFormItem,
|
|
InputNumber as AInputNumber,
|
|
message,
|
|
Select as ASelect
|
|
} from 'ant-design-vue';
|
|
import type { FormInstance } from 'ant-design-vue';
|
|
import type { ColumnsType } from 'ant-design-vue/es/table';
|
|
import { useI18n } from 'vue-i18n';
|
|
const { t } = useI18n();
|
|
|
|
interface BillRule {
|
|
id: number;
|
|
traffic: number;
|
|
price: number;
|
|
unit: number;
|
|
enable: boolean;
|
|
createBy: string | null;
|
|
createTime: string;
|
|
updateBy: string | null;
|
|
updateTime: string | null;
|
|
}
|
|
|
|
interface BillRuleUpdate {
|
|
traffic: number;
|
|
price: number;
|
|
unit: number;
|
|
enable: boolean;
|
|
}
|
|
|
|
const loading = ref(false);
|
|
const submitLoading = ref(false);
|
|
const data = ref<BillRule[]>([]);
|
|
const drawerVisible = ref(false);
|
|
const drawerTitle = ref(t('page.rule.modaltitle'));
|
|
const currentRule = ref<BillRuleUpdate | null>(null);
|
|
const formRef = ref<FormInstance>();
|
|
|
|
// 单位选项
|
|
const unitOptions = [
|
|
{ label: 'B', value: 0 },
|
|
{ label: 'KB', value: 1 },
|
|
{ label: 'MB', value: 2 },
|
|
{ label: 'GB', value: 3 },
|
|
{ label: 'TB', value: 4 }
|
|
];
|
|
|
|
// 获取单位显示文本
|
|
const getUnitText = (unit: number) => {
|
|
return unitOptions.find(option => option.value === unit)?.label || '';
|
|
};
|
|
|
|
const columns: ColumnsType = [
|
|
{
|
|
title: t('page.rule.traffic'),
|
|
dataIndex: 'traffic',
|
|
key: 'traffic',
|
|
align: 'center',
|
|
width: 150
|
|
},
|
|
{
|
|
title: t('page.rule.price'),
|
|
dataIndex: 'price',
|
|
key: 'price',
|
|
align: 'center',
|
|
width: 150
|
|
},
|
|
{
|
|
title: t('page.rule.unit'),
|
|
dataIndex: 'unit',
|
|
key: 'unit',
|
|
align: 'center',
|
|
width: 150,
|
|
customRender: ({ text }) => getUnitText(text)
|
|
},
|
|
{
|
|
title: t('page.rule.status'),
|
|
dataIndex: 'enable',
|
|
key: 'enable',
|
|
align: 'center',
|
|
width: 100,
|
|
customRender: ({ text: enable }) => (enable ? t('page.rule.use') : t('page.rule.unuse'))
|
|
},
|
|
{
|
|
title: t('page.rule.action'),
|
|
key: 'action',
|
|
align: 'center',
|
|
width: 100,
|
|
fixed: 'right'
|
|
}
|
|
];
|
|
|
|
const rules = {
|
|
traffic: [{ required: true, message: t('page.rule.pletraffic') }],
|
|
price: [{ required: true, message: t('page.rule.pleprice') }],
|
|
unit: [{ required: true, message: t('page.rule.pleunit') }]
|
|
};
|
|
|
|
// 获取列表数据
|
|
const getData = async () => {
|
|
loading.value = true;
|
|
try {
|
|
const res = await fetchBillRuleList();
|
|
if (res.data && Array.isArray(res.data)) {
|
|
data.value = res.data;
|
|
} else {
|
|
data.value = [];
|
|
}
|
|
} catch (error) {
|
|
data.value = [];
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
// 打开编辑抽屉
|
|
const handleEdit = (record: BillRule) => {
|
|
currentRule.value = { ...record };
|
|
drawerVisible.value = true;
|
|
};
|
|
|
|
// 关闭抽屉
|
|
const closeDrawer = () => {
|
|
drawerVisible.value = false;
|
|
currentRule.value = null;
|
|
formRef.value?.resetFields();
|
|
};
|
|
|
|
// 提交表单
|
|
const handleSubmit = async () => {
|
|
if (!currentRule.value) return;
|
|
|
|
try {
|
|
await formRef.value?.validate();
|
|
submitLoading.value = true;
|
|
|
|
await updateBillRule(currentRule.value);
|
|
message.success(t('page.rule.updatesuc'));
|
|
closeDrawer();
|
|
getData();
|
|
} catch (error) {
|
|
} finally {
|
|
submitLoading.value = false;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
getData();
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
:deep(.ant-form-item) {
|
|
margin-bottom: 24px;
|
|
}
|
|
</style>
|