Ver código fonte

feat: 个人智能体允许修改企业名与职位

王晓东 2 semanas atrás
pai
commit
d0e456a592

+ 1 - 1
project.config.json

@@ -17,7 +17,7 @@
     }
   },
   "compileType": "miniprogram",
-  "libVersion": "3.6.0",
+  "libVersion": "3.8.10",
   "srcMiniprogramRoot": "dist/",
   "packOptions": {
     "ignore": [],

+ 1 - 0
src/app.config.ts

@@ -36,6 +36,7 @@ export default defineAppConfig({
     'pages/editor-pages/editor-email/index',
     'pages/editor-pages/editor-address/index',
     'pages/editor-pages/editor-qrcode/index',
+    'pages/editor-pages/editor-ent-name/index',
 
 
     

+ 72 - 54
src/components/KnowledgeList/index.tsx

@@ -2,74 +2,83 @@ import { ScrollView, View, Image } from "@tarojs/components";
 
 import FigureList from "@/components/list/FigureList";
 import FigureListItem from "@/components/list/FigureListItem";
-import { useEffect } from "react";
 import WemetaRadio from "@/components/WemetaRadio/index";
 
-import IconFIleLink from "@/components/icon/IconFileLink"
-
+import IconFIleLink from "@/components/icon/IconFileLink";
 
 import { useKnowledge } from "./knowledge";
 import type { TKnowledgeItem } from "@/types/knowledge";
 import { EKnowlegeTypes } from "@/consts/enum";
+import { useDidShow } from "@tarojs/taro";
+import { useEffect } from "react";
+
+import EmptyData from "../empty-data";
 export interface IProps {
   multi?: boolean; // 是否多选
   types?: EKnowlegeTypes[]; // 列表类型
-  entId?: string|number;// 企业id
-  onChange: (value: TKnowledgeItem[]) => void 
+  entId?: string | number; // 企业id
+  onChange: (value: TKnowledgeItem[]) => void;
 }
-const Index = ({ types, multi,  entId, onChange }: IProps) => {
-  const {
-    list,
-    scrollTop,
-    checkedValue,
-    loadMore,
-    initLoad,
-    setCheckedValue,
-  } = useKnowledge({ types: types, entId });
+const Index = ({ types, multi, entId, onChange }: IProps) => {
+  const { list, checkedValue, initLoad, setCheckedValue, loadMore } =
+    useKnowledge({ types: types, entId });
 
   const onScrollToLower = async () => {
     loadMore();
   };
 
+  useDidShow(() => {
+    loadMore();
+  });
+
   useEffect(() => {
     initLoad();
-  }, [])
+  }, [entId]);
 
   const handleClick = (item: TKnowledgeItem) => {
-    let results:TKnowledgeItem[] = [];
+    let results: TKnowledgeItem[] = [];
     // 单选
-    if(!multi){
-      const found = checkedValue.find( _item => _item.knowledgeId === item.knowledgeId)
-      if(found){
-        setCheckedValue(results)
-        onChange(results)
+    if (!multi) {
+      const found = checkedValue.find(
+        (_item) => _item.knowledgeId === item.knowledgeId
+      );
+      if (found) {
+        setCheckedValue(results);
+        onChange(results);
         return;
-      }  
-      results = [item]
-      setCheckedValue(results)
-      onChange(results)
+      }
+      results = [item];
+      setCheckedValue(results);
+      onChange(results);
       return;
     }
 
     // 多选
-    const found = checkedValue.find( _item => _item.knowledgeId === item.knowledgeId)
-    if(found){
-      results = checkedValue.filter(_item => _item.knowledgeId != item.knowledgeId)
-      setCheckedValue(results)
-      onChange(results)
+    const found = checkedValue.find(
+      (_item) => _item.knowledgeId === item.knowledgeId
+    );
+    if (found) {
+      results = checkedValue.filter(
+        (_item) => _item.knowledgeId != item.knowledgeId
+      );
+      setCheckedValue(results);
+      onChange(results);
       return;
     }
-    results = [...checkedValue, item]
-    setCheckedValue(results)
-    onChange(results)
+    results = [...checkedValue, item];
+    setCheckedValue(results);
+    onChange(results);
   };
   const rightRenderer = (item: TKnowledgeItem) => {
-    
     return (
       <View className="flex items-center">
         <WemetaRadio
           checkbox
-          checked={!!checkedValue.find(_item =>  _item.knowledgeId === item.knowledgeId)}
+          checked={
+            !!checkedValue.find(
+              (_item) => _item.knowledgeId === item.knowledgeId
+            )
+          }
         ></WemetaRadio>
       </View>
     );
@@ -79,32 +88,41 @@ const Index = ({ types, multi,  entId, onChange }: IProps) => {
     <ScrollView
       scrollY
       onScrollToLower={onScrollToLower}
-      scrollTop={scrollTop}
       style={{
         flex: 1,
         height: "100%", // 高度自适应
       }}
     >
       <FigureList>
-      
-        {list.map((item) => {
-          return (
-            <FigureListItem
-              figure={()=> <IconFIleLink />}
-              underline
-              onClick={() => handleClick(item)}
-              rightRenderer={() => rightRenderer(item)}
-            >
-              <View className="flex flex-col flex-1 gap-2 w-full overflow-hidden">
-                <View className="text-14 leading-22 truncate">{item.title}</View>
-                <View className="text-12 leading-20 text-gray-45">
-                
-                  {item.createTime} | {item.fileSizeStr}
-                </View>
+        <>
+          {!list.length && (
+            <EmptyData type={"plane"}>
+              <View className="text-gray-45">
+                <View>暂无数据</View>
+                <View>可在电脑端管理知识库</View>
               </View>
-            </FigureListItem>
-          );
-        })}
+            </EmptyData>
+          )}
+          {list.map((item) => {
+            return (
+              <FigureListItem
+                figure={() => <IconFIleLink />}
+                underline
+                onClick={() => handleClick(item)}
+                rightRenderer={() => rightRenderer(item)}
+              >
+                <View className="flex flex-col flex-1 gap-2 w-full overflow-hidden">
+                  <View className="text-14 leading-22 truncate">
+                    {item.title}
+                  </View>
+                  <View className="text-12 leading-20 text-gray-45">
+                    {item.createTime} | {item.fileSizeStr}
+                  </View>
+                </View>
+              </FigureListItem>
+            );
+          })}
+        </>
       </FigureList>
     </ScrollView>
   );

+ 24 - 56
src/components/KnowledgeList/knowledge.ts

@@ -6,86 +6,54 @@ import {
   getKnowledgeList,
 } from "@/service/knowledge";
 import { EKnowlegeTypes } from "@/consts/enum";
-
+import { useLoadMoreInfinite, createKey } from "@/utils/loadMoreInfinite";
 export interface UseKnowledgeHook {
-  scrollTop: number;
-  totalCount: number;
+  
   list: TKnowledgeItem[];
   isLoading: boolean;
-  startId?: string;
   checkedValue: TKnowledgeItem[],
   listTypes?: EKnowlegeTypes[];
-  loadMore: (force?: boolean) => Promise<void>;
-  initLoad: () => Promise<void>;
+  loadMore: () => void;
+  initLoad: () => void;
   setListTypes: (types: EKnowlegeTypes[]) => void;
   setCheckedValue: React.Dispatch<React.SetStateAction<TKnowledgeItem[]>>;
 }
 
 export function useKnowledge({entId, types = []}: {entId?: string|number, types?: EKnowlegeTypes[]}): UseKnowledgeHook {
-  const req = entId ? getEntKnowledgeList : getKnowledgeList
-  const [scrollTop, setScrollTop] = useState(9999);
-  const [totalCount, setTotalCount] = useState(10000);
-  const [list, setList] = useState<TKnowledgeItem[]>([]);
-  const [isLoading, setIsLoading] = useState(false);
-  const [startId, setStartId] = useState<string | undefined>(undefined);
+  
+  const fetcher = async ([url, {nextId, pageSize}])=> {
+    if(entId !== undefined){
+      const response = await getEntKnowledgeList({startId: nextId, entId, types, pageSize })
+      return response.data
+    }
+    const response = await getKnowledgeList({startId: nextId, types, pageSize })
+    return response.data
+  }
+
+  const {list, isLoading, loadMore, mutate} = useLoadMoreInfinite<TKnowledgeItem[]>(
+    createKey(`${entId ? getEntKnowledgeList : getKnowledgeList}`),
+    fetcher
+  )
   const [listTypes, setListTypesState] = useState<EKnowlegeTypes[]>(types);
   const [checkedValue, setCheckedValue] = useState<TKnowledgeItem[]>([]);
 
-  const loadMore = useCallback(async (force?: boolean) => {
-    if (!force && (list.length >= totalCount || isLoading)) {
-      return;
-    }
-    setIsLoading(true);
-    try {
-      const params = entId ? ({
-        startId,
-        pageSize: 10,
-        types: listTypes,
-        entId: entId,
-      }) : ({
-        startId,
-        pageSize: 10,
-        types: listTypes,
-      })
-      const response = await req(params);
-      const result = isSuccess(response.status);
-      if (result) {
-        // 提取所有 TKnowledgeItem
-        const newData = [...list, ...response.data.data ?? []];
-        setList(newData);
-        setStartId(response.data.nextId);
-        setTotalCount(response.data.totalCount ?? 0);
-      }
-    } finally {
-      setIsLoading(false);
-      setScrollTop((prev) => prev + 1);
-    }
-  }, [list, totalCount, isLoading, startId]);
-
-  const initLoad = useCallback(async () => {
-    setList([]);
-    setStartId(undefined);
-    setTotalCount(9999);
-    setIsLoading(false);
-    // eslint-disable-next-line no-console
-    console.log("initLoad");
-    await loadMore();
-  }, [loadMore]);
+  const initLoad = ()=> {
+    mutate(undefined, {revalidate: true})
+    setCheckedValue([])
+    setListTypesState([])
+  }
 
   const setListTypes = useCallback((types: EKnowlegeTypes[]) => {
     setListTypesState(types);
   }, []);
 
   return {
-    scrollTop,
-    totalCount,
     list,
     isLoading,
-    startId,
     listTypes,
     checkedValue,
-    loadMore,
     initLoad,
+    loadMore,
     setListTypes,
     setCheckedValue,
   };

+ 12 - 11
src/components/KnowledgePicker/index.tsx

@@ -12,6 +12,7 @@ import IconArrowDownRounded from "@/components/icon/IconArrowDownRounded";
 import Taro from "@tarojs/taro";
 import { useUserStore } from "@/store/userStore";
 import { TKnowledgeItem } from "@/types/knowledge";
+import { TEntItem } from "@/types/user";
 export interface IProps {
   show: boolean;
   multi?: boolean; // 是否多选
@@ -19,18 +20,16 @@ export interface IProps {
   setShow: (show: boolean) => void;
   onPicked: (picked?: TKnowledgeItem[]) => void
 }
-type TEnt = { entId: string | number; entName: string };
+
 export default function Index({ show, setShow, multi, types, onPicked }: IProps) {
   const entList = useUserStore((state) => state.entList);
-  const [ent, setEnt] = useState<TEnt>();
+  const [ent, setEnt] = useState<TEntItem>();
   const [picked, setPicked] = useState<TKnowledgeItem[]>();
 
   
 
   // 如果没有当前企业,则默认第一个
-  if (!ent) {
-    setEnt(entList[0]);
-  }
+  
 
   // 当前选中的值
   const options = entList.map((item) => item.entName);
@@ -58,15 +57,17 @@ export default function Index({ show, setShow, multi, types, onPicked }: IProps)
     setShow(false)
   };
 
+  useEffect(()=> {
+    if(!ent){
+      setEnt(entList[0])
+      setSelected(entList[0].entName)
+    }
+  }, [entList])
+
   const renderEntContent = () => {
     if (!entList.length) {
       return (
         <View className={style.dataEmpty}>
-          {/* <Image
-                showMenuByLongpress
-                src="https://nexthuman.cn/api-web/img/wechat.9d5eaf4d.jpg"
-                style={{ width: "160px", height: "160px" }}
-              /> */}
           <View className="pt-20 text-center">
             <View className="leading-24 text-black font-medium text-16 mb-4">
               你还没有加入任何企业
@@ -94,7 +95,7 @@ export default function Index({ show, setShow, multi, types, onPicked }: IProps)
         <PickerSingleColumn
           options={options}
           selected={selected}
-          onChange={handleChange}
+          onPicked={handleChange}
           showPicker={showPicker}
           setShowPicker={setShowPicker}
         >

+ 7 - 4
src/components/buttons/ButtonMain.tsx

@@ -1,17 +1,20 @@
 import { View } from "@tarojs/components";
 
 interface IProps {
-  onClick: ()=> {}
+  onClick?: ()=> void
   disabled?: boolean
+  className?: string
+  type?: 'main'|'normal'
   children: JSX.Element|JSX.Element[]|string
 }
-export default function ButtonMain({ onClick, disabled = false, children }:IProps) {
+export default function ButtonMain({ onClick, type = 'main', disabled = false, className='', children }:IProps) {
+  const typeClass = type === 'main'? 'button-primary' : ''
   const handleClick = ()=> {
     if(!disabled){
-      onClick()
+      onClick && onClick()
     }
   }
   return (
-    <View className={`button-rounded button-primary flex-1 ${disabled ? 'opacity-50': ''}`} onClick={handleClick}>{children}</View>
+    <View className={`button-rounded ${typeClass} ${disabled ? 'opacity-50': ''} ${className}`} onClick={handleClick}>{children}</View>
   );
 }

+ 2 - 3
src/components/chat-message/index.tsx

@@ -9,13 +9,12 @@ interface Props {
   text: string
   textReasoning?: string
   message: TMessage
-  mutate: (data?: any, options?: { revalidate?: boolean } ) => void
 }
-export default ({agent, text, role, message, mutate, textReasoning=''}:Props) => {
+export default ({agent, text, role, message, textReasoning=''}:Props) => {
   if(role === EChatRole.User ){
     return <Message text={text}/>
   }
-  return <MessageRobot mutate={mutate} message={message} textReasoning={textReasoning} text={text} agent={agent}/>
+  return <MessageRobot message={message} textReasoning={textReasoning} text={text} agent={agent}/>
 }
 
 

+ 0 - 101
src/pages/agent-gen/components/step/GenAvatarVideo.tsx

@@ -1,101 +0,0 @@
-import { View, Image } from "@tarojs/components";
-import React, { useEffect, useState } from "react";
-import style from "./index.module.less";
-import IconStarColor from "@/components/icon/icon-star-color";
-import useSWR from 'swr';
-import Taro from "@tarojs/taro";
-interface IProps {
-  prev: () => void;
-  next: () => void;
-  setPickedAvatar: (pickedAvatar: TAvatarItem)=> void
-  taskId: string|number
-}
-export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }: IProps) {
-  const [currentSwiperIndex, setCurrentSwiperIndex] = useState(0);
-  const [avatars, setAvatars] = useState<TAvatarItem[]>([]);
-  const [shouldPoll, setShouldPoll] = useState(false);
-  
-  
-  const goNext = () => {
-    const pickedAvatar = avatars[currentSwiperIndex]
-    setPickedAvatar(pickedAvatar)
-    console.log(pickedAvatar)
-    next()
-  }
-  
-  Taro.hideLoading()
-
-  const { data } = useSWR(
-    shouldPoll ? `genAvatarVideo${taskId}` : null,
-    ()=> getUploadedAvatarStatus(taskId),
-    {
-      revalidateOnFocus: false,
-      refreshInterval: shouldPoll ? 3000 : 0,
-      refreshWhenHidden: false,
-      refreshWhenOffline: false,
-      revalidateOnMount: false
-    }
-  );
-
-  useEffect(() => {
-    setShouldPoll(true);
-    return () => {
-      setShouldPoll(false);
-    };
-  }, []);
-
-  useEffect(()=> {
-    if(data?.data.status === 'success'){
-      setAvatars(data.data?.data.reverse())
-      setShouldPoll(false);
-    }
-    if(data?.data.status === 'process_fail'){
-      setShouldPoll(false);
-    }
-    return ()=> {
-      
-    }
-  }, [data])
-
-
-  const genVideo = () => {
-
-  }
-
-  const renderProgressStatus = () => {
-    if(data?.data.status === 'process_fail'){
-      return <View className="gradient-text">AI生成失败</View>
-    }
-    if(data?.data.status === 'success'){
-      return <View className="gradient-text">AI生成成功</View>
-    }
-    return <View className="text-gray-500">AI生中</View>
-  }
-
-
-  
-
-  return (
-    <View>
-      <View className={style.pickContainer}>
-        <View className={`${style.pickAvatarCard} ${style.pickGenCard}`}>
-          <View className="flex items-center gap-4">
-            <IconStarColor></IconStarColor>{" "}
-            {renderProgressStatus()}
-          </View>
-        </View>
-      </View>
-
-      <View className="bottom-bar">
-        <View className="grid grid-cols-2 gap-8 px-20 py-12">
-          <View className={`button-rounded`} onClick={prev}>
-            上一步
-          </View>
-          <View className={`button-rounded primary ${avatars.length ? '' : 'opacity-20'}`} onClick={()=> goNext()}>
-            使用这张
-          </View>
-        </View>
-      </View>
-    </View>
-  );
-});

+ 47 - 22
src/pages/agent-gen/components/step/StepPick.tsx

@@ -7,28 +7,48 @@ import { getUploadedAvatarStatus, genAvatarVideo, type TAvatarItem } from '@/ser
 import useSWR from 'swr';
 import Taro from "@tarojs/taro";
 import { isSuccess } from "@/utils";
+import ButtonMain from '@/components/buttons/ButtonMain'
 interface IProps {
   prev: () => void;
   next: () => void;
   setPickedAvatar: (pickedAvatar: TAvatarItem)=> void
+  avatars: TAvatarItem[],
+  videos: TAvatarItem[],
+  setAvatars: (avatars: TAvatarItem[])=> void
+  setVideos: (avatars: TAvatarItem[])=> void
   taskId: string|number
 }
-export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }: IProps) {
+export default React.memo(function Index({ prev, next, taskId, avatars, videos, setVideos, setAvatars, setPickedAvatar }: IProps) {
   const [currentSwiperIndex, setCurrentSwiperIndex] = useState(0);
-  const [avatars, setAvatars] = useState<TAvatarItem[]>([]);
   const [shouldPoll, setShouldPoll] = useState(false);
-  const [videoGen, setVideoGen] = useState(false);
+  const [videoGenerating, setVideoGenerating] = useState(false);
   const [currentTaskId, setCurrentTaskId] = useState<string|number>(taskId);
+
+  const avatarsList = (videoGenerating) ? videos : avatars
   
   const goNext = () => {
-    const pickedAvatar = avatars[currentSwiperIndex]
+    const pickedAvatar = avatarsList[currentSwiperIndex]
+    console.log(avatarsList, currentSwiperIndex, 11111, pickedAvatar)
     setPickedAvatar(pickedAvatar)
     console.log(pickedAvatar)
     next()
   }
+
+  const handlePrev = () => {
+    // 如果是生成微视频后,点击的上一步,则退回到生成微视频前
+    if(videoGenerating){
+      setVideoGenerating(false)
+      setVideos([])
+    }else{
+      setShouldPoll(false);
+      // 否则退回到生成 ai 图片的第一步
+      prev()
+    }
+  }
   
   Taro.hideLoading()
 
+  // 隔 3 秒轮询生成微视频任务
   const { data, mutate } = useSWR(
     shouldPoll ? `getUploadedAvatarStatus${currentTaskId}` : null,
     ()=> getUploadedAvatarStatus(currentTaskId),
@@ -50,7 +70,12 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
 
   useEffect(()=> {
     if(data?.data.status === 'success'){
-      setAvatars(data.data?.data.reverse())
+      const results = data.data?.data
+      if(videoGenerating){
+        setVideos(results)
+      }else{
+        setAvatars(results)
+      }
       setShouldPoll(false);
     }
     if(data?.data.status === 'process_fail'){
@@ -61,6 +86,10 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
     }
   }, [data])
 
+  useEffect(()=> {
+    setShouldPoll(true);
+  }, [taskId])
+
 
   const genVideo = async () => {
     const a  = avatars[currentSwiperIndex]
@@ -68,10 +97,12 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
       return 
     }
     const avatarUrl = a.avatarUrl
-    setVideoGen(true)
+    setVideoGenerating(true)
     // 清空 useSWR 缓存
     mutate(undefined, false); 
-    setAvatars([]);
+    // 清空上一次可能生成的 videos
+    setVideos([])
+    setCurrentSwiperIndex(0)
     const response = await genAvatarVideo({avatarUrl})
     if(isSuccess(response.status)){
       setCurrentTaskId(response.data.taskId)
@@ -82,6 +113,7 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
 
   const onSwiperChange = (e: any) => {
     const i = e.detail.current;
+    console.log(i)
     setCurrentSwiperIndex(i);
   };  
 
@@ -90,7 +122,7 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
       return (
         <>
           <View className={style.indicatorContainer}>
-            {avatars.map((_item, index) => {
+            {avatarsList.map((_item, index) => {
               return (
                 <View
                   key={index}
@@ -119,7 +151,7 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
           current={currentSwiperIndex}
           onChange={(e) => onSwiperChange(e)}
         >
-          {avatars.map(avatar => {
+          {avatarsList.map(avatar => {
             return <SwiperItem>
               <View className={style.swiperItem}>
                 <AvatarMedia source={avatar.avatarUrl} className="w-full h-full" />
@@ -143,8 +175,7 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
   
   
   const renderProcessingStatus = () => {
-    const targetText = !videoGen ? 'AI' : '视频'
-      
+    const targetText = !videoGenerating ? 'AI' : '视频'
     if(data?.data.status === 'process_fail'){
       return <View className="gradient-text">{`${targetText}生成失败`}</View>
     }
@@ -155,7 +186,7 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
   }
 
   const renderContent = ()=> {
-    if(avatars.length){
+    if((avatars.length && !videoGenerating) || (videos.length)){
       
       return renderSwipers()
     }
@@ -177,16 +208,10 @@ export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }
       </View>
 
       <View className="bottom-bar">
-        <View className="grid grid-cols-3 gap-8 px-20 py-12">
-          <View className={`button-rounded`} onClick={prev}>
-            上一步
-          </View>
-          <View className={`button-rounded ${avatars.length ? '' : 'opacity-20'}`} onClick={genVideo}>
-            生成微视频
-          </View>
-          <View className={`button-rounded primary ${avatars.length ? '' : 'opacity-20'}`} onClick={()=> goNext()}>
-            使用这张
-          </View>
+        <View className="flex items-center gap-8 px-20 py-12">
+          <ButtonMain type="normal" disabled={videoGenerating && !videos.length}  className="w-[76px]" onClick={handlePrev}>上一步</ButtonMain>
+          {!videoGenerating &&  <ButtonMain className="flex-1" type="normal" onClick={genVideo} disabled={!avatars.length} >生成微视频</ButtonMain> }
+          <ButtonMain className="flex-1" onClick={goNext} disabled={(!avatars.length && !videoGenerating) || (videoGenerating && !videos.length )} >使用这张</ButtonMain>
         </View>
       </View>
     </View>

+ 12 - 2
src/pages/agent-gen/index.tsx

@@ -14,23 +14,33 @@ export default function Index() {
   const [state, setState] = useState<TStep>('start')
   const [taskId, setTaskId] = useState<string>()
   const [pickedAvatar, setPickedAvatar] = useState<TAvatarItem>()
+  const [avatars, setAvatars] = useState<TAvatarItem[]>([]);
+  const [videos, setVideos] = useState<TAvatarItem[]>([]);
   
   const getClassName = useCallback((_state: TStep) => {
     return state === _state ? 'block': 'hidden'
   }, [state]);
-
+  const handleStartNext = ()=> {
+    setAvatars([])
+    setVideos([])
+    setState('pick')
+  }
   return (
     <PageCustom>
       <NavBarNormal backText="形象照"></NavBarNormal>
       <View className="px-16 w-full flex flex-col gap-20">
         {/* 第一步开始 */}
         <View className={getClassName('start')}>
-          <StepStart next={()=> setState('pick')} setTaskId={setTaskId}/>
+          <StepStart next={()=> handleStartNext()} setTaskId={setTaskId}/>
         </View>
         {/* 第二步 生成多个形象提供用户选择 */}
         <View className={getClassName('pick')}>
         {taskId &&  <StepPick 
             taskId={taskId}
+            setAvatars={setAvatars}
+            avatars={avatars}
+            videos={videos}
+            setVideos={setVideos}
             setPickedAvatar={setPickedAvatar}
             prev={()=> setState('start')} 
             next={()=> setState('confirm')} 

+ 52 - 0
src/pages/chat/components/RecommendQuestions/index.tsx

@@ -0,0 +1,52 @@
+import { View, ScrollView } from "@tarojs/components";
+
+import { useChatInput } from "../input-bar/chatInput";
+import { TAgentDetail } from "@/types/agent";
+
+interface IProps {
+  agent: TAgentDetail;
+}
+
+export default function Index({ agent }: IProps) {
+  const { handleOnSend, setQuestions, questions } = useChatInput({
+    agent,
+  });
+
+  const handleClick = (q: string) => {
+    handleOnSend(q);
+    setQuestions([]);
+  };
+
+  if (!questions.length) {
+    return <></>;
+  }
+
+  return (
+    <ScrollView scrollX>
+      <View className="flex items-center gap-8 pl-18">
+        {questions.map((q, index) => {
+          if (index < questions.length - 1) {
+            return (
+              <View
+                onClick={() => handleClick(q)}
+                className="px-12 py-4 text-[#777E95] leading-22 bg-white whitespace-nowrap rounded-10"
+              >
+                {q}
+              </View>
+            );
+          }
+          return (
+            <View className="pr-18">
+              <View
+                onClick={() => handleClick(q)}
+                className="px-12 py-4 text-[#777E95] leading-22 bg-white whitespace-nowrap rounded-10"
+              >
+                {q}
+              </View>
+            </View>
+          );
+        })}
+      </View>
+    </ScrollView>
+  );
+}

+ 199 - 0
src/pages/chat/components/input-bar/chatInput.ts

@@ -0,0 +1,199 @@
+import { useState } from "react";
+import TextInputBar from "./TextInputBar";
+import VoiceInputBar from "./VoiceInputBar";
+import { textChat } from "@/service/bot";
+import { TMessage,TRobotMessage, useTextChat } from "@/store/textChat";
+import { TAgentDetail } from "@/types/agent";
+import { delay, getLoginId, isSuccess } from "@/utils";
+import { EAI_MODEL } from "@/consts/enum";
+import { useUnload } from "@tarojs/taro";
+import { EChatRole, EContentType } from "@/types/bot";
+
+import { saveMessageToServer } from './message'
+
+import { getRecommendPrompt } from "@/service/bot"
+
+
+interface Props {
+  agent: TAgentDetail | null;
+  setShowWelcome?: (b: boolean) => void;
+  setIsVoice?: (b: boolean) => void;
+  setDisabled?: (b: boolean) => void;
+}
+
+let stopReceiveChunk: (() => void) | undefined;
+export const useChatInput = ({ agent, setShowWelcome, setDisabled, }: Props) => {
+  const {
+    pushRobotMessage,
+    updateRobotMessage,
+    getCurrentRobotMessage,
+    updateRobotReasoningMessage,
+    pushMessage,
+    updateMessage,
+    deleteMessage,
+    setQuestions,
+    questions,
+  } = useTextChat();
+  
+  let myMsgUk = '';
+  let mySessionId = '';
+
+
+  const chatWithGpt = async (message: string, sessionId: string, msgUk: string) => {
+    setShowWelcome?.(false)
+    let currentRobotMsgUk = "";
+    await delay(300);
+    setDisabled?.(true);
+    if (!agent?.agentId) {
+      return;
+    }
+    const loginId = getLoginId();
+    if (!loginId) {
+      return;
+    }
+
+    // const greeting = "欢迎光临我的智能体,你想问什么?";
+    // {
+    //   content: greeting,
+    //   contentType: EContentType.TextPlain,
+    //   role: EChatRole.System,
+    // },
+    
+    const newMsg = {
+      content: message,
+      contentType: EContentType.TextPlain,
+      role: EChatRole.User,
+    }
+    
+    saveMessageToServer({
+      loginId,
+      messages: [{
+        ...newMsg,
+        isStreaming: false,
+        msgUk,
+      }],
+      agentId: agent.agentId,
+      sessionId,
+    })
+
+    // 发起文本聊天
+    stopReceiveChunk = textChat({
+      params: {
+        agentId: agent.agentId,
+        isEnableOutputAudioStream: false,
+        isEnableSearch: false,
+        isEnableThinking: false,
+        loginId,
+        messages: [newMsg],
+        sessionId,
+      },
+      onStart: () => {
+        currentRobotMsgUk = pushRobotMessage({
+          role: EChatRole.Assistant,
+          saveStatus: 2,
+          content: "",
+          reasoningContent: "",
+          robot: {
+            avatar: agent?.avatarUrl ?? "",
+            name: agent?.name ?? "",
+            agentId: agent?.agentId ?? "",
+          },
+        });
+      },
+      onReceived: (m) => {
+        console.log("received:", m);
+        if (m.reasoningContent) {
+          updateRobotReasoningMessage(
+            m.reasoningContent,
+            currentRobotMsgUk
+          );
+        } else {
+          updateRobotMessage(m.content);
+        }
+      },
+      onFinished: async () => {
+        console.log("回复完毕 ok");
+        const currentRobotMessage = getCurrentRobotMessage();
+        console.log(currentRobotMessage,333)
+        if(!agent.agentId){
+          return
+        }
+        setDisabled?.(false);
+        // 如果没有任何回答,则显示
+        if (!currentRobotMessage?.content?.length) {
+          updateRobotMessage("服务器繁忙...");
+          return 
+        }
+
+        // 将智能体的回答保存至服务器
+        await saveMessageToServer({
+          loginId,
+          messages: [{
+            content: currentRobotMessage.content,
+            contentType: EContentType.TextPlain,
+            isStreaming: false,
+            role: currentRobotMessage.role,
+            msgUk: currentRobotMessage.msgUk,
+          }],
+          agentId: agent.agentId,
+          sessionId,
+        })
+        
+        const response = await getRecommendPrompt({
+          agentId: agent.agentId,
+          sessionId,
+        })
+
+        if(isSuccess(response.status)){
+          console.log(response.data.questions, 444)
+          setQuestions(response.data.questions)
+        }
+
+      },
+      onError: () => {
+        deleteMessage(currentRobotMsgUk);
+        setDisabled?.(false);
+      },
+    });
+  };
+  const handleVoiceSend = (message: string) => {
+    updateMessage(message, myMsgUk);
+    chatWithGpt(message, mySessionId, myMsgUk);
+  };
+  const handleOnSend = async (message: string) => {
+    if(!agent?.agentId){
+      return
+    }
+    const {sessionId, msgUk} = pushMessage(message);
+    chatWithGpt(message, sessionId, msgUk);
+  };
+
+  // 推一个自己的空气泡框
+  const handleBeforeSend = () => {
+    if(!agent?.agentId){
+      return
+    }
+    const {sessionId, msgUk} = pushMessage("");
+    myMsgUk = msgUk
+    mySessionId = sessionId
+  };
+
+  // 发生主意识别错误时,删除当前自己发出的气泡框
+  const handleVoiceError = () => {
+    deleteMessage(myMsgUk);
+  };
+
+  useUnload(() => {
+    if (stopReceiveChunk) {
+      stopReceiveChunk();
+    }
+  });
+  return {
+    setQuestions,
+    handleVoiceSend,
+    handleOnSend,
+    questions,
+    handleBeforeSend,
+    handleVoiceError,
+  }
+}

+ 9 - 169
src/pages/chat/components/input-bar/index.tsx

@@ -1,17 +1,12 @@
 import { useState } from "react";
 import TextInputBar from "./TextInputBar";
 import VoiceInputBar from "./VoiceInputBar";
-import { textChat } from "@/service/bot";
 import { TMessage,TRobotMessage, useTextChat } from "@/store/textChat";
 import { TAgentDetail } from "@/types/agent";
-import { delay, getLoginId, isSuccess } from "@/utils";
 import { EAI_MODEL } from "@/consts/enum";
-import { useUnload } from "@tarojs/taro";
-import { EChatRole, EContentType } from "@/types/bot";
 
-import { saveMessageToServer } from './message'
 
-import { getRecommendPrompt } from "@/service/bot"
+import { useChatInput } from './chatInput'
 
 
 interface Props {
@@ -21,22 +16,15 @@ interface Props {
   setShowWelcome: (b: boolean) => void;
 }
 
-let stopReceiveChunk: (() => void) | undefined;
-export default ({ agent, setShowWelcome, histories }: Props) => {
+export default ({ agent, setShowWelcome }: Props) => {
   const [isVoice, setIsVoice] = useState(false);
   const [disabled, setDisabled] = useState(false);
-  const {
-    pushRobotMessage,
-    updateRobotMessage,
-    getCurrentRobotMessage,
-    updateRobotReasoningMessage,
-    pushMessage,
-    updateMessage,
-    deleteMessage,
-  } = useTextChat();
-  
-  let myMsgUk = '';
-  let mySessionId = '';
+  const {handleBeforeSend, handleVoiceError, handleVoiceSend, handleOnSend} = useChatInput({
+    agent,
+    setShowWelcome,
+    setIsVoice,
+    setDisabled,
+  })
 
   const handleTextInputBarSwitch = () => {
     console.log("voice input on");
@@ -46,155 +34,7 @@ export default ({ agent, setShowWelcome, histories }: Props) => {
     console.log("voice input off");
     setIsVoice(false);
   };
-
-  const chatWithGpt = async (message: string, sessionId: string, msgUk: string) => {
-    setShowWelcome(false)
-    let currentRobotMsgUk = "";
-    await delay(300);
-    setDisabled(true);
-    if (!agent?.agentId) {
-      return;
-    }
-    const loginId = getLoginId();
-    if (!loginId) {
-      return;
-    }
-
-    // const greeting = "欢迎光临我的智能体,你想问什么?";
-    // {
-    //   content: greeting,
-    //   contentType: EContentType.TextPlain,
-    //   role: EChatRole.System,
-    // },
-    
-    const newMsg = {
-      content: message,
-      contentType: EContentType.TextPlain,
-      role: EChatRole.User,
-    }
-    
-    saveMessageToServer({
-      loginId,
-      messages: [{
-        ...newMsg,
-        isStreaming: false,
-        msgUk,
-      }],
-      agentId: agent.agentId,
-      sessionId,
-    })
-
-    // 发起文本聊天
-    stopReceiveChunk = textChat({
-      params: {
-        agentId: agent.agentId,
-        isEnableOutputAudioStream: false,
-        isEnableSearch: false,
-        isEnableThinking: false,
-        loginId,
-        messages: [newMsg],
-        sessionId,
-      },
-      onStart: () => {
-        currentRobotMsgUk = pushRobotMessage({
-          role: EChatRole.Assistant,
-          saveStatus: 2,
-          content: "",
-          reasoningContent: "",
-          robot: {
-            avatar: agent?.avatarUrl ?? "",
-            name: agent?.name ?? "",
-            agentId: agent?.agentId ?? "",
-          },
-        });
-      },
-      onReceived: (m) => {
-        console.log("received:", m);
-        if (m.reasoningContent) {
-          updateRobotReasoningMessage(
-            m.reasoningContent,
-            currentRobotMsgUk
-          );
-        } else {
-          updateRobotMessage(m.content);
-        }
-      },
-      onFinished: async () => {
-        console.log("回复完毕 ok");
-        const currentRobotMessage = getCurrentRobotMessage();
-        console.log(currentRobotMessage,333)
-        if(!agent.agentId){
-          return
-        }
-        setDisabled(false);
-        // 如果没有任何回答,则显示
-        if (!currentRobotMessage?.content?.length) {
-          updateRobotMessage("服务器繁忙...");
-          return 
-        }
-
-        // 将智能体的回答保存至服务器
-        await saveMessageToServer({
-          loginId,
-          messages: [{
-            content: currentRobotMessage.content,
-            contentType: EContentType.TextPlain,
-            isStreaming: false,
-            role: currentRobotMessage.role,
-            msgUk: currentRobotMessage.msgUk,
-          }],
-          agentId: agent.agentId,
-          sessionId,
-        })
-        
-        const response = await getRecommendPrompt({
-          agentId: agent.agentId,
-          sessionId,
-        })
-
-        if(isSuccess(response.status)){
-          console.log(response.data.questions)
-        }
-
-      },
-      onError: () => {
-        deleteMessage(currentRobotMsgUk);
-        setDisabled(false);
-      },
-    });
-  };
-  const handleVoiceSend = (message: string) => {
-    updateMessage(message, myMsgUk);
-    chatWithGpt(message, mySessionId, myMsgUk);
-  };
-  const handleOnSend = async (message: string) => {
-    if(!agent?.agentId){
-      return
-    }
-    const {sessionId, msgUk} = pushMessage(message);
-    chatWithGpt(message, sessionId, msgUk);
-  };
-
-  // 推一个自己的空气泡框
-  const handleBeforeSend = () => {
-    if(!agent?.agentId){
-      return
-    }
-    const {sessionId, msgUk} = pushMessage("");
-    myMsgUk = msgUk
-    mySessionId = sessionId
-  };
-
-  // 发生主意识别错误时,删除当前自己发出的气泡框
-  const handleVoiceError = () => {
-    deleteMessage(myMsgUk);
-  };
-
-  useUnload(() => {
-    if (stopReceiveChunk) {
-      stopReceiveChunk();
-    }
-  });
+  
 
   if (isVoice) {
     console.log(agent)

+ 9 - 4
src/pages/chat/index.tsx

@@ -20,6 +20,8 @@ import { useLoadMoreInfinite, createKey } from "@/utils/loadMoreInfinite";
 import { getMessageHistories } from "@/service/bot";
 import { useAppStore } from "@/store/appStore";
 
+import RecommendQuestions from './components/RecommendQuestions'
+
 
 
 export default function Index() {
@@ -29,8 +31,9 @@ export default function Index() {
     return <View>没有相应的智能体</View>;
   }
   const headerHeight = useAppStore((state) => state.headerHeight);
-  const { fetchAgent, fetchAgentProfile, } = useAgentStore();
-  const agent = useAgentStore((state) => {
+  const { fetchAgent, fetchAgentProfile, } = useAgentStore()
+  
+const agent = useAgentStore((state) => {
     if(isVisitor === 'true'){
       return state.agentProfile
     }
@@ -232,7 +235,7 @@ export default function Index() {
           onScrollToUpper={onScrollToUpper}
         >
           {showWelcome && <ChatWelcome agent={agent} />}
-          <View id="messageList" className="flex flex-col gap-8 px-18 pb-140">
+          <View id="messageList" className="flex flex-col gap-8 px-18">
             {/* 复制 histories 再 reverse 否则会影响 state */}
             {[...[...list].reverse(), ...messageList].map((message) => {
               return (
@@ -243,11 +246,13 @@ export default function Index() {
                   role={message.role}
                   text={message.content}
                   message={message}
-                  mutate={mutate}
                 ></ChatMessage>
               );
             })}
           </View>
+          <View className="pb-140 pt-8">
+          {(agent) &&  <RecommendQuestions agent={agent} />}
+          </View>
         </ScrollView>
         <View className="h-140 w-10"></View>
         <View

+ 29 - 2
src/pages/editor-contact/index.tsx

@@ -30,9 +30,36 @@ const RenderEntCard = (
     setSelected(value)
     submit(value, false)
   }
+
   
-  if (!agent?.entName) {
-    return <></>;
+  if (!agent?.isEnt) {
+    return <View className="px-16 w-full pt-12">
+        <ListWrapper>
+            <ListRow
+              underline
+              arrow
+              onClick={()=> {navToUrl('/pages/editor-pages/editor-ent-name/index')}}
+            >
+              <View className="flex items-center font-normal">
+                <View className="flex-1 font-normal">企业</View>
+                <View className="text-gray-65 truncate max-w-[188px]">
+                  {agent?.entName}
+                </View>
+              </View>
+            </ListRow>
+            <ListRow
+              arrow
+            >
+              
+              <PickerSingleColumn headerTitle="您的岗位" options={options} selected={selected} onPicked={handlePicked} showPicker={showPicker} setShowPicker={setShowPicker}>
+                <View className="flex items-center font-normal" onClick={() => setShowPicker(true)}>
+                  <View className="flex-1 font-normal">职位</View>
+                  <View className="text-gray-65 mr-8">{agent?.position}</View>
+                </View>
+              </PickerSingleColumn>
+            </ListRow>
+        </ListWrapper>
+      </View>;
   }
   return (
     <View className="px-16 w-full pt-12">

+ 5 - 0
src/pages/editor-pages/editor-ent-name/index.config.ts

@@ -0,0 +1,5 @@
+export default definePageConfig({
+  navigationBarTitleText: '章节标题',
+  "usingComponents": {},
+  navigationStyle: 'custom'
+})

+ 2 - 0
src/pages/editor-pages/editor-ent-name/index.module.less

@@ -0,0 +1,2 @@
+
+

+ 40 - 0
src/pages/editor-pages/editor-ent-name/index.tsx

@@ -0,0 +1,40 @@
+import { useState } from "react";
+import { View } from "@tarojs/components";
+
+import PageCustom from "@/components/page-custom/index";
+import NavBarNormal from "@/components/NavBarNormal/index";
+import ButtonMain from "@/components/buttons/ButtonMain";
+import BottomBar from "@/components/BottomBar";
+
+import WemetaTextarea from "@/components/wemeta-textarea/index";
+import { useAgentStore } from "@/store/agentStore";
+import useEditContactCard from "@/hooks/useEditContactCard";
+export default function Index() {
+  const agentContactCard = useAgentStore((state)=> state.agentContactCard)
+  const {value, onChange, handleSubmit} = useEditContactCard('entName', agentContactCard?.entName)
+  
+  
+
+  return (
+    <PageCustom>
+      <NavBarNormal backText="企业名称"></NavBarNormal>
+      <View className="flex flex-col items-center w-full">
+        <View
+          className="w-full p-16"
+        >
+          <WemetaTextarea
+            value={value}
+            onBlur={(value: string) => onChange(value)}
+            onInput={(value: string) => onChange(value)}
+            placeholder="填写企业名称"
+            autoFocus
+            maxlength={20}
+          />
+        </View>
+        <BottomBar>
+          <ButtonMain className="flex-1" disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
+        </BottomBar>
+      </View>
+    </PageCustom>
+  );
+}

+ 1 - 1
src/pages/editor-pages/editor-greeting/index.tsx

@@ -29,7 +29,7 @@ const {handleSubmit, onChange, value} = useEditAgent('greeting', agent?.greeting
         </View>
 
         <BottomBar>
-          <ButtonMain disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
+          <ButtonMain className="flex-1" disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
         </BottomBar>  
       </View>
     </PageCustom>

+ 46 - 35
src/pages/editor-pages/editor-media/index.tsx

@@ -3,7 +3,7 @@ import { View } from "@tarojs/components";
 import PageCustom from "@/components/page-custom/index";
 import NavBarNormal from "@/components/NavBarNormal/index";
 
-import KnowledgePicker from '@/components/KnowledgePicker'
+import KnowledgePicker from "@/components/KnowledgePicker";
 import Taro, { useUnload } from "@tarojs/taro";
 import { uploadImage } from "@/utils/http";
 import { useComponentStore } from "@/store/componentStore";
@@ -11,20 +11,17 @@ import { useComponentStore } from "@/store/componentStore";
 import type { TMediaType } from "@/types/index";
 import { EComponentType, EKnowlegeTypes } from "@/consts/enum";
 
-import UploaderGrid from '@/components/UploaderGrid'
+import UploaderGrid from "@/components/UploaderGrid";
 import BottomBar from "@/components/BottomBar";
 import { TKnowledgeItem } from "@/types/knowledge";
 
-
 interface Props {
   editMode?: boolean;
 }
 
 export default function Index({ editMode }: Props) {
-  
-  
   let currentComponent = useComponentStore((state) => state.currentComponent);
-  
+
   const { saveComponent } = useComponentStore();
   const loading = useComponentStore((state) => state.loading);
 
@@ -32,10 +29,9 @@ export default function Index({ editMode }: Props) {
     currentComponent?.data?.media ?? []
   );
 
-
   const handleSubmit = async () => {
-    if(!currentComponent?.data?.id){
-      return
+    if (!currentComponent?.data?.id) {
+      return;
     }
     if (loading) {
       return;
@@ -43,7 +39,7 @@ export default function Index({ editMode }: Props) {
     const c = {
       data: {
         media: mediaValue,
-        layout: currentComponent.data.layout ?? 'mini',
+        layout: currentComponent.data.layout ?? "mini",
         id: currentComponent.data.id,
         index: currentComponent.data.index,
       },
@@ -80,12 +76,12 @@ export default function Index({ editMode }: Props) {
               fileType: t.fileType,
             });
             console.log(arr);
-          }else{
+          } else {
             Taro.showModal({
-              title: '上传异常',
-              content: '文件上传失败',
+              title: "上传异常",
+              content: "文件上传失败",
               showCancel: false,
-            })
+            });
           }
         }
         setMediaValue([...mediaValue, ...arr]);
@@ -104,40 +100,55 @@ export default function Index({ editMode }: Props) {
   };
   const [showPopup, setShowPopup] = useState(false);
 
-  const showKnowlegePopup = ()=> {
-    setShowPopup(true)
-  }
-  
+  const showKnowlegePopup = () => {
+    setShowPopup(true);
+  };
+
   const onPicked = (picked?: TKnowledgeItem[]) => {
-    if(picked){
-      const r = picked.map( item => {
+    if (picked) {
+      const r = picked.map((item) => {
         return {
           size: item.fileSize,
           url: item.picUrl,
           fileType: item.type,
-        }
-      })
-      if(r.length){
-        setMediaValue([...mediaValue, ...r])
+        };
+      });
+      if (r.length) {
+        setMediaValue([...mediaValue, ...r]);
       }
     }
-  }
+  };
 
   return (
     <PageCustom isflex={false} bgColor="global-light-green-bg">
-      <NavBarNormal
-      >
-        图片/视频
-      </NavBarNormal>
-    
+      <NavBarNormal>图片/视频</NavBarNormal>
+
       <View className="flex flex-col w-full px-16 pt-12 gap-12">
-        <View className="text-primary" onClick={showKnowlegePopup}>知识库导入</View>
-        <UploaderGrid onNewUpload={handleChooseMedia}  list = {mediaValue} onChange={()=> {}} onDelete={handleDeleteMedia} />
+        <View className="text-primary" onClick={showKnowlegePopup}>
+          知识库导入
+        </View>
+        <UploaderGrid
+          onNewUpload={handleChooseMedia}
+          list={mediaValue}
+          onChange={() => {}}
+          onDelete={handleDeleteMedia}
+        />
       </View>
-      <KnowledgePicker types={[EKnowlegeTypes.image]} multi onPicked={onPicked} setShow={setShowPopup} show={showPopup}></KnowledgePicker>
+      <KnowledgePicker
+        types={[EKnowlegeTypes.image]}
+        multi
+        onPicked={onPicked}
+        setShow={setShowPopup}
+        show={showPopup}
+      ></KnowledgePicker>
       <BottomBar>
-          <View className="button-rounded button-primary flex-1" onClick={handleSubmit}>保存</View>
-        </BottomBar>
+        <View
+          className="button-rounded button-primary flex-1"
+          onClick={handleSubmit}
+        >
+          保存
+        </View>
+      </BottomBar>
     </PageCustom>
   );
 }

+ 1 - 1
src/pages/editor-pages/editor-name/index.tsx

@@ -32,7 +32,7 @@ export default function Index() {
           />
         </View>
         <BottomBar>
-          <ButtonMain disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
+          <ButtonMain className="flex-1" disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
         </BottomBar>
       </View>
     </PageCustom>

+ 1 - 1
src/pages/editor-pages/editor-personality/index.tsx

@@ -33,7 +33,7 @@ export default function Index() {
           </View>
         
         <BottomBar>
-          <ButtonMain disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
+          <ButtonMain className="flex-1" disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
         </BottomBar>
       </View>
     </PageCustom>

+ 1 - 1
src/pages/editor-pages/editor-title/index.tsx

@@ -64,7 +64,7 @@ export default function Index() {
           </View>
           
         <BottomBar>
-          <ButtonMain disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
+          <ButtonMain className="flex-1" disabled={!value.length} onClick={handleSubmit}>保存</ButtonMain>
         </BottomBar>
       </View>
     </PageCustom>

+ 9 - 1
src/store/textChat.ts

@@ -39,9 +39,11 @@ export interface TextChat {
   currentRobotMsgUk: string; // 当前正在说话的 AI 机器人 id, 可用于控制是否继续输出文本至当前 message 框内
   scrollTop: number; // 控制聊天内容变化后滚动至最底部
   list: (TMessage | TRobotMessage)[];
+  questions: string[]; //推荐问题
   sessionId: string|null
   // 显示聊天历史
   genSessionId: () => void // 进入聊天界面后,本次的 sessionId
+  setQuestions: (q:string[]) => void // 设置推荐问题
   setScrollTop: () => void
   // 将机器人气泡框推入聊天框
   pushRobotMessage: (message: TRobotMessageWithOptionalId) => string;
@@ -69,15 +71,21 @@ export const useTextChat = create<TextChat>((set, get) => ({
   scrollTop: 9999,
   list: [],
   sessionId: null,
+  questions: [],
+  setQuestions: (q:string[])=> {
+    set({questions: q})
+  },
   genSessionId: ()=> {
     const sessionId = generateUUID();
     set({
       sessionId
     })
   },
+  // 重置
   destroy: () => {
     set({
       list: [],
+      questions: [],
       currentRobotMsgUk: INIT_CURRENT_ROBOT_MSG_UK,
       scrollTop: 9999,
       sessionId: null,
@@ -125,7 +133,7 @@ export const useTextChat = create<TextChat>((set, get) => ({
       });
     }, 100)
     
-    return {msgUk, sessionId: get().sessionId}
+    return {msgUk, sessionId: get().sessionId ?? ''}
   },
   updateMessage: (content, msgUk) => {
     set((state) => {

+ 3 - 2
src/utils/loadMoreInfinite.ts

@@ -35,7 +35,7 @@ export const createKey = (query: string, pageSize: number = 10, extra: Record<st
   };
 }
 export const useLoadMoreInfinite = <T>(getKey, fetcher, params = {}) => {
-  const { data, setSize, size, mutate } = useSWRInfinite<{
+  const { data, setSize, size, mutate, isLoading } = useSWRInfinite<{
     data: T
     nextId?: string
     totalCount?: null | number
@@ -65,9 +65,10 @@ export const useLoadMoreInfinite = <T>(getKey, fetcher, params = {}) => {
   return {
     list,
     pageIndex,
+    isLoading,
     pages,
     mutate,
     setSize,
-    loadMore
+    loadMore,
   }
 }