130 lines
3.6 KiB
TypeScript
Executable File
130 lines
3.6 KiB
TypeScript
Executable File
import { Button, Input, Pagination } from "antd";
|
|
import { PlusOutlined } from "@ant-design/icons";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { api } from "@nice/client";
|
|
import { PostType } from "@nice/common";
|
|
import { useAuth } from "@web/src/providers/auth-provider";
|
|
import { ExampleCard } from "./ExampleCard";
|
|
import { useState, useEffect, useMemo } from "react";
|
|
|
|
export function ExampleContent() {
|
|
const navigate = useNavigate();
|
|
const { user, hasSomePermissions, isAuthenticated } = useAuth();
|
|
const [exampleList, setExampleList] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
const [searchTerm, setSearchTerm] = useState("");
|
|
const pageSize = 10; // 每页显示5条案例
|
|
const isDomainAdmin = useMemo(() => {
|
|
return hasSomePermissions("MANAGE_DOM_STAFF", "MANAGE_ANY_STAFF");
|
|
}, [hasSomePermissions]);
|
|
const { data, isLoading } = api.post.findManyWithPagination.useQuery(
|
|
{
|
|
page: currentPage,
|
|
pageSize: pageSize,
|
|
where: {
|
|
type: PostType.EXAMPLE,
|
|
isPublic: true,
|
|
deletedAt: null,
|
|
title: searchTerm
|
|
? { contains: searchTerm, mode: "insensitive" }
|
|
: undefined,
|
|
},
|
|
orderBy: {
|
|
updatedAt: "desc",
|
|
},
|
|
},
|
|
{
|
|
enabled: true,
|
|
}
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (data?.items) {
|
|
setExampleList(data.items);
|
|
setLoading(false);
|
|
} else if (!isLoading) {
|
|
setExampleList([]);
|
|
setLoading(false);
|
|
}
|
|
}, [data, isLoading]);
|
|
|
|
useEffect(() => {
|
|
if (searchTerm) {
|
|
setCurrentPage(1);
|
|
}
|
|
}, [searchTerm]);
|
|
|
|
const handleAddExample = () => {
|
|
navigate("/example");
|
|
};
|
|
|
|
const handlePageChange = (page) => {
|
|
setCurrentPage(page);
|
|
};
|
|
|
|
const handleSearch = (value: string) => {
|
|
setSearchTerm(value);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-[400px]">
|
|
<div className="flex justify-between items-center mt-2 mx-2 mb-4">
|
|
<Input.Search
|
|
placeholder="搜索标题"
|
|
allowClear
|
|
onSearch={handleSearch}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
style={{ width: 300 }}
|
|
/>
|
|
{isDomainAdmin && (
|
|
<Button
|
|
type="primary"
|
|
icon={<PlusOutlined />}
|
|
onClick={handleAddExample}
|
|
size="middle"
|
|
className="shadow-md hover:scale-105 transition-all duration-300"
|
|
style={{
|
|
background: "#1677ff",
|
|
borderRadius: "6px",
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: "4px",
|
|
}}
|
|
>
|
|
发布
|
|
</Button>
|
|
)}
|
|
</div>
|
|
|
|
{loading || isLoading ? (
|
|
<div className="text-center py-8">加载中...</div>
|
|
) : exampleList.length > 0 ? (
|
|
<>
|
|
<div className="grid grid-cols-2 gap-4 mb-4 mx-2">
|
|
{exampleList.map((example) => (
|
|
<ExampleCard key={example.id} example={example} />
|
|
))}
|
|
</div>
|
|
|
|
{/* 分页组件 */}
|
|
<div className="flex justify-center my-6">
|
|
<Pagination
|
|
current={currentPage}
|
|
total={data?.totalCount || 0}
|
|
pageSize={pageSize}
|
|
onChange={handlePageChange}
|
|
showSizeChanger={false}
|
|
showQuickJumper
|
|
size="default"
|
|
/>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<div className="text-center py-8 text-gray-500">
|
|
{searchTerm ? `未找到标题包含"${searchTerm}"的案例` : "暂无案例分析"}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |