王晓东 1 mesiac pred
rodič
commit
eee0bed00f

+ 1 - 0
src/app.config.ts

@@ -10,6 +10,7 @@ export default defineAppConfig({
     'pages/knowledge-item-editor/index',
     'pages/member/index',
     'pages/agent/index',
+    'pages/agent-avatars/index',
     'pages/editor-pages/editor-personality/index',
     'pages/editor-pages/editor-greeting/index',
     'pages/editor-pages/editor-greeting-questions/index',

+ 4 - 0
src/components/AgentPage/components/SummaryBar/index.module.less

@@ -41,4 +41,8 @@
   height: 24px;
   border-radius: 100%;
   background-color: rgba(#317CFA, .1);
+}
+.buttonRow{
+  position: sticky;
+  top: calc(100vh - 420px);
 }

+ 0 - 1
src/components/AgentPage/index.tsx

@@ -45,7 +45,6 @@ export default function Index({ agentId }: IProps) {
     <View className="w-full">
       <NavBarNormal scrollFadeIn showBgColor leftColumn={Logo}></NavBarNormal>
       <SummaryBar></SummaryBar>
-      
       <View className="flex flex-col w-full p-16 gap-12">
         <ComponentList components={components}></ComponentList>
       </View>

+ 5 - 0
src/pages/agent-avatars/index.config.ts

@@ -0,0 +1,5 @@
+export default definePageConfig({
+  navigationBarTitleText: '开场提问引导',
+  "usingComponents": {},
+  navigationStyle: 'custom'
+})

+ 39 - 0
src/pages/agent-avatars/index.module.less

@@ -0,0 +1,39 @@
+.grid {
+  width: 100%;
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  grid-gap: 6px;
+}
+
+.gridItem {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  min-height: 196px;
+  border-radius: 12px;
+  overflow: hidden;
+  background-color: white;
+  border: 1px solid white;
+}
+.gridItemActived {
+  .gridItem();
+  border: 1px solid var(--color-primary);
+}
+
+.icon{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 28px;
+  height: 28px;
+  border-radius: 100%;
+  background-color: var(--color-primary);
+}
+
+.container{
+  overflow: hidden;
+  width: 100%;
+  height: calc(100vh - 120px);
+}

+ 124 - 0
src/pages/agent-avatars/index.tsx

@@ -0,0 +1,124 @@
+import { useEffect, useState } from "react";
+import { Image, View, ScrollView } from "@tarojs/components";
+
+import PageCustom from "@/components/page-custom/index";
+import NavBarNormal from "@/components/nav-bar-normal/index";
+
+import { uploadAndGenNewAvatar } from "@/utils/avatar";
+import { useAvatars } from "./useAvatars";
+import IconPlusBig from "@/components/icon/icon-plus-big";
+
+import { editAgentAvatar } from "@/service/agent";
+
+import style from "./index.module.less";
+import { TAvatarItem } from "@/service/storage";
+import { useAgentStore } from "@/store/agentStore";
+import useSWRMutation from "swr/mutation";
+import Taro from "@tarojs/taro";
+
+export default function Index() {
+  const { agent, fetchAgent } = useAgentStore();
+  const { avatars, initLoad, loadAvatars } = useAvatars();
+  const [current, setCurrent] = useState<TAvatarItem | null>(null);
+
+  // 用 useSWRMutation 包装 editAgentAvatar
+  const { trigger: editAvatar, isMutating } = useSWRMutation(
+    ["editAgentAvatar"],
+    async (
+      _key,
+      {
+        arg,
+      }: {
+        arg: {
+          agentId: string;
+          avatarId: string | number;
+          enabledChatBg: boolean;
+        };
+      }
+    ) => {
+      return await editAgentAvatar(
+        arg.agentId,
+        arg.avatarId,
+        arg.enabledChatBg
+      );
+    }
+  );
+
+  const handleClick = async (item: TAvatarItem) => {
+    console.log(item);
+    if (!agent?.agentId) {
+      return;
+    }
+    // if (item.avatarId === current?.avatarId) {
+    //   setCurrent(null);
+    //   return;
+    // }
+
+    Taro.showLoading();
+    await editAvatar({
+      agentId: agent.agentId,
+      avatarId: item.avatarId,
+      enabledChatBg: false,
+    });
+    await fetchAgent(agent.agentId)
+    Taro.hideLoading();
+    setCurrent(item);
+  };
+  const onScrollToLower = () => {
+    loadAvatars();
+  };
+  const handleCreate = () => {
+    uploadAndGenNewAvatar();
+  };
+
+  useEffect(() => {
+    initLoad();
+  }, []);
+
+  return (
+    <PageCustom>
+      <NavBarNormal backText="历史形象"></NavBarNormal>
+      <View className={style.container}>
+      <ScrollView
+        scrollY
+        onScrollToLower={onScrollToLower}
+        style={{
+          flex: 1,
+          height: "100%", // 高度自适应
+        }}
+      >
+        <View className="w-full p-16 pb-120">
+          <View className={style.grid}>
+            <View className={style.gridItem} onClick={handleCreate}>
+              <View className={style.icon}>
+                <IconPlusBig></IconPlusBig>
+              </View>
+              <View className="pt-8 text-12 leading-20 text-gray-45">
+                创建新形象
+              </View>
+            </View>
+            {avatars.map((avatar) => {
+              return (
+                <View
+                  className={
+                    current?.avatarId === avatar.avatarId
+                      ? style.gridItemActived
+                      : style.gridItem
+                  }
+                  onClick={() => handleClick(avatar)}
+                >
+                  <Image
+                    src={avatar.avatarUrl}
+                    mode="widthFix"
+                    className="w-full"
+                  />
+                </View>
+              );
+            })}
+          </View>
+        </View>
+      </ScrollView>
+      </View>
+    </PageCustom>
+  );
+}

+ 57 - 0
src/pages/agent-avatars/useAvatars.ts

@@ -0,0 +1,57 @@
+import { fetchMyAvatars, TAvatarItem } from "@/service/storage";
+import { isSuccess } from "@/utils";
+import { useState, useCallback } from "react";
+
+export const useAvatars = (initPageSize: number = 20) => {
+  const [avatars, setAvatars] = useState<TAvatarItem[]>([]);
+  const [pageIndex, setPageIndex] = useState(1);
+  const [pageSize] = useState(initPageSize);
+  const [totalCount, setTotalCount] = useState(0);
+  const [isLoading, setIsLoading] = useState(false);
+  const [hasMore, setHasMore] = useState(true);
+
+  const loadAvatars = useCallback(async (reset: boolean = false) => {
+    if (isLoading) return;
+    setIsLoading(true);
+    const currentPage = reset ? 1 : pageIndex;
+    try {
+      const response = await fetchMyAvatars({ pageSize, pageIndex: currentPage });
+      if (isSuccess(response.status)) {
+        const { data, totalCount: total } = response.data;
+        setTotalCount(total);
+        if (reset) {
+          setAvatars(data);
+        } else {
+          setAvatars(prev => [...prev, ...data]);
+        }
+        setHasMore((currentPage * pageSize) < total);
+        setPageIndex(currentPage + 1);
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  }, [isLoading, pageIndex, pageSize]);
+
+  const resetAvatars = useCallback(() => {
+    setAvatars([]);
+    setPageIndex(1);
+    setTotalCount(0);
+    setHasMore(true);
+  }, []);
+
+  // 首次加载
+  const initLoad = useCallback(async () => {
+    resetAvatars();
+    await loadAvatars(true);
+  }, [resetAvatars, loadAvatars]);
+
+  return {
+    avatars,
+    isLoading,
+    hasMore,
+    totalCount,
+    loadAvatars,
+    resetAvatars,
+    initLoad,
+  };
+};

+ 48 - 32
src/pages/agent-gen/components/step/StepConfirm.tsx

@@ -3,52 +3,68 @@ import React, { useState } from "react";
 import style from "./index.module.less";
 import WemetaRadio from '@/components/wemeta-radio'
 import Taro from "@tarojs/taro";
+import { TAvatarItem } from "@/service/storage";
+import { editAgentAvatar } from "@/service/agent";
+import { useAgentStore } from "@/store/agentStore";
 interface IProps {
   prev: ()=>void
+  pickedAvatar: TAvatarItem
 }
-export default React.memo(function Index({prev}:IProps) {
-  
-  const handleEdit = ()=> {
-    Taro.downloadFile({
-      url: 'https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png',
-      success (res) {
-        // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
-        if (res.statusCode === 200) {
-          Taro.cropImage({
-            src: res.tempFilePath,
-            cropScale: "1:1",
-            success: async (cropRes) => {
-              const result = cropRes.tempFilePath;
-              console.log(result)
-              // const res = await uploadImage(path);
-              // if (res?.code === 0 && res.data) {
-              //   setValueByKey('poster', res.data)
-              // }
-            },
-          });
-        }
-      }
-    })
-  }
+export default React.memo(function Index({prev, pickedAvatar}:IProps) {
+  const {agent, fetchAgent} = useAgentStore()
+  const [enabledChatBg, setEnabledChatBg] = useState(false)
+  // const handleEdit = ()=> {
+  //   Taro.downloadFile({
+  //     url: 'https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png',
+  //     success (res) {
+  //       // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
+  //       if (res.statusCode === 200) {
+  //         Taro.cropImage({
+  //           src: res.tempFilePath,
+  //           cropScale: "1:1",
+  //           success: async (cropRes) => {
+  //             const result = cropRes.tempFilePath;
+  //             console.log(result)
+  //             // const res = await uploadImage(path);
+  //             // if (res?.code === 0 && res.data) {
+  //             //   setValueByKey('poster', res.data)
+  //             // }
+  //           },
+  //         });
+  //       }
+  //     }
+  //   })
+  // }
 
-  const handleConfirm = () => {
+  const handleConfirm = async () => {
+    if(!agent?.agentId){
+      return
+    }
+    Taro.showLoading();
+    await editAgentAvatar(
+      agent.agentId,
+      pickedAvatar.avatarId,
+      enabledChatBg,
+    );
+    await fetchAgent(agent.agentId)
+    Taro.hideLoading();
     Taro.navigateTo({url: '/pages/agent/index'})
   }
   return (
     <View>
       <View className={style.confirmContainer}>
-        <View className={style.confirmRoundedAvatarWrap} onClick={handleEdit}>
+        <View className={style.confirmRoundedAvatarWrap}>
           <Image
             mode='aspectFill'
             className={style.confirmRoundedAvatar}
-            src="https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png"
+            src={pickedAvatar.avatarLogo}
           ></Image>
         </View>
         <View className={style.confirmChatAvatarBg}>
           <Image
                 mode="widthFix"
-                className={style.confirmChatAvatarBg}
-                src="https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png"
+                className="w-full"
+                src={pickedAvatar.avatarUrl}
               ></Image>
           <View className={style.confirmChatAvatarBgCover}>
               <View className={style.block1}></View>
@@ -56,8 +72,8 @@ export default React.memo(function Index({prev}:IProps) {
               <View className={style.block3}></View>
           </View>
         </View>
-        <View className="flex-center gap-8 text-14 font-medium leading-22 text-black">
-          <WemetaRadio checked checkbox></WemetaRadio>
+        <View className="flex-center gap-8 text-14 font-medium leading-22 text-black" onClick={()=> setEnabledChatBg((prev)=> !prev)}>
+          <WemetaRadio checked={enabledChatBg} checkbox></WemetaRadio>
           启用聊天背景
         </View>
       </View>
@@ -65,7 +81,7 @@ export default React.memo(function Index({prev}:IProps) {
       <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 opacity-20`} onClick={handleConfirm}>确定</View>
+          <View className={`button-rounded primary`} onClick={handleConfirm}>确定</View>
         </View>
       </View>
     </View>

+ 123 - 64
src/pages/agent-gen/components/step/StepPick.tsx

@@ -2,91 +2,150 @@ import { View, Swiper, SwiperItem, 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 { getUploadedAvatarStatus, TAvatarItem } from '@/service/storage'
+import useSWR from 'swr';
 interface IProps {
-  prev: ()=>void
-  next: ()=>void
+  prev: () => void;
+  next: () => void;
+  setPickedAvatar: (pickedAvatar: TAvatarItem)=> void
+  taskId: string|number
 }
-export default React.memo(function Index({prev, next}:IProps) {
+export default React.memo(function Index({ prev, next, taskId, setPickedAvatar }: IProps) {
   const [currentSwiperIndex, setCurrentSwiperIndex] = useState(0);
-  const characters = [1, 2];
+  const [avatars, setAvatars] = useState<TAvatarItem[]>([]);
+  const [shouldPoll, setShouldPoll] = useState(false);
+  
+  
+  const goNext = () => {
+    const pickedAvatar = avatars[currentSwiperIndex]
+    setPickedAvatar(pickedAvatar)
+    console.log(pickedAvatar)
+    next()
+  }
+  
+
+  const { data } = useSWR(
+    shouldPoll ? 'getUploadedAvatarStatus' : 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);
+    }
+    return ()=> {
+      
+    }
+  }, [data])
+  
+
   const onSwiperChange = (e: any) => {
     const i = e.detail.current;
     setCurrentSwiperIndex(i);
   };
-  useEffect(()=> {
-    console.log('helloworldrendeer')
-  }, [])
-  const renderIndicator = (currentIndex: number) => {
-    return (
-      <>
-        <View className={style.indicatorContainer}>
-          {characters.map((_item, index) => {
-            return (
-              <View
-                key={index}
-                className={
-                  index === currentIndex
-                    ? `${style.indicator} ${style.indicatorActive}`
-                    : style.indicator
-                }
-              ></View>
-            );
-          })}
-        </View>
-      </>
-    );
-  };
 
-  return (
-    <View>
-      <View className={style.pickContainer}>
-        {/* <View className={`${style.pickAvatarCard} ${style.pickGenCard}`}>
-          <View className="flex items-center gap-4">
-            <IconStarColor></IconStarColor> <View className="gradient-text">AI生成中</View>
+
+
+  
+
+  const renderSwipers = () => {
+    const renderIndicator = (currentIndex: number) => {
+      return (
+        <>
+          <View className={style.indicatorContainer}>
+            {avatars.map((_item, index) => {
+              return (
+                <View
+                  key={index}
+                  className={
+                    index === currentIndex
+                      ? `${style.indicator} ${style.indicatorActive}`
+                      : style.indicator
+                  }
+                ></View>
+              );
+            })}
           </View>
-        </View> */}
+        </>
+      );
+    };
 
-        <View className={`${style.pickAvatarCard}`}>
-          <Swiper
-            className={style.mySwiper}
-            indicatorColor="#999"
-            indicatorActiveColor="#333"
-            indicatorDots={false}
-            duration={200}
-            next-margin="-120rpx"
-            current={currentSwiperIndex}
-            onChange={(e) => onSwiperChange(e)}
-          >
-            <SwiperItem>
-            <View className={style.swiperItem}>
-              <Image
-                mode="widthFix"
-                src="https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png"
-              ></Image>
-              </View>
-            </SwiperItem>
-            
-            <SwiperItem>
+    return (
+      <View className={`${style.pickAvatarCard}`}>
+        <Swiper
+          className={style.mySwiper}
+          indicatorColor="#999"
+          indicatorActiveColor="#333"
+          indicatorDots={false}
+          duration={200}
+          next-margin="-120rpx"
+          current={currentSwiperIndex}
+          onChange={(e) => onSwiperChange(e)}
+        >
+          {avatars.map(avatar => {
+            return <SwiperItem>
               <View className={style.swiperItem}>
                 <Image
                   mode="widthFix"
-                  src="https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png"
+                  src={avatar.avatarUrl}
                 ></Image>
-                <View className={style.pickAvatarOriginal}>
+                {avatar.isOriginal && <View className={style.pickAvatarOriginal}>
                   <View>原图</View>
-                </View>
+                </View> }
               </View>
             </SwiperItem>
-          </Swiper>
-          {/* <!-- 自定义指示点容器 --> */}
-          {renderIndicator(currentSwiperIndex)}
-        </View>
+          })}
+        </Swiper>
+        {/* <!-- 自定义指示点容器 --> */}
+        {renderIndicator(currentSwiperIndex)}
+      </View>
+    );
+  };
+
+  const renderContent = ()=> {
+    if(avatars.length){
+      return renderSwipers()
+    }
+
+    return <View className={`${style.pickAvatarCard} ${style.pickGenCard}`}>
+      <View className="flex items-center gap-4">
+        <IconStarColor></IconStarColor>{" "}
+        <View className="gradient-text">AI生成中</View>
+      </View>
+    </View>
+  }
+
+  
+
+  return (
+    <View>
+      <View className={style.pickContainer}>
+        {renderContent()}
       </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 opacity-20`} onClick={next}>使用这张</View>
+          <View className={`button-rounded`} onClick={prev}>
+            上一步
+          </View>
+          <View className={`button-rounded primary ${avatars.length ? '' : 'opacity-20'}`} onClick={()=> goNext()}>
+            使用这张
+          </View>
         </View>
       </View>
     </View>

+ 9 - 4
src/pages/agent-gen/components/step/StepStart.tsx

@@ -4,14 +4,15 @@ import style from './index.module.less'
 import IconChange from "@/components/icon/icon-change";
 import IconStar from "@/components/icon/icon-star";
 import WemetaTextarea from "@/components/wemeta-textarea/index";
-import { useRouter } from "@tarojs/taro";
+import Taro, { useRouter } from "@tarojs/taro";
 import { uploadAvatar } from '@/service/storage'
 import { isSuccess } from "@/utils";
 interface IProps {
-  next: ()=>void
+  next: () =>void
+  setTaskId: (value:any)=> void 
 }
 
-export default React.memo(function StepStart({ next }: IProps) {
+export default React.memo(function StepStart({ next, setTaskId }: IProps) {
   
   const router = useRouter();
   const { avatarUrl } = router.params
@@ -32,13 +33,17 @@ export default React.memo(function StepStart({ next }: IProps) {
     if(!uploadedAvatarUrl){
       return
     }
+    
+    Taro.showLoading();
     const response = await uploadAvatar({
       aiGenerated: true,
       avatarUrl: uploadedAvatarUrl,
       description: value,
     })
-    
+    Taro.hideLoading();
+    console.log(response,1111)
     if(isSuccess(response.status)){
+      setTaskId(response.data.taskId)
       next();
     }
   }, [next]);

+ 5 - 1
src/pages/agent-gen/components/step/index.module.less

@@ -60,6 +60,9 @@
 
 .swiperItem{
   position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   width: 300px;
   height: 533px;
 }
@@ -134,6 +137,7 @@
   border-radius: 24px;
 }
 .confirmChatAvatarBgCover{
+  position: absolute;
   display: flex;
   flex-direction: column;
   justify-content: flex-end;
@@ -143,7 +147,7 @@
   right: 0;
   z-index: 1;
   width: 240px;
-  height: 427px;
+  height: 373px;
   box-sizing: border-box;
   padding: 0 24px 54px;
   border-radius: 24px;

+ 17 - 38
src/pages/agent-gen/index.tsx

@@ -5,64 +5,43 @@ import { useState, useCallback, useEffect } from "react";
 import StepStart from './components/step/StepStart'
 import StepPick from "./components/step/StepPick";
 import StepConfirm from "./components/step/StepConfirm";
-import { useRouter } from "@tarojs/taro";
-import { fetchMyAvatars } from "@/service/storage";
-import { isSuccess } from "@/utils";
+import { TAvatarItem } from "@/service/storage";
 
 type TStep = 'start'|'pick'|'confirm'
 
 export default function Index() {
-  const router = useRouter();
-  const { avatarUrl } = router.params
-
-  
 
   const [state, setState] = useState<TStep>('start')
+  const [taskId, setTaskId] = useState<string>()
+  const [pickedAvatar, setPickedAvatar] = useState<TAvatarItem>()
   
   const getClassName = useCallback((_state: TStep) => {
     return state === _state ? 'block': 'hidden'
   }, [state]);
 
-  const gotoStart = useCallback(() => {
-    setState('pick')
-  }, []);
-
-  const gotoPick = useCallback(() => {
-    setState('confirm')
-  }, []);
-
-  const gotoConfirm = useCallback(() => {
-    setState('start')
-  }, []);
-
-  const getMyAvatars = async () => {
-    const response =  await fetchMyAvatars()
-    if(isSuccess(response.status)){
-      console.log(response.data)
-    }
-  }
-
-  useEffect(()=> {
-    getMyAvatars()
-  }, [])
-
   return (
     <PageCustom>
       <NavBarNormal backText="形象照"></NavBarNormal>
       <View className="px-16 w-full flex flex-col gap-20">
+        {/* 第一步开始 */}
         <View className={getClassName('start')}>
-          <StepStart next={gotoStart}/>
+          <StepStart next={()=> setState('pick')} setTaskId={setTaskId}/>
         </View>
+        {/* 第二步 生成多个形象提供用户选择 */}
         <View className={getClassName('pick')}>
-          <StepPick 
-            prev={gotoConfirm} 
-            next={gotoPick} 
-          />
+        {taskId &&  <StepPick 
+            taskId={taskId}
+            setPickedAvatar={setPickedAvatar}
+            prev={()=> setState('start')} 
+            next={()=> setState('confirm')} 
+          />}
         </View>
+        {/* 第三步 确认选择作为智能体的形象 */}
         <View className={getClassName('confirm')}>
-          <StepConfirm 
-            prev={gotoStart}  
-          />
+        {pickedAvatar && <StepConfirm 
+            pickedAvatar={pickedAvatar}
+            prev={()=> setState('pick')}  
+          />}
         </View>
       </View>
     </PageCustom>

+ 0 - 0
src/pages/agent/components/AgentSetting/components/AgentEmptyCard/index.module.less → src/pages/agent/components/AgentSetting/components/AgentCard/index.module.less


+ 50 - 0
src/pages/agent/components/AgentSetting/components/AgentCard/index.tsx

@@ -0,0 +1,50 @@
+import { Image, View } from "@tarojs/components";
+import style from "./index.module.less";
+import IconPlusBig from "@/components/icon/icon-plus-big";
+import Taro from "@tarojs/taro";
+import { uploadAndGenNewAvatar } from "@/utils/avatar";
+import { useAgentStore } from "@/store/agentStore";
+
+export default () => {
+  const {agent} = useAgentStore()
+  const handleChange = () => {};
+  const handleClick = () => {
+    if (agent?.avatarUrl) {
+      return;
+    }
+    uploadAndGenNewAvatar()
+    
+  };
+
+  const renderContent = () => {
+    if (!agent?.avatarUrl) {
+      return (
+        <View className={style.tips}>
+          <View className={style.icon}>
+            <IconPlusBig></IconPlusBig>
+          </View>
+          <View className={style.tipsText}>形象照</View>
+        </View>
+      );
+    }
+
+    return (
+      <Image src={agent.avatarUrl} mode="widthFix" className={style.card} />
+    );
+  };
+
+  return (
+    <View className={style.container}>
+      <View className={style.card} onClick={handleClick}>
+        {renderContent()}
+      </View>
+      <View className="w-full flex-center pt-16" onClick={handleChange}>
+        <View className="flex-center w-80 h-28 rounded-20 bg-white text-12 text-gray-85 font-medium leading-20 text-center" onClick={()=> {
+          Taro.navigateTo({url: '/pages/agent-avatars/index'})
+        }}>
+          更换形象
+        </View>
+      </View>
+    </View>
+  );
+};

+ 0 - 66
src/pages/agent/components/AgentSetting/components/AgentEmptyCard/index.tsx

@@ -1,66 +0,0 @@
-import { View } from "@tarojs/components"
-import style from './index.module.less'
-import IconPlusBig from "@/components/icon/icon-plus-big"
-import Taro from "@tarojs/taro";
-import { uploadImage } from '@/utils/http'
-import { EUploadFileScene } from "@/consts/enum";
-export default ()=> {
-  const maxAvatarVideoSize = 10
-  let isUploading = false
-  const handleClick = () => {
-    Taro.chooseMedia({
-      count: 1,
-      mediaType: ["image"],
-      sourceType: ["album", "camera"],
-      async success(r) {
-        const tempFile = r.tempFiles[0]
-        const tmpPath = tempFile.tempFilePath;
-        if (maxAvatarVideoSize && tempFile.size > maxAvatarVideoSize * 1024 * 1024) {
-          Taro.showToast({
-            title: `文件不能超过${maxAvatarVideoSize}MB`,
-            icon: 'none'
-          });
-          return;
-        }
-
-        Taro.showLoading()
-        const response = await uploadImage(tmpPath, EUploadFileScene.AVATAR)
-        Taro.hideLoading()
-        if(response?.publicUrl){
-            Taro.navigateTo({
-                url: `/pages/agent-gen/index?avatarUrl=${response?.publicUrl}`
-              })
-        }
-        // setAvatarUrl(tmpPath);
-        // if(r.type === 'image'){
-        //   Taro.cropImage({
-        //     src: tmpPath,
-        //     cropScale: "4:3",
-        //     success: async (res) => {
-        //       const path = res.tempFilePath;
-        //       console.log(path)
-        //       Taro.showLoading()
-        //       Taro.navigateTo({
-        //         url: '/pages/agent-gen/index'
-        //       })
-        //       const response = await uploadAvatar(path);
-        //       // processChooseResult(response)
-        //     },
-        //   });
-        // }
-      },
-    });
-  }
-  return(
-    <View className={style.container}>
-      <View className={style.card} onClick={handleClick}>
-      <View className={style.tips}>
-        <View className={style.icon}>
-          <IconPlusBig></IconPlusBig>
-        </View>
-        <View className={style.tipsText}>形象照</View>
-      </View>
-      </View>
-    </View>
-  )
-}

+ 19 - 4
src/pages/agent/components/AgentSetting/index.tsx

@@ -1,17 +1,32 @@
 import { View } from "@tarojs/components";
 import AgentSettingList from './components/AgentSettingList'
 import AgentKnowledgeLib from './components/AgentKnowledgeLib'
-import AgentEmptyCard from './components/AgentEmptyCard'
+import AgentCard from './components/AgentCard'
 import AgentContactCard from './components/AgentContactCard'
 
 import React, { useEffect, useState } from "react";
 import { useAgentStore } from "@/store/agentStore";
+import { fetchMyAvatars, TAvatarItem } from "@/service/storage";
+import { isSuccess } from "@/utils";
 
 export default React.memo(function Index() {
   console.log('agent setting')
-  const {fetchAgents} = useAgentStore()
-  
+
+  const [avatars, setAvatars] = useState<TAvatarItem[]>([])
+
+  const {agent, fetchAgents} = useAgentStore()
   
+  // const getMyAvatars = async () => {
+  //   const response =  await fetchMyAvatars({pageSize: 20, pageIndex: 1})
+  //   if(isSuccess(response.status)){
+  //     console.log(response.data)
+  //     setAvatars(response.data.data)
+  //   }
+  // }
+
+  // useEffect(()=> {
+  //   getMyAvatars()
+  // }, [])
   
 
   useEffect(()=> {
@@ -20,7 +35,7 @@ export default React.memo(function Index() {
 
   return (
     <View>
-      <AgentEmptyCard></AgentEmptyCard>
+      <AgentCard></AgentCard>
       <View className="mb-20">
         <AgentContactCard></AgentContactCard>
       </View>

+ 1 - 1
src/pages/agent/index.tsx

@@ -12,7 +12,7 @@ import { useComponentStore } from "@/store/componentStore";
 import { useUserStore } from "@/store/userStore";
 
 export default function Index() {
-  const [tabIndex, setTabIndex] = useState("2");
+  const [tabIndex, setTabIndex] = useState('1');
   const router = useRouter();
   const agentId = router.params.agentId;
   const { fetchAgent } = useAgentStore();

+ 2 - 2
src/service/agent.ts

@@ -23,9 +23,9 @@ export const editAgentCharacter = (agentId: string, data: TEditAgentCharacter) =
 }
 
 // 编辑智能体--设置形象ID
-export const editAgentAvatar = (agentId: string, avatarUrl: string, enabledChatBg:boolean) => {
+export const editAgentAvatar = (agentId: string, avatarId: string|number, enabledChatBg:boolean) => {
   return request.put(`${bluebookAiAgent}api/v1/my/agent/${agentId}/avatar`, {
-    avatarUrl,
+    avatarId,
     enabledChatBg,
   })
 }

+ 14 - 8
src/service/storage.ts

@@ -9,9 +9,10 @@ import {FileTypes} from '@/consts'
 
 
 export type TAvatarItem = {
-  "avatarId": number,
-  "avatarUrl": string,
-  "isOriginal": boolean
+  avatarId: number,
+  avatarLogo: string,
+  avatarUrl: string,
+  isOriginal: boolean
 }
 // 上传形象--并生成微视频
 export type TUploadAvatarResponse = {
@@ -30,15 +31,20 @@ export const uploadAvatar = (data: {
 }
 
 // 获取上传形象任务的处理状态
-export const getUploadedAvatarStatus = (taskId: string) => {
+export const getUploadedAvatarStatus = (taskId: string|number) => {
   return request.get<TUploadAvatarResponse>(`${bluebookAiAgent}api/v1/my/avatar/task/${taskId}`)
 }
 
 // 获取个人形象库
-export const fetchMyAvatars = () => {
-  return request.get<TAvatarItem[]>(`${bluebookAiAgent}api/v1/my/avatars`, {params: {
-    pageSize: 10,
-    pageIndex: 1
+export const fetchMyAvatars = ({pageSize = 20, pageIndex = 1}:{pageSize?: number, pageIndex?: number}) => {
+  return request.get<{
+    pageIndex: number
+    pageSize: number
+    totalCount: number
+    data: TAvatarItem[]
+  }>(`${bluebookAiAgent}api/v1/my/avatars`, {params: {
+    pageSize,
+    pageIndex
   }})
 }
 

+ 34 - 0
src/utils/avatar.ts

@@ -0,0 +1,34 @@
+import Taro from "@tarojs/taro";
+import { uploadImage } from "@/utils/http";
+import { EUploadFileScene } from "@/consts/enum";
+
+
+const MAX_IMAGE_SIZE = 10;
+// 上传新形象,成功后跳转至 ai 生成页
+export const uploadAndGenNewAvatar = () => {
+  Taro.chooseMedia({
+    count: 1,
+    mediaType: ["image"],
+    sourceType: ["album", "camera"],
+    async success(r) {
+      const tempFile = r.tempFiles[0];
+      const tmpPath = tempFile.tempFilePath;
+      if (MAX_IMAGE_SIZE && tempFile.size > MAX_IMAGE_SIZE * 1024 * 1024) {
+        Taro.showToast({
+          title: `文件不能超过${MAX_IMAGE_SIZE}MB`,
+          icon: "none",
+        });
+        return;
+      }
+
+      Taro.showLoading();
+      const response = await uploadImage(tmpPath, EUploadFileScene.AVATAR);
+      Taro.hideLoading();
+      if (response?.publicUrl) {
+        Taro.navigateTo({
+          url: `/pages/agent-gen/index?avatarUrl=${response?.publicUrl}`,
+        });
+      }
+    },
+  });
+};

+ 1 - 0
tailwind.config.js

@@ -49,6 +49,7 @@ module.exports = {
       'gray-25': 'rgba(0, 0, 0, 0.25)',
       'gray-45': 'rgba(0, 0, 0, 0.45)',
       'gray-65': 'rgba(0, 0, 0, 0.65)',
+      'gray-85': 'rgba(0, 0, 0, 0.85)',
       'gray-sub': 'rgba(0, 0, 0, 0.75)',
       'gray-light': 'rgba(0, 0, 0, 0.08)',
       'gray-2': 'rgba(0, 0, 0, 0.02)',