123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- import { View, ScrollView } from "@tarojs/components";
- import NavBarNormal from "@/components/NavBarNormal/index";
- import PageCustom from "@/components/page-custom/index";
- import Taro, { useRouter, useUnload } from "@tarojs/taro";
- import ChatMessage from "@/components/chat-message";
- import style from "./index.module.less";
- import InputBar from "./components/input-bar";
- import { useEffect, useState, useRef } from "react";
- import { useTextChat } from "@/store/textChat";
- import { EAI_MODEL } from "@/consts/enum";
- import type { TMessage, TRobotMessage } from "@/store/textChat";
- import ChatWelcome from "./components/chat-welcome";
- import IconArrowLeft from "@/components/icon/icon-arrow-left";
- import PersonalCard from "./components/personal-card";
- import { useAgentStore } from "@/store/agentStore";
- import { useLoadMore } from "@/utils/loadMore";
- import { getMessageHistories } from "@/service/bot";
- import { useAppStore } from "@/store/appStore";
- // 类型谓词函数
- function isRobotMessage(
- message: TMessage | TRobotMessage
- ): message is TRobotMessage {
- return "robot" in message && "reasoningContent" in message;
- }
- export default function Index() {
- const router = useRouter();
- const { agentId, isVisitor } = router.params;
- if (!agentId) {
- return <View>没有相应的智能体</View>;
- }
- const headerHeight = useAppStore((state) => state.headerHeight);
- const { fetchAgent, fetchAgentProfile, } = useAgentStore();
- const agent = useAgentStore((state) => {
- if(isVisitor === 'true'){
- return state.agentProfile
- }
- return state.agent
- });
- const [deepThink, setDeepThink] = useState(EAI_MODEL.DeepseekChat);
- const [histories, setHistories] = useState<(TMessage | TRobotMessage)[]>([]);
- const [keyboardHeight, setKeyboardHeight] = useState(0);
- const [contentHeight, setContentHeight] = useState(0);
- const [scrollViewHeight, setScrollViewHeight] = useState(0);
- const scrollViewRef = useRef<any>(null);
- const messageList = useTextChat((state) => state.list);
- const { destroy, setScrollTop, genSessionId } = useTextChat();
- const scrollTop = useTextChat((state) => state.scrollTop);
- const fetcher = async ([_url, nextId, page, pageSize]) => {
- if (!agent) {
- return null;
- }
- const _nextId = nextId ? decodeURIComponent(nextId) : nextId;
- const res = await getMessageHistories({
- agentId,
- startId: _nextId,
- pageSize,
- });
- return res.data;
- };
- const { data, loadMore, page } = useLoadMore<(TMessage | TRobotMessage)[]>({
- url: `messeagehistories${isVisitor}${agentId}`,
- fetcher,
- });
- const [showWelcome, setShowWelcome] = useState(!histories.length);
- // 加载更多
- const onScrollToUpper = () => {
- console.log("onscroll");
- loadMore();
- };
- useEffect(() => {
- if(agentId){
- if(isVisitor){
- fetchAgentProfile(agentId)
- }else{
- fetchAgent(agentId);
- }
- }
- }, [agentId, isVisitor]);
- useEffect(() => {
- setShowWelcome(!histories.length);
- }, [histories]);
- useEffect(() => {
- if (data?.data) {
- const combine = [...histories, ...data.data]
- setHistories(combine);
- if (page === 1) {
- setTimeout(() => {
- setScrollTop();
- }, 300);
- }
- }
- }, [data, page,]);
- // 计算 marginTopOffset 偏移的距离
- const marginTopOffset = (() => {
- if (keyboardHeight <= 0) return 0;
- // 如果内容超过滚动容器,取键盘弹起高度
- if (contentHeight > scrollViewHeight) {
- return -keyboardHeight;
- }
- // 如果内容+键盘弹起高度超过滚动容器, 则取其差值
- if (contentHeight + keyboardHeight > scrollViewHeight) {
- // 内容+键盘弹起高度 - 滚动容器高度
- return -(contentHeight + keyboardHeight - scrollViewHeight);
- }
- })();
- useEffect(() => {
- // 监听键盘高度变化
- Taro.onKeyboardHeightChange((res) => {
- if (res.height <= 0) {
- return setKeyboardHeight(0);
- }
- setKeyboardHeight(res.height - 24);
- });
- return () => {
- // 清理监听器
- Taro.offKeyboardHeightChange();
- };
- }, []);
- // 监听内容高度和 ScrollView 高度变化
- useEffect(() => {
- if (scrollViewRef.current) {
- const query = Taro.createSelectorQuery();
- // 获取聊天内容高度
- query
- .select("#message-list")
- .boundingClientRect((rect: any) => {
- if (rect) {
- setContentHeight(rect.height);
- }
- })
- .exec();
- // 获取滚动容器高度
- query
- .select("#scroll-view")
- .boundingClientRect((rect: any) => {
- if (rect) {
- setScrollViewHeight(rect.height);
- }
- })
- .exec();
- }
- }, [messageList]);
- useEffect(() => {
- genSessionId();
- }, []);
- useUnload(() => {
- destroy();
- });
- const switchDeepThink = () => {
- if (deepThink === EAI_MODEL.DeepseekChat) {
- setDeepThink(EAI_MODEL.DeepseekReasoner);
- return;
- }
- setDeepThink(EAI_MODEL.DeepseekChat);
- };
- const renderNavLeft = () => {
- return (
- <View
- className="flex items-center gap-8"
- onClick={() => Taro.navigateBack()}
- >
- <IconArrowLeft />
- <View className={showWelcome ? "hidden" : "block"}>
- <PersonalCard agent={agent} size="mini" />
- </View>
- </View>
- );
- };
- // 自定义背景样式
- const bgImageStyle = {
- backgroundImage: `url(${agent?.avatarUrl})`,
- };
- return (
- <PageCustom fullPage style={{ overflow: "hidden" }}>
- <NavBarNormal leftColumn={renderNavLeft}></NavBarNormal>
- {(!!agent?.enabledChatBg) ? <View className={style.topBg} style={bgImageStyle}></View> : <></>}
- <View
- className="flex flex-col w-full h-screen relative z-10"
- style={{ marginTop: `${marginTopOffset}px` }}
- >
- <ScrollView
- ref={scrollViewRef}
- scrollY
- id="scrollView"
- style={{
- flex: 1,
- height: "1px", // 高度自适应
- }}
- scrollTop={scrollTop}
- scrollWithAnimation
- onScrollToUpper={onScrollToUpper}
- >
- {showWelcome && <ChatWelcome agent={agent} />}
- <View id="messageList" className="flex flex-col gap-8 px-18 pb-140">
- {/* 复制 histories 再 reverse 否则会影响 state */}
- {[...[...histories].reverse(), ...messageList].map((message) => {
- const robotMessage = isRobotMessage(message) ? message : null;
- return (
- <ChatMessage
- key={message.msgUk}
- textReasoning={robotMessage?.reasoningContent}
- agent={agent}
- role={message.role}
- text={message.content}
- message={message}
- ></ChatMessage>
- );
- })}
- </View>
- </ScrollView>
- <View className="h-140 w-10"></View>
- <View
- className="fixed left-0 right-0 bottom-0 min-h-130 z-50"
- style={{
- bottom: `${keyboardHeight}px`,
- }}
- >
- {/* <View
- onClick={switchDeepThink}
- className={
- deepThink === EAI_MODEL.DeepseekReasoner
- ? style.deepMindMarkActive
- : style.deepMindMark
- }
- >
- 深度思考(R1)
- </View> */}
- {agent && (
- <InputBar
- aiModel={deepThink}
- agent={agent}
- histories={histories}
- setShowWelcome={setShowWelcome}
- ></InputBar>
- )}
- </View>
- </View>
- </PageCustom>
- );
- }
|