feat:历史账单界面接通
This commit is contained in:
@@ -136,4 +136,13 @@ export function submitOrder(data: Api.Order.SubmitOrderParams) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/** Get bill history records */
|
||||||
|
export function fetchBillHistory(params: Api.Bill.BillQueryParams) {
|
||||||
|
return request<Api.Bill.BillListResponse>({
|
||||||
|
url: '/u/bill/page',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
33
src/typings/api.d.ts
vendored
33
src/typings/api.d.ts
vendored
@@ -629,4 +629,37 @@ declare namespace Api {
|
|||||||
/** Combined order params type */
|
/** Combined order params type */
|
||||||
type SubmitOrderParams = PackageOrderParams | RechargeOrderParams;
|
type SubmitOrderParams = PackageOrderParams | RechargeOrderParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace Bill
|
||||||
|
*
|
||||||
|
* Backend api module: "bill"
|
||||||
|
*/
|
||||||
|
namespace Bill {
|
||||||
|
/** Bill record information */
|
||||||
|
interface BillRecord {
|
||||||
|
id: string;
|
||||||
|
startTime: string | null;
|
||||||
|
endTime: string | null;
|
||||||
|
traffic: string | null;
|
||||||
|
amount: string;
|
||||||
|
status: number;
|
||||||
|
createTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Bill list response */
|
||||||
|
interface BillListResponse {
|
||||||
|
rows: BillRecord[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Bill query parameters */
|
||||||
|
interface BillQueryParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,160 +1,93 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, h } from 'vue'
|
import { ref, h, onMounted, computed } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import type { TableColumnsType } from 'ant-design-vue'
|
import type { TableColumnsType } from 'ant-design-vue'
|
||||||
import { Tag as ATag, Table as ATable } from 'ant-design-vue'
|
import { Tag as ATag, Table as ATable } from 'ant-design-vue'
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { fetchBillHistory } from '@/service/api/auth';
|
||||||
|
import { useWindowSize } from '@vueuse/core';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
router.push('/billing/billservice');
|
router.push('/billing/billservice');
|
||||||
};
|
};
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
interface BillDetail {
|
|
||||||
deviceName: string
|
|
||||||
usage: number
|
|
||||||
unit: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BillRecord {
|
const billData = ref<Api.Bill.BillRecord[]>([]);
|
||||||
id: number
|
const total = ref(0);
|
||||||
date: string
|
|
||||||
amount: number
|
|
||||||
status: 'paid' | 'unpaid'
|
|
||||||
details: BillDetail[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 模拟数据
|
const { width } = useWindowSize();
|
||||||
const billData = ref<BillRecord[]>([
|
const isMobile = computed(() => width.value < 768);
|
||||||
{
|
|
||||||
id: 1,
|
const getBillData = async () => {
|
||||||
date: '2024-03-01',
|
try {
|
||||||
amount: 299,
|
const response = await fetchBillHistory({
|
||||||
status: 'paid',
|
pageNum: 1,
|
||||||
details: [
|
pageSize: 10
|
||||||
{ deviceName: 'Device A', usage: 50, unit: 'GB' },
|
});
|
||||||
{ deviceName: 'Device B', usage: 30, unit: 'GB' }
|
console.log('API Response:', response);
|
||||||
]
|
if (response?.data?.rows) {
|
||||||
},
|
console.log('Rows data:', response.data.rows);
|
||||||
{
|
billData.value = response.data.rows;
|
||||||
id: 2,
|
total.value = response.data.total;
|
||||||
date: '2024-02-01',
|
console.log('billData value:', billData.value);
|
||||||
amount: 199,
|
} else {
|
||||||
status: 'paid',
|
console.log('No data found. Response structure:', JSON.stringify(response, null, 2));
|
||||||
details: [
|
}
|
||||||
{ deviceName: 'Device A', usage: 30, unit: 'GB' },
|
} catch (error) {
|
||||||
{ deviceName: 'Device C', usage: 20, unit: 'GB' }
|
console.error('Failed to fetch bill history:', error);
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
date: '2024-01-01',
|
|
||||||
amount: 399,
|
|
||||||
status: 'paid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device B', usage: 80, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device D', usage: 40, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
date: '2023-12-01',
|
|
||||||
amount: 159,
|
|
||||||
status: 'paid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device A', usage: 25, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device E', usage: 15, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
date: '2023-11-01',
|
|
||||||
amount: 499,
|
|
||||||
status: 'unpaid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device C', usage: 100, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device D', usage: 60, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device E', usage: 40, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
date: '2023-10-01',
|
|
||||||
amount: 259,
|
|
||||||
status: 'paid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device B', usage: 45, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device D', usage: 35, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
date: '2023-09-01',
|
|
||||||
amount: 359,
|
|
||||||
status: 'paid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device A', usage: 60, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device C', usage: 40, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
date: '2023-08-01',
|
|
||||||
amount: 189,
|
|
||||||
status: 'unpaid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device B', usage: 25, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device E', usage: 20, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
date: '2023-07-01',
|
|
||||||
amount: 299,
|
|
||||||
status: 'paid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device A', usage: 45, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device D', usage: 35, unit: 'GB' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
date: '2023-06-01',
|
|
||||||
amount: 459,
|
|
||||||
status: 'paid',
|
|
||||||
details: [
|
|
||||||
{ deviceName: 'Device C', usage: 70, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device E', usage: 50, unit: 'GB' },
|
|
||||||
{ deviceName: 'Device B', usage: 30, unit: 'GB' }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
])
|
};
|
||||||
|
|
||||||
const columns: TableColumnsType = [
|
onMounted(() => {
|
||||||
|
getBillData();
|
||||||
|
});
|
||||||
|
|
||||||
|
const formatDateTime = (dateTimeString: string) => {
|
||||||
|
if (!dateTimeString) return '';
|
||||||
|
const date = new Date(dateTimeString);
|
||||||
|
return date.toLocaleString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = computed<TableColumnsType>(() => [
|
||||||
{
|
{
|
||||||
title: t('page.histories.billdate'),
|
title: t('page.histories.billdate'),
|
||||||
dataIndex: 'date',
|
dataIndex: 'createTime',
|
||||||
key: 'date'
|
key: 'createTime',
|
||||||
|
responsive: ['md'],
|
||||||
|
customRender: ({ text }) => text ? formatDateTime(text) : ''
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('page.histories.amount'),
|
title: t('page.histories.amount'),
|
||||||
dataIndex: 'amount',
|
dataIndex: 'amount',
|
||||||
key: 'amount',
|
key: 'amount',
|
||||||
customRender: ({ text }: { text: number }) => `¥${text}`
|
customRender: ({ text }: { text: string }) => {
|
||||||
|
const formattedAmount = Number(text).toFixed(2);
|
||||||
|
return `¥${formattedAmount}`;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('page.histories.status'),
|
title: t('page.histories.status'),
|
||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
key: 'status',
|
key: 'status',
|
||||||
customRender: ({ text }: { text: 'paid' | 'unpaid' }) => {
|
customRender: ({ text }: { text: number }) => {
|
||||||
return h(ATag, {
|
return h(ATag, {
|
||||||
color: text === 'paid' ? 'success' : 'warning'
|
color: text === 1 ? 'success' : 'warning'
|
||||||
}, {
|
}, {
|
||||||
default: () => text === 'paid' ? t('page.histories.Paid') : t('page.histories.Unpaid')
|
default: () => text === 1 ? t('page.histories.Paid') : t('page.histories.Unpaid')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -168,11 +101,10 @@ const columns: TableColumnsType = [
|
|||||||
<ATable
|
<ATable
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data-source="billData"
|
:data-source="billData"
|
||||||
:row-key="(record: BillRecord) => record.id"
|
:row-key="(record: Api.Bill.BillRecord) => record.id"
|
||||||
:expand-column-width="60"
|
|
||||||
:pagination="{
|
:pagination="{
|
||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
total: billData.length,
|
total: total,
|
||||||
showTotal: (total: number) => `共 ${total} 条`,
|
showTotal: (total: number) => `共 ${total} 条`,
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
@@ -181,8 +113,21 @@ const columns: TableColumnsType = [
|
|||||||
>
|
>
|
||||||
<template #expandedRowRender="{ record }">
|
<template #expandedRowRender="{ record }">
|
||||||
<div class="pl-4">
|
<div class="pl-4">
|
||||||
<div v-for="(detail, index) in record.details" :key="index">
|
<div v-if="isMobile" class="mb-2">
|
||||||
{{ t('page.histories.device') }}: {{ detail.deviceName }} - {{ t('page.histories.Usetraffic') }}: {{ detail.usage }}{{ detail.unit }}
|
<strong>{{ t('page.histories.billdate') }}:</strong>
|
||||||
|
{{ formatDateTime(record.createTime) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="record.traffic">
|
||||||
|
<strong>{{ t('page.histories.traffic') }}:</strong>
|
||||||
|
{{ record.traffic }}
|
||||||
|
</div>
|
||||||
|
<div v-if="record.startTime">
|
||||||
|
<strong>{{ t('page.histories.startTime') }}:</strong>
|
||||||
|
{{ formatDateTime(record.startTime) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="record.endTime">
|
||||||
|
<strong>{{ t('page.histories.endTime') }}:</strong>
|
||||||
|
{{ formatDateTime(record.endTime) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user