Browse Source

feat: 添加小蓝本组件

王晓东 1 month ago
parent
commit
e437ad5027
34 changed files with 563 additions and 935 deletions
  1. 10 11
      src/app.config.ts
  2. 10 0
      src/app.less
  3. 1 1
      src/components/AgentPage/components/AgentQRcode/index.tsx
  4. 4 3
      src/components/AgentPage/components/SummaryBar/index.tsx
  5. 1 1
      src/components/AgentPage/index.tsx
  6. 0 81
      src/components/chat-ai/components/AvatarMedia.tsx
  7. 0 76
      src/components/chat-ai/components/record-button/record-buttonh5.tsx
  8. 0 26
      src/components/chat-ai/components/speak-status/index.tsx
  9. 0 175
      src/components/chat-ai/index.module.less
  10. 0 316
      src/components/chat-ai/index.tsx
  11. 18 8
      src/components/component-list/components/card-contacts/index.tsx
  12. 8 10
      src/components/contact-card/index.module.less
  13. 1 1
      src/components/contact-card/index.tsx
  14. 7 0
      src/components/icon/IconHomeOutline/index.tsx
  15. 0 0
      src/components/icon/IconMoreBlack/index.tsx
  16. 2 2
      src/components/wemeta-radio/index.module.less
  17. 0 3
      src/images/svgs/Iconly/Regular/Bold/IconArrowDownRounded.svg
  18. 3 0
      src/images/svgs/icon-home-outline.svg
  19. 0 22
      src/pages/agent-gen/components/step/StepConfirm.tsx
  20. 13 3
      src/pages/agent-gen/components/step/index.module.less
  21. 0 66
      src/pages/editor-pages/editor-link-contact/components/AgentScrollList/index.tsx
  22. 0 0
      src/pages/editor-pages/editor-link-contact/components/MyAgentsScrollList/index.module.less
  23. 81 0
      src/pages/editor-pages/editor-link-contact/components/MyAgentsScrollList/index.tsx
  24. 0 0
      src/pages/editor-pages/editor-link-contact/components/MyContactsScrollList/index.module.less
  25. 103 0
      src/pages/editor-pages/editor-link-contact/components/MyContactsScrollList/index.tsx
  26. 0 0
      src/pages/editor-pages/editor-link-contact/components/MyEntAgentsScrollList/index.module.less
  27. 82 0
      src/pages/editor-pages/editor-link-contact/components/MyEntAgentsScrollList/index.tsx
  28. 4 0
      src/pages/editor-pages/editor-link-contact/index.module.less
  29. 121 36
      src/pages/editor-pages/editor-link-contact/index.tsx
  30. 3 3
      src/pages/login/index.tsx
  31. 12 52
      src/pages/profile/index.module.less
  32. 60 30
      src/pages/profile/index.tsx
  33. 16 9
      src/utils/avatar.ts
  34. 3 0
      src/xiaolanbenlib/module/axios.js

+ 10 - 11
src/app.config.ts

@@ -63,17 +63,16 @@ export default defineAppConfig({
         text: '主页'
       },
       {
-        pagePath: 'pages/contact/index',
+        pagePath: 'pages/knowledge/index',
         selectedIconPath: 'images/tabbar/contact-actived.png',
         iconPath: 'images/tabbar/contact.png',
-        text: '联系人'
+        text: '知识库'
       },
-      
       {
-        pagePath: 'pages/knowledge/index',
+        pagePath: 'pages/contact/index',
         selectedIconPath: 'images/tabbar/contact-actived.png',
         iconPath: 'images/tabbar/contact.png',
-        text: '知识库'
+        text: '联系人'
       },
       
       {
@@ -83,12 +82,12 @@ export default defineAppConfig({
         text: '数据'
       },
 
-      {
-        pagePath: 'pages/member/index',
-        selectedIconPath: 'images/tabbar/vip-actived.png',
-        iconPath: 'images/tabbar/vip.png',
-        text: '我的'
-      }
+      // {
+      //   pagePath: 'pages/member/index',
+      //   selectedIconPath: 'images/tabbar/vip-actived.png',
+      //   iconPath: 'images/tabbar/vip.png',
+      //   text: '我的'
+      // }
     ]
   },
   window: {

+ 10 - 0
src/app.less

@@ -283,6 +283,16 @@
   -webkit-background-clip: text;
   background-clip: text;
   -webkit-text-fill-color: transparent;
+  background-size: 200% auto;
+  animation: gradientMove 3s linear infinite;
+}
+@keyframes gradientMove {
+  0% {
+    background-position: 200% center;
+  }
+  100% {
+    background-position: -200% center;
+  }
 }
 
 // 边框相关

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

@@ -59,7 +59,7 @@ export default ({ show, setShow }: IProps) => {
             {renderQrcode()}
           </View>
 
-          {agent?.isMineAgent && <View className={style.bottomButtons}>
+          {(agent?.isMineAgent !== false) && <View className={style.bottomButtons}>
             <View className="pr-16" onClick={handleClick}>替换</View>
             <View className="text-gray-25">|</View>
             <View className="pl-16" onClick={handleClear}>清空</View>

+ 4 - 3
src/components/AgentPage/components/SummaryBar/index.tsx

@@ -7,7 +7,7 @@ import IconChatWhite from "@/components/icon/icon-chat-white";
 import IconQRCodeBlack from "@/components/icon/icon-qrcode-black";
 import IconSendBlack from "@/components/icon/icon-send-black";
 import IconEditBlack from "@/components/icon/icon-edit-black";
-import IconMoreBlack from "@/components/icon/icon-more-black";
+import IconMoreBlack from "@/components/icon/IconMoreBlack";
 
 import ContactIcon from '@/components/ContactIcon'
 import { useAppStore } from "@/store/appStore";
@@ -47,14 +47,15 @@ export default ({agent, isVisitor}: IProps) => {
   // 允许更多操作,非企业智能体且非访问者身份
   const enableMoreAction = !agent?.isEnt && !isVisitor
   // 是自己的智能体或者有二维码地址
-  const enableQrcode = agent?.isMineAgent || !!agent?.qrCodeUrl
+  const enableQrcode = agent?.isMineAgent !== false || !!agent?.qrCodeUrl
 
 
   // 自定义背景样式
   const bgImageStyle = {
     marginTop: -headerHeight,
     // background: `linear-gradient(rgba(242, 244, 245, 0) 0%, rgba(242, 244, 245, .8) 80% , rgba(242, 244, 245,1) 100%), url(${customBgImg})`,
-    backgroundImage: `url(https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png)`,
+    // backgroundImage: `url(https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png)`,
+    backgroundImage: `url(${agent?.avatarUrl})`,
   };
 
   return (

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

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

+ 0 - 81
src/components/chat-ai/components/AvatarMedia.tsx

@@ -1,81 +0,0 @@
-import { Image, Video, VideoProps } from "@tarojs/components";
-import { ECharacterAISTATUS } from "@/types/index";
-import { useCharacterAIStore } from "@/store/characterAIStore";
-import style from "../index.module.less";
-import { ICharacter } from "@/types";
-import { useEffect, useRef } from "react";
-import Taro from "@tarojs/taro";
-
-interface Props {
-  character: ICharacter;
-}
-
-export const AvatarMedia = ({ character }: Props) => {
-  const AIStatus = useCharacterAIStore((state) => state.status);
-  const videoRef = useRef<React.ComponentType<VideoProps>|null>(null);
-  const videoContext = useRef<Taro.VideoContext|null>(null);
-  const videoId = useRef(`video-${Math.random().toString(36).substr(2, 9)}`);
-
-  const videoErrorCallback = (e) =>  {
-    console.log('Video error info:')
-    console.log(e.detail)
- }
-
- // 处理 ios 上无法循环播放的 bug
- const handleOnEnded = () => {
-  if(AIStatus === ECharacterAISTATUS.RESPONDING && videoContext.current){
-    videoContext.current.seek(0)
-    videoContext.current.play()
-  }
- }
-
-
-  useEffect(() => {
-    if (videoRef.current) {
-      videoContext.current = Taro.createVideoContext(videoId.current, this);
-    }
-  }, []);
-
-  useEffect(() => {
-    if (videoContext.current) {
-      if (AIStatus === ECharacterAISTATUS.RESPONDING) {
-        videoContext.current.play();
-      } else {
-        videoContext.current.seek(0)
-        videoContext.current.pause();
-        console.log('video play end')
-      }
-    }
-  }, [AIStatus]);
-
-  if (!character?.avatar) {
-    return <></>;
-  }
-
-  if (character.avatar?.lastIndexOf('.mp4') > -1) {
-    return (
-      <Video
-        id={videoId.current}
-        ref={videoRef}
-        controls={false}
-        showCenterPlayBtn={false}
-        loop={true}
-        muted={true}
-        onEnded={handleOnEnded}
-        objectFit="cover"
-        className={`${style.avatar}`}
-        onError={videoErrorCallback}
-        // src="https://cdn.wehome.cn/cmn/mp4/3/META-H8UKWHWU-YAUTZH7ECGRDC57FD3NI3-CUGVCS8M-CD.mp4"
-        src={character.avatar}
-      />
-    );  
-  }
-
-  return (
-    <Image
-      mode="aspectFill"
-      className={style.avatar}
-      src={character.avatar}
-    />
-  );
-};

+ 0 - 76
src/components/chat-ai/components/record-button/record-buttonh5.tsx

@@ -1,76 +0,0 @@
-import { useRef,useEffect } from "react";
-import { useLongPress } from "use-long-press";
-import style from '../../index.module.less';
-interface Props {
-  speechStatus: number,
-  onLongPress: () => void,
-  onTouchEnd: () => void,
-}
-export default ({speechStatus, onLongPress, onTouchEnd}:Props) => {
-  // 适配 h5
-  const recordRef = useRef<HTMLDivElement | null>(null);
-  useEffect(() => {
-    console.log("[ 首次挂载 ] >");
-    const handleTouchStart = (e: TouchEvent) => {
-      console.log("touchstart", e);
-      e.preventDefault();
-      e.stopPropagation();
-    };
-    recordRef.current?.addEventListener("click", handleTouchStart);
-    recordRef.current?.addEventListener("touchstart", handleTouchStart);
-    return () => {
-      recordRef.current?.removeEventListener("touchstart", handleTouchStart);
-      recordRef.current?.removeEventListener("click", handleTouchStart);
-    };
-  }, []);
-  const bind = useLongPress(
-    () => {
-      console.log("[ longpress ] >");
-      onLongPress();
-    },
-    {
-      onStart: (e) => {
-        e.stopPropagation();
-        e.preventDefault();
-        console.log("start");
-      },
-      onCancel: () => {
-        console.log("cancel");
-      },
-      onFinish: () => {
-        console.log("finish");
-        onTouchEnd();
-      },
-      threshold: 150,
-    }
-  );
-  const render = () =>{
-    if (speechStatus === 0) {
-      return (
-        <div className={style.speechButton} {...bind()} ref={recordRef}>
-          <div
-            className={`iconfont icon-a-icon_24_micon ${style.iconMic}`}
-          ></div>
-          <div>按住对话</div>
-        </div>
-      );
-    }
-    if (speechStatus === 1) {
-      return (
-        <div className={style.speechButtonActive}>
-          <img
-            src='https://cdn.wehome.cn/cmn/gif/199/META-H8UKVHWU-KIGP3BIL7M5AYC6XHNUA2-OSAK6A2M-72.gif'
-            style={{
-              objectFit: "contain",
-
-              height: "80%",
-            }}
-          ></img>
-        </div>
-      );
-    }
-  }
-  return <>
-    {render()}
-  </>
-}

+ 0 - 26
src/components/chat-ai/components/speak-status/index.tsx

@@ -1,26 +0,0 @@
-import { Image } from "@tarojs/components";
-import { ECharacterAISTATUS } from "@/types/index";
-import { useCharacterAIStore } from "@/store/characterAIStore";
-import style from '../../index.module.less'
-export default () => {
-  const AIStatus = useCharacterAIStore((state) => state.status);
-  if (AIStatus === ECharacterAISTATUS.THINKING) {
-    return (
-      <Image
-        mode="widthFix"
-        className={style.AIStatus}
-        src='https://cdn.wehome.cn/cmn/gif/56/META-H8UKYHWU-E9EPKMQUBSVOJ4T4NHO63-LPH8X92M-NI.gif'
-      />
-    );
-  }
-  if (AIStatus === ECharacterAISTATUS.RESPONDING) {
-    return (
-      <Image
-        mode="widthFix"
-        className={style.AIStatus}
-        src='https://cdn.wehome.cn/cmn/gif/52/META-H8UK1IWU-R9EPMWD4CDA7Y5NKEQSM2-EPXFX92M-EI.gif'
-      />
-    );
-  }
-  return <></>
-}

+ 0 - 175
src/components/chat-ai/index.module.less

@@ -1,175 +0,0 @@
-.wrapper{
-  width: 319px;
-  overflow-x: clip;
-  // min-height: 1046px;
-}
-
-.cardContainer{
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  width: 100%;
-  height: 100%;
-  z-index: 2;
-  box-sizing: border-box;
-}
-
-.nickname{
-  padding: 40px 0;
-  text-align: center;
-  font-size: 18px;
-  line-height: 26px;
-  color: #000;
-  text-shadow: 0 0 1px #FFF, 0 0 1px #FFF, 0 0 1px #FFF, 0 0 1px #FFF;
-  font-weight: 600;
-  max-width: 240px;
-}
-
-.circleOurter{
-  margin-top: 10px;
-  margin-bottom: 36px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 210px;
-  height: 210px;
-  box-sizing: border-box;
-  flex-shrink: 0;
-  overflow: hidden;
-  border-radius: 100%;
-  background-color: rgba(#000, .03);
-}
-.circleInner{
-  position: relative;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 174px;
-  height: 174px;
-  box-sizing: content-box;
-  overflow: hidden;
-  border-radius: 100%;
-  border: 4px solid #000;
-  background-color: white;
-}
-.avatar{
-  position: absolute;
-  left: 0;
-  top: 0;
-  z-index: 1;
-  width: 174px;
-  height: 174px;
-  overflow: hidden;
-  // border-radius: 100%;
-}
-
-
-.speachAnimation{
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  gap: 3px;
-  width: 33px;
-  height: 40px;
-  .speachAnimationItem{
-    width: 6px;
-    height: 15px;
-    border-radius: 7px;
-    background-color: #000;
-  }
-}
-
-
-.cardButtons{
-  position: absolute;
-  left: 0px;
-  right: 0px;
-  bottom: 0px;
-}
-.cardButtonRow{
-  padding: 2px;
-  display: flex;
-  width: 100%;
-  // border-radius: 0 0 40px 40px;
-  // overflow: hidden;
-  box-sizing: border-box;
-}
-.cardButton{
-  flex: 1;
-  height: 20px;
-  font-size: 14px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-// .speech{
-//   width: 124px;
-//   height: 27px;
-// }
-.speechButton{
-  display: flex;
-  align-items: center;
-  --button-width: 303px;
-  --speech-text-padding-left: 68px;
-  width: var(--button-width);
-  height: 54px;
-  background-color: var(--color-bg-primary);
-  border-radius: 50px;
-  overflow: hidden;
-}
-.speechButtonInner{
-  position: relative;
-  display: flex;
-  width: 100%;
-  height: 100%;
-  align-items: center;
-}
-
-.speechText{
-  padding-left: var(--speech-text-padding-left);
-}
-
-.speechButtonActive{
-  .speechButton();
-  justify-content: center;
-  background: url(https://cdn.wehome.cn/cmn/gif/199/META-H8UKVHWU-KIGP3BIL7M5AYC6XHNUA2-OSAK6A2M-72.gif) center center no-repeat;
-  background-size: 124px 27px;
-  background-color: #000;
-}
-
-// 小尺寸按钮样式覆盖
-.buttonSmall{
-  --button-width: 247px;
-  --speech-text-padding-left: 54px;
-}
-
-
-.keyboardButton{
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 54px;
-  height: 54px;
-  background-color: rgba(#000, .03)
-}
-.shareButton{
-  .speechButton();
-  position: relative;
-  display: flex;
-  gap: 4px;
-  justify-content: center;
-  align-items: center;
-  background-color: white;
-}
-.iconMic{
-  font-size: 20px;
-}
-.AIStatus{
-  position: absolute;
-  width: 174px;
-  height: 32px;
-  left: 0;
-  bottom: 0;
-  z-index: 2;
-}

+ 0 - 316
src/components/chat-ai/index.tsx

@@ -1,316 +0,0 @@
-import { Image, Text, View, type CommonEvent } from "@tarojs/components";
-import {
-  forwardRef,
-  useEffect,
-  useImperativeHandle,
-  useState,
-  useMemo,
-  useCallback,
-  memo,
-} from "react";
-
-import { useVoiceRecord } from "@/components/voice-recorder";
-import IconShare from "@/images/icon-share.png";
-import { chat } from "@/service/character";
-import { useCharacterAIStore } from "@/store/characterAIStore";
-import {
-  greeting,
-} from '@/service/character'
-import type { ICharacter } from "@/types";
-import { ECharacterAISTATUS } from "@/types/index";
-import { useAudioPlayer } from "@/utils/audio";
-import { useBase64AudioPlayer } from "@/utils/audioBase64";
-import { handleShare } from "@/utils/share";
-import Taro, { useDidHide, useUnload } from "@tarojs/taro";
-import { axios } from "taro-axios";
-import style from "./index.module.less";
-import SharePopup from "@/components/custom-share/share-popup/index";
-import SpeakStatus from "./components/speak-status"
-import IconKeyboard from '@/components/icon/icon-keyboard';
-import { AvatarMedia } from "./components/AvatarMedia";
-import { setChatSession, getChatSession } from '@/store/chat'
-let cancelTokenSource = axios.CancelToken.source();
-interface Props {
-  character: ICharacter;
-  getSession?: boolean; // 是否发起greeting 请求获取聊天用的 session
-  playGreeting?: boolean; // 是否播放欢迎语
-  shareButton?: boolean; // 是否显示分享按钮
-  avatarRenderer?: () => JSX.Element; // 自定义渲染头像
-  nicknameRenderer?: () => JSX.Element; // 自定义渲染昵称
-  enableGoPreview?: boolean; // 允许点击头像去预览
-  buttonSize?: string; // 按钮大小
-}
-let source: AudioBufferSourceNode;
-export interface IChatAIComponent {
-  stop: () => void;
-}
-
-
-const ChatAI = memo(forwardRef(
-  (
-    {
-      character,
-      playGreeting = false,
-      getSession = false,
-      enableGoPreview = false,
-      shareButton = true,
-      avatarRenderer,
-      nicknameRenderer,
-      buttonSize,
-    }: Props,
-    ref
-  ) => {
-    const currentCharacter = character;
-    const [speechStatus, setSpeechStatus] = useState(0);
-    const { start, stop, onVolumeChange, onStop } = useVoiceRecord();
-    const { stopPlayChunk, onPlayerStatusChanged } = useAudioPlayer();
-    const { playAudio, stopAudio, onEnded } = useBase64AudioPlayer();
-    const { setStatus } = useCharacterAIStore();
-    const [sharePopupVisible, setSharePopupVisible] = useState(false);
-    // console.log(
-    //   "currentCharacter:",
-    //   currentCharacter?.profileId,
-    //   character.profileId,
-    //   getSession
-    // );
-
-    const handleShareClick = () => {
-      handleShare();
-      Taro.hideTabBar();
-      setSharePopupVisible(true);
-    };
-    const handleSharePopupClosed = () => {
-      Taro.showTabBar();
-      setSharePopupVisible(false);
-    };
-
-    const stopSpeek = () => {
-      setSpeechStatus(0);
-      stop();
-    };
-
-    onEnded(()=> {
-      setStatus(ECharacterAISTATUS.IDLE)
-    })
-
-
-    onPlayerStatusChanged((status: ECharacterAISTATUS) => {
-      setStatus(status)
-    });
-
-    const stopPlay = () => {
-      source && source.stop();
-      stopPlayChunk();
-    };
-
-    const stopPropagation = (e?: CommonEvent)=> {
-      e?.stopPropagation();
-    }
-    const onLongPress = (e?: CommonEvent) => {
-      e?.stopPropagation();
-      setSpeechStatus(1);
-      stopPlay();
-      start();
-    };
-    const onTouchEnd = () => {
-      stopSpeek();
-    };
-
-    const handleTouchStart = (e: CommonEvent) => {
-      // fix 解决pc端长按呼出右键菜单
-      e.preventDefault();
-      // fix 解决移动端长按依旧穿透
-      e.stopPropagation();
-    };
-
-    onVolumeChange((_v) => {});
-
-    onStop((res) => {
-      const session = getChatSession()
-      console.log("record stop:", res, session);
-      stopSpeek();
-      if (!res) {
-        return;
-      }
-      console.log(character.profileId, session);
-      if (character?.profileId && session) {
-        setStatus(ECharacterAISTATUS.THINKING);
-        chat(
-          character.profileId,
-          session,
-          res?.tempFilePath || res?.arrayBuffer
-        );
-      }
-    });
-
-    // 打招呼,聊天前都需要先招呼获取聊天所需的 session
-    const showGreeting = async () => {
-      // cancelTokenSource.cancel('Previous showGreeting request canceled')
-      // 重新创建一个新的取消令牌源
-      if (!getSession) {
-        return;
-      }
-      cancelTokenSource = axios.CancelToken.source();
-      const res = await greeting(currentCharacter.profileId, {
-        cancelToken: cancelTokenSource.token,
-      });
-      if(res.code !== 0){
-        return
-      }
-      if (res?.data?.audio && playGreeting) {
-        setStatus(ECharacterAISTATUS.RESPONDING);
-        const _source = await playAudio(res?.data?.audio);
-        if (_source) {
-          source = _source;
-        }
-      }
-      if (res?.data?.session) {
-        setChatSession(res.data?.session);
-      }
-    };
-
-    const handleNav = () => {
-      if (enableGoPreview) {
-        Taro.navigateTo({
-          url: "/pages/profile/index?profileId=" + character.profileId,
-        });
-      }
-    };
-    
-    const gotoChat = () => {
-      Taro.navigateTo({
-        url: "/pages/chat/index?profileId=" + character.profileId,
-      });
-    };
-
-    // 侦听卡片是否为当前卡片,是的话需要播放欢迎语拿session
-    // 后期是否优化考虑保存住每个卡片的 session
-    useEffect(() => {
-      if (currentCharacter?.profileId === character.profileId) {
-        showGreeting();
-      }
-      return () => {
-        cancelTokenSource.cancel("Previous showGreeting request canceled");
-        source && source.stop();
-      };
-    }, [currentCharacter?.profileId, character.profileId, getSession]);
-    const stopChatAI = useCallback(() => {
-      // todo: 调用此方法会导致组件重新渲染,需要优化
-      setStatus(ECharacterAISTATUS.IDLE);
-      stopPlay();
-    },[]);
-
-    // 对外暴露 stop 方法
-    useImperativeHandle(ref, () => {
-      return {
-        stop: stopChatAI,
-      };
-    });
-
-    useDidHide(() => {
-      stopPlay();
-      stopAudio();
-    });
-
-    useUnload(() => {
-      stopPlay();
-      stopAudio();
-    });
-
-    // 使用 useCallback 缓存渲染函数
-    const renderSpeechButton = useMemo(() => {
-      if (process.env.TARO_ENV == "h5") {
-        return <></>;
-      }
-      const idle = speechStatus === 0;
-      return (
-        <View className={`${idle ? style.speechButton : style.speechButtonActive} ${buttonSize === 'small' ? style.buttonSmall : ''}`}>
-          <View className={idle ? style.speechButtonInner : "hidden"}>
-            <View className={style.keyboardButton} onLongPress={stopPropagation}
-            onTouchStart={stopPropagation}
-            onTouchEnd={stopPropagation}
-            onClick={()=> {gotoChat()}}
-            >
-              <IconKeyboard></IconKeyboard>
-            </View>
-            <Text className={`font-medium ${style.speechText}`}>按住对话</Text>
-          </View>
-        </View>
-      );
-    }, [speechStatus]);
-
-    const renderNickName = useMemo(() => {
-      if (nicknameRenderer) {
-        return nicknameRenderer();
-      }
-      return <View className="truncate">{character?.name}</View>;
-    }, [character?.name, nicknameRenderer]);
-
-    const renderNameAndAvatar = useMemo(() => {
-      return (
-        <>
-          <View
-            className={`flex items-center justify-center ${style.nickname} truncate`}
-            onClick={handleNav}
-            id="user-name"
-          >
-            {renderNickName}
-          </View>
-
-          <View className={style.circleOurter} onClick={handleNav}>
-            <View className={style.circleInner}>
-              {/* {renderAIStatus} */}
-              <SpeakStatus></SpeakStatus>
-              {avatarRenderer && avatarRenderer()}
-              {character?.avatar && !avatarRenderer && (
-                <AvatarMedia character={character}></AvatarMedia>
-              )}
-            </View>
-          </View>
-        </>
-      );
-    }, [character?.avatar, avatarRenderer, handleNav, renderNickName]);
-
-    return (
-      <View
-        className={`flex flex-col items-center relative w-full ${style.wrapper}`}
-      >
-        <View
-          className={`${style.cardContainer}`}
-          style={character.customStyled}
-        >
-          {renderNameAndAvatar}
-          <View
-            className={`flex flex-col items-center justify-center pt-42 gap-12`}
-            onLongPress={onLongPress}
-            onTouchStart={handleTouchStart}
-            onTouchEnd={onTouchEnd}
-          >
-            {renderSpeechButton}
-
-            {shareButton && (
-              <>
-              <View className={style.shareButton} onClick={handleShareClick}>
-                <Image src={IconShare} className="w-20 h-20" />
-                {/* <Button openType={"share"} className="share-button"></Button> */}
-                <Text>分享</Text>
-              </View>
-              <SharePopup
-                character={character}
-                visible={sharePopupVisible}
-                onClose={handleSharePopupClosed}
-              ></SharePopup>
-              </>
-            )}
-            
-          </View>
-        </View>
-      </View>
-    );
-  }
-));
-
-// 添加显示名称,方便调试
-ChatAI.displayName = 'ChatAI';
-
-export default ChatAI;

+ 18 - 8
src/components/component-list/components/card-contacts/index.tsx

@@ -10,7 +10,8 @@ import type {
   ICharacter,
 } from "@/types/index";
 import { useEffect, useState } from "react";
-import { TComponentItem } from "@/types/agent";
+import { TAgent, TComponentItem } from "@/types/agent";
+import { TContactItem } from "@/types/contact";
 
 interface Props {
   index: number;
@@ -36,12 +37,20 @@ export default ({
   onStyleChanged,
 }: Props) => {
   
-  const contacts = component.data.values
+  const contacts = (component.data.values ?? []) as (TAgent|TContactItem)[]
 
 
   // 非编辑模式且垂直平铺,背景显示为白色
   const bgStyle = (component.data?.layout === "mini" || editMode) ? style.bgMini : style.bgFull
 
+  const handleClick= (item: TAgent|TContactItem) => {
+    if(!editMode){
+      Taro.navigateTo({
+        url: "/pages/profile/index?agentId=" + item?.agentId,
+      });
+    }
+  }
+
   
   const renderEmpty = ()=> {
     if(contacts.length){
@@ -50,7 +59,7 @@ export default ({
     return <View className="px-16"><View className="component-card-empty">
       <View className="component-card-content">
         <View className="component-card-empty-figure"></View>
-        <View className="component-card-empty-tips">点击配置视频号视频</View>
+        <View className="component-card-empty-tips">点击配置小蓝本名片跳转</View>
       </View>
     </View>
     </View>
@@ -63,10 +72,10 @@ export default ({
         <View className="grid grid-cols-3 gap-x-18 gap-y-20 px-16">
           {contacts.map((item) => {
             return (
-              <View className="flex flex-col gap-8" onClick={() => {}}>
+              <View className="flex flex-col gap-8" onClick={()=> {handleClick(item)}}>
                 <View className={style.avatar}>
-                  {item.avatar && (
-                    <Image src={item.avatar} mode='aspectFill' className={style.avatar} lazyLoad></Image>
+                  {item.avatarUrl && (
+                    <Image src={item.avatarUrl} mode='aspectFill' className={style.avatar} lazyLoad></Image>
                   )}
                 </View>
                 <View className={`truncate ${style.nickName}`}>
@@ -85,10 +94,10 @@ export default ({
         {contacts.map((item) => {
           return (
             <ContactCard
-              className={ bgStyle }
+              className={`${bgStyle} p-16`}
               key={item.agentId}
               data={item}
-              onClick={() => {}}
+              onClick={()=> {handleClick(item)}}
               renderRight={() => {
                 return (
                   <Image
@@ -115,6 +124,7 @@ export default ({
     )
   }
   
+  // 编辑模式下,添加一个外包框
   return (
     <>
       <WidgetCard

+ 8 - 10
src/components/contact-card/index.module.less

@@ -1,31 +1,29 @@
 .contactCard{
   display: flex;
-  padding: 16px;
   align-items: center;
-  gap: 4px;
-  align-self: stretch;
-  border-radius: 20px;
+  gap: 12px;
+  border-radius: 12px;
+  align-self: stretch;;
   background: white;
   color: #262626;
   font-family: "PingFang SC";
-  box-shadow: 0 4px 12px rgba(#6A685E, .03);
 }
 
 .avatar{
   display: flex;
-  width: 72px;
-  height: 72px;
+  width: 55px;
+  height: 55px;
   justify-content: center;
   align-items: center;
-  border-radius: 72px;
+  border-radius: 55px;
   overflow: hidden;
   flex-shrink: 0;
   border: 1px solid rgba(0, 0, 0, 0.04);
 }
 .avatarImg{
   display: block;
-  width: 72px;
-  height: 72px;
+  width: 55px;
+  height: 55px;
 }
 .infoColumn{
   display: flex;

+ 1 - 1
src/components/contact-card/index.tsx

@@ -3,7 +3,7 @@ import style from './index.module.less'
 import { TContactItem } from '@/types/contact'
 import { TAgent } from '@/types/agent'
 interface Props {
-  data: TContactItem
+  data: TContactItem|TAgent
   onClick?: (data: TContactItem|TAgent)=>void
   renderRight?: ()=> JSX.Element | JSX.Element[]
   className?: string

+ 7 - 0
src/components/icon/IconHomeOutline/index.tsx

@@ -0,0 +1,7 @@
+import { Image } from '@tarojs/components'
+import Icon from '@/images/svgs/icon-home-outline.svg'
+export default () => {
+  return (
+    <Image src={Icon} mode="widthFix" style={{width: '17px', height: '17px'}}></Image>
+  )
+}

+ 0 - 0
src/components/icon/icon-more-black/index.tsx → src/components/icon/IconMoreBlack/index.tsx


+ 2 - 2
src/components/wemeta-radio/index.module.less

@@ -19,8 +19,8 @@
   background: #EDEDED;
 }
 .radio.checked{
-  border: 1px solid #000;
-  background-color: #000;
+  border: 1px solid var(--color-primary);
+  background-color: var(--color-primary);
   .inner{
     opacity: 1;
   }

+ 0 - 3
src/images/svgs/Iconly/Regular/Bold/IconArrowDownRounded.svg

@@ -1,3 +0,0 @@
-<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M5.4345 8.31539C5.4055 8.28714 5.2815 8.18047 5.1795 8.0811C4.538 7.49854 3.488 5.97881 3.1675 5.18339C3.116 5.06259 3.007 4.75718 3 4.59401C3 4.43765 3.036 4.2886 3.109 4.14637C3.211 3.96907 3.3715 3.82684 3.561 3.7489C3.6925 3.69873 4.086 3.6208 4.093 3.6208C4.5235 3.54286 5.223 3.5 5.996 3.5C6.7325 3.5 7.4035 3.54286 7.8405 3.60667C7.8475 3.61398 8.3365 3.69191 8.504 3.77716C8.81 3.93351 9 4.23892 9 4.56576V4.59401C8.9925 4.80687 8.8025 5.25451 8.7955 5.25451C8.4745 6.00706 7.476 7.49172 6.8125 8.08841C6.8125 8.08841 6.642 8.25645 6.5355 8.32952C6.3825 8.4435 6.193 8.5 6.0035 8.5C5.792 8.5 5.595 8.43619 5.4345 8.31539Z" fill="black" fill-opacity="0.25"/>
-</svg>

+ 3 - 0
src/images/svgs/icon-home-outline.svg

@@ -0,0 +1,3 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path opacity="0.8" d="M10.5726 17.8047V12.7684C10.5726 11.8412 9.82097 11.0896 8.89382 11.0896C7.98927 11.0896 7.25182 11.805 7.21639 12.7009L7.21505 12.7684V17.8047H1.87353C1.13663 17.8047 0.535257 17.2244 0.501495 16.4958L0.5 16.4312V7.26941C0.5 6.67634 0.765209 6.11589 1.22029 5.73994L1.28351 5.68983L6.76989 1.52019C7.99844 0.586486 9.68877 0.56662 10.937 1.46059L11.0177 1.52019L16.5041 5.68983C16.9763 6.04869 17.262 6.59896 17.286 7.18875L17.2876 7.26941V16.4312C17.2876 17.1681 16.7073 17.7694 15.9788 17.8032L15.9141 17.8047H10.5726ZM7.76063 2.68628L7.69333 2.73525L2.20696 6.90489C2.1057 6.98185 2.04159 7.09696 2.0286 7.22208L2.02615 7.26941V16.2785L5.6889 16.2783V12.7684C5.6889 10.9984 7.12379 9.56349 8.89382 9.56349C10.6348 9.56349 12.0516 10.9517 12.0976 12.6816L12.0987 12.7684V16.2783L15.7615 16.2785V7.26941C15.7615 7.14223 15.7086 7.02154 15.6169 6.93549L15.5807 6.90489L10.0943 2.73525C9.40697 2.21288 8.46394 2.19656 7.76063 2.68628Z" fill="black"/>
+</svg>

+ 0 - 22
src/pages/agent-gen/components/step/StepConfirm.tsx

@@ -13,28 +13,6 @@ interface IProps {
 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 = async () => {
     if(!agent?.agentId){

+ 13 - 3
src/pages/agent-gen/components/step/index.module.less

@@ -49,6 +49,17 @@
   justify-content: center;
   align-items: center;
   background: linear-gradient(162.45deg, rgba(206, 49, 250, 0.1) 1.4%, rgba(49, 124, 250, 0.2) 100.04%);
+  background-size: auto 400%;
+  animation: gradientMove 4s linear infinite;
+}
+
+@keyframes gradientMove {
+  0% {
+    background-position: center 400%;
+  }
+  100% {
+    background-position: center -400%;
+  }
 }
 
 .mySwiper{
@@ -111,7 +122,6 @@
 
 .confirmContainer{
   width: 343px;
-  height: 511px;
   display: flex;
   flex-direction: column;
   align-items: center;
@@ -132,7 +142,7 @@
 .confirmChatAvatarBg{
   position: relative;
   width: 240px;
-  height: 427px;
+  min-height: 373px;
   margin-bottom: 16px;
   border-radius: 24px;
 }
@@ -147,7 +157,7 @@
   right: 0;
   z-index: 1;
   width: 240px;
-  height: 373px;
+  min-height: 373px;
   box-sizing: border-box;
   padding: 0 24px 54px;
   border-radius: 24px;

+ 0 - 66
src/pages/editor-pages/editor-link-contact/components/AgentScrollList/index.tsx

@@ -1,66 +0,0 @@
-import Taro, { useReachBottom,} from "@tarojs/taro";
-import { View, Text } from "@tarojs/components";
-import style from "./index.module.less";
-import { useEffect, useState } from "react";
-import { getContactList } from "@/service/contact";
-import { useLoadMore } from "@/utils/loadMore";
-import { TContactItem } from "@/types/contact";
-
-
-
-export default function Index() {
-  const [list, setList] = useState<TContactItem[]>([]);
-
-  const fetcher = async ([_url, nextId, page, pageSize, _keyword]) => {
-    let keyword = _keyword
-    const res = await getContactList({ startId: nextId, pageSize, keyword });
-    return res.data;
-  };
-  const { data, loadMore, refetch } = useLoadMore<{
-    data?: TContactItem[]
-    nextId?: string,
-    totalCount?: number
-  }>({
-    url: '/blue-aiagent/api/v1/my/contacts',
-    fetcher,
-  });
-
-  useReachBottom(() => {
-    // 加载更多数据
-    loadMore();
-  });
-
-  useEffect(() => {
-    if (data?.data) {
-      setList([...list, ...data.data]);
-    }
-  }, [data]);
-
-
-  const handleHello = async (e: any) => {
-    
-    
-  };
-
-  const renderContent = () => {
-    if (list?.length) {
-      return list.map((item) => (
-        <View className='bg-white'>
-          {item.name}
-        </View>
-      ));
-    }
-    return (
-      <View className="flex flex-col pt-56 items-center">
-        <View className="data-empty"></View>
-        <View className="text-12 text-gray-45 text-center leading-24 mt-12">
-          暂无数据
-        </View>
-      </View>
-    );
-  };
-
-  return (
-    <View>{renderContent()}</View>
-  );
-}

+ 0 - 0
src/pages/editor-pages/editor-link-contact/components/AgentScrollList/index.module.less → src/pages/editor-pages/editor-link-contact/components/MyAgentsScrollList/index.module.less


+ 81 - 0
src/pages/editor-pages/editor-link-contact/components/MyAgentsScrollList/index.tsx

@@ -0,0 +1,81 @@
+import Taro, { useReachBottom,} from "@tarojs/taro";
+import { View, ScrollView } from "@tarojs/components";
+import style from "./index.module.less";
+import { useEffect, useState } from "react";
+import { getContactList } from "@/service/contact";
+import { useLoadMore } from "@/utils/loadMore";
+import { TContactItem } from "@/types/contact";
+import ContactCard from "@/components/contact-card/index";
+import WemetaRadio from "@/components/wemeta-radio/index";
+import { useAgentStore } from "@/store/agentStore";
+import { TAgent } from "@/types/agent";
+
+export interface IProps {
+  selected: any[]
+  setSelected: (values) => void
+}
+
+
+export default function Index({selected, setSelected}: IProps) {
+
+  const {agents} = useAgentStore()
+  const myAgents = agents.filter(item => !item.isEnt)
+  
+
+  const handleClick = (item: TAgent) => {
+    console.log(item)
+    const exist = selected.find(_item =>  _item.agentId === item.agentId)
+    console.log(exist)
+    if(exist){
+      const filtered = selected.filter(_item => _item.agentId !== item.agentId)
+      setSelected(filtered)
+    }else{
+      setSelected([...selected, item])
+    }
+  };
+
+  const renderContent = () => {
+    if (myAgents?.length) {
+      return myAgents.map((item) => (
+        <View className='bg-white'>
+          <ContactCard
+              className="border-bottom1-gray py-16"
+              key={item.agentId}
+              data={item}
+              onClick={()=> handleClick(item)}
+              renderRight={() => {
+                return (
+                  <View className="flex items-center">
+                    <WemetaRadio
+                      checkbox
+                      checked={!!selected.find(_item =>  _item.agentId === item.agentId)}
+                    ></WemetaRadio>
+                  </View>
+                );
+              }}
+            ></ContactCard>
+        </View>
+      ));
+    }
+    return (
+      <View className="flex flex-col pt-56 items-center">
+        <View className="data-empty"></View>
+        <View className="text-12 text-gray-45 text-center leading-24 mt-12">
+          暂无数据
+        </View>
+      </View>
+    );
+  };
+
+  return (
+    <ScrollView
+      scrollY
+      style={{
+        flex: 1,
+        height: "100%", // 高度自适应
+      }}
+    >
+      {renderContent()}
+    </ScrollView>
+  );
+}

+ 0 - 0
src/pages/editor-pages/editor-link-contact/components/MyContactsScrollList/index.module.less


+ 103 - 0
src/pages/editor-pages/editor-link-contact/components/MyContactsScrollList/index.tsx

@@ -0,0 +1,103 @@
+import Taro, { useReachBottom,} from "@tarojs/taro";
+import { View, ScrollView } from "@tarojs/components";
+import style from "./index.module.less";
+import { useEffect, useState } from "react";
+import { getContactList } from "@/service/contact";
+import { useLoadMore } from "@/utils/loadMore";
+import { TContactItem } from "@/types/contact";
+import ContactCard from "@/components/contact-card/index";
+import WemetaRadio from "@/components/wemeta-radio/index";
+
+export interface IProps {
+  selected: any[]
+  setSelected: (values) => void
+}
+
+
+export default function Index({selected, setSelected}: IProps) {
+  const [list, setList] = useState<TContactItem[]>([]);
+
+  const fetcher = async ([_url, nextId, page, pageSize, _keyword]) => {
+    let keyword = _keyword
+    const res = await getContactList({ startId: nextId, pageSize, keyword });
+    return res.data;
+  };
+  const { data, loadMore, refetch } = useLoadMore<{
+    data?: TContactItem[]
+    nextId?: string,
+    totalCount?: number
+  }>({
+    url: '/blue-aiagent/api/v1/my/contacts',
+    fetcher,
+  });
+
+  const onScrollToLower = () => {
+    // 加载更多数据
+    loadMore();
+  };
+
+  useEffect(() => {
+    if (data?.data) {
+      setList([...list, ...data.data]);
+    }
+  }, [data]);
+
+
+  const handleClick = (item: TContactItem) => {
+    console.log(item)
+    const exist = selected.find(_item =>  _item.contactId === item.contactId)
+    console.log(exist)
+    if(exist){
+      const filtered = selected.filter(_item => _item.contactId !== item.contactId)
+      setSelected(filtered)
+    }else{
+      setSelected([...selected, item])
+    }
+  };
+
+  const renderContent = () => {
+    if (list?.length) {
+      return list.map((item) => (
+        <View className=''>
+          <ContactCard
+              className="border-bottom1-gray py-16"
+              key={item.contactId}
+              data={item}
+              onClick={()=> handleClick(item)}
+              renderRight={() => {
+                return (
+                  <View className="flex items-center">
+                    <WemetaRadio
+                      checkbox
+                      checked={!!selected.find(_item =>  _item.contactId === item.contactId)}
+                    ></WemetaRadio>
+                  </View>
+                );
+              }}
+            ></ContactCard>
+        </View>
+      ));
+    }
+    return (
+      <View className="flex flex-col pt-56 items-center">
+        <View className="data-empty"></View>
+        <View className="text-12 text-gray-45 text-center leading-24 mt-12">
+          暂无数据
+        </View>
+      </View>
+    );
+  };
+
+  return (
+    <ScrollView
+      scrollY
+      onScrollToLower={onScrollToLower}
+      style={{
+        flex: 1,
+        height: "100%", // 高度自适应
+      }}
+    >
+      {renderContent()}
+    </ScrollView>
+  );
+}

+ 0 - 0
src/pages/editor-pages/editor-link-contact/components/MyEntAgentsScrollList/index.module.less


+ 82 - 0
src/pages/editor-pages/editor-link-contact/components/MyEntAgentsScrollList/index.tsx

@@ -0,0 +1,82 @@
+import Taro, { useReachBottom,} from "@tarojs/taro";
+import { View, ScrollView } from "@tarojs/components";
+import style from "./index.module.less";
+import { useEffect, useState } from "react";
+import { getContactList } from "@/service/contact";
+import { useLoadMore } from "@/utils/loadMore";
+import { TContactItem } from "@/types/contact";
+import ContactCard from "@/components/contact-card/index";
+import WemetaRadio from "@/components/wemeta-radio/index";
+import { useAgentStore } from "@/store/agentStore";
+import { TAgent } from "@/types/agent";
+
+export interface IProps {
+  selected: any[]
+  setSelected: (values) => void
+}
+
+
+export default function Index({selected, setSelected}: IProps) {
+
+  const { agents } = useAgentStore()
+
+  const entAgents = agents.filter(item => item.isEnt)
+  
+
+  const handleClick = (item: TAgent) => {
+    console.log(item)
+    const exist = selected.find(_item =>  _item.agentId === item.agentId)
+    console.log(exist)
+    if(exist){
+      const filtered = selected.filter(_item => _item.agentId !== item.agentId)
+      setSelected(filtered)
+    }else{
+      setSelected([...selected, item])
+    }
+  };
+
+  const renderContent = () => {
+    if (entAgents.length) {
+      return entAgents.map((item) => (
+        <View className='bg-white'>
+          <ContactCard
+              className="border-bottom1-gray py-16"
+              key={item.agentId}
+              data={item}
+              onClick={()=> handleClick(item)}
+              renderRight={() => {
+                return (
+                  <View className="flex items-center">
+                    <WemetaRadio
+                      checkbox
+                      checked={!!selected.find(_item =>  _item.agentId === item.agentId)}
+                    ></WemetaRadio>
+                  </View>
+                );
+              }}
+            ></ContactCard>
+        </View>
+      ));
+    }
+    return (
+      <View className="flex flex-col pt-56 items-center">
+        <View className="data-empty"></View>
+        <View className="text-12 text-gray-45 text-center leading-24 mt-12">
+          暂无数据
+        </View>
+      </View>
+    );
+  };
+
+  return (
+    <ScrollView
+      scrollY
+      style={{
+        flex: 1,
+        height: "100%", // 高度自适应
+      }}
+    >
+      {renderContent()}
+    </ScrollView>
+  );
+}

+ 4 - 0
src/pages/editor-pages/editor-link-contact/index.module.less

@@ -0,0 +1,4 @@
+.tabContainer{
+  height: 60vh;
+  margin-bottom: 100px;
+}

+ 121 - 36
src/pages/editor-pages/editor-link-contact/index.tsx

@@ -6,24 +6,98 @@ import NavBarNormal from "@/components/nav-bar-normal/index";
 import ButtonCardAdd from "@/components/button-card-add";
 import ContactCard from "@/components/contact-card/index";
 import editorStyle from "../editor.module.less";
+import style from './index.module.less'
 import Popup from "@/components/popup/popup";
 import WemetaTabs from "@/components/wemeta-tabs/index";
 import BottomBar from "@/components/BottomBar";
 import { TContactItem } from "@/types/contact";
-import AgentScrollList from './components/AgentScrollList'
+import AgentScrollList from './components/MyContactsScrollList'
+import MyAgentsScrollList from './components/MyAgentsScrollList'
+import MyEntAgentsScrollList from './components/MyEntAgentsScrollList'
+import { TAgent } from "@/types/agent";
+
+import IconMoreBlack from "@/components/icon/IconMoreBlack";
+import PopupSheets from "@/components/popup/popup-sheets";
+import { EComponentType } from "@/consts/enum";
+import { useComponentStore } from "@/store/componentStore";
 
 export default function Index() {
-  const router = useRouter();
-  const { id } = router.params;
-  const [picked, setPicked] = useState<TContactItem[]>([]);
-  
+  const { saveComponent } = useComponentStore();
+  let currentComponent = useComponentStore((state) => state.currentComponent);
+  const loading = useComponentStore((state) => state.loading);
+  const prevData = currentComponent?.data.values ?? []
+  const [picked, setPicked] = useState<(TContactItem|TAgent)[]>(prevData);
+  const [agents, setAgents] = useState<TAgent[]>(prevData);
+  const [current, setCurrent] = useState<(TContactItem|TAgent)|null>(null);
+
   // 是否显示选择器
   const [show, setShow] = useState(false);
+
+  const [showPopupSheets, setShowPopupSheets] = useState(false);
   
-  const deleteFunc = () => {
-    
+
+
+
+  const handleSubmit = async () => {
+    if(!currentComponent?.data?.id){
+      return
+    }
+    if (loading) {
+      return;
+    }
+    const c = {
+      data: {
+        values: picked,
+        layout: currentComponent.data.layout ?? 'mini',
+        id: currentComponent.data.id,
+        index: currentComponent.data.index,
+      },
+      enabled: currentComponent?.enabled ?? true,
+      type: EComponentType.bluebook,
+    };
+
+    await saveComponent(c);
+    Taro.navigateBack();
+  };
+  
+  const handleClickMore = (item: TAgent|TContactItem) => {
+    setCurrent(item)
+    setShowPopupSheets(true)
   };
 
+  const handleClick = () => {
+    setShow(true)
+  }
+  const handlePicked = () => {
+    setShow(false)
+    setPicked(agents)
+  }
+
+  const visitorCurrent = ()=> {
+    if(!current){
+      return;
+    }
+    
+    setShowPopupSheets(false)
+    Taro.navigateTo({
+      url: "/pages/profile/index?agentId=" + current?.agentId,
+    });
+    setCurrent(null)
+  }
+
+  const removePicked = ()=> {
+    if(!current){
+      return;
+    }
+    
+    setShowPopupSheets(false)
+    setPicked(picked.filter(item => item.agentId !== current.agentId))
+    setCurrent(null)
+  }
+
+  
+  
+
   const renderContactList = () => {
     if (!picked.length) {
       return (
@@ -39,18 +113,20 @@ export default function Index() {
       <View className="flex flex-col gap-8">
         {picked.map((item) => {
           return (
-            <ContactCard
-              key={item.contactId}
-              data={item}
-              renderRight={() => {
-                return (
-                  <View
-                    className={`iconfont icon-icon_24_delet icon-24`}
-                    onClick={() => deleteFunc()}
-                  ></View>
-                );
-              }}
-            ></ContactCard>
+            <View className=''>
+              <ContactCard
+                className="p-16"
+                key={item.agentId}
+                data={item}
+                renderRight={() => {
+                  return (
+                    <View onClick={() => handleClickMore(item)}>
+                      <IconMoreBlack />
+                    </View>
+                  );
+                }}
+              ></ContactCard>
+            </View>
           );
         })}
       </View>
@@ -59,19 +135,14 @@ export default function Index() {
 
   
 
-  const handleSubmit = async () => {
-    
-  };
-  
-
   
   const tabList = [
     {
       key: "1",
       label: "我创建的",
       children: (
-        <View >
-          <AgentScrollList></AgentScrollList>
+        <View className={style.tabContainer}>
+          <MyAgentsScrollList selected={agents} setSelected={setAgents}></MyAgentsScrollList>
         </View>
       ),
     },
@@ -79,8 +150,8 @@ export default function Index() {
       key: "2",
       label: "我的联系⼈",
       children: (
-        <View >
-          
+        <View className={style.tabContainer}>
+          <AgentScrollList selected={agents} setSelected={setAgents}></AgentScrollList>
         </View>
       ),
     },
@@ -88,28 +159,31 @@ export default function Index() {
       key: "3",
       label: "企业同事",
       children: (
-        <View >
-          
+        <View className={style.tabContainer}>
+          <MyEntAgentsScrollList selected={agents} setSelected={setAgents}></MyEntAgentsScrollList>
         </View>
       ),
     },
   ];
 
 
-  const handleClick = () => {
-
-  }
+  
 
   return (
     <PageCustom>
       <NavBarNormal>智能体</NavBarNormal>
+      <View>
+      </View>
       <View className="flex flex-col items-center w-full">
         <View className={editorStyle.container}>
           <ButtonCardAdd
-            text={`选择展示的智能体`}
+            text={`添加展示的智能体`}
             onClick={handleClick}
           ></ButtonCardAdd>
-          {renderContactList()}
+
+          <View className="pt-24">
+            {renderContactList()}
+          </View>
         </View>
       </View>
       <Popup setShow={setShow} show={show} title="知识库-链接">
@@ -117,12 +191,23 @@ export default function Index() {
         <BottomBar>
           <View
             className="button-rounded button-primary flex-1"
-            onClick={handleSubmit}
+            onClick={handlePicked}
           >
             引用
           </View>
         </BottomBar>
       </Popup>
+
+      <PopupSheets 
+          setShow={setShowPopupSheets} 
+          show={showPopupSheets}
+          content={[
+            {item: '访问TA的主页', type: 'primary', onClick: visitorCurrent}, 
+            {item:'删除', type: 'warn', onClick: removePicked},
+          ]}
+        >
+      </PopupSheets>
+
       <BottomBar>
         <View className="button-rounded button-primary flex-1" onClick={handleSubmit}>保存</View>
       </BottomBar>

+ 3 - 3
src/pages/login/index.tsx

@@ -15,9 +15,9 @@ export default function Index() {
   const { onGetPhoneNumber, onError, onClick, openType } = useLogin({
     onSuccess: () => {
       console.log('yes')
-      // Taro.reLaunch({
-      //   url: '/pages/index/index',
-      // })
+      Taro.reLaunch({
+        url: '/pages/index/index',
+      })
     },
   })
   

+ 12 - 52
src/pages/profile/index.module.less

@@ -1,56 +1,16 @@
-.mySwiper{
-  width: 320px;
-  height: 573px;
-  overflow: hidden;
-  border-radius: 20px;
-}
-
-.swiperItem{
-  margin-right: 30px;
-  
-}
-
-
-/* 自定义指示点容器 */
-.indicatorContainer {
-  padding-top: 18px;
+.navButtons{
   display: flex;
-  gap: 3px;
-  justify-content: center;
-}
-
-/* 单个指示点 */
-.indicator {
-  width: 6px;
-  height: 6px;
-  transition: all .3s;
-  border-radius: 100%;
-  background-color: rgba(#000, .15);
-  border-radius: 50%;
-}
-
-/* 当前选中的指示点 */
-.indicatorActive{
-  width: 16px;
-  border-radius: 30px;
-  background-color: rgba(#000, .35);
+  align-items: center;
+  padding: 4px 13px 4px 19px;
+  border-radius: 25px;
+  border: 1px solid rgba(151,151,151, 0.2);
+  background-color: rgba(255, 255, 255, 0.6);
 }
-
-.logo{
-  margin-right: 5px;
-  width: 24px;
-  height: 24px;
+.navGapLine{
+  margin: 0 14px;
+  height: 18px;
+  width: 1px;
+  font-size: 0;
+  background-color: rgba(0, 0, 0, 0.2);
 }
 
-.vipTips{
-  display: flex;
-  align-items: center;
-  flex-direction: column;
-}
-.vipTipsFigure{
-  margin-top: 48px;
-  width: 135px;
-  height: 96px;
-  background-image: url(https://cdn.wehome.cn/cmn/png/50/META-H8UK0IWU-9NNPJOLLD1MU95DE0NMA3-DAWUHO2M-AJ.png);
-  background-size: 100%;
-}

+ 60 - 30
src/pages/profile/index.tsx

@@ -4,51 +4,81 @@ import { useEffect, useState } from "react";
 import ComponentList from "@/components/component-list";
 import { TAgentDetail } from "@/types/agent";
 import NavBarNormal from "@/components/nav-bar-normal/index";
-import { getAgent, postVisitorLog } from '@/service/agent'
-import { useRouter } from "@tarojs/taro";
+import { getAgent, postVisitorLog } from "@/service/agent";
+import Taro, { useRouter } from "@tarojs/taro";
 import { getLoginId, isSuccess } from "@/utils";
 
-import Logo from "@/components/logo";
-import SummaryBar from "@/components/AgentPage/components/SummaryBar"
+import IconArrowLeft from "@/components/icon/icon-arrow-left";
+import IconHomeOutline from "@/components/icon/IconHomeOutline";
+import SummaryBar from "@/components/AgentPage/components/SummaryBar";
 import { useAgentStore } from "@/store/agentStore";
+import style from "./index.module.less";
 
 export default function Index() {
-  const {agent, fetchAgent} = useAgentStore()
-  const router = useRouter()
-  const { agentId } = router.params
+  const { agent, fetchAgent } = useAgentStore();
+  const router = useRouter();
+  const { agentId } = router.params;
 
-  if(!agentId){
-    return <View>loading...</View>
+  if (!agentId) {
+    return <View>loading...</View>;
   }
 
+  const renderNavBarLeft = () => {
+    return (
+      <View className={style.navButtons}>
+        <View
+          className="flex-center"
+          onClick={() => {
+            Taro.navigateBack();
+          }}
+        >
+          <IconArrowLeft></IconArrowLeft>
+        </View>
+        <View className={style.navGapLine}></View>
+        <View
+          className="flex-center"
+          onClick={() => {
+            Taro.switchTab({
+              url: "/pages/index/index",
+            });
+          }}
+        >
+          <IconHomeOutline></IconHomeOutline>
+        </View>
+      </View>
+    );
+  };
 
+  useEffect(() => {
+    fetchAgent(agentId);
+  }, [agentId]);
 
-  useEffect(()=> {
-    fetchAgent(agentId)
-  }, [agentId])
-  
-  useEffect(()=> {
-    if(agentId){
-      const loginId = getLoginId()
-      postVisitorLog({agentId, loginId})
+  useEffect(() => {
+    if (agentId) {
+      const loginId = getLoginId();
+      postVisitorLog({ agentId, loginId });
     }
-  }, [agentId])
+  }, [agentId]);
 
-
-  
-  
   return (
     <PageCustom>
       <View className="w-full">
-      <NavBarNormal scrollFadeIn showBgColor leftColumn={Logo}></NavBarNormal>
-      {agent && <>
-        <SummaryBar isVisitor agent={agent}></SummaryBar>
-        <View className="flex flex-col w-full p-16 gap-12">
-          <ComponentList components={agent.components ?? []}></ComponentList>
-        </View>  
-      </>}
-      
-    </View>
+        <NavBarNormal
+          scrollFadeIn
+          showBgColor
+          leftColumn={renderNavBarLeft}
+        ></NavBarNormal>
+        {agent && (
+          <>
+            <SummaryBar isVisitor agent={agent}></SummaryBar>
+            <View className="flex flex-col w-full p-16 gap-12">
+              <ComponentList
+                components={agent.components ?? []}
+              ></ComponentList>
+            </View>
+          </>
+        )}
+      </View>
     </PageCustom>
   );
 }

+ 16 - 9
src/utils/avatar.ts

@@ -12,7 +12,6 @@ export const uploadAndGenNewAvatar = () => {
     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`,
@@ -21,14 +20,22 @@ export const uploadAndGenNewAvatar = () => {
         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}`,
-        });
-      }
+      Taro.cropImage({
+        src: tempFile.tempFilePath,
+        cropScale: "9:16",
+        success: async (cropRes) => {
+          const path = cropRes.tempFilePath;
+          Taro.showLoading();
+
+          const response = await uploadImage(path, EUploadFileScene.AVATAR);
+          Taro.hideLoading();
+          if (response?.publicUrl) {
+            Taro.navigateTo({
+              url: `/pages/agent-gen/index?avatarUrl=${response?.publicUrl}`,
+            });
+          }
+        },
+      });
     },
   });
 };

+ 3 - 0
src/xiaolanbenlib/module/axios.js

@@ -68,6 +68,9 @@ axiosIns.interceptors.response.use(
     }
     if (error.code === 401) {
       //   await customCallback()
+      Taro.navigateTo({
+        url: '/pages/login/index'
+      })
       return Promise.reject(error)
     } else if (error.code === 1020 || error.code === 1021) {
       return error