2024-06-05 14:27:06 +08:00
|
|
|
import { Trash2 } from "lucide-react";
|
|
|
|
|
import { useContext, useEffect, useRef, useState } from "react";
|
|
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
|
import { bsconfirm } from "../../alerts/confirm";
|
|
|
|
|
import { TabsContext } from "../../contexts/tabsContext";
|
|
|
|
|
import { deleteChatApi, getChatsApi } from "../../controllers/API";
|
|
|
|
|
import { getFlowApi, readOnlineFlows } from "../../controllers/API/flow";
|
|
|
|
|
import { FlowType } from "../../types/flow";
|
|
|
|
|
import { generateUUID } from "../../utils";
|
|
|
|
|
import SkillTemps from "../SkillPage/components/SkillTemps";
|
|
|
|
|
import ChatPanne from "./components/ChatPanne";
|
|
|
|
|
import { captureAndAlertRequestErrorHoc } from "../../controllers/request";
|
2024-06-13 15:11:41 +08:00
|
|
|
import { useDebounce, useTable } from "../../util/hook";
|
2024-06-05 14:27:06 +08:00
|
|
|
import duihuaDel from "../../assets/chat/duihua-del.png";
|
|
|
|
|
import robot from "../../assets/robot.png";
|
|
|
|
|
import robot2 from "../../assets/robot2.png";
|
|
|
|
|
import robot3 from "../../assets/robot3.png";
|
|
|
|
|
import duihuaItemTop from "../../assets/chat/duihua-item-top.png";
|
|
|
|
|
import duihuaItemJia from "../../assets/chat/duihua-item-+.png";
|
|
|
|
|
import duihuaItemGuan from "../../assets/chat/duihua-item-x.png";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function SkillChatPage() {
|
|
|
|
|
const [open, setOpen] = useState(false)
|
|
|
|
|
const [face, setFace] = useState(true);
|
|
|
|
|
|
|
|
|
|
const { t } = useTranslation()
|
|
|
|
|
|
|
|
|
|
const { flow: initFlow } = useContext(TabsContext);
|
|
|
|
|
const [flow, setFlow] = useState<FlowType>(null)
|
2024-06-13 15:11:41 +08:00
|
|
|
const {
|
|
|
|
|
data: onlineFlows,
|
|
|
|
|
loading,
|
|
|
|
|
search,
|
|
|
|
|
} = useTable<FlowType>({}, (param) =>
|
|
|
|
|
readOnlineFlows(param.page, param.keyword).then((res) => {
|
|
|
|
|
return res;
|
|
|
|
|
})
|
|
|
|
|
);
|
2024-06-05 14:27:06 +08:00
|
|
|
// 对话列表
|
|
|
|
|
const { chatList, chatId, chatsRef, setChatId, addChat, deleteChat } = useChatList()
|
|
|
|
|
const chatIdRef = useRef('')
|
|
|
|
|
|
|
|
|
|
// select flow
|
|
|
|
|
const handlerSelectFlow = async (node: FlowType) => {
|
|
|
|
|
// 会话ID
|
|
|
|
|
chatIdRef.current = generateUUID(32)
|
|
|
|
|
setOpen(false)
|
|
|
|
|
// add list
|
|
|
|
|
addChat({
|
|
|
|
|
"flow_name": node.name,
|
|
|
|
|
"flow_description": node.description,
|
|
|
|
|
"flow_id": node.id,
|
|
|
|
|
"chat_id": chatIdRef.current,
|
|
|
|
|
"create_time": "-",
|
|
|
|
|
"update_time": "-"
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const flow = await getFlowApi(node.id)
|
|
|
|
|
setFlow(flow)
|
|
|
|
|
setChatId(chatIdRef.current)
|
|
|
|
|
setFace(false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// select chat
|
|
|
|
|
const handleSelectChat = useDebounce(async (chat) => {
|
|
|
|
|
if (chat.chat_id === chatId) return
|
|
|
|
|
|
|
|
|
|
chatIdRef.current = chat.chat_id
|
|
|
|
|
const flow = initFlow?.id === chat.flow_id ? initFlow : await getFlowApi(chat.flow_id)
|
|
|
|
|
|
|
|
|
|
// if (!flow) {
|
|
|
|
|
// setInputState({ lock: true, errorCode: '1004' })
|
|
|
|
|
// clearHistory()
|
|
|
|
|
// return setFace(false)
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
setFlow(flow)
|
|
|
|
|
setChatId(chat.chat_id)
|
|
|
|
|
setFace(false)
|
|
|
|
|
}, 100, false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// del
|
|
|
|
|
const handleDeleteChat = (e, id) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
bsconfirm({
|
|
|
|
|
desc: t('chat.confirmDeleteChat'),
|
|
|
|
|
onOk(next) {
|
|
|
|
|
deleteChat(id);
|
|
|
|
|
setFace(true)
|
|
|
|
|
next()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return <div className="flex">
|
|
|
|
|
<div className="h-screen w-[288px] border-r xinDuiHua-box relative">
|
|
|
|
|
<div className="xinDuiHua absolute">
|
|
|
|
|
<div className="xinDuiHua-btn cursor-pointer" onClick={() => setOpen(true)}>{t('chat.newChat')}</div>
|
|
|
|
|
{/* <div className="xinDuiHua-del cursor-pointer">
|
|
|
|
|
<img src={duihuaDel} alt=""/>
|
|
|
|
|
</div> */}
|
|
|
|
|
</div>
|
|
|
|
|
<div ref={chatsRef} className="absolute w-[100%] scroll p-[10px] h-full overflow-y-scroll no-scrollbar pt-[63px]">
|
|
|
|
|
{
|
|
|
|
|
chatList.map((chat, i) => (
|
|
|
|
|
<div key={chat.chat_id}
|
|
|
|
|
className={` group item xinDuiHua-list-item relative hover:xinDuiHua-list-active cursor-pointer dark:hover:xinDuiHua-list-active ${chatId === chat.chat_id && 'xinDuiHua-list-active dark:xinDuiHua-list-active'}`}
|
|
|
|
|
onClick={() => handleSelectChat(chat)}>
|
|
|
|
|
<div>
|
|
|
|
|
{(chat.flow_id == "06b1d374-ba97-46e6-8782-c56dec8dcc17" || chat.flow_id == "ed8e21f6-9757-43d0-b076-8c6e81bb0580") && <img src={robot2} alt=""/>}
|
|
|
|
|
{chat.flow_id == "ca214b41-2b73-4585-b172-bf1e546cf6ec" && <img src={robot3} alt=""/>}
|
|
|
|
|
{(chat.flow_id != "06b1d374-ba97-46e6-8782-c56dec8dcc17" && chat.flow_id != "ed8e21f6-9757-43d0-b076-8c6e81bb0580" && chat.flow_id != "ca214b41-2b73-4585-b172-bf1e546cf6ec") && <img src={robot} alt=""/>}
|
|
|
|
|
{/* <img src={robot} alt=""/> */}
|
|
|
|
|
<div>
|
|
|
|
|
<p>{chat.flow_name}</p>
|
|
|
|
|
{/* <div>离线</div> */}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
{/* <img src={duihuaItemTop} alt=""/>
|
|
|
|
|
<img src={duihuaItemJia} alt=""/> */}
|
|
|
|
|
</div>
|
|
|
|
|
<img className="absolute w-[10px] top-[5px] right-[5px] hidden group-hover:block" src={duihuaItemGuan} onClick={(e) => handleDeleteChat(e, chat.chat_id)} alt=""/>
|
|
|
|
|
{/* <span className="text-xs text-gray-500">{chat.flow_description}</span> */}
|
|
|
|
|
{/* <Trash2 size={14} className="absolute bottom-2 right-2 text-gray-400 hidden group-hover:block" onClick={(e) => handleDeleteChat(e, chat.chat_id)}></Trash2> */}
|
|
|
|
|
</div>
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{/* chat */}
|
|
|
|
|
{face
|
|
|
|
|
? <div className="flex-1 chat-box h-screen overflow-hidden relative">
|
|
|
|
|
<p className="text-center mt-[100px] text-sm text-gray-600">{t('chat.selectChat')}</p>
|
|
|
|
|
</div>
|
|
|
|
|
: <div className="flex-1 chat-box h-screen relative">
|
|
|
|
|
{flow && <ChatPanne chatId={chatId} flow={flow} />}
|
|
|
|
|
</div>}
|
|
|
|
|
{/* 选择对话技能 */}
|
|
|
|
|
<SkillTemps
|
|
|
|
|
flows={onlineFlows}
|
|
|
|
|
title={t('chat.skillTempsTitle')}
|
|
|
|
|
desc={t('chat.skillTempsDesc')}
|
|
|
|
|
open={open} setOpen={setOpen}
|
|
|
|
|
onSelect={handlerSelectFlow}></SkillTemps>
|
|
|
|
|
</div>
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* 本地对话列表
|
|
|
|
|
*/
|
|
|
|
|
const useChatList = () => {
|
|
|
|
|
const [id, setId] = useState('')
|
|
|
|
|
const [chatList, setChatList] = useState([])
|
|
|
|
|
const chatsRef = useRef(null)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getChatsApi().then(setChatList)
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
chatList,
|
|
|
|
|
chatId: id,
|
|
|
|
|
chatsRef,
|
|
|
|
|
setChatId: setId,
|
|
|
|
|
addChat: (chat) => {
|
|
|
|
|
const newList = [chat, ...chatList]
|
|
|
|
|
// localStorage.setItem(ITEM_KEY, JSON.stringify(newList))
|
|
|
|
|
setChatList(newList)
|
|
|
|
|
setId(chat.chat_id)
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
chatsRef.current.scrollTop = 1
|
|
|
|
|
}, 0);
|
|
|
|
|
},
|
|
|
|
|
deleteChat: (id: string) => {
|
|
|
|
|
// api
|
|
|
|
|
captureAndAlertRequestErrorHoc(deleteChatApi(id).then(res => {
|
|
|
|
|
setChatList(oldList => oldList.filter(item => item.chat_id !== id))
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|