ChatHome.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { Badge } from "@/components/bs-ui/badge";
  2. import { Button } from "@/components/bs-ui/button";
  3. import { getChatOnlineApi } from "@/controllers/API/assistant";
  4. import { useContext, useEffect, useMemo, useRef, useState } from "react";
  5. import { useNavigate } from "react-router-dom";
  6. import { SearchInput } from "@/components/bs-ui/input";
  7. import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "@/components/bs-ui/sheet";
  8. import CardComponent, { TitleIconBg } from "@/components/bs-comp/cardComponent";
  9. import { SkillIcon } from "@/components/bs-icons/skill";
  10. import { AssistantIcon } from "@/components/bs-icons/assistant";
  11. import { useTranslation } from "react-i18next";
  12. import borderR from "../../../assets/npc/border-r.png";
  13. import { SpotlightCard } from "@lobehub/ui";
  14. import { Flexbox } from 'react-layout-kit';
  15. import robot from "../../../assets/robot.png";
  16. import robot2 from "../../../assets/robot2.png";
  17. import robot3 from "../../../assets/robot3.png";
  18. import zidingyi1 from "../../../assets/npc/zidingyi1.png";
  19. import zidingyi2 from "../../../assets/npc/zidingyi2.png";
  20. import npcIcon from "../../../assets/npc/npcIcon.png";
  21. import nengliIcon from "../../../assets/npc/nengliIcon.png";
  22. import biaoqianPaixu from "../../../assets/chat/biaoqian-paixu.png";
  23. import sousuo from "../../../assets/npc/sousuo.png";
  24. import shengQue from "../../../assets/chat/shengQue.png";
  25. import { useDebounce } from "@/util/hook";
  26. import LoadMore from "@/components/bs-comp/loadMore";
  27. import { userContext } from "@/contexts/userContext";
  28. import { getHomeLabelApi } from "@/controllers/API/label";
  29. import MarkLabel from "@/pages/ChatAppPage/components/MarkLabel";
  30. export default function HomePage({ onSelect }) {
  31. const { t } = useTranslation()
  32. const { user } = useContext(userContext)
  33. const chatListRef = useRef([])
  34. const navigate = useNavigate()
  35. const [labels, setLabels] = useState([])
  36. const [open, setOpen] = useState(false)
  37. const pageRef = useRef(1)
  38. const [options, setOptions] = useState<any>([])
  39. const searchRef = useRef('')
  40. const [flag, setFlag] = useState(null) // 解决筛选之后再次发起请求覆盖筛选数据
  41. const [keyword, setKeyword] = useState(' ')
  42. const allDataRef = useRef([])
  43. const [markLabelOpen, setMarkLabelOpen] = useState(false)
  44. const loadData = (more = false) => {
  45. getChatOnlineApi(pageRef.current, searchRef.current, -1).then((res: any) => {
  46. setFlag(true)
  47. chatListRef.current = res
  48. setOptions(more ? [...options, ...res] : res)
  49. })
  50. }
  51. useEffect(() => {
  52. debounceLoad()
  53. getHomeLabelApi().then((res: any) => {
  54. setLabels(res.map(d => ({ label: d.name, value: d.id, selected: true })))
  55. })
  56. }, [])
  57. const debounceLoad = useDebounce(loadData, 600, false)
  58. const handleSearch = (e) => {
  59. pageRef.current = 1
  60. searchRef.current = e.target.value
  61. debounceLoad()
  62. }
  63. const handleClose = async (bool) => {
  64. const newHome = await getHomeLabelApi()
  65. // @ts-ignore
  66. setLabels(newHome.map(d => ({ label: d.name, value: d.id, selected: true })))
  67. setMarkLabelOpen(bool)
  68. }
  69. const [chooseId, setChooseId] = useState() // 筛选项样式变化
  70. const handleTagSearch = (id) => {
  71. setChooseId(id)
  72. setFlag(false)
  73. pageRef.current = 1
  74. getChatOnlineApi(pageRef.current, '', id).then((res: any) => {
  75. setOptions(res)
  76. })
  77. }
  78. const handleLoadMore = async () => {
  79. pageRef.current++
  80. await debounceLoad(true)
  81. }
  82. const render = (item: any) => (
  83. <Flexbox align={'flex-start'} className={`selectNpcFlexbox relative`} onClick={() => { onSelect(item); setOpen(false) }}>
  84. <div className="npcInfoItemBg">
  85. <span>
  86. <span>
  87. <div>
  88. <TitleIconBg className="w-[160px] h-[160px] min-w-[160px]" img={item.avatar_img} id={item.avatar_color ? item.avatar_color : item.id} ><img src={item.avatar_img ? item.avatar_img : (item.flow_type == "assistant" ? npcIcon : nengliIcon)} alt="" /></TitleIconBg>
  89. </div>
  90. </span>
  91. </span>
  92. </div>
  93. <div>
  94. <TitleIconBg className="w-[40px] h-[40px] min-w-[40px]" img={item.avatar_img} id={item.avatar_color ? item.avatar_color : item.id} ><img src={item.avatar_img ? item.avatar_img : (item.flow_type == "assistant" ? npcIcon : nengliIcon)} alt="" /></TitleIconBg>
  95. <div>
  96. <p>{item.name}</p>
  97. <div>
  98. </div>
  99. </div>
  100. </div>
  101. <p className="mt-[10px] test-[13px]">{item.desc}</p>
  102. <div className={`absolute right-0 top-0 w-[41px] h-[16px] flex justify-center items-center text-[9px] ${item.flow_type === 'flow' ? 'text-[#333333] bg-[#FFD54C]' : 'text-[#FFFFFF] bg-[#2586FF]'}`} style={{borderRadius:"0px 10px 0px 7px",fontWeight:"bold"}}>
  103. {item.flow_type === 'flow' ? '能力' : 'NPC'}
  104. </div>
  105. </Flexbox>
  106. );
  107. return <div className="h-[100vh]" style={{width: 'calc(100% - 288px)'}}>
  108. <div className="w-[100%] h-full xinDuiHua-box" onClick={e => e.stopPropagation()}>
  109. {/* <div className="xinDuiHua-boxR">
  110. </div> */}
  111. <div className="p-6 flex justify-center items-center" style={{flexDirection:"column"}}>
  112. {/* <SheetTitle>选择对话</SheetTitle>
  113. <SheetDescription className="text-[#999999]">选择一个您想使用的上线NPC或能力</SheetDescription> */}
  114. {/* <SearchInput value={keyword} placeholder="搜索" className="my-6" onChange={(e) => setKeyword(e.target.value)} /> */}
  115. <p className="text-[#FFFFFF] text-[12px] mt-[30px]">选择对话</p>
  116. <p className="text-[#999999] text-[11px] mt-[10px]">选择一个您想使用的上线NPC或能力</p>
  117. <div className="relative my-6">
  118. <SearchInput placeholder="搜索" className="npcInput3 w-[610px] chatHomeInput" onChange={handleSearch} />
  119. <div className="absolute w-[54px] h-[34px] bg-[#FFD54C] right-0 top-0 border-radius-35 flex justify-center items-center cursor-pointer" onClick={handleSearch}><img src={sousuo} className="w-[14px]" alt="" /></div>
  120. </div>
  121. <div className="flex flex-wrap duihuaTab w-[610px]">
  122. {/* @ts-ignore */}
  123. {user.role === 'admin' && <img src={biaoqianPaixu} alt="" className="h-[20px] w-[20px] cursor-pointer mr-[13px]" onClick={() => setMarkLabelOpen(true)} />}
  124. {/* <Button variant={chooseId ? "outline" : "default"} className="mb-2 mr-5" size="sm"
  125. onClick={() => { setChooseId(null); loadData(false) }}>全部</Button> */}
  126. <div className={`h-[20px] px-[13px] mr-[13px] text-[9px] flex justify-center items-center border-radius-14 cursor-pointer ${chooseId ? "text-[#999999] bg-[#1A1A1A]" : "text-[#FFD54C] bg-[#4D4017]"}`} onClick={() => { setChooseId(null); loadData(false) }}>全部</div>
  127. {
  128. labels.map((l, index) => index <= 11 &&
  129. <div className={`h-[20px] px-[13px] mb-[10px] mr-[13px] text-[9px] flex justify-center items-center border-radius-14 cursor-pointer ${l.value === chooseId ? "text-[#FFD54C] bg-[#4D4017]" : "text-[#999999] bg-[#1A1A1A]"}`} onClick={() => handleTagSearch(l.value)}>{l.label}</div>)
  130. }
  131. </div>
  132. </div>
  133. <div className="overflow-y-auto scrollbar-hide skillSheet">
  134. {options.length ? <SpotlightCard items={options} renderItem={render} className="mt-[14px] skillSheetSpotlightCard"/>
  135. :<div className="flex justify-center items-center" style={{flexDirection:"column",height:"calc(100% - 210px"}}>
  136. <img src={shengQue} className="w-[176px]" alt="" />
  137. <p className="mt-[26px] text-[#666666] text-[11px]">未找到您搜索的「NPC」或「能力」</p>
  138. </div>}
  139. {flag && <LoadMore onScrollLoad={handleLoadMore} />}
  140. </div>
  141. <MarkLabel open={markLabelOpen} home={labels} onClose={handleClose}></MarkLabel>
  142. </div>
  143. </div>
  144. }