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

150 lines
3.7 KiB
TypeScript

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