feat(web): 健康模块通用组件 8 个

- StatusTag: 通用状态标签(预约/随访/咨询/患者状态)
- PatientSelect: 患者远程搜索选择器
- DoctorSelect: 医护远程搜索选择器
- VitalSignsChart: ECharts 趋势图(可切换指标)
- CalendarView: 日历视图(排班展示)
- ChatBubble: 聊天气泡(角色区分左右布局)
- ImagePreview: 图片预览(Ant Design Image.PreviewGroup)
- ExportButton: 导出按钮(blob 下载)
This commit is contained in:
iven
2026-04-25 00:40:11 +08:00
parent 778ae79d84
commit 6296ce22d2
8 changed files with 381 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import { Button, message } from 'antd';
import { DownloadOutlined } from '@ant-design/icons';
interface Props {
fetchUrl: string;
params?: Record<string, string>;
filename?: string;
label?: string;
}
export function ExportButton({
fetchUrl,
params,
filename,
label = '导出',
}: Props) {
const handleExport = async () => {
try {
const query = params
? '?' + new URLSearchParams(params).toString()
: '';
const token = localStorage.getItem('access_token');
const resp = await fetch(`/api/v1${fetchUrl}${query}`, {
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
if (!resp.ok) throw new Error('导出失败');
const blob = await resp.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename ?? `export_${Date.now()}.csv`;
a.click();
URL.revokeObjectURL(url);
message.success('导出成功');
} catch {
message.error('导出失败');
}
};
return (
<Button icon={<DownloadOutlined />} onClick={handleExport}>
{label}
</Button>
);
}