123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- "use client";
- import { useRef, useState, useEffect } from "react";
- import { useRouter } from "next/navigation";
- import {
- RiSearch2Line,
- RiAddCircleFill,
- RiCalendarCloseLine,
- RiLoader2Fill,
- } from "react-icons/ri";
- import { useGlobalContext } from "@/providers/GlobalProvider";
- import { getCategoryList, getEmployeeSearch } from "@/api/client";
- import { CategoryListResult, EmployeeSearchResult } from "@/utils/clientsApis";
- import {
- Storage_setListType,
- Storage_setAgentId,
- Storage_setConversationId,
- } from "@/utils/chat";
- export default function Home() {
- const router = useRouter();
- const boxRef = useRef<HTMLDivElement | null>(null);
- const { changeMenuIndex } = useGlobalContext();
- const [categoryList, setCategoryList] = useState<CategoryListResult[]>([]);
- const [employeeList, setEmployeeList] = useState<EmployeeSearchResult[]>([]);
- const [categoryId, setCategoryId] = useState<number>(0);
- const [keyword, setKeyword] = useState<string>("");
- const [page, setPage] = useState<number>(1);
- const [isBottom, setIsBottom] = useState<boolean>(false);
- const page_getEmployeeSearch = () => {
- getEmployeeSearch({
- page: page,
- pageSize: 20,
- categoryId: categoryId,
- title: keyword,
- }).then((data) => {
- if (data.code === 0 && data.data.data !== null) {
- setEmployeeList((prevEmployeeList) => [
- ...prevEmployeeList,
- ...data.data.data, // Append new data to the existing list
- ]);
- if (data.data.total <= 20) {
- setIsBottom(true);
- }
- } else {
- setIsBottom(true);
- }
- });
- };
- const handleScroll = () => {
- if (
- boxRef.current &&
- boxRef.current.scrollHeight - boxRef.current.clientHeight ===
- boxRef.current.scrollTop
- ) {
- setPage((prevPage) => {
- const nextPage = prevPage + 1;
- page_getEmployeeSearch(); // Load the next page
- return nextPage;
- });
- }
- };
- const selectCategory = (id: number) => {
- if (categoryId != id) {
- setIsBottom(false);
- setCategoryId(id);
- setPage(1);
- setEmployeeList([]);
- }
- };
- const handleKeywordChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- setKeyword(event.target.value);
- };
- const handleSearch = () => {
- setIsBottom(false);
- setPage(1);
- setEmployeeList([]);
- };
- const addChat = (id: number) => {
- Storage_setListType(1);
- Storage_setAgentId(id);
- Storage_setConversationId("");
- router.push("/dialogue");
- };
- const [isFocused, setIsFocused] = useState(false);
- const handleFocus = () => setIsFocused(true);
- const handleBlur = () => setIsFocused(false);
- useEffect(() => {
- changeMenuIndex(2);
- getCategoryList({ page: 1, pageSize: 20 }).then((data) => {
- if (data.code === 0) {
- setCategoryList(data.data.data);
- }
- });
- page_getEmployeeSearch();
- setPage(page + 1);
- }, [isBottom, categoryId, keyword]);
- return (
- <div
- className="absolute top-0 w-full overflow-auto scroll-smooth h-calc-8 md:h-calc-5"
- onScroll={handleScroll}
- ref={boxRef}
- >
- <div className="sticky top-0 z-50 dark:shadow-[rgba(255,255,255,.15)] backdrop-blur dark:bg-transparent transition-all">
- <div className="flex flex-row justify-center pt-9">
- <div className="w-11/12 md:basis-1/2 2xl:basis-1/3 relative">
- <input
- className="w-full border rounded-full pl-4 pr-12 py-2 focus:border-[#0061ff] dark:focus:border-slate-700 focus:outline-none"
- type="text"
- placeholder="输入关键词查询智能体..."
- value={keyword}
- onChange={handleKeywordChange}
- onFocus={handleFocus}
- onBlur={handleBlur}
- onKeyDown={(e) => {
- if (e.key === "Enter") {
- handleSearch();
- }
- }}
- />
- <div
- className={`absolute right-0 top-0 py-2 mr-4 cursor-pointer ${
- isFocused ? "text-[#0061ff]" : "text-gray-400"
- }`}
- >
- <RiSearch2Line size={24} onClick={handleSearch} />
- </div>
- </div>
- </div>
- {categoryList !== null && categoryList.length > 0 && (
- <div className="flex flex-row justify-center py-4">
- <div className="w-full md:container mx-auto flex flex-wrap justify-center gap-2 text-sm">
- <div className="w-full md:hidden overflow-x-auto scroll-smooth focus:scroll-auto">
- <div className="flex space-x-2 p-3">
- <button
- type="button"
- className={`px-4 py-1 border rounded-full whitespace-nowrap ${
- categoryId == 0
- ? "bg-blue-50 dark:bg-blue-950 text-[#0061ff]"
- : "text-gray-500 dark:text-gray-500 bg-white dark:bg-gray-800 hover:text-gray-900 dark:hover:text-white hover:bg-blue-50 dark:hover:bg-gray-800"
- }`}
- onClick={() => selectCategory(0)}
- >
- 全部分类
- </button>
- {categoryList.map((item) => (
- <button
- key={item.id}
- type="button"
- className={`px-4 py-1 border rounded-full whitespace-nowrap ${
- categoryId == item.id
- ? "bg-blue-50 dark:bg-blue-950 text-[#0061ff]"
- : "text-gray-500 dark:text-gray-500 bg-white dark:bg-gray-800 hover:text-gray-900 dark:hover:text-white hover:bg-blue-50 dark:hover:bg-gray-800"
- }`}
- onClick={() => selectCategory(item.id)}
- >
- {item.name}
- </button>
- ))}
- </div>
- </div>
- <div className="hidden md:flex flex-wrap justify-center gap-2">
- <button
- type="button"
- className={`px-4 py-1 border rounded-full ${
- categoryId == 0
- ? "bg-blue-50 dark:bg-blue-950 text-[#0061ff]"
- : "text-gray-500 dark:text-gray-500 bg-white dark:bg-gray-800 hover:text-gray-900 dark:hover:text-white hover:bg-blue-50 dark:hover:bg-gray-800"
- }`}
- onClick={() => selectCategory(0)}
- >
- 全部分类
- </button>
- {categoryList.map((item) => (
- <button
- key={item.id}
- type="button"
- className={`px-4 py-1 border rounded-full ${
- categoryId == item.id
- ? "bg-blue-50 dark:bg-blue-950 text-[#0061ff]"
- : "text-gray-500 dark:text-gray-500 bg-white dark:bg-gray-800 hover:text-gray-900 dark:hover:text-white hover:bg-blue-50 dark:hover:bg-gray-800"
- }`}
- onClick={() => selectCategory(item.id)}
- >
- {item.name}
- </button>
- ))}
- </div>
- </div>
- </div>
- )}
- </div>
- {employeeList !== null && employeeList.length > 0 && (
- <section className="text-gray-600 body-font">
- <div className="container px-5 py-5 md:py-20 mx-auto">
- <div className="flex flex-wrap -m-4 text-sm">
- {employeeList.map((item) => (
- <div
- className="p-4 lg:w-1/2 xl:w-1/3 transition transform hover:-translate-y-1 motion-reduce:transition-none motion-reduce:hover:transform-none grow"
- key={item.id}
- >
- <a
- onClick={() => addChat(item.id)}
- className="relative block overflow-hidden rounded-lg border border-gray-100 dark:border-slate-700 p-4 sm:p-6 lg:p-8 shadow-md cursor-pointer hover:bg-blue-50 dark:hover:bg-blue-950"
- >
- <span className="absolute inset-x-0 bottom-0 h-2 bg-gradient-to-r from-[#0061ff] via-[#347bec] to-[#6c62fd]"></span>
- <div className="flex justify-between gap-4">
- <div>
- <h3 className="text-lg font-bold text-gray-900 dark:text-white sm:text-xl text-ellipsis line-clamp-1 h-8">
- {item.title}
- </h3>
- <p className="mt-1 text-xs font-medium text-gray-600 text-ellipsis line-clamp-2 h-8">
- {item.skill}
- </p>
- </div>
- <div className="shrink-0">
- <img
- alt={item.title}
- src={item.avatar}
- className="size-16 object-contain"
- />
- </div>
- </div>
- <div className="mt-4">
- <p className="text-pretty text-sm text-gray-500 text-ellipsis line-clamp-4 h-20">
- {item.estimate}
- </p>
- </div>
- </a>
- </div>
- ))}
- </div>
- </div>
- {isBottom && (
- <div className="w-full mx-auto text-center text-sm text-gray-400 dark:text-gray-600 pb-20 md:pb-6">
- 已显示全部智能体
- </div>
- )}
- </section>
- )}
- {employeeList === null ||
- (employeeList.length === 0 && (
- <div className="w-full px-5 text-gray-200 flex flex-col mt-20">
- <div className="flex justify-center">
- <RiCalendarCloseLine className="w-16 h-16 text-center" />
- </div>
- <div className="text-center mt-4">查询结果为空</div>
- </div>
- ))}
- </div>
- );
- }
|