feat:计费规则界面接通
This commit is contained in:
@@ -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
80
src/typings/api.d.ts
vendored
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
256
src/views/billing/rule/index.vue
Normal file
256
src/views/billing/rule/index.vue
Normal 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>
|
||||
Reference in New Issue
Block a user