123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- import { View, ScrollView } from "@tarojs/components";
- import NavBarNormal from "@/components/NavBarNormal/index";
- import PageCustom from "@/components/page-custom/index";
- import { useDidShow, useRouter, useUnload } from "@tarojs/taro";
- import ChatMessage from "@/components/chat-message";
- import InputBar from "./components/InputBar";
- import { useEffect, useState } from "react";
- import { useTextChat } from "@/store/textChatStore";
- import { formatMessageTime } from "@/utils/timeUtils";
- import ChatGreeting from "./components/ChatGreeting";
- import IconArrowLeftWhite24 from "@/components/icon/IconArrowLeftWhite24";
- import IconArrowLeft from "@/components/icon/icon-arrow-left";
- import PersonalCard from "./components/PersonalCard";
- import ButtonEnableStreamVoice from "./components/OptionButtons/ButtonEnableStreamVoice";
- import RecommendQuestions from "./components/RecommendQuestions";
- import { usePersistentState } from "@/hooks/usePersistentState";
- // 导入我们抽离的 hooks 和常量
- import {
- useChatMessages,
- useChatScrollManager,
- useChatUI,
- useChatAgent,
- } from "./hooks";
- import { useChatInput } from "./components/InputBar/useChatInput";
- export default function Index() {
- const router = useRouter();
- const { agentId, isVisitor } = router.params;
- if (!agentId) {
- return <View>没有相应的智能体</View>;
- }
- // 使用抽离的 hooks
- const { agent } = useChatAgent(agentId, isVisitor);
-
- const {
- historyList,
- groupedMessages,
- messagesLength,
- loadMore,
- pageIndex,
- mutate,
- resetAndLoadFirstPage,
- } = useChatMessages(agentId, isVisitor);
- // 获取原始历史消息列表长度(用于UI状态判断)
- const rawHistoryListLength = historyList.length;
- const {
- scrollViewRef,
- scrollTop,
- keyboardHeight,
- marginTopOffset,
- handleScrollToUpper,
- handleTouchMove,
- handleScrollToLower,
- } = useChatScrollManager(messagesLength, pageIndex, loadMore);
- // 获取当前消息列表长度
- const currentMessageListLength = useTextChat((state) => state.list.length);
-
- const {
- showWelcome,
- haveBg,
- inputContainerHeight,
- inputContainerBottomOffset,
- setShowWelcome,
- getBgContent,
- createNavLeftRenderer,
- } = useChatUI(agent, rawHistoryListLength, currentMessageListLength);
- const [streamVoiceEnable, setStreamVoiceEnable] = usePersistentState(
- "streamVoiceEnable",
- false
- );
- // InputBar 相关状态
- const [isVoice, setIsVoice] = useState(false);
- const [disabled, setDisabled] = useState(false);
- const { destroy, genSessionId, clearList } = useTextChat();
- // 统一的聊天输入逻辑 - 只在主组件中实例化一次
- const chatInputActions = useChatInput({
- agent,
- enableOutputAudioStream: streamVoiceEnable,
- setShowWelcome,
- setIsVoice,
- setDisabled,
- historyList,
- });
- // 页面显示时刷新数据
- useDidShow(() => {
- // 需要清掉当前已经进行的聊天
- // clearList();
- });
-
- // 首次进入聊天生成 session id
- useEffect(() => {
- genSessionId();
- // 重新拉取第一页数据,
- resetAndLoadFirstPage()
- }, [genSessionId]);
- // 页面卸载时清理
- useUnload(() => {
- destroy();
- });
- // 加载更多的处理函数(已经在 useChatScrollManager 中处理)
- const onScrollToUpper = handleScrollToUpper;
- // 使用工厂函数创建导航栏左侧渲染器
- const renderNavLeft = createNavLeftRenderer(PersonalCard, IconArrowLeftWhite24, IconArrowLeft);
- // console.log('----scrollTop: ', scrollTop, '----')
- return (
- <PageCustom
- fullPage
- style={{ overflow: "hidden" }}
- styleBg={getBgContent()}
- >
- <NavBarNormal blur leftColumn={renderNavLeft}>
- {/* <>{`${scrollTop}`}--</> */}
- </NavBarNormal>
- <View
- className="flex flex-col w-full h-full relative z-10 flex-1"
- style={{ top: `${marginTopOffset}px` }}
- >
- <ScrollView
- ref={scrollViewRef}
- scrollY
- id="scrollView"
- style={{
- flex: 1,
- height: "1px", // 高度自适应
- }}
- scrollTop={scrollTop}
- scrollWithAnimation
- onScrollToUpper={onScrollToUpper}
- onScrollToLower={handleScrollToLower}
- >
- <View
- id="messageList"
- className="flex flex-col gap-16 px-18"
- onTouchMove={handleTouchMove}
- >
- {showWelcome && <ChatGreeting agent={agent} chatInputActions={chatInputActions} />}
- {groupedMessages.map((group, groupIndex) => {
- return (
- <View key={groupIndex} className="flex flex-col gap-16">
- <View
- className={`text-12 leading-20 block text-center w-full ${
- haveBg
- ? "text-white-70"
- : "text-black-25"
- }`}
- >
- {formatMessageTime(group.dt)}
- </View>
- {group.list.map((message) => {
- const reasoningContent =
- (message as any).reasoningContent || "";
- return (
- <ChatMessage
- key={message.msgUk}
- textReasoning={reasoningContent}
- agent={agent}
- role={message.role}
- text={message.content}
- message={message}
- mutate={mutate as any}
- />
- );
- })}
- </View>
- );
- })}
- </View>
- <View className="pb-40 pt-8">
- {agent && (
- <RecommendQuestions
- enableOutputAudioStream={streamVoiceEnable}
- agent={agent}
- chatInputActions={chatInputActions}
- />
- )}
- </View>
- </ScrollView>
- <View
- className="w-full h-60"
- style={{
- height: inputContainerHeight,
- }}
- ></View>
- {/* ${keyboardHeight <= 0 ? 'transition-[bottom] delay-300' : ''} */}
- <View
- className={`bottom-bar px-16 pt-12 z-50`}
- id="inputContainer"
- style={{
- bottom: `${keyboardHeight + inputContainerBottomOffset}px`,
- }}
- >
- <View className="bg-[#F5FAFF]">
- {agent && (
- <View className="flex flex-col w-full gap-8">
- <InputBar
- enableOutputAudioStream={streamVoiceEnable}
- agent={agent}
- // histories={historyList}
- setShowWelcome={setShowWelcome}
- chatInputActions={chatInputActions}
- isVoice={isVoice}
- setIsVoice={setIsVoice}
- disabled={disabled}
- />
- <View>
- <ButtonEnableStreamVoice
- setEnable={setStreamVoiceEnable}
- enable={streamVoiceEnable}
- />
- </View>
- </View>
- )}
- </View>
- </View>
- </View>
- </PageCustom>
- );
- }
|