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
|
|
|
}
|