2
0

feat:计费规则界面接通

This commit is contained in:
zhongzm
2025-01-07 17:39:07 +08:00
parent 6dee934e9a
commit fd49c64c76
3 changed files with 368 additions and 2 deletions

View File

@@ -163,4 +163,38 @@ export function fetchBillList(params: Api.Auth.BillParams) {
params
});
}
/** 获取AP设备列表 */
export function fetchApDeviceList(params: Api.Device.ApDeviceParams) {
return request<Api.Device.ApDeviceResponse>({
url: '/system/device/list',
method: 'get',
params
});
}
/** 获取终端设备列表 */
export function fetchTerminalList(params: Api.Device.TerminalDeviceParams) {
return request<Api.Device.TerminalDeviceResponse>({
url: '/system/client/list',
method: 'get',
params
});
}
/** 获取计费规则列表 */
export function fetchBillRuleList() {
return request<Api.Billing.BillRuleResponse>({
url: '/system/billRule/list',
method: 'get'
});
}
/** 更新计费规则 */
export function updateBillRule(data: Api.Billing.BillRuleUpdate) {
return request<any>({
url: '/system/billRule',
method: 'put',
data
});
}

80
src/typings/api.d.ts vendored
View File

@@ -182,7 +182,7 @@ declare namespace Api {
packageName: string;
periodNum: number;
periodType: number;
price: number;
price: string;
trafficEnable: boolean;
traffic: number;
rateLimitEnable: boolean;
@@ -202,7 +202,7 @@ declare namespace Api {
packageName: string;
periodNum: number;
periodType: number;
price: number;
price: string;
trafficEnable: boolean;
traffic: number;
rateLimitEnable: boolean;
@@ -535,6 +535,82 @@ declare namespace Api {
type DictSearchParams = Partial<Pick<Dict, 'dictName' | 'dictType' | 'status'> & CommonSearchParams>;
type DictList = Common.PaginatingQueryRecord<Dict>;
}
namespace Device {
interface ApDevice {
id: number;
deviceName: string;
deviceIp: string;
deviceMac: string;
deviceModel: string;
delFlag: boolean;
createBy: string | null;
createTime: string;
updateBy: string | null;
updateTime: string | null;
userId: number | null;
}
interface ApDeviceResponse {
code: number;
msg: string;
data: {
rows: ApDevice[];
total: number;
};
}
interface ApDeviceParams {
pageNum: number;
pageSize: number;
deviceName?: string;
deviceIp?: string;
deviceMac?: string;
}
interface TerminalDevice {
id: number;
clientName: string;
clientDeviceType: string;
clientMac: string;
createBy: string | null;
createTime: string;
updateBy: string | null;
updateTime: string | null;
}
type TerminalDeviceResponse = App.Service.Response<TerminalDevice[]>;
interface TerminalDeviceParams {
pageNum: number;
pageSize: number;
clientName?: string;
clientDeviceType?: string;
clientMac?: string;
}
}
namespace Billing {
interface BillRule {
id: number;
traffic: number;
price: number;
unit: number;
enable: boolean;
createBy: string | null;
createTime: string;
updateBy: string | null;
updateTime: string | null;
}
type BillRuleResponse = App.Service.Response<BillRule[]>;
interface BillRuleUpdate {
traffic: number;
price: number;
unit: number;
enable: boolean;
}
}
}

View File

@@ -0,0 +1,256 @@
<template>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<ACard
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" @click="handleEdit(record)">编辑</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="流量(MB)" name="traffic">
<AInputNumber
v-model:value="currentRule.traffic"
:min="1"
style="width: 100%"
placeholder="请输入流量大小"
/>
</AFormItem>
<AFormItem label="价格" name="price">
<AInputNumber
v-model:value="currentRule.price"
:min="0"
:precision="2"
style="width: 100%"
placeholder="请输入价格"
/>
</AFormItem>
<AFormItem label="单位" name="unit">
<ASelect
v-model:value="currentRule.unit"
style="width: 100%"
placeholder="请选择单位"
>
<ASelect.Option
v-for="option in unitOptions"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</ASelect.Option>
</ASelect>
</AFormItem>
<AFormItem label="状态" name="enable">
<ASwitch v-model:checked="currentRule.enable" />
</AFormItem>
</AForm>
<template #footer>
<ASpace>
<AButton @click="closeDrawer">取消</AButton>
<AButton type="primary" :loading="submitLoading" @click="handleSubmit">确定</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';
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('编辑规则');
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: '流量(MB)',
dataIndex: 'traffic',
key: 'traffic',
align: 'center',
width: 150
},
{
title: '价格',
dataIndex: 'price',
key: 'price',
align: 'center',
width: 150
},
{
title: '单位',
dataIndex: 'unit',
key: 'unit',
align: 'center',
width: 150,
customRender: ({ text }) => getUnitText(text)
},
{
title: '状态',
dataIndex: 'enable',
key: 'enable',
align: 'center',
width: 100,
customRender: ({ text: enable }) => (enable ? '启用' : '未启用')
},
{
title: '操作',
key: 'action',
align: 'center',
width: 100,
fixed: 'right'
}
];
const rules = {
traffic: [{ required: true, message: '请输入流量大小' }],
price: [{ required: true, message: '请输入价格' }],
unit: [{ required: true, message: '请输入单位' }]
};
// 获取列表数据
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) {
console.error('获取计费规则失败:', error);
message.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('更新成功');
closeDrawer();
getData();
} catch (error) {
console.error('更新失败:', error);
message.error('更新失败');
} finally {
submitLoading.value = false;
}
};
onMounted(() => {
getData();
});
</script>
<style scoped>
:deep(.ant-form-item) {
margin-bottom: 24px;
}
</style>