doctor-mail/apps/web/src/app/main/letter/write/page.tsx

137 lines
5.4 KiB
TypeScript
Raw Normal View History

2025-01-25 02:27:40 +08:00
import { useState, useCallback, useEffect } from 'react';
2025-01-24 15:05:03 +08:00
import { motion, AnimatePresence } from 'framer-motion';
2025-01-25 02:27:40 +08:00
import { useSearchParams } from 'react-router-dom';
2025-01-25 00:37:59 +08:00
import { SendCard } from './SendCard';
2025-01-25 02:27:40 +08:00
import { Spin, Empty, Input, Alert, Pagination } from 'antd';
2025-01-25 19:51:16 +08:00
import { api, useTerm } from '@nice/client';
2025-01-25 00:37:59 +08:00
import DepartmentSelect from '@web/src/components/models/department/department-select';
import debounce from 'lodash/debounce';
import { SearchOutlined } from '@ant-design/icons';
2025-01-25 02:27:40 +08:00
import WriteHeader from './WriteHeader';
2025-01-22 19:24:52 +08:00
export default function WriteLetterPage() {
2025-01-25 02:27:40 +08:00
const [searchParams] = useSearchParams();
const termId = searchParams.get('termId');
2025-01-22 19:24:52 +08:00
const [searchQuery, setSearchQuery] = useState('');
2025-01-25 00:37:59 +08:00
const [selectedDept, setSelectedDept] = useState<string>();
const [currentPage, setCurrentPage] = useState(1);
const pageSize = 10;
2025-01-25 19:51:16 +08:00
const { getTerm } = useTerm()
2025-01-22 19:24:52 +08:00
2025-01-25 00:37:59 +08:00
const { data, isLoading, error } = api.staff.findManyWithPagination.useQuery({
page: currentPage,
pageSize,
where: {
deptId: selectedDept,
OR: [{
showname: {
contains: searchQuery
}
}, {
username: {
contains: searchQuery
}
}]
}
});
2025-01-25 02:27:40 +08:00
const resetPage = useCallback(() => {
2025-01-25 00:37:59 +08:00
setCurrentPage(1);
2025-01-25 02:27:40 +08:00
}, []);
// Reset page when search or department changes
useEffect(() => {
resetPage();
}, [searchQuery, selectedDept, resetPage]);
2025-01-22 19:24:52 +08:00
return (
2025-01-25 20:48:16 +08:00
<div className="min-h-screen shadow-elegant border-2 border-white rounded-xl bg-gradient-to-b from-slate-100 to-slate-50">
2025-01-25 19:51:16 +08:00
<WriteHeader term={getTerm(termId)} />
2025-01-24 15:05:03 +08:00
<div className="container mx-auto px-4 py-8">
2025-01-25 00:37:59 +08:00
<div className="mb-8 space-y-4">
{/* Search and Filter Section */}
<div className="flex flex-col md:flex-row gap-4 items-center">
<div className="w-full md:w-96">
<Input
prefix={<SearchOutlined className="text-gray-400" />}
placeholder="搜索领导姓名或职级..."
onChange={debounce((e) => setSearchQuery(e.target.value), 300)}
className="w-full"
size="large"
/>
</div>
<DepartmentSelect
size="large"
value={selectedDept}
onChange={setSelectedDept as any}
className="w-full md:w-64"
/>
</div>
{error && (
<Alert
message="加载失败"
description="获取数据时出现错误,请刷新页面重试。"
type="error"
showIcon
/>
)}
</div>
2025-01-22 19:24:52 +08:00
2025-01-24 15:05:03 +08:00
<AnimatePresence>
2025-01-25 00:37:59 +08:00
{isLoading ? (
<div className="flex justify-center items-center py-12">
<Spin size="large" tip="加载中..." />
</div>
) : data?.items.length > 0 ? (
2025-01-24 15:05:03 +08:00
<motion.div
className="grid grid-cols-1 gap-6"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
2025-01-25 02:27:40 +08:00
{data?.items.map((item: any) => (
2025-01-25 00:37:59 +08:00
<SendCard
key={item.id}
2025-01-25 02:27:40 +08:00
staff={item}
termId={termId || undefined}
2025-01-24 15:05:03 +08:00
/>
))}
</motion.div>
) : (
2025-01-22 19:24:52 +08:00
<motion.div
2025-01-24 15:05:03 +08:00
className="text-center py-12"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
2025-01-22 19:24:52 +08:00
>
2025-01-25 00:37:59 +08:00
<Empty
description="没有找到匹配的收信人"
className="py-12"
/>
2025-01-22 19:24:52 +08:00
</motion.div>
2025-01-24 15:05:03 +08:00
)}
</AnimatePresence>
2025-01-25 00:37:59 +08:00
{/* Pagination */}
{data?.items.length > 0 && (
<div className="flex justify-center mt-8">
<Pagination
current={currentPage}
total={data?.totalPages || 0}
pageSize={pageSize}
2025-01-25 20:48:16 +08:00
onChange={(page) => {
setCurrentPage(page);
window.scrollTo(0, 0);
}}
2025-01-25 00:37:59 +08:00
showSizeChanger={false}
showTotal={(total) => `${total} 条记录`}
/>
</div>
)}
2025-01-22 19:24:52 +08:00
</div>
</div>
);
}