封装AXIOS,添加接口

- 今日体检统计信息
- 营收数据统计
This commit is contained in:
xianyi
2025-12-10 14:56:07 +08:00
parent 5f81667c60
commit 9c8b679689
8 changed files with 640 additions and 108 deletions

View File

@@ -1,104 +1,170 @@
import { B1_ROWS, B1_SUMMARY, HOME_STATS, NORTH3_ROWS, NORTH3_SUMMARY, REVENUE_STATS } from '../../data/mockData';
import { useEffect, useMemo, useState } from 'react';
import { getRevenueStatistics, getTodayExamStatistics } from '../../api';
import { B1_ROWS, B1_SUMMARY, NORTH3_ROWS, NORTH3_SUMMARY } from '../../data/mockData';
import { Card, CardContent, CardHeader, InfoCard } from '../ui';
export const HomeSection = () => (
<div className='space-y-6'>
<Card>
<CardHeader></CardHeader>
<CardContent>
<div className='grid grid-cols-5 gap-3'>
{HOME_STATS.map(([label, value]) => (
<InfoCard key={label} label={label} value={value} />
))}
</div>
</CardContent>
</Card>
type HomeStatItem = { label: string; value: number };
type RevenueStatItem = { label: string; value: string | number };
<Card>
<CardHeader></CardHeader>
<CardContent>
<div className='grid grid-cols-3 gap-3'>
{REVENUE_STATS.map(([label, value]) => (
<InfoCard key={label} label={label} value={value} />
))}
</div>
</CardContent>
</Card>
export const HomeSection = () => {
const [homeStats, setHomeStats] = useState<HomeStatItem[]>([
{ label: '今日预约', value: 0 },
{ label: '签到人数', value: 0 },
{ label: '在检人数', value: 0 },
{ label: '打印导检单', value: 0 },
{ label: '已完成人数', value: 0 },
]);
const [revenueStats, setRevenueStats] = useState<RevenueStatItem[]>([
{ label: '体检收入', value: '¥ 0' },
{ label: '加项收入', value: '¥ 0' },
{ label: '整体收入', value: '¥ 0' },
{ label: '目标收入', value: '¥ 0' },
{ label: '完成百分比', value: '0%' },
{ label: '缺口', value: '¥ 0' },
]);
<div className='grid grid-cols-2 gap-4'>
const currencyFormatter = useMemo(() => new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}), []);
useEffect(() => {
getTodayExamStatistics({})
.then((res) => {
const d = res.Data;
setHomeStats([
{ label: '今日预约', value: Number(d?.today_appointment_count ?? 0) },
{ label: '签到人数', value: Number(d?.today_signin_count ?? 0) },
{ label: '在检人数', value: Number(d?.today_in_exam_count ?? 0) },
{ label: '打印导检单', value: Number(d?.today_print_guide_count ?? 0) },
{ label: '已完成人数', value: Number(d?.today_completed_count ?? 0) },
]);
})
.catch((err) => {
console.error('获取今日体检统计失败', err);
});
}, []);
useEffect(() => {
getRevenueStatistics({})
.then((res) => {
const d = res.Data;
const fmt = (n?: number | null) => currencyFormatter.format(Number(n ?? 0));
setRevenueStats([
{ label: '体检收入', value: fmt(d?.physical_exam_income) },
{ label: '加项收入', value: fmt(d?.add_item_income) },
{ label: '整体收入', value: fmt(d?.total_income) },
{ label: '目标收入', value: fmt(d?.target_income) },
{ label: '完成百分比', value: d?.completion_percentage ?? '0%' },
{ label: '缺口', value: fmt(d?.gap_amount) },
]);
})
.catch((err) => {
console.error('获取营收数据统计失败', err);
});
}, [currencyFormatter]);
return (
<div className='space-y-6'>
<Card>
<CardHeader>B1 </CardHeader>
<CardHeader></CardHeader>
<CardContent>
<div className='grid grid-cols-3 gap-3 mb-3'>
<InfoCard label='当前客户总数' value={B1_SUMMARY.totalClients} />
<InfoCard label='待检人数' value={B1_SUMMARY.waiting} />
<InfoCard label='在检人数' value={B1_SUMMARY.inExam} />
<div className='grid grid-cols-5 gap-3'>
{homeStats.map(({ label, value }) => (
<InfoCard key={label} label={label} value={value} />
))}
</div>
<table className='w-full text-xs'>
<thead>
<tr className='text-gray-500 border-b'>
<th className='py-2 text-left'></th>
<th className='py-2 text-left'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
</tr>
</thead>
<tbody>
{B1_ROWS.map(([dept, doctor, done, inExam, waiting, avg]) => {
const parts = done * 3;
const totalTime = done * avg;
return (
<tr key={dept} className='border-b last:border-b-0'>
<td className='py-2'>{dept}</td>
<td className='py-2'>{doctor}</td>
<td className='py-2 text-right'>{done}</td>
<td className='py-2 text-right'>{parts}</td>
<td className='py-2 text-right'>{totalTime}</td>
<td className='py-2 text-right'>{avg}</td>
<td className='py-2 text-right'>{inExam}</td>
<td className='py-2 text-right'>{waiting}</td>
</tr>
);
})}
</tbody>
</table>
</CardContent>
</Card>
<Card>
<CardHeader>3</CardHeader>
<CardHeader></CardHeader>
<CardContent>
<div className='grid grid-cols-3 gap-3 mb-3'>
<InfoCard label='今日家医数' value={NORTH3_SUMMARY.totalDoctor} />
<InfoCard label='分配客户数' value={NORTH3_SUMMARY.totalAssigned} />
<InfoCard label='面诊数' value={NORTH3_SUMMARY.consult} />
<div className='grid grid-cols-3 gap-3'>
{revenueStats.map(({ label, value }) => (
<InfoCard key={label} label={label} value={value} />
))}
</div>
<table className='w-full text-xs'>
<thead>
<tr className='text-gray-500 border-b'>
<th className='py-2 text-left'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
</tr>
</thead>
<tbody>
{NORTH3_ROWS.map(([name, total, consult]) => (
<tr key={name} className='border-b last:border-b-0'>
<td className='py-2'>{name}</td>
<td className='py-2 text-right'>{total}</td>
<td className='py-2 text-right'>{consult}</td>
</CardContent>
</Card>
<div className='grid grid-cols-2 gap-4'>
<Card>
<CardHeader>B1 </CardHeader>
<CardContent>
<div className='grid grid-cols-3 gap-3 mb-3'>
<InfoCard label='当前客户总数' value={B1_SUMMARY.totalClients} />
<InfoCard label='待检人数' value={B1_SUMMARY.waiting} />
<InfoCard label='在检人数' value={B1_SUMMARY.inExam} />
</div>
<table className='w-full text-xs'>
<thead>
<tr className='text-gray-500 border-b'>
<th className='py-2 text-left'></th>
<th className='py-2 text-left'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
</tr>
))}
</tbody>
</table>
</CardContent>
</Card>
</thead>
<tbody>
{B1_ROWS.map(([dept, doctor, done, inExam, waiting, avg]) => {
const parts = done * 3;
const totalTime = done * avg;
return (
<tr key={dept} className='border-b last:border-b-0'>
<td className='py-2'>{dept}</td>
<td className='py-2'>{doctor}</td>
<td className='py-2 text-right'>{done}</td>
<td className='py-2 text-right'>{parts}</td>
<td className='py-2 text-right'>{totalTime}</td>
<td className='py-2 text-right'>{avg}</td>
<td className='py-2 text-right'>{inExam}</td>
<td className='py-2 text-right'>{waiting}</td>
</tr>
);
})}
</tbody>
</table>
</CardContent>
</Card>
<Card>
<CardHeader>3</CardHeader>
<CardContent>
<div className='grid grid-cols-3 gap-3 mb-3'>
<InfoCard label='今日家医数' value={NORTH3_SUMMARY.totalDoctor} />
<InfoCard label='分配客户数' value={NORTH3_SUMMARY.totalAssigned} />
<InfoCard label='面诊数' value={NORTH3_SUMMARY.consult} />
</div>
<table className='w-full text-xs'>
<thead>
<tr className='text-gray-500 border-b'>
<th className='py-2 text-left'></th>
<th className='py-2 text-right'></th>
<th className='py-2 text-right'></th>
</tr>
</thead>
<tbody>
{NORTH3_ROWS.map(([name, total, consult]) => (
<tr key={name} className='border-b last:border-b-0'>
<td className='py-2'>{name}</td>
<td className='py-2 text-right'>{total}</td>
<td className='py-2 text-right'>{consult}</td>
</tr>
))}
</tbody>
</table>
</CardContent>
</Card>
</div>
</div>
</div>
);
);
};