瀏覽代碼

fix: 调整访问详情样式

王晓东 1 天之前
父節點
當前提交
48a865ba1b
共有 35 個文件被更改,包括 384 次插入226 次删除
  1. 1 1
      package.json
  2. 8 0
      pnpm-lock.yaml
  3. 1 1
      src/app.less
  4. 5 0
      src/app.tsx
  5. 1 1
      src/components/AgentPage/components/AgentQRcode/index.module.less
  6. 5 2
      src/components/AgentPage/components/AgentQRcode/index.tsx
  7. 14 2
      src/components/AgentPage/index.tsx
  8. 11 0
      src/components/ChatRecordItem/index.module.less
  9. 67 45
      src/components/ChatRecordItem/index.tsx
  10. 2 2
      src/components/EmptyData/index.tsx
  11. 17 21
      src/components/KnowledgePicker/index.tsx
  12. 11 0
      src/components/marks/MarkDislike.tsx
  13. 11 0
      src/components/marks/MarkLike.tsx
  14. 0 1
      src/components/wemeta-textarea/index.module.less
  15. 1 1
      src/hooks/useEditContactCard.ts
  16. 3 0
      src/images/svgs/dashboard/IconCopy.svg
  17. 6 0
      src/images/svgs/dashboard/IconDislike.svg
  18. 6 0
      src/images/svgs/dashboard/IconLike.svg
  19. 5 5
      src/images/svgs/dashboard/IconMark.svg
  20. 6 0
      src/images/svgs/dashboard/IconPhone.svg
  21. 5 5
      src/images/svgs/dashboard/IconTime.svg
  22. 9 26
      src/pages/chat-session-messages/components/VisitorSummary/index.tsx
  23. 47 19
      src/pages/chat-session-messages/index.tsx
  24. 30 2
      src/pages/chat/index.tsx
  25. 3 1
      src/pages/dashboard/components/VisitorCard/index.tsx
  26. 7 9
      src/pages/knowledge/components/CompanyList/index.tsx
  27. 1 3
      src/pages/knowledge/components/CompanyTab/components/ScrollListChat.tsx
  28. 12 1
      src/pages/knowledge/components/CompanyTab/index.tsx
  29. 10 8
      src/pages/message-editor/index.tsx
  30. 39 31
      src/pages/visiteor-detail/components/VisitorSummary/index.tsx
  31. 1 1
      src/pages/visiteor-detail/index.module.less
  32. 5 3
      src/pages/visiteor-detail/index.tsx
  33. 1 0
      src/types/visitor.ts
  34. 5 34
      src/utils/index.ts
  35. 28 1
      src/utils/upload.ts

+ 1 - 1
package.json

@@ -23,7 +23,6 @@
     "build:jd": "taro build --type jd",
     "build:quickapp": "taro build --type quickapp",
     "build:harmony-hybrid": "taro build --type harmony-hybrid",
-    
     "dev:swan": "npm run build:swan -- --watch",
     "dev:alipay": "npm run build:alipay -- --watch",
     "dev:tt": "npm run build:tt -- --watch",
@@ -64,6 +63,7 @@
     "axios": "^1.9.0",
     "browser-id": "^2.0.96",
     "classnames": "^2.5.1",
+    "dayjs": "^1.11.13",
     "event-target-polyfill": "^0.0.4",
     "miniprogram-blob": "^2.0.0",
     "miniprogram-formdata": "^2.0.0",

+ 8 - 0
pnpm-lock.yaml

@@ -71,6 +71,9 @@ importers:
       classnames:
         specifier: ^2.5.1
         version: 2.5.1
+      dayjs:
+        specifier: ^1.11.13
+        version: 1.11.13
       event-target-polyfill:
         specifier: ^0.0.4
         version: 0.0.4
@@ -3280,6 +3283,9 @@ packages:
     resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
     engines: {node: '>= 0.4'}
 
+  dayjs@1.11.13:
+    resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
+
   debug@2.6.9:
     resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
     peerDependencies:
@@ -12772,6 +12778,8 @@ snapshots:
       es-errors: 1.3.0
       is-data-view: 1.0.1
 
+  dayjs@1.11.13: {}
+
   debug@2.6.9:
     dependencies:
       ms: 2.0.0

+ 1 - 1
src/app.less

@@ -244,7 +244,7 @@
   background-image: url(https://cdn.wehome.cn/cmn/png/87/META-H8UKWHWU-HGXWYHZT5H6E78JCO9YE2-QYTHCUCM-XC.png);
 }
 // 三角牌感叹号
-.data-empty4{
+.data-empty-triangle{
   background-image: url(https://cdn.wehome.cn/cmn/png/63/META-H8UKWHWU-8HXWA0PE7HXUV4QMQUBV2-NYTHCUCM-SC.png);
 }
 // 两个对话框

+ 5 - 0
src/app.tsx

@@ -4,6 +4,11 @@ import "./app.less";
 import { useAppStore } from "./store/appStore";
 import { generateRandomId } from '@/utils/index'
 import {LOGIN_ID_STORAGE_KEY } from '@/xiaolanbenlib/constant'
+import dayjs from "dayjs";
+import 'dayjs/locale/zh-cn'
+import relativeTime from  'dayjs/plugin/relativeTime'
+
+dayjs.extend(relativeTime)
 
 if (process.env.TARO_ENV == "h5") {
   const VConsole = require("vconsole");

+ 1 - 1
src/components/AgentPage/components/AgentQRcode/index.module.less

@@ -1,6 +1,6 @@
 .container{
   padding-top: 12px;
-  height: 70vh;
+  height: 60vh;
   display: flex;
   align-items: center;
   flex-direction: column;

+ 5 - 2
src/components/AgentPage/components/AgentQRcode/index.tsx

@@ -29,7 +29,10 @@ export default ({ show, setShow, isVisitor }: IProps) => {
   const handleClick = async () => {
     Taro.showLoading();
     try{
-      const result = await pickAndUploadImage(["album"], EUploadFileScene.OTHER);
+      const result = await pickAndUploadImage(["album"], EUploadFileScene.OTHER, {
+        maxWidth: 1024,
+        maxHeight: 1024,
+      });
       if (!result?.url) {
         return;
       }
@@ -50,7 +53,7 @@ export default ({ show, setShow, isVisitor }: IProps) => {
 
   const renderQrcode = () => {
     if (agentContactCard?.qrCodeUrl) {
-      return <Image src={agentContactCard?.qrCodeUrl} showMenuByLongpress mode="widthFix"></Image>;
+      return <Image src={agentContactCard?.qrCodeUrl} showMenuByLongpress mode="aspectFit"></Image>;
     }
     
     if(isMine){

+ 14 - 2
src/components/AgentPage/index.tsx

@@ -11,7 +11,7 @@ import ComponentList from "@/components/component-list";
 import { useUserStore } from "@/store/userStore";
 import {  DEFAULT_AVATAR_BG } from '@/config'
 
-import { useDidShow } from "@tarojs/taro";
+import Taro, { useDidShow } from "@tarojs/taro";
 
 
 interface IProps {
@@ -22,6 +22,7 @@ export default function Index({ agentId }: IProps) {
   const agent = useAgentStore((state)=> state.agent);
   const { fetchMyEntList } = useUserStore();
   const [bg, setBg] = useState('')
+  const [isDefaultBg, setIsDefaultBg] = useState(false)
   
   const { setComponentList } = useComponentStore()
   const components = useComponentStore((state) => state.components);
@@ -32,6 +33,7 @@ export default function Index({ agentId }: IProps) {
       // 要等请求结束才能判断要不要显示默认形象图
       // 设置 背景
       setBg(_agent?.avatarUrl ?? DEFAULT_AVATAR_BG)
+      setIsDefaultBg(!_agent?.avatarUrl)
     }
   }
 
@@ -52,11 +54,21 @@ export default function Index({ agentId }: IProps) {
     fetchMyEntList()
   }, [])
   
-  
+  // 如果是默认形象,设置占位空间,点击后跳转至编辑页
+  const renderDefaultPlaceholder = ()=> {
+    if(!isDefaultBg){
+      return <></>
+    }
+    return <View className="absolute w-full h-[400px] z-0" onClick={() => {
+          Taro.navigateTo({ url: `/pages/agent/index?agentId=${agent?.agentId}` });
+        }}>
+    </View>
+  }
 
   return (
     <PageCustom styleBg={bg}>
       <NavBarNormal blur scrollFadeIn scrollFadeInDelta={240} leftColumn={Logo}></NavBarNormal>
+      {renderDefaultPlaceholder()}
       <View className="blur-rounded-container">
         {(!!agent) ? <AgentActionBar isVisitor={false} agent={agent}></AgentActionBar> : <></>}
         <View className={`flex flex-col gap-12 w-full p-16`}>

+ 11 - 0
src/components/ChatRecordItem/index.module.less

@@ -10,4 +10,15 @@
   height: 20px;
   background: rgba(#327BF9, .1);
   border-radius:  8px 0 8px 0;
+}
+.blurMask{
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 1;
+  width: 100%;
+  height: 48px;
+  pointer-events: none;
+  background-image: linear-gradient(180deg, #ffffff00 0%, #FFFFFF 100%);
 }

+ 67 - 45
src/components/ChatRecordItem/index.tsx

@@ -1,43 +1,50 @@
-import { View,Image, Text } from "@tarojs/components";
+import { View, Image, Text } from "@tarojs/components";
 import { useEffect, useState } from "react";
 import { isSuccess } from "@/utils";
 import { getVisitorMessages } from "@/service/visitor";
 import { TVisitorChat } from "@/types/visitor";
-import IconEditButtonBlue from '@/images/svgs/dashboard/IconEditButtonBlue.svg'
+import IconEditButtonBlue from "@/images/svgs/dashboard/IconEditButtonBlue.svg";
 
 import style from "./index.module.less";
 import Taro from "@tarojs/taro";
 import { EContentType, TMessageBodyContent } from "@/types/bot";
+import MarkDislike from "@/components/marks/MarkDislike";
+import MarkLike from "@/components/marks/MarkLike";
 
 interface IProps {
-  visitorId: string,
-  sessionId: string,
-  showMoreButton?: boolean
+  visitorId: string;
+  sessionId: string;
+  showMoreButton?: boolean;
 }
-export default ({ visitorId, sessionId, showMoreButton = false }:IProps) => {
-  
-  const [question, setQuestion] = useState<TVisitorChat|null>(null);
-  const [answer, setAnswer] = useState<TVisitorChat|null>(null);
+export default ({ visitorId, sessionId, showMoreButton = false }: IProps) => {
+  const [question, setQuestion] = useState<TVisitorChat | null>(null);
+  const [answer, setAnswer] = useState<TVisitorChat | null>(null);
 
   const fetchData = async () => {
-    const response = await getVisitorMessages({pageSize: 2, visitorId, sessionId });
+    const response = await getVisitorMessages({
+      pageSize: 2,
+      visitorId,
+      sessionId,
+    });
     if (isSuccess(response.status)) {
-      const [q, a] = response.data.data ?? []
-      if(q){
-        setQuestion(q)
+      const [q, a] = response.data.data ?? [];
+      if (q) {
+        setQuestion(q);
       }
-      if(a){
-        if(a.contentType == EContentType.AiseekQA){
-          try{
-            const contentJson = JSON.parse(a.content as string) as TMessageBodyContent
-            a.content = contentJson.answer.text
+      if (a) {
+        if (a.contentType == EContentType.AiseekQA) {
+          try {
+            const contentJson = JSON.parse(
+              a.content as string
+            ) as TMessageBodyContent;
+            a.content = contentJson.answer.text;
             // 把消息详情放入统一 body 中
-            a.body = {contentType: a.contentType, content: contentJson,}
-          }catch(e){
+            a.body = { contentType: a.contentType, content: contentJson };
+          } catch (e) {
             // console.error(e)
           }
         }
-        setAnswer(a)
+        setAnswer(a);
       }
     }
   };
@@ -46,31 +53,30 @@ export default ({ visitorId, sessionId, showMoreButton = false }:IProps) => {
     fetchData();
   }, [sessionId]);
 
-  
   const handleClick = () => {
     Taro.navigateTo({
       url: `/pages/chat-session-messages/index?visitorId=${visitorId}&sessionId=${sessionId}`,
     });
   };
 
-  const handleEdit = (item)=> {
-    if(!answer){
+  const handleEdit = (item) => {
+    if (!answer) {
       return;
     }
     Taro.navigateTo({
       url: `/pages/message-editor/index?msgId=${answer.msgId}&visitorId=${answer.visitorId}&agentId=${answer.agentId}`,
     });
-  }
+  };
 
   const renderAnswerContent = (item: TVisitorChat) => {
-    if(item.contentType === EContentType.AiseekQA){
-      const body = item.body
+    if (item.contentType === EContentType.AiseekQA) {
+      const body = item.body;
       const payload = body?.content?.answer?.payload;
       const links = payload?.links ?? [];
       const pics = payload?.pics ?? [];
       return (
-        <View className='break-words'>
-          <View className='break-words'>{item.content}</View>
+        <View className="break-words h-max-[360px] overflow-hidden">
+          <View className="break-words">{item.content}</View>
           <View className="pb-12">
             {pics.map((pic: string) => {
               return (
@@ -88,30 +94,47 @@ export default ({ visitorId, sessionId, showMoreButton = false }:IProps) => {
         </View>
       );
     }
-    return <View className='break-words'>{item.content}</View>
-  }
-  
+    return (
+      <View className="break-words h-max-[360px] overflow-hidden">
+        {item.content}
+      </View>
+    );
+  };
 
   return (
     <View className="w-full">
       <View className={` bg-white rounded-12 overflow-hidden`}>
-        <View className="p-16">
-          <View className="text-14 text-title mb-8">{question?.content}</View>
-          {!!answer?.content?.length && <View className="p-16 text-title rounded-8 relative" style={{backgroundColor: '#F4F9FF'}}>
-              <View>{renderAnswerContent(answer)}</View>
+        <View className="p-16 relative">
+          <View className="text-14 text-title font-medium leading-22 mb-8 font-pingfangSCMedium">
+            {question?.content}
+          </View>
+          {!!answer?.content?.length && (
+            <View
+              className="p-16 text-title rounded-8 relative max-h-[360px] overflow-hidden"
+              style={{ backgroundColor: "#F4F9FF" }}
+            >
+              {renderAnswerContent(answer)}
+              <View className="absolute top-0 right-0 z-10">
+                {answer.isDislike ? <MarkDislike /> : <></>}
+                {answer.isLike ? <MarkLike /> : <></>}
+              </View>
               <View className={style.editButton} onClick={handleEdit}>
                 <Image src={IconEditButtonBlue} className="w-14 h-14" />
               </View>
-            </View>}
+            </View>
+          )}
+          <View className={style.blurMask}></View>
         </View>
-        {showMoreButton && <View
-          className="text-primary flex-center border-top1-gray bg-white py-10"
-          onClick={handleClick}
-        >
-          查看更多
-        </View>}
+        {showMoreButton && (
+          <View
+            className="text-primary flex-center border-top1-gray bg-white py-10"
+            onClick={handleClick}
+          >
+            查看更多
+          </View>
+        )}
       </View>
-      
+
       {/* <View className="text-primary flex-center" onClick={handleClick}>查看更多</View> */}
       {/* {list.map(item => {
         return <View className="px-16 bg-white">
@@ -119,6 +142,5 @@ export default ({ visitorId, sessionId, showMoreButton = false }:IProps) => {
         </View>
       })} */}
     </View>
-    
   );
 };

+ 2 - 2
src/components/EmptyData/index.tsx

@@ -5,11 +5,11 @@ export const EmptyDataTitle = ({children}) => {
   return <View className='text-16 text-black font-medium text-center leading-24 mt-20 font-pingfangSCMedium'>{children}</View>
 }
 export const EmptyDataSubInfo= ({children}) => {
-  return <View className='leading-28 text-gray-45 text-14'>{children}</View>
+  return <View className='leading-28 text-gray-45 text-14 text-center'>{children}</View>
 }
 
 interface IProps {
-  type?: 'plane'|'search'|'chat' | 'box' | 'whiteboard' | (string & {}),
+  type?: 'plane'|'search'|'chat' | 'box' | 'whiteboard' | 'triangle' | (string & {}),
   text?: string,
   children?: JSX.Element|JSX.Element[]
   className?: string

+ 17 - 21
src/components/KnowledgePicker/index.tsx

@@ -13,7 +13,7 @@ import Taro from "@tarojs/taro";
 import { useUserStore } from "@/store/userStore";
 import { TKnowledgeItem } from "@/types/knowledge";
 import { TEntItem } from "@/types/user";
-import EmptyData from "../EmptyData";
+import EmptyData, { EmptyDataSubInfo, EmptyDataTitle } from "../EmptyData";
 export interface IProps {
   show: boolean;
   multi?: boolean; // 是否多选
@@ -67,30 +67,26 @@ export default function Index({title = '知识库',  show, setShow, multi, types
   }, [entList])
 
   const renderEntContent = () => {
+    
     if (!entList.length) {
       return (
         <View className="bg-gray-3 rounded-12 pt-44 h-full">
-          <EmptyData type='box' className="mt-0">
-            <View className="pt-20 text-center">
-              <View className="leading-24 text-black font-medium text-16 mb-4 font-pingfangSCMedium">
-                你还没有加入任何企业
-              </View>
-              <View className="leading-28 text-gray-45 mb-12 text-14">
-                访问公司统一知识内容, 提升回复效率与专业度
-              </View>
-              <View
-                className="button-rounded button-primary-light button-border-primary button-inline-flex"
-                onClick={() => {
-                  Taro.navigateTo({
-                    url: "/pages/contact-us/index",
-                  });
-                }}
-              >
-                联系我们
-              </View>
+        <EmptyData type={'box'} className="mt-0">
+          <EmptyDataTitle>开通企业知识库</EmptyDataTitle>
+            <EmptyDataSubInfo>
+              <View>让员工智能体高效运转,全公司知识自动同步</View>
+              <View>客户咨询准确率提升80%+</View>
+            </EmptyDataSubInfo>
+            <View
+              className="button-rounded button-primary-light button-border-primary button-inline-flex mt-20"
+              onClick={() =>
+                Taro.navigateTo({ url: "/pages/contact-us/index" })
+              }
+            >
+              联系我们
             </View>
-          </EmptyData>
-        </View>
+        </EmptyData>
+      </View>
       );
     }
 

+ 11 - 0
src/components/marks/MarkDislike.tsx

@@ -0,0 +1,11 @@
+import { View, Image } from "@tarojs/components";
+import IconDislike from '@/images/svgs/dashboard/IconDislike.svg'
+
+const MarkDislike = () => {
+  return <View className="flex items-center rounded-bl-8 rounded-tr-8 gap-4 px-8 bg-[#FF4747]">
+    <Image src={IconDislike} className="w-12 h-12"></Image>
+    <View className="text-12 text-white leading-16">差评</View>
+  </View>
+}
+
+export default MarkDislike;

+ 11 - 0
src/components/marks/MarkLike.tsx

@@ -0,0 +1,11 @@
+import { View, Image } from "@tarojs/components";
+import IconLike from '@/images/svgs/dashboard/IconLike.svg'
+
+const MarkLike = () => {
+  return <View className="flex items-center rounded-bl-8 rounded-tr-8 gap-4 bg-[#FF8200] px-8">
+    <Image src={IconLike} className="w-12 h-12"></Image>
+    <View className="text-12 leading-16 text-white">好评</View>
+  </View>
+}
+
+export default MarkLike;

+ 0 - 1
src/components/wemeta-textarea/index.module.less

@@ -8,7 +8,6 @@
 }
 .textInput{
   display: block;
-  color: #000;
   font-family: "PingFang SC";
   font-size: 15px;
   font-style: normal;

+ 1 - 1
src/hooks/useEditContactCard.ts

@@ -5,7 +5,7 @@ import { TAgentDetail } from "@/types/agent";
 
 const useEditContactCard = (
   editKey: string,
-  initValue?: string,
+  initValue?: string | null,
   _agent?: TAgentDetail
 ) => {
   const agent = useAgentStore((state) => _agent ?? state.agent);

+ 3 - 0
src/images/svgs/dashboard/IconCopy.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="design-iconfont">
+  <path d="M13.3333281,3.5 L12.5,3.5 L12.5,2.66667188 C12.5,2.03332813 11.9666719,1.5 11.3333281,1.5 L2.66667188,1.5 C2.03332813,1.5 1.5,2.03332813 1.5,2.66667188 L1.5,11.3333281 C1.5,11.9666719 2.03332813,12.5 2.66667188,12.5 L3.5,12.5 L3.5,13.3333281 C3.5,13.9666719 4.03332812,14.5 4.66667187,14.5 L13.3333281,14.5 C13.9666719,14.5 14.5,13.9666719 14.5,13.3333281 L14.5,4.66667187 C14.5,4.03332812 13.9666719,3.5 13.3333281,3.5 Z M2.5,11.3333281 L2.5,2.66667188 C2.5,2.56667187 2.56667187,2.5 2.66667188,2.5 L11.3333281,2.5 C11.4333281,2.5 11.5,2.56667187 11.5,2.66667188 L11.5,11.3333281 C11.5,11.4333281 11.4333281,11.5 11.3333281,11.5 L2.66667188,11.5 C2.56667187,11.5 2.5,11.4333281 2.5,11.3333281 L2.5,11.3333281 Z M13.5,13.3333281 C13.5,13.4333281 13.4333281,13.5 13.3333281,13.5 L4.66667187,13.5 C4.56667187,13.5 4.5,13.4333281 4.5,13.3333281 L4.5,12.5 L11.3333281,12.5 C11.9666719,12.5 12.5,11.9666719 12.5,11.3333281 L12.5,4.5 L13.3333281,4.5 C13.4333281,4.5 13.5,4.56667187 13.5,4.66667187 L13.5,13.3333281 Z M9,6.5 L7.5,6.5 L7.5,5 C7.5,4.73332812 7.26667188,4.5 7,4.5 C6.73332812,4.5 6.5,4.73332812 6.5,5 L6.5,6.5 L5,6.5 C4.73332812,6.5 4.5,6.73332812 4.5,7 C4.5,7.26667188 4.73332812,7.5 5,7.5 L6.5,7.5 L6.5,9 C6.5,9.26667188 6.73332812,9.5 7,9.5 C7.26667188,9.5 7.5,9.26667188 7.5,9 L7.5,7.5 L9,7.5 C9.26667188,7.5 9.5,7.26667188 9.5,7 C9.5,6.73332812 9.26667188,6.5 9,6.5 Z" fill="#111A34" fill-rule="nonzero"/>
+</svg>

+ 6 - 0
src/images/svgs/dashboard/IconDislike.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" class="design-iconfont">
+  <g fill-rule="nonzero" fill="none">
+    <path d="M8.2331543,0 C8.53769531,0 8.80004883,0.228076172 8.84355469,0.529980469 L9.63457031,6.01699219 C9.6609375,6.1949707 9.60820313,6.37558594 9.49086914,6.51269531 C9.37353516,6.64980469 9.20214844,6.72758789 9.0215332,6.72758789 L5.52788086,6.72758789 L5.80869141,7.43422852 C5.96821289,7.83632813 5.96162109,8.27797852 5.79023438,8.67612305 C5.61884766,9.07426758 5.30244141,9.38276367 4.89902344,9.54228516 L4.51933594,9.69257812 C4.44418945,9.72158203 4.36772461,9.73608398 4.29125977,9.73608398 C4.04604492,9.73608398 3.81269531,9.58842773 3.71645508,9.34584961 L2.7355957,6.87788086 C2.7,6.78691406 2.61298828,6.72758789 2.51411133,6.72758789 L0.619628906,6.72758789 C0.278173828,6.72758789 0,6.44941406 0,6.10795898 L0,0.619628906 C0,0.278173828 0.278173828,0 0.619628906,0 Z" transform="translate(1.5 1.5)" fill="#FFF"/>
+    <path fill="#FF4747" d="M2.34375 2.34375L2.97524414 2.34375 2.97524414 7.38383789 2.34375 7.38383789z"/>
+  </g>
+</svg>

+ 6 - 0
src/images/svgs/dashboard/IconLike.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" class="design-iconfont">
+  <g fill-rule="nonzero" fill="none">
+    <path d="M8.2331543,0 C8.53769531,0 8.80004883,0.228076172 8.84355469,0.529980469 L9.63457031,6.01699219 C9.6609375,6.1949707 9.60820313,6.37558594 9.49086914,6.51269531 C9.37353516,6.64980469 9.20214844,6.72758789 9.0215332,6.72758789 L5.52788086,6.72758789 L5.80869141,7.43422852 C5.96821289,7.83632813 5.96162109,8.27797852 5.79023438,8.67612305 C5.61884766,9.07426758 5.30244141,9.38276367 4.89902344,9.54228516 L4.51933594,9.69257812 C4.44418945,9.72158203 4.36772461,9.73608398 4.29125977,9.73608398 C4.04604492,9.73608398 3.81269531,9.58842773 3.71645508,9.34584961 L2.7355957,6.87788086 C2.7,6.78691406 2.61298828,6.72758789 2.51411133,6.72758789 L0.619628906,6.72758789 C0.278173828,6.72758789 0,6.44941406 0,6.10795898 L0,0.619628906 C0,0.278173828 0.278173828,0 0.619628906,0 Z" transform="matrix(1 0 0 -1 1.5 10.5)" fill="#FFF"/>
+    <path fill="#FF8200" d="M2.34375 2.34375L2.97524414 2.34375 2.97524414 7.38383789 2.34375 7.38383789z" transform="matrix(1 0 0 -1 0 12)"/>
+  </g>
+</svg>

+ 5 - 5
src/images/svgs/dashboard/IconMark.svg

@@ -1,10 +1,10 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="design-iconfont">
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="design-iconfont">
   <g fill="none" fill-rule="evenodd">
-    <path d="M12 0A12 12 0 1 0 12 24A12 12 0 1 0 12 0Z" fill="#777E95" fill-opacity=".1"/>
+    <path d="M10 0A10 10 0 1 0 10 20A10 10 0 1 0 10 0Z" fill="#777E95" fill-opacity=".1"/>
     <g fill-rule="nonzero">
-      <path d="M4.98909091,8.44727272 C5.10181817,8.44727272 5.21272727,8.47636363 5.31272728,8.53636364 L8.72,10.5472727 L8.72,1.27454545 L1.27454545,1.27454545 L1.27454545,10.5454545 L4.66545455,8.53818181 C4.76545455,8.47818181 4.87636364,8.44727272 4.98909091,8.44727272 L4.98909091,8.44727272 Z" fill="#000" transform="translate(7 6)"/>
-      <path d="M9.35454545,12.2981818 C9.24181819,12.2981818 9.13090909,12.2690909 9.03090909,12.2090909 L4.98909091,9.82363636 L0.961818187,12.2090909 C0.765454547,12.3254545 0.521818188,12.3272727 0.321818187,12.2145455 C0.123636375,12.1018182 0,11.8909091 0,11.6618182 L0,0.636363641 C0,0.285454547 0.285454547,0 0.636363641,0 L9.35454545,0 C9.70545455,0 9.99090909,0.285454547 9.99090909,0.636363641 L9.99090909,11.66 C9.99090909,11.8890909 9.86909091,12.1 9.67090909,12.2127273 C9.57272728,12.2690909 9.46363636,12.2981818 9.35454545,12.2981818 Z" fill="#777E95" transform="translate(7 6)"/>
-      <path d="M2.52181819,3.85673295 L7.47090909,3.85673295 M2.52181819,3.17818181 L7.47090909,3.17818181 L7.47090909,4.45090909 L2.52181819,4.45090909 L2.52181819,3.17818181 Z" fill="#FFF" transform="translate(7 6)"/>
+      <path d="M4.15757576,7.03939393 C4.25151514,7.03939393 4.34393939,7.06363635 4.42727273,7.11363637 L7.26666667,8.78939393 L7.26666667,1.06212121 L1.06212121,1.06212121 L1.06212121,8.78787879 L3.88787879,7.11515151 C3.97121212,7.06515151 4.06363637,7.03939393 4.15757576,7.03939393 L4.15757576,7.03939393 Z" fill="#000" transform="translate(5.8334 5)"/>
+      <path d="M7.79545454,10.2484848 C7.70151516,10.2484848 7.60909091,10.2242424 7.52575758,10.1742424 L4.15757576,8.18636363 L0.801515156,10.1742424 C0.637878789,10.2712121 0.43484849,10.2727273 0.268181823,10.1787879 C0.103030312,10.0848485 0,9.90909091 0,9.71818181 L0,0.530303034 C0,0.237878789 0.237878789,0 0.530303034,0 L7.79545454,0 C8.08787879,0 8.32575758,0.237878789 8.32575758,0.530303034 L8.32575758,9.71666667 C8.32575758,9.90757576 8.22424242,10.0833333 8.05909091,10.1772727 C7.97727273,10.2242424 7.88636363,10.2484848 7.79545454,10.2484848 Z" fill="#777E95" transform="translate(5.8334 5)"/>
+      <path d="M2.10151516,3.22227746 L6.22575758,3.22227746 M2.10151516,2.64848484 L6.22575758,2.64848484 L6.22575758,3.70909091 L2.10151516,3.70909091 L2.10151516,2.64848484 Z" fill="#FFF" transform="translate(5.8334 5)"/>
     </g>
   </g>
 </svg>

+ 6 - 0
src/images/svgs/dashboard/IconPhone.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="design-iconfont">
+  <g fill="none" fill-rule="evenodd">
+    <path fill-opacity=".1" fill="#777E95" d="M10 0A10 10 0 1 0 10 20A10 10 0 1 0 10 0Z"/>
+    <path d="M3.55454546,0.0281943707 C3.6939394,0.0751640712 3.81060607,0.176679214 3.87272727,0.310012548 L5.13333333,2.93273983 C5.24393939,3.164558 5.17727272,3.44637619 4.97272727,3.60243679 L3.88181818,4.43425497 C4.07575757,4.85092164 4.32121212,5.22364891 4.62272727,5.56607316 C4.89696969,5.87667921 5.21515151,6.15546711 5.58636363,6.41304285 L6.60454546,5.45243679 C6.79545454,5.27213376 7.08787879,5.25395195 7.29848484,5.40849739 L9.62272727,7.10092164 C9.8590909,7.27364891 9.91818181,7.59940648 9.75454546,7.84334588 L7.79848484,10.7857701 L7.4030303,10.6357701 C6.43636363,10.2691035 5.5530303,9.82970951 4.77878788,9.33122467 C3.95909091,8.80395195 3.23181818,8.19031558 2.61666667,7.51001255 C1.97424242,6.79789134 1.43636363,5.98880043 1.01666667,5.10546709 C0.583333333,4.19334588 0.26515151,3.17516406 0.0681818099,2.07819437 L0,1.69486104 L3.13030303,0.061527704 C3.26060607,-0.00665411891 3.41515152,-0.0187753298 3.55454546,0.0281943707 Z" transform="translate(5 5)" fill="#777E95" fill-rule="nonzero"/>
+  </g>
+</svg>

+ 5 - 5
src/images/svgs/dashboard/IconTime.svg

@@ -1,10 +1,10 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="design-iconfont">
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="design-iconfont">
   <g fill="none" fill-rule="evenodd">
-    <path fill-opacity=".1" fill="#777E95" d="M12 0A12 12 0 1 0 12 24A12 12 0 1 0 12 0Z"/>
+    <path fill-opacity=".1" fill="#777E95" d="M10 0A10 10 0 1 0 10 20A10 10 0 1 0 10 0Z"/>
     <g fill-rule="nonzero">
-      <path d="M6.28727273,1.27272728 C4.94727273,1.27272728 3.68909092,1.79454547 2.74181819,2.74181819 C1.79454545,3.68909092 1.27272728,4.94909092 1.27272728,6.28727273 C1.27272728,7.62545455 1.79454547,8.88545455 2.74181819,9.83272728 C3.68909092,10.78 4.94909092,11.3018182 6.28727273,11.3018182 C7.62545455,11.3018182 8.88545455,10.78 9.83272728,9.83272728 C10.78,8.88545456 11.3018182,7.62545455 11.3018182,6.28727273 C11.3018182,4.94909092 10.78,3.68909092 9.83272728,2.74181819 C8.88545455,1.79454545 7.62727273,1.27272728 6.28727273,1.27272728 Z" fill="#000" transform="translate(6 6)"/>
-      <path d="M6.28727273,12.5745455 C5.43818183,12.5745455 4.61454547,12.4090909 3.84,12.08 C3.09090909,11.7636364 2.41818181,11.3090909 1.84181819,10.7327273 C1.26545455,10.1563636 0.810909094,9.48363638 0.494545469,8.73454547 C0.167272734,7.95818183 0,7.13454547 0,6.28727273 C0,5.44 0.165454547,4.61454547 0.494545469,3.84 C0.810909109,3.09090909 1.26545456,2.41818181 1.84181819,1.84181819 C2.41818181,1.26545456 3.09090909,0.810909094 3.84,0.494545469 C4.61636364,0.167272734 5.44,0 6.28727273,0 C7.13454547,0 7.96,0.165454547 8.73454547,0.494545469 C9.48363638,0.810909109 10.1563637,1.26545456 10.7327273,1.84181819 C11.3090909,2.41818183 11.7636364,3.09090909 12.08,3.84 C12.4072727,4.61636364 12.5745455,5.44 12.5745455,6.28727273 C12.5745455,7.13454547 12.4090909,7.96 12.08,8.73454547 C11.7636364,9.48363638 11.3090909,10.1563637 10.7327273,10.7327273 C10.1563636,11.3090909 9.48363638,11.7636364 8.73454547,12.08 C7.96000002,12.4090909 7.13636366,12.5745455 6.28727273,12.5745455 Z" fill="#777E95" transform="translate(6 6)"/>
-      <path fill="#FFF" d="M7.70909092 8.58727273L5.55818183 6.43454547 5.55818183 2.77090909 6.83090909 2.77090909 6.83090909 5.90727273 8.60909092 7.68727273z" transform="translate(6 6)"/>
+      <path d="M5.23939395,1.06060607 C4.12272728,1.06060607 3.07424243,1.49545456 2.28484849,2.28484849 C1.49545454,3.07424243 1.06060607,4.12424243 1.06060607,5.23939395 C1.06060607,6.35454546 1.49545456,7.40454546 2.28484849,8.1939394 C3.07424243,8.98333335 4.12424243,9.41818182 5.23939395,9.41818182 C6.35454546,9.41818182 7.40454546,8.98333333 8.1939394,8.1939394 C8.98333335,7.40454547 9.41818182,6.35454546 9.41818182,5.23939395 C9.41818182,4.12424243 8.98333333,3.07424243 8.1939394,2.28484849 C7.40454546,1.49545454 6.35606061,1.06060607 5.23939395,1.06060607 Z" fill="#000" transform="translate(5 5)"/>
+      <path d="M5.23939395,10.4787879 C4.53181819,10.4787879 3.84545456,10.3409091 3.2,10.0666667 C2.57575758,9.8030303 2.01515151,9.42424242 1.53484849,8.9439394 C1.05454546,8.46363637 0.675757578,7.90303031 0.412121224,7.27878789 C0.139393945,6.63181819 0,5.94545456 0,5.23939395 C0,4.53333333 0.137878789,3.84545456 0.412121224,3.2 C0.675757591,2.57575758 1.05454547,2.01515151 1.53484849,1.53484849 C2.01515151,1.05454547 2.57575758,0.675757578 3.2,0.412121224 C3.8469697,0.139393945 4.53333333,0 5.23939395,0 C5.94545456,0 6.63333333,0.137878789 7.27878789,0.412121224 C7.90303031,0.675757591 8.46363638,1.05454547 8.9439394,1.53484849 C9.42424243,2.01515152 9.80303031,2.57575758 10.0666667,3.2 C10.3393939,3.8469697 10.4787879,4.53333333 10.4787879,5.23939395 C10.4787879,5.94545456 10.3409091,6.63333333 10.0666667,7.27878789 C9.8030303,7.90303031 9.42424242,8.46363638 8.9439394,8.9439394 C8.46363637,9.42424243 7.90303031,9.80303031 7.27878789,10.0666667 C6.63333335,10.3409091 5.94696971,10.4787879 5.23939395,10.4787879 Z" fill="#777E95" transform="translate(5 5)"/>
+      <path fill="#FFF" d="M6.42424243 7.15606061L4.63181819 5.36212122 4.63181819 2.30909091 5.69242424 2.30909091 5.69242424 4.92272728 7.17424243 6.40606061z" transform="translate(5 5)"/>
     </g>
   </g>
 </svg>

+ 9 - 26
src/pages/chat-session-messages/components/VisitorSummary/index.tsx

@@ -1,45 +1,28 @@
 import { View, Text, Image } from "@tarojs/components";
-import DigitalCardBasic from "@/components/DigitalCard/DigitalCardBasic";
 import { TVisitorAgent } from "@/types/visitor";
-import TagCertificated from "@/components/tag-certificated";
+import { AvatarMedia } from '@/components/AvatarMedia';
 export interface IndexProps {
   data: TVisitorAgent;
 }
 
 const VisitorSummary = ({ data }: IndexProps) => {
   return (
-    <View className="w-full p-12">
-      <View className="flex items-center gap-12">
-        <View className="flex items-center rounded-full overflow-hidden">
-          <View className="w-60 h-60 bg-gray-3 rounded-full">
-            {!!data.avatarUrl && (
-              <Image
-                src={data.avatarUrl}
-                mode="aspectFill"
-                className="w-60 h-60 bg-gray-3 rounded-full"
-              ></Image>
-            )}
-          </View>
-        </View>
+    <View className="w-full p-16">
+      <View className="flex items-start gap-12">
+        <AvatarMedia source={data.avatarUrl ?? ''} roundedFull className='w-48 h-48 shrink-0' mode="aspectFill" />
         <View className="flex flex-col gap-8">
           <View className="flex items-start">
             <View className="flex flex-col flex-1">
               <View className="flex items-end gap-8">
-                <View className="text-24 font-medium leading-32">{data.name}</View>
-                <View className="text-12 leading-20">{data.position ?? ""}</View>
+                <View className="text-14 font-semibold leading-20">{data.name}</View>
               </View>
-              <View className="flex items-center gap-2">
-                <View className="text-12 leading-20 truncate max-w-[188px]">{}</View>
-                {data.isEnt && <TagCertificated />}
+              <View className="text-12 leading-20">
+                <Text className="text-gray-45 leading-20">{data.lastChatTime}</Text>
+                和 「<Text className="text-primary">{data.myAgentName}</Text>」
+                <Text className="text-[#414A64]">进行</Text><Text className="text-primary">{data.chatRound}</Text> <Text>轮对话</Text>
               </View>
             </View>
           </View>
-          <View className="flex-center text-12 leading-20">
-            <View className="flex-1">
-              <Text className="text-primary">{data.chatRound}</Text> 轮对话
-            </View>
-            <View className="text-gray-45 leading-20">{data.lastChatTime}</View>
-          </View>
         </View>
       </View>
     </View>

+ 47 - 19
src/pages/chat-session-messages/index.tsx

@@ -11,8 +11,10 @@ import { getVisitorMessages } from "@/service/visitor";
 import { TVisitorAgent, TVisitorChat } from "@/types/visitor";
 import { createKey, useLoadMoreInfinite } from "@/utils/loadMoreInfinite";
 import IconEditButtonBlue from "@/images/svgs/dashboard/IconEditButtonBlue.svg";
+import MarkDislike from "@/components/marks/MarkDislike";
+import MarkLike from "@/components/marks/MarkLike";
 import style from "./index.module.less";
-import { EContentType } from "@/types/bot";
+import { EContentType, TMessage } from "@/types/bot";
 
 export default () => {
   const router = useRouter();
@@ -48,19 +50,43 @@ export default () => {
     fetcher,
     );
   
-  const parsedList = list.map((item: TMessage|TRobotMessage) => {
-      if(item.contentType == EContentType.AiseekQA){
-        try{
-          const contentJson = JSON.parse(item.content as string)
-          item.content = contentJson.answer.text
-          // 把消息详情放入统一 body 中
-          item.body = {...item, content: contentJson,}
-        }catch(e){
-          // console.error(e)
+  // const parsedList = list.map((item: TMessage) => {
+  //     if(item.contentType == EContentType.AiseekQA){
+  //       try{
+  //         const contentJson = JSON.parse(item.content as string)
+  //         item.content = contentJson.answer.text
+  //         // 把消息详情放入统一 body 中
+  //         item.body = {...item, content: contentJson,}
+  //       }catch(e){
+  //         // console.error(e)
+  //       }
+  //     }
+  //     return item
+  //   })
+    const qaList: { user?: TVisitorChat; assistant?: TVisitorChat }[] = [];
+    for (let i = 0; i < list.length; i++) {
+      const item: { user?: TVisitorChat; assistant?: TVisitorChat } = {};
+      if (list[i].role === "user") {
+        item.user = list[i];
+        if (list[i + 1]?.role === "assistant") {
+          item.assistant = list[i + 1];
+          if(item.assistant.contentType == EContentType.AiseekQA){
+            try{
+              const contentJson = JSON.parse(item.assistant.content as string)
+              item.assistant.content = contentJson.answer.text
+              // 把消息详情放入统一 body 中
+              item.assistant.body = {...item.assistant, content: contentJson, contentType: item.assistant.contentType}
+            }catch(e){
+              // console.error(e)
+            }
+          }
+          qaList.push(item);
+          i++; // 跳过下一个元素,因为它已经被配对了
+        }else{
+          continue; // 如果下一个不是 assistant,则跳过当前 user
         }
       }
-      return item
-    })
+    }
 
     const handleEdit = (item: TVisitorChat)=> {
       if(!item){
@@ -109,9 +135,6 @@ export default () => {
   }
 
   const renderContent = (item: TVisitorChat) => {
-    if (item.role === "user") {
-      return <View className="text-14 text-title mb-8">{item?.content}</View>;
-    }
 
     return (
       <View
@@ -119,6 +142,10 @@ export default () => {
         style={{ backgroundColor: "#F4F9FF" }}
       >
         <View>{renderAsistentContent(item)}</View>
+        <View className="absolute top-0 right-0 z-10">
+          {item.isDislike ? <MarkDislike/>:<></>}
+          {item.isLike ? <MarkLike />:<></>}
+        </View>
         <View className={style.editButton} onClick={()=> handleEdit(item)}>
           <Image src={IconEditButtonBlue} className="w-14 h-14" />
         </View>
@@ -128,16 +155,17 @@ export default () => {
 
   return (
     <PageCustom>
-      <NavBarNormal backText="返回" scrollFadeIn></NavBarNormal>
+      <NavBarNormal backText="对话记录" scrollFadeIn></NavBarNormal>
       {visitor ? <VisitorSummary data={visitor} /> : <></>}
       <View className="flex-1 overflow-hidden w-full mb-100">
         <View className="flex flex-col gap-16 px-16 w-full">
-          {parsedList.map((item) => {
+          {qaList.map((item) => {
             return (
               <View className={` bg-white rounded-12 overflow-hidden`}>
-                <View className="p-16">{renderContent(item)}</View>
+                <View className="text-14 text-title mb-8 pt-16 px-16 font-pingfangSCMedium leading-22">{item.user?.content}</View>
+                {item.assistant && <View className="px-16 pb-16">{renderContent(item.assistant)}</View>}
               </View>
-            );
+            )
           })}
         </View>
       </View>

+ 30 - 2
src/pages/chat/index.tsx

@@ -6,7 +6,7 @@ import ChatMessage from "@/components/chat-message";
 import InputBar from "./components/input-bar";
 import { useEffect, useState, useRef, useMemo } from "react";
 import { useTextChat } from "@/store/textChat";
-import { TRobotMessage, TMessage, EContentType } from "@/types/bot";
+import { TRobotMessage, TMessage, EContentType, EChatRole } from "@/types/bot";
 
 import ChatGreeting from "./components/ChatGreeting";
 import IconArrowLeftWhite24 from "@/components/icon/IconArrowLeftWhite24";
@@ -19,6 +19,8 @@ import { getMessageHistories } from "@/service/bot";
 
 import RecommendQuestions from './components/RecommendQuestions'
 import {useKeyboard} from './components/keyboard'
+import { saveMessageToServer } from "./components/input-bar/message";
+import { generateUUID, getLoginId } from '@/utils/index'
 
 
 export default function Index() {
@@ -46,7 +48,7 @@ const agent = useAgentStore((state) => {
   
 
   
-  const { destroy, setScrollTop, genSessionId, setAutoScroll } = useTextChat();
+  const { destroy, setScrollTop, genSessionId, sessionId, setAutoScroll } = useTextChat();
   const scrollTop = useTextChat((state) => state.scrollTop);
   // const autoScroll = useTextChat((state) => state.autoScroll);
   
@@ -114,6 +116,32 @@ const agent = useAgentStore((state) => {
     setShowWelcome(!messageList.length && !list.length);
   }, [list, messageList]);
 
+
+  // 将 greeting 开场白存入聊天记录里
+  // useEffect(()=> {
+  //   console.log(showWelcome, agent)
+  //   if(!showWelcome){
+  //     return;
+  //   }
+  //   const loginId = getLoginId();
+  //   if (!loginId || !agent?.agentId || !agent?.greeting || !sessionId) {
+  //     return;
+  //   }
+  //   saveMessageToServer({
+  //     loginId,
+  //     messages: [{
+  //       content: agent.greeting,
+  //       contentType: EContentType.TextPlain,
+  //       role: EChatRole.Assistant,
+  //       saveStatus: 2,
+  //       isStreaming: false,
+  //       msgUk: generateUUID(),
+  //     }],
+  //     agentId: agent.agentId,
+  //     sessionId,
+  //   })
+  // }, [showWelcome, sessionId])
+
   // 首次进入界面滚动到底
   useEffect(() => {
     if (pageIndex === 1) {

+ 3 - 1
src/pages/dashboard/components/VisitorCard/index.tsx

@@ -4,6 +4,8 @@ import Taro from "@tarojs/taro";
 import { TVisitorAgent } from "@/types/visitor";
 import { AvatarMedia } from "@/components/AvatarMedia";
 
+import dayjs from "dayjs";
+
 export interface IndexProps {
   data:TVisitorAgent;
 }
@@ -37,7 +39,7 @@ const Index = ({ data }: IndexProps) => {
             <View className="flex-1">
               <Text className="text-primary font-medium leading-20">{data.chatRound}</Text> 轮对话
             </View>
-            <View className="text-gray-45 leading-20">{data.lastChatTime}</View>
+            <View className="text-gray-45 leading-20">{dayjs(data.lastChatTime).fromNow()}</View>
           </View>
         </View>
       </View>

+ 7 - 9
src/pages/knowledge/components/CompanyList/index.tsx

@@ -1,6 +1,6 @@
 import { View } from "@tarojs/components";
 
-import EmptyData from "@/components/EmptyData";
+import EmptyData, { EmptyDataTitle, EmptyDataSubInfo } from "@/components/EmptyData";
 import { useEffect, useState } from "react";
 
 import PickerSingleColumn from "@/components/Picker/PickerSingleColumn";
@@ -63,21 +63,19 @@ const Index = ({currentEnt, setCurrentEnt, extraEnt = []}: IProps) => {
     return (
       <View className="flex-center pt-22 w-full">
         <EmptyData type={'box'}>
-          <View className="text-center text-14 leading-28 text-gray-45 mb-44 w-full">
-            <View className="text-center text-16 leading-24 font-medium text-black">
-            开通企业知识库
-            </View>
-            <View>让员工智能体高效运转,全公司知识自动同步</View>
-            <View>客户咨询准确率提升80%+</View>
+          <EmptyDataTitle>开通企业知识库</EmptyDataTitle>
+            <EmptyDataSubInfo>
+              <View>让员工智能体高效运转,全公司知识自动同步</View>
+              <View>客户咨询准确率提升80%+</View>
+            </EmptyDataSubInfo>
             <View
-              className="button-rounded button-primary-light button-border-primary button-inline-flex mt-24"
+              className="button-rounded button-primary-light button-border-primary button-inline-flex mt-20"
               onClick={() =>
                 Taro.navigateTo({ url: "/pages/contact-us/index" })
               }
             >
               联系我们
             </View>
-          </View>
         </EmptyData>
       </View>
     );

+ 1 - 3
src/pages/knowledge/components/CompanyTab/components/ScrollListChat.tsx

@@ -86,13 +86,11 @@ const Index = ({ entId, assistantOnly, setTotalCount }: Iprops) => {
         <View className="flex flex-col gap-20 pb-32 mx-16">
           {reversedList.length <= 0 ? (
             <EmptyData type={"search"}>
-              <View className="text-center text-14 leading-28 text-gray-45 mb-44 w-full">
-                <EmptyDataTitle>暂无数据</EmptyDataTitle>
+              <EmptyDataTitle>暂无数据</EmptyDataTitle>
                 <EmptyDataSubInfo>
                   <View>可登录电报端管理企业知识库</View>
                   <View>也可以开启个人知识库同步到企业知识库</View>
                 </EmptyDataSubInfo>
-              </View> 
             </EmptyData>
           ) : (
             <></>

+ 12 - 1
src/pages/knowledge/components/CompanyTab/index.tsx

@@ -9,6 +9,7 @@ import CompanyList from '../CompanyList'
 import { TEntItem } from "@/types/user";
 import StyleFilter, {TListStyle} from '../StyleFilter'
 import { useUserStore } from "@/store/userStore";
+import EmptyData, { EmptyDataSubInfo, EmptyDataTitle } from "@/components/EmptyData";
 
 
 const Index = () => {
@@ -22,6 +23,16 @@ const Index = () => {
     if (!ent?.entId) {
       return <></>;
     }
+    if(ent?.isExpired){
+      return <EmptyData type="triangle">
+        <EmptyDataTitle>100 份企业知识已暂停服务</EmptyDataTitle>
+        <EmptyDataSubInfo>
+          <View>你的企业会员已到期,建议联系企业管理员进行</View>
+          <View>续费,以便恢复使用和正常对话支持。</View>
+        </EmptyDataSubInfo>
+      </EmptyData>
+    }
+
     if (listStyle === "chat") {
       return <ScrollListChat setTotalCount={setTotalCount}  assistantOnly entId={ent.entId} />;
     }
@@ -34,7 +45,7 @@ const Index = () => {
         <View className="px-16">
           <CompanyList setCurrentEnt={setEnt} currentEnt={ent}></CompanyList>
         </View>
-        {entList.length > 0 && <StyleFilter checked={assistantOnly} setChecked={setAssistantOnly} listStyle={listStyle} setListStyle={setListStyle}>
+        {(entList.length > 0 && !ent?.isExpired) && <StyleFilter checked={assistantOnly} setChecked={setAssistantOnly} listStyle={listStyle} setListStyle={setListStyle}>
           <View className="flex-1 text-12 leading-20 text-gray-45">
             共 {totalCount ?? 0} 个文件
           </View>

+ 10 - 8
src/pages/message-editor/index.tsx

@@ -30,6 +30,8 @@ import { editVisitorDislikeAnswer, getVisitorMessagesByMsgId } from "@/service/v
 
 import { TVisitorChat } from "@/types/visitor";
 import { EContentType, TMessageBodyContent } from "@/types/bot";
+import MarkDislike from "@/components/marks/MarkDislike";
+import MarkLike from "@/components/marks/MarkLike";
 
 type TFormdata = {content:string, correctionAnswer: string, links: string[], mediaList: TMediaType[]}
 
@@ -197,10 +199,10 @@ export default function Index() {
 
   return (
     <PageCustom>
-      <NavBarNormal scrollFadeIn backText={isDislike ? '纠错记录' : '访问详情'}></NavBarNormal>
+      <NavBarNormal scrollFadeIn backText={isDislike ? '纠错记录' : '编辑问答'}></NavBarNormal>
       <View className="w-full pb-120">
         <View className="p-16">
-          {isDislike && <View className="text-gray-45 text-14 text-center py-8">修改后的问答将存入知识库,持续训练提升您的智能体</View>}
+          {isDislike && <View className="text-gray-45 text-12 text-center py-8">修改后的问答将存入知识库,持续训练提升您的智能体</View>}
           <View className="flex flex-col gap-16">
             <View className="flex flex-col">
               <View className="flex items-start gap-8 mb-6">
@@ -220,12 +222,12 @@ export default function Index() {
                 </View>
                 <View className="flex-1 text-14 leading-28">原回答</View>
               </View>
-              <View className="">
-                <WemetaTextarea
-                  value={formData.content}
-                  disabled
-                  onInput={handleInput}
-                />
+              <View className="text-[#777E95] rounded-12 overflow-hidden relative p-16 bg-white">
+              <View className="absolute top-0 right-0 z-10">
+                {visitor?.isDislike ? <MarkDislike/>:<></>}
+                {visitor?.isLike ? <MarkLike />:<></>}
+              </View>
+                {formData.content}
               </View>
             </View>
 

+ 39 - 31
src/pages/visiteor-detail/components/VisitorSummary/index.tsx

@@ -1,19 +1,38 @@
 import { View, Text, Image } from "@tarojs/components";
-import DigitalCardBasic from "@/components/DigitalCard/DigitalCardBasic";
 import { TVisitorAgent } from "@/types/visitor";
-import TagCertificated from "@/components/tag-certificated";
 import Taro from "@tarojs/taro";
-import { AvatarMedia } from '@/components/AvatarMedia';
+import IconPhone from '@/images/svgs/dashboard/IconPhone.svg'
+import IconCopy from '@/images/svgs/dashboard/IconCopy.svg'
+import IconTime from '@/images/svgs/dashboard/IconTime.svg'
+import IconMark from '@/images/svgs/dashboard/IconMark.svg'
 import AgentCard from "@/components/AgentCard/index";
 export interface IndexProps {
   data: TVisitorAgent;
 }
 
 const VisitorSummary = ({ data }: IndexProps) => {
+  const handleCopy = (value: string)=> {
+    // 手动复制并 toast 提示
+    Taro.setClipboardData({
+      data: value,
+      success(){
+        Taro.showToast({
+          title: '复制成功',
+          icon: 'none'
+        })
+      },fail(res) {
+        console.log(res)
+        Taro.showToast({
+          title: '复制失败',
+          icon: 'none'
+        })
+      },
+    })
+  }
   return (
-    <View className="w-full p-12">
+    <View className="w-full p-16">
       <AgentCard
-        className="bg-opacity-0 p-0 rounded-none"
+        className="bg-opacity-0 p-0 rounded-none mb-16"
         key={data.agentId}
         data={data}
         onClick={() => {
@@ -22,36 +41,25 @@ const VisitorSummary = ({ data }: IndexProps) => {
           })
         }}
       >
-
       </AgentCard>
-      {/* <View className="flex items-center gap-12">
-        <View className="flex items-center rounded-full overflow-hidden" onClick={}>
-          <View className="w-60 h-60 bg-gray-3 rounded-full">
-            <AvatarMedia source={data.avatarUrl || ''} mode="aspectFill"
-                className="w-60 h-60 bg-gray-3 rounded-full"></AvatarMedia>
-          </View>
+      <View className="flex flex-col w-full gap-8">
+        <View className="flex gap-8 items-center text-12 leading-20">
+          <Image src={IconPhone} className="w-16 h-16 shrink-0"></Image>
+          <Text>{data.mobile}</Text>
+          <Image src={IconCopy} className="w-16 h-16 shrink-0" onClick={()=> handleCopy(data.mobile)}></Image>
         </View>
-        <View className="flex flex-col gap-8">
-          <View className="flex items-start">
-            <View className="flex flex-col flex-1">
-              <View className="flex items-end gap-8">
-                <View className="text-24 font-medium leading-32">{data.name}</View>
-                <View className="text-12 leading-20">{data.position ?? ""}</View>
-              </View>
-              <View className="flex items-center gap-2">
-                <View className="text-12 leading-20 truncate max-w-[188px]">{data?.entName || ''}</View>
-                {data.isEnt && <TagCertificated />}
-              </View>
-            </View>
-          </View>
-          <View className="flex-center text-12 leading-20">
-            <View className="flex-1">
-              <Text className="text-primary">{data.chatRound}</Text> 轮对话
-            </View>
-            <View className="text-gray-45 leading-20">{data.lastChatTime}</View>
+        <View className="flex gap-8 items-center text-12 leading-20">
+          <Image src={IconMark} className="w-16 h-16 shrink-0"></Image>
+          <View>
+            第<Text className="text-primary text-12 font-medium px-6">{data.visitTimes}</Text>
+          次访问了你的智能体「<Text className="text-primary text-12 font-medium px-6">{data.myAgentName}</Text>」
           </View>
         </View>
-      </View> */}
+        <View className="flex gap-8 items-center text-12 leading-20">
+          <Image src={IconTime} className="w-16 h-16 shrink-0"></Image>
+          {data.lastChatTime}
+        </View>
+      </View>
     </View>
   );
 };

+ 1 - 1
src/pages/visiteor-detail/index.module.less

@@ -6,7 +6,7 @@
 
 
 .gutterLine{
-  margin: 8px 0 4px;
+  margin: 8px 4px 0;
   display: flex;
   flex-direction: column;
   align-items: center;

+ 5 - 3
src/pages/visiteor-detail/index.tsx

@@ -73,9 +73,11 @@ export default () => {
 
   return (
     <PageCustom fullPage style={{ overflow: "hidden" }}>
-      <NavBarNormal scrollFadeIn>访问详情</NavBarNormal>
+      <NavBarNormal scrollFadeIn backText="访问详情"></NavBarNormal>
       {visitor ? <VisitorSummary data={visitor} /> : <></>}
-      <View className="rounded-container-header"></View>
+      <View className="rounded-container-header">
+        <View className="text-14 font-medium text-black font-pingfangSCMedium px-16 pb-14">访问记录</View>
+      </View>
       <View className="flex-1 overflow-hidden w-full">
         <ScrollView
           scrollY
@@ -107,7 +109,7 @@ export default () => {
                         <View className="w-full h-full flex flex-col gap-8">
                           <View className="text-14 leading-24 text-title">
                             第{" "}
-                            <Text className="text-primary">
+                            <Text className="text-primary text-16">
                               {item?.visitTimes}
                             </Text>{" "}
                             次访问你的智能体

+ 1 - 0
src/types/visitor.ts

@@ -60,6 +60,7 @@ export type TVisitorAgent = {
   myAgentName: string,// myAgentName (string, optional): 访问我的智能体名称 ,
   isNewEnt: boolean
   isDefault: boolean
+  mobile?: string
   name: string, // name (string, optional): 访客名称 -- 最后一次访问的快照信息 ,
   entName?: string|null, // name (string, optional): 访客名称 -- 最后一次访问的快照信息 ,
   entId?: string|null, // name (string, optional): 访客名称 -- 最后一次访问的快照信息 ,

+ 5 - 34
src/utils/index.ts

@@ -474,37 +474,8 @@ export function convertFileSize(size: number, options: FileSizeOptions = {}): st
   const result = Number(convertedSize.toFixed(precision));
   return withUnit ? `${result} ${units[unitIndex]}` : result;
 }
-
-// 示例用法
-// const examples = [
-//   1024, // 1 KB (二进制)
-//   1000000, // ~0.95 MB (二进制)
-//   1000000, // 1 MB (十进制)
-//   1099511627776, // 1 TB (二进制)
-//   8, // 1 B
-//   1, // 1 bit
-//   0, // 0 B
-//   -1024, // -1 KB (二进制)
-//   NaN, // Invalid size
-//   Infinity // Invalid size
-// ];
-
-// console.log("二进制单位 (1024进制):");
-// examples.forEach(size => {
-//   console.log(`${size} bit = ${convertFileSize(size)}`);
-// });
-
-// console.log("\n十进制单位 (1000进制):");
-// examples.forEach(size => {
-//   console.log(`${size} bit = ${convertFileSize(size, { binary: false })}`);
-// });
-
-// console.log("\n强制转换为KB:");
-// examples.forEach(size => {
-//   console.log(`${size} bit = ${convertFileSize(size, { unit: 'KB' })}`);
-// });
-
-// console.log("\n不显示单位:");
-// examples.forEach(size => {
-//   console.log(`${size} bit = ${convertFileSize(size, { withUnit: false })}`);
-// });
+// 
+export const pxToRpx = (px: number) => {
+  const systemInfo = Taro.getSystemInfoSync()
+  return (750 / systemInfo.windowWidth) * px
+}

+ 28 - 1
src/utils/upload.ts

@@ -7,7 +7,8 @@ const FILE_LIMIT = 100 * 1024 * 1024 // 100MB
 
 export async function pickAndUploadImage(
   sourceType: Array<'album' | 'camera'> = ['album', 'camera'],
-  scene: EUploadFileScene
+  scene: EUploadFileScene,
+  maxSize?: {maxWidth: number, maxHeight: number}
 ): Promise<{ url: string; size: number }| null> {
   try {
     const res = await Taro.chooseImage({
@@ -17,6 +18,7 @@ export async function pickAndUploadImage(
     })
 
     const file = res.tempFiles[0]
+    console.log(file,111)
     if (file.size >= IMAGE_LIMIT) {
       Taro.showToast({
         title: '图片大小超限',
@@ -25,6 +27,31 @@ export async function pickAndUploadImage(
       })
       throw new Error('Image size exceeds limit')
     }
+
+    if(maxSize){
+      const {width, height} = await new Promise<{width: number, height: number}>((resolve) => {
+        Taro.getImageInfo({
+          src: file.path,
+          success(result) {
+            resolve({width: result.width, height: result.height})
+          },
+          fail(res) {
+            resolve({width: 0, height: 0})
+          },
+        })
+      })
+      if(width > maxSize.maxWidth || height > maxSize.maxHeight){
+        Taro.showToast({
+          title: '图片宽高超限',
+          icon: 'error',
+          duration: 1500,
+        })
+        throw new Error('Image size exceeds limit')
+      }
+    }
+    
+
+
     const uploadResult = await uploadFile(
       file.path,
       scene,