import { history, useAccess } from '@umijs/max';
|
import { Button, Cascader, DatePicker, Form, Input, Pagination, Select, Space, Table, Upload, message } from 'antd';
|
import type { ColumnsType } from 'antd/es/table';
|
import dayjs, { type Dayjs } from 'dayjs';
|
import React, { useEffect, useState } from 'react';
|
import { downloadBlob } from '../../trade/points-exchange/shared';
|
import { clinicRegionOptions } from './regionOptions';
|
import { downloadClinicImportTemplate, exportClinics, getClinicPage, importClinicAgentBindings } from './service';
|
import './style.less';
|
|
type SearchValues = {
|
regionCode?: string[];
|
name?: string;
|
phone?: string;
|
status?: number;
|
createdRange?: Dayjs[];
|
};
|
|
type ClinicItem = {
|
id: number;
|
name: string;
|
phone?: string;
|
regionName?: string;
|
status: number;
|
userCount: number;
|
createdAt: string;
|
businessLicenseUrl?: string;
|
};
|
|
const getSelectedRegionCode = (regionCode?: string[]) =>
|
regionCode && regionCode.length ? regionCode[regionCode.length - 1] : undefined;
|
|
const buildSearchParams = (values: SearchValues) => ({
|
regionCode: getSelectedRegionCode(values.regionCode),
|
name: values.name?.trim() || undefined,
|
phone: values.phone?.trim() || undefined,
|
status: values.status,
|
createdFrom: values.createdRange?.[0]
|
? dayjs(values.createdRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
|
: undefined,
|
createdTo: values.createdRange?.[1]
|
? dayjs(values.createdRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
: undefined,
|
});
|
|
const ClinicListPage: React.FC = () => {
|
const access = useAccess();
|
const [searchForm] = Form.useForm<SearchValues>();
|
const [list, setList] = useState<ClinicItem[]>([]);
|
const [loading, setLoading] = useState(false);
|
const [templateDownloading, setTemplateDownloading] = useState(false);
|
const [importing, setImporting] = useState(false);
|
const [pagination, setPagination] = useState({ page: 1, pageSize: 10, total: 0 });
|
|
const canView = access['member:clinic:view'];
|
|
const loadList = async (page = pagination.page, pageSize = pagination.pageSize) => {
|
setLoading(true);
|
try {
|
const res = await getClinicPage({
|
page,
|
pageSize,
|
...buildSearchParams(searchForm.getFieldsValue()),
|
});
|
setList(res.data?.list || []);
|
setPagination({
|
page: Number(res.data?.page || page),
|
pageSize: Number(res.data?.pageSize || pageSize),
|
total: Number(res.data?.total || 0),
|
});
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
useEffect(() => {
|
if (!canView) {
|
history.replace('/Welcome');
|
return;
|
}
|
loadList(1, 10);
|
}, [canView]);
|
|
const handleExport = async () => {
|
const blob = await exportClinics(buildSearchParams(searchForm.getFieldsValue()));
|
downloadBlob(blob, '诊所列表.xlsx');
|
};
|
|
const handleTemplateDownload = async () => {
|
setTemplateDownloading(true);
|
try {
|
const blob = await downloadClinicImportTemplate();
|
downloadBlob(blob, '诊所省区代理导入模板.xlsx');
|
} finally {
|
setTemplateDownloading(false);
|
}
|
};
|
|
const handleBindingImport = async (file: File) => {
|
setImporting(true);
|
try {
|
await importClinicAgentBindings(file);
|
message.success('绑定关系更新成功');
|
await loadList(pagination.page, pagination.pageSize);
|
} catch (error) {
|
message.error((error as Error)?.message || '更新绑定关系失败');
|
} finally {
|
setImporting(false);
|
}
|
};
|
const columns: ColumnsType<ClinicItem> = [
|
{
|
title: '序号',
|
width: 72,
|
render: (_, __, index) => (pagination.page - 1) * pagination.pageSize + index + 1,
|
},
|
{
|
title: '诊所名称',
|
dataIndex: 'name',
|
width: 200,
|
render: (value) => value || '-',
|
},
|
{
|
title: '电话',
|
dataIndex: 'phone',
|
width: 150,
|
render: (value) => value || '-',
|
},
|
{
|
title: '诊所区域',
|
dataIndex: 'regionName',
|
width: 180,
|
render: (value) => value || '-',
|
},
|
{
|
title: '绑定用户数',
|
dataIndex: 'userCount',
|
width: 120,
|
render: (value) => <span className="member-clinic-table__count">{value ?? 0}</span>,
|
},
|
{
|
title: '状态',
|
dataIndex: 'status',
|
width: 150,
|
render: (value) => (value === 1 ? '启用' : value === 2 ? '注销' : '禁用'),
|
},
|
{
|
title: '注册时间',
|
dataIndex: 'createdAt',
|
width: 180,
|
},
|
{
|
title: '操作',
|
width: 150,
|
render: (_, record) => (
|
<Space size={16} className="member-clinic-table__actions">
|
<button
|
type="button"
|
className="member-clinic-table__action"
|
onClick={() => history.push(`/member/user/clinic/${record.id}`)}
|
>
|
详情
|
</button>
|
{access["member:clinic:edit"] ? <button type="button" className="member-clinic-table__action" onClick={() => history.push(`/member/user/clinic/${record.id}/edit`)}>编辑</button> : null}
|
</Space>
|
),
|
},
|
];
|
|
return (
|
<div className="member-clinic-page">
|
<div className="member-clinic-page__panel">
|
<div className="member-clinic-page__title">诊所管理</div>
|
<div className="member-clinic-search-card">
|
<Form form={searchForm} layout="horizontal" className="member-clinic-search-form">
|
<Form.Item label="诊所区域" name="regionCode">
|
<Cascader
|
placeholder="全部"
|
allowClear
|
changeOnSelect
|
options={clinicRegionOptions}
|
/>
|
</Form.Item>
|
<Form.Item label="诊所名称" name="name">
|
<Input placeholder="请输入" allowClear />
|
</Form.Item>
|
<Form.Item label="电话" name="phone">
|
<Input placeholder="请输入" allowClear />
|
</Form.Item>
|
<Form.Item label="状态" name="status">
|
<Select
|
placeholder="请选择"
|
allowClear
|
options={[
|
{ label: '启用', value: 1 },
|
{ label: '禁用', value: 0 },
|
]}
|
/>
|
</Form.Item>
|
<Form.Item label="注册时间" name="createdRange">
|
<DatePicker.RangePicker className="member-clinic-search-form__range" />
|
</Form.Item>
|
<div className="member-clinic-search-form__actions">
|
<Button
|
onClick={async () => {
|
searchForm.resetFields();
|
await loadList(1, pagination.pageSize);
|
}}
|
>
|
重置
|
</Button>
|
<Button type="primary" onClick={() => loadList(1, pagination.pageSize)}>
|
查询
|
</Button>
|
</div>
|
</Form>
|
</div>
|
|
<div className="member-clinic-toolbar">
|
<Button onClick={handleExport}>导出</Button>
|
<Upload
|
accept=".xlsx,.xls"
|
showUploadList={false}
|
beforeUpload={(file) => {
|
void handleBindingImport(file);
|
return false;
|
}}
|
>
|
<Button loading={importing}>更新绑定关系</Button>
|
</Upload>
|
<Button loading={templateDownloading} onClick={handleTemplateDownload}>
|
下载模板
|
</Button>
|
</div>
|
|
<div className="member-clinic-table-card">
|
<Table<ClinicItem>
|
rowKey="id"
|
columns={columns}
|
dataSource={list}
|
loading={loading}
|
pagination={false}
|
scroll={{ x: 1200 }}
|
/>
|
<div className="member-clinic-pagination">
|
<Pagination
|
current={pagination.page}
|
pageSize={pagination.pageSize}
|
total={pagination.total}
|
showSizeChanger
|
showQuickJumper
|
showTotal={(total) => `共 ${total} 条`}
|
onChange={(page, pageSize) => loadList(page, pageSize)}
|
/>
|
</div>
|
</div>
|
</div>
|
</div>
|
);
|
};
|
|
export default ClinicListPage;
|