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

150 lines
3.7 KiB
TypeScript
Raw Normal View History

2025-01-26 09:47:04 +08:00
import { useState, useCallback, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useSearchParams } from "react-router-dom";
2025-01-25 02:27:40 +08:00
2025-01-26 09:47:04 +08:00
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";
2025-01-22 19:24:52 +08:00
export default function WriteLetterPage() {
2025-01-26 09:47:04 +08:00
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();
2025-01-22 19:24:52 +08:00
2025-01-26 09:47:04 +08:00
const { data, isLoading, error } =
api.staff.findManyWithPagination.useQuery({
page: currentPage,
pageSize,
where: {
deptId: selectedDept,
OR: [
{
showname: {
contains: searchQuery,
},
},
{
username: {
contains: searchQuery,
},
},
],
},
orderBy: {
2025-01-26 12:45:59 +08:00
order: "asc",
2025-01-26 09:47:04 +08:00
},
// orderBy:{
2025-01-25 02:27:40 +08:00
2025-01-26 09:47:04 +08:00
// }
});
2025-01-25 02:27:40 +08:00
2025-01-26 09:47:04 +08:00
const resetPage = useCallback(() => {
setCurrentPage(1);
}, []);
2025-01-22 19:24:52 +08:00
2025-01-26 09:47:04 +08:00
// Reset page when search or department changes
useEffect(() => {
resetPage();
}, [searchQuery, selectedDept, resetPage]);
2025-01-26 08:26:17 +08:00
2025-01-26 09:47:04 +08:00
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>
2025-01-26 08:26:17 +08:00
2025-01-26 09:47:04 +08:00
{error && (
<Alert
message="加载失败"
description="获取数据时出现错误,请刷新页面重试。"
type="error"
showIcon
/>
)}
</div>
2025-01-25 00:37:59 +08:00
2025-01-26 09:47:04 +08:00
<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>
2025-01-22 19:24:52 +08:00
2025-01-26 09:47:04 +08:00
{/* 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>
);
2025-01-22 19:24:52 +08:00
}