Browse Source

feat: 编辑差评

王晓东 3 weeks ago
parent
commit
ed7c294d8e
37 changed files with 944 additions and 335 deletions
  1. 2 0
      src/app.config.ts
  2. 2 0
      src/app.less
  3. 13 0
      src/components/ChatRecordItem/index.module.less
  4. 75 0
      src/components/ChatRecordItem/index.tsx
  5. 1 1
      src/components/DigitalCard/DigitalCardBasic.tsx
  6. 3 0
      src/images/svgs/dashboard/IconEditButtonBlue.svg
  7. 10 0
      src/images/svgs/dashboard/IconMark.svg
  8. 10 0
      src/images/svgs/dashboard/IconTime.svg
  9. 49 0
      src/pages/chat-messages/components/VisitorSummary/index.tsx
  10. 5 0
      src/pages/chat-messages/index.config.ts
  11. 14 0
      src/pages/chat-messages/index.module.less
  12. 85 0
      src/pages/chat-messages/index.tsx
  13. 36 0
      src/pages/chat-messages/visitedDetail.ts
  14. 49 0
      src/pages/chat-session-messages/components/VisitorSummary/index.tsx
  15. 5 0
      src/pages/chat-session-messages/index.config.ts
  16. 14 0
      src/pages/chat-session-messages/index.module.less
  17. 105 0
      src/pages/chat-session-messages/index.tsx
  18. 36 0
      src/pages/chat-session-messages/visitedDetail.ts
  19. 49 36
      src/pages/dashboard-dislike-messages/index.tsx
  20. 15 9
      src/pages/dashboard-visited-detail/components/VisitorSummary/index.tsx
  21. 22 1
      src/pages/dashboard-visited-detail/index.module.less
  22. 83 23
      src/pages/dashboard-visited-detail/index.tsx
  23. 0 25
      src/pages/dashboard-visited-detail/visitedDetail.ts
  24. 63 35
      src/pages/dashboard-visitor-message-editor/index.tsx
  25. 0 1
      src/pages/dashboard/components/VisitorCard/index.tsx
  26. 1 1
      src/pages/knowledge/components/CompanyList/index.tsx
  27. 4 2
      src/pages/knowledge/components/CompanyTab/components/ScrollList.tsx
  28. 8 4
      src/pages/knowledge/components/CompanyTab/components/ScrollListChat.tsx
  29. 8 44
      src/pages/knowledge/components/CorrectionList/index.tsx
  30. 1 1
      src/pages/knowledge/components/PersonalTab/components/ScrollList.tsx
  31. 1 1
      src/pages/knowledge/components/PersonalTab/components/ScrollListChat.tsx
  32. 24 14
      src/pages/knowledge/components/view-style/ViewStyleListCorrection.tsx
  33. 5 5
      src/pages/knowledge/index.tsx
  34. 133 130
      src/service/visitor.ts
  35. 1 1
      src/types/user.ts
  36. 11 1
      src/types/visitor.ts
  37. 1 0
      tailwind.config.js

+ 2 - 0
src/app.config.ts

@@ -7,6 +7,8 @@ export default defineAppConfig({
     'pages/dashboard-visited-detail/index',
     'pages/dashboard-dislike-messages/index',
     'pages/dashboard-visitor-message-editor/index',
+    'pages/chat-messages/index',
+    'pages/chat-session-messages/index',
     'pages/contact/index',
     'pages/knowledge/index',
     'pages/knowledge-item/index',

+ 2 - 0
src/app.less

@@ -26,6 +26,7 @@ page {
   --color-primary-light: rgba(49, 124, 250, 0.1);
   --color-primary-dark: #1E6FF8;
   --color-text-primary: #262626;
+  --color-text-title: #111A34;;
   --color-bg-primary: #F4F9FF;
   --color-bg-gray: #F4F9FF;
 }
@@ -37,6 +38,7 @@ page {
   --color-primary-light: rgba(49, 124, 250, 0.1);
   --color-primary-dark: #1E6FF8;
   --color-text-primary: #262626;
+  --color-text-title: #111A34;;
   --color-bg-primary: #F6F6F6;
   --color-bg-gray: #F6F6F6;
 }

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

@@ -0,0 +1,13 @@
+.editButton{
+  position: absolute;
+  z-index: 1;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 20px;
+  height: 20px;
+  background: rgba(#327BF9, .1);
+  border-radius:  8px 0 8px 0;
+}

+ 75 - 0
src/components/ChatRecordItem/index.tsx

@@ -0,0 +1,75 @@
+import { View,Image } 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 style from "./index.module.less";
+import Taro from "@tarojs/taro";
+
+interface IProps {
+  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);
+
+  const fetchData = async () => {
+    const response = await getVisitorMessages({pageSize: 2, visitorId, sessionId });
+    if (isSuccess(response.status)) {
+      const [q, a] = response.data.data ?? []
+      if(q){
+        setQuestion(q)
+      }
+      if(a){
+        setAnswer(a)
+      }
+    }
+  };
+
+  useEffect(() => {
+    fetchData();
+  }, [sessionId]);
+
+  
+  const handleClick = () => {
+    Taro.navigateTo({
+      url: `/pages/chat-session-messages/index?visitorId=${visitorId}&sessionId=${sessionId}`,
+    });
+  };
+  
+
+  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>{answer?.content}</View>
+              <View className={style.editButton}>
+                <Image src={IconEditButtonBlue} className="w-14 h-14" />
+              </View>
+            </View>}
+        </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">
+          <View className="text-14 text-title"></View>
+        </View>
+      })} */}
+    </View>
+    
+  );
+};

+ 1 - 1
src/components/DigitalCard/DigitalCardBasic.tsx

@@ -12,7 +12,7 @@ const DigitalCardBasic = ({name, position, company, certificated }: DigitalCardB
   return <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">{name}</View>
+                  <View className="text-16 font-medium leading-32">{name}</View>
                   <View className="text-12 leading-20">{position}</View>
                 </View>
                 <View className="flex items-center gap-2">

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

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" class="design-iconfont">
+  <path d="M12.1041621,6.72291211 C11.8708379,6.72291211 11.6666621,6.92708789 11.6666621,7.16041211 L11.6666621,11.5354121 C11.6666621,11.6229121 11.6083379,11.68125 11.5208379,11.68125 L2.77083789,11.68125 C2.68333789,11.68125 2.625,11.6229121 2.625,11.5354121 L2.625,2.78541211 C2.625,2.69791211 2.68333789,2.63958789 2.77083789,2.63958789 L7.14583789,2.63958789 C7.37916211,2.63958789 7.58333789,2.43541211 7.58333789,2.20208789 C7.58333789,1.96876367 7.37916211,1.76458789 7.14583789,1.76458789 L2.77083789,1.76458789 C2.21666211,1.76458789 1.75,2.23125 1.75,2.78541211 L1.75,11.5354121 C1.75,12.0895879 2.21666211,12.55625 2.77083789,12.55625 L11.5208379,12.55625 C12.075,12.55625 12.5416621,12.0895879 12.5416621,11.5354121 L12.5416621,7.16041211 C12.5416621,6.92708789 12.3375,6.72291211 12.1041621,6.72291211 Z M5.97916211,6.48958789 L5.54166211,8.21041211 C5.5125,8.35625 5.54166211,8.53125 5.65833789,8.61875 C5.74583789,8.70625 5.8625,8.73541211 5.97916211,8.73541211 L6.09583789,8.73541211 L7.81666211,8.29791211 C7.90416211,8.26875 7.9625,8.23958789 8.02083789,8.18125 L12.1333379,4.06875 C12.6583379,3.54375 12.6583379,2.66875 12.1333379,2.14375 C11.6083379,1.61875 10.7333379,1.61875 10.2083379,2.14375 L6.09583789,6.28541211 C6.0375,6.34375 6.00833789,6.40208789 5.97916211,6.48958789 Z M6.79583789,6.81041211 L10.85,2.78541211 C11.025,2.61041211 11.3458379,2.61041211 11.5208379,2.78541211 C11.6958379,2.96041211 11.6958379,3.28125 11.5208379,3.45625 L7.49583789,7.51041211 L6.59166211,7.74375 L6.79583789,6.81041211 Z" fill="#327BF9" fill-rule="nonzero"/>
+</svg>

+ 10 - 0
src/images/svgs/dashboard/IconMark.svg

@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" 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"/>
+    <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)"/>
+    </g>
+  </g>
+</svg>

+ 10 - 0
src/images/svgs/dashboard/IconTime.svg

@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" 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"/>
+    <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)"/>
+    </g>
+  </g>
+</svg>

+ 49 - 0
src/pages/chat-messages/components/VisitorSummary/index.tsx

@@ -0,0 +1,49 @@
+import { View, Text, Image } from "@tarojs/components";
+import DigitalCardBasic from "@/components/DigitalCard/DigitalCardBasic";
+import { TVisitorAgent } from "@/types/visitor";
+import TagCertificated from "@/components/tag-certificated";
+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="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]">{}</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>
+        </View>
+      </View>
+    </View>
+  );
+};
+
+export default VisitorSummary;

+ 5 - 0
src/pages/chat-messages/index.config.ts

@@ -0,0 +1,5 @@
+export default definePageConfig({
+  navigationBarTitleText: '分析',
+  "usingComponents": {},
+  "navigationStyle": 'custom',
+})

+ 14 - 0
src/pages/chat-messages/index.module.less

@@ -0,0 +1,14 @@
+.editButton{
+  position: absolute;
+  z-index: 1;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 20px;
+  height: 20px;
+  background: rgba(#327BF9, .1);
+  border-radius:  8px 0 8px 0;
+}
+

+ 85 - 0
src/pages/chat-messages/index.tsx

@@ -0,0 +1,85 @@
+import { View, Image, Text } from "@tarojs/components";
+import Taro, { useReachBottom, useRouter } from "@tarojs/taro";
+import NavBarNormal from "@/components/NavBarNormal/index";
+import PageCustom from "@/components/page-custom/index";
+import { useEffect, useState } from "react";
+import { isSuccess } from "@/utils";
+import { getVisitorInfo } from "@/service/visitor";
+import VisitorSummary from "./components/VisitorSummary";
+
+import { getVisitorMessagesByMsgId } from "@/service/visitor";
+import { TVisitorAgent, TVisitorChat } from "@/types/visitor";
+import IconEditButtonBlue from "@/images/svgs/dashboard/IconEditButtonBlue.svg";
+import style from "./index.module.less";
+
+export default () => {
+  const router = useRouter();
+  const { visitorId, msgId } = router.params;
+  if (!visitorId || !msgId) {
+    return <View>...</View>;
+  }
+
+  const [visitor, setVisitor] = useState<TVisitorAgent>();
+  const [list, setList] = useState<TVisitorChat[]>([]);
+
+  const fetchVisitor = async ()=> {
+    const response = await getVisitorInfo(visitorId);
+      if (isSuccess(response.status)) {
+        setVisitor(response.data);
+      }
+  }
+  const fetchData = async () => {
+    const response = await getVisitorMessagesByMsgId({
+      visitorId,
+      msgId,
+      size: 10,
+    });
+    if (isSuccess(response.status)) {
+      setList(response.data)
+    }
+  };
+
+  
+
+  
+  useEffect(() => {
+    fetchVisitor();
+    fetchData();
+  }, []);
+
+
+  
+
+  const renderContent = (item: TVisitorChat) => {
+    if (item.role === "user") {
+      return <View className="text-14 text-title mb-8">{item?.content}</View>;
+    }
+
+    return (
+      <View
+        className="p-16 text-title rounded-8 relative"
+        style={{ backgroundColor: "#F4F9FF" }}
+      >
+        <View>{item.content}</View>
+      </View>
+    );
+  };
+
+  return (
+    <PageCustom>
+      <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">
+          {list.map((item) => {
+            return (
+              <View className={` bg-white rounded-12 overflow-hidden`}>
+                <View className="p-16">{renderContent(item)}</View>
+              </View>
+            );
+          })}
+        </View>
+      </View>
+    </PageCustom>
+  );
+};

+ 36 - 0
src/pages/chat-messages/visitedDetail.ts

@@ -0,0 +1,36 @@
+import { getVisitorMessages, getVisitorSessions } from "@/service/visitor";
+import { TSessionItem, TVisitorMessage } from "@/types/visitor";
+import { useLoadMore } from "@/utils/loadMore";
+
+export const useVisitorMessages = (visitorId: string|number, sessionId: string) => {
+  const fetcher = async ([_url, nextId, page, pageSize, sessionId]) => {
+    const res = await getVisitorMessages({ startId: nextId, pageSize, visitorId, sessionId });
+    return res.data;
+  };
+
+  const { data, loadMore, refetch } = useLoadMore<{
+    data?: TVisitorMessage[]
+    nextId?: string,
+    totalCount?: number
+  }>({
+    url: `api/v1/my/visitor/messages/${visitorId}`,
+    fetcher,
+    params: [sessionId]
+  });
+
+  return {
+    data,
+    loadMore,
+    refetch
+  }
+}
+
+export const useVisitorSessions = (visitorId: string|number) => {
+  
+
+  return {
+    data,
+    loadMore,
+    refetch
+  }
+}

+ 49 - 0
src/pages/chat-session-messages/components/VisitorSummary/index.tsx

@@ -0,0 +1,49 @@
+import { View, Text, Image } from "@tarojs/components";
+import DigitalCardBasic from "@/components/DigitalCard/DigitalCardBasic";
+import { TVisitorAgent } from "@/types/visitor";
+import TagCertificated from "@/components/tag-certificated";
+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="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]">{}</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>
+        </View>
+      </View>
+    </View>
+  );
+};
+
+export default VisitorSummary;

+ 5 - 0
src/pages/chat-session-messages/index.config.ts

@@ -0,0 +1,5 @@
+export default definePageConfig({
+  navigationBarTitleText: '分析',
+  "usingComponents": {},
+  "navigationStyle": 'custom',
+})

+ 14 - 0
src/pages/chat-session-messages/index.module.less

@@ -0,0 +1,14 @@
+.editButton{
+  position: absolute;
+  z-index: 1;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 20px;
+  height: 20px;
+  background: rgba(#327BF9, .1);
+  border-radius:  8px 0 8px 0;
+}
+

+ 105 - 0
src/pages/chat-session-messages/index.tsx

@@ -0,0 +1,105 @@
+import { View, Image, Text } from "@tarojs/components";
+import Taro, { useReachBottom, useRouter } from "@tarojs/taro";
+import NavBarNormal from "@/components/NavBarNormal/index";
+import PageCustom from "@/components/page-custom/index";
+import { useEffect, useState } from "react";
+import { isSuccess } from "@/utils";
+import { getVisitorInfo } from "@/service/visitor";
+import VisitorSummary from "./components/VisitorSummary";
+
+import { getVisitorMessages } from "@/service/visitor";
+import { TSessionItem, TVisitorAgent, TVisitorChat } from "@/types/visitor";
+import { useLoadMore } from "@/utils/loadMore";
+import IconEditButtonBlue from "@/images/svgs/dashboard/IconEditButtonBlue.svg";
+import style from "./index.module.less";
+
+export default () => {
+  const router = useRouter();
+  const { visitorId, sessionId } = router.params;
+  if (!visitorId || !sessionId) {
+    return <View>...</View>;
+  }
+
+  const [visitor, setVisitor] = useState<TVisitorAgent>();
+  const [list, setList] = useState<TVisitorChat[]>([]);
+
+  const fetchData = async () => {
+    if (visitorId) {
+      const response = await getVisitorInfo(visitorId);
+      if (isSuccess(response.status)) {
+        setVisitor(response.data);
+      }
+    }
+  };
+
+  const fetcher = async ([_url, nextId, page, pageSize, sessionId]) => {
+    const res = await getVisitorMessages({
+      startId: nextId,
+      pageSize,
+      visitorId,
+      sessionId,
+    });
+    return res.data;
+  };
+
+  const { data, loadMore } = useLoadMore<{
+    data?: TVisitorChat[];
+    nextId?: string;
+    totalCount?: number;
+  }>({
+    url: `api/v1/my/visitor/sessions${visitorId}`,
+    fetcher,
+    params: [sessionId],
+  });
+
+  useEffect(() => {
+    fetchData();
+  }, []);
+
+  useEffect(() => {
+    if (data?.data) {
+      //@ts-ignore
+      setList([...list, ...data.data]);
+    }
+  }, [data]);
+
+  useReachBottom(() => {
+    loadMore();
+  });
+
+  const renderContent = (item: TVisitorChat) => {
+    if (item.role === "user") {
+      return <View className="text-14 text-title mb-8">{item?.content}</View>;
+    }
+
+    return (
+      <View
+        className="p-16 text-title rounded-8 relative"
+        style={{ backgroundColor: "#F4F9FF" }}
+      >
+        <View>{item.content}</View>
+        <View className={style.editButton}>
+          <Image src={IconEditButtonBlue} className="w-14 h-14" />
+        </View>
+      </View>
+    );
+  };
+
+  return (
+    <PageCustom>
+      <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">
+          {list.map((item) => {
+            return (
+              <View className={` bg-white rounded-12 overflow-hidden`}>
+                <View className="p-16">{renderContent(item)}</View>
+              </View>
+            );
+          })}
+        </View>
+      </View>
+    </PageCustom>
+  );
+};

+ 36 - 0
src/pages/chat-session-messages/visitedDetail.ts

@@ -0,0 +1,36 @@
+import { getVisitorMessages, getVisitorSessions } from "@/service/visitor";
+import { TSessionItem, TVisitorMessage } from "@/types/visitor";
+import { useLoadMore } from "@/utils/loadMore";
+
+export const useVisitorMessages = (visitorId: string|number, sessionId: string) => {
+  const fetcher = async ([_url, nextId, page, pageSize, sessionId]) => {
+    const res = await getVisitorMessages({ startId: nextId, pageSize, visitorId, sessionId });
+    return res.data;
+  };
+
+  const { data, loadMore, refetch } = useLoadMore<{
+    data?: TVisitorMessage[]
+    nextId?: string,
+    totalCount?: number
+  }>({
+    url: `api/v1/my/visitor/messages/${visitorId}`,
+    fetcher,
+    params: [sessionId]
+  });
+
+  return {
+    data,
+    loadMore,
+    refetch
+  }
+}
+
+export const useVisitorSessions = (visitorId: string|number) => {
+  
+
+  return {
+    data,
+    loadMore,
+    refetch
+  }
+}

+ 49 - 36
src/pages/dashboard-dislike-messages/index.tsx

@@ -12,81 +12,94 @@ import { useEffect, useState } from "react";
 import CardEditable from "@/components/card/card-editable/index";
 import Taro, { useRouter, useDidShow } from "@tarojs/taro";
 import {
+  deleteVisitorDislikeAnswer,
   getVisitorDislikeMessages
 } from "@/service/visitor";
-import { TVisitorDetail } from "@/types/visitor";
+import { TVisitorChat } from "@/types/visitor";
 
 import { useLoadMore } from "@/utils/loadMore";
+import { useModalStore } from "@/store/modalStore";
+import { isSuccess } from "@/utils";
+import { TQAListItem } from "@/types/knowledge";
 
 export default function Index() {
   const router = useRouter()
+  const {showModal} = useModalStore()
   const {agentId} = router.params as {agentId:string}
   const [scrollTop, setScrollTop] = useState(0)
-  const [list, setList] = useState<TVisitorDetail[]>([]);
+  const [list, setList] = useState<TVisitorChat[]>([]);
 
   const fetcher = async ([_url, nextId, page, pageSize]) => {
     const res = await getVisitorDislikeMessages({agentId, startId: nextId, pageSize });
     return res.data;
   };
-  const { data, loadMore } = useLoadMore<TVisitorDetail[]>({
+  const { data, loadMore, page, refetch } = useLoadMore<TVisitorChat[]>({
     url: `getVisitorDislikeMessages${agentId}`,
     fetcher,
   });
     
 
-  const handleEdit = (qaId: number | string) => {
-
-    // Taro.navigateTo({
-    //   url: `/pages/knowledge-item-editor/index?knowledgeId=${knowledgeId}&qaId=${qaId}&knowledgeTitle=${detail?.title}`,
-    // });
+  const handleEdit = (item: TVisitorChat) => {
+    Taro.navigateTo({
+      url: `/pages/dashboard-visitor-message-editor/index?msgId=${item.msgId}&visitorId=${item.visitorId}&agentId=${item.agentId}`,
+    });
   };
   
   
   
   // 删除问答项
-  const handleDeleteItem = async (qaId: number | string) => {
-    // if (!detail) {
-    //   return;
-    // }
-    // showModal({
-    //   content: "确定删除该问答项吗?",
-    //   onConfirm: async () => {
-    //     const { status } = await deleteKnowledgeQa(detail.knowledgeId, qaId);
-    //     if (isSuccess(status)) {
-    //       Taro.showToast({ title: "删除成功", icon: "success" });
-    //       getDetail(detail.knowledgeId);
-    //     }
-    //   },
-    // });
+  const handleDeleteItem = async (item: TVisitorChat) => {
+    showModal({
+      content: "确定删除该问答项吗?",
+      onConfirm: async () => {
+        
+        const { status } = await deleteVisitorDislikeAnswer({
+          visitorId: item.visitorId,
+          msgId: item.msgId
+        })
+        if (isSuccess(status)) {
+          Taro.showToast({ title: "删除成功", icon: "success" });
+          refetch()
+        }
+      },
+    });
+  };
+  const handleView = async (item: TVisitorChat) => {
+    Taro.navigateTo({
+      url: `/pages/chat-messages/index?visitorId=${item.visitorId}&msgId=${item.msgId}`,
+    });
   };
 
   const onScrollEnd = async () => {
-    console.log("toEnd");
     loadMore();
   };
 
   
-
-  
-
   useEffect(() => {
     if (data?.data) {
-      setList([...list, ...data.data]);
+      const r = data.data.filter((item)=> item.role === 'assistant')
+      if(page === 1){
+        setList(r);  
+      }else{
+        setList([...list, ...r]);
+      }
       setScrollTop(prev => prev + 1)
     }
   }, [data]);
 
-  useEffect(() => {
-    loadMore();
-  }, []);
+  
+  useDidShow(()=> {
+    setList([])
+    refetch()
+  })
 
-  const createCardOptions = (item: TQAListItem) => {
+  const createCardOptions = (item: TVisitorChat) => {
     return [
-      <View onClick={() => handleDeleteItem(item.qaId)}>
+      <View onClick={() => handleDeleteItem(item)}>
         删除
       </View>,
-      <View onClick={() => handleEdit(item.qaId)}>查看对话</View>,
-      <View onClick={() => handleEdit(item.qaId)}>编辑</View>,
+      <View onClick={() => handleView(item)}>查看对话</View>,
+      <View onClick={() => handleEdit(item)}>编辑</View>,
     ]
   }
 
@@ -95,10 +108,10 @@ export default function Index() {
       <NavBarNormal backText="待处理差评" scrollFadeIn></NavBarNormal>
       <View className="w-full flex flex-col overflow-hidden h-full pt-2">
         <View className="rounded-container-header"></View>
-        <View className="text-14 font-medium leading-22 px-16 pb-16">
+        {/* <View className="text-14 font-medium leading-22 px-16 pb-16">
           问答列表共
           <Text className="text-primary"> 10 </Text>条
-        </View>
+        </View> */}
         <ScrollView
           scrollY
           onScrollEnd={onScrollEnd}

+ 15 - 9
src/pages/dashboard-visited-detail/components/VisitorSummary/index.tsx

@@ -1,7 +1,7 @@
 import { View, Text, Image } from "@tarojs/components";
 import DigitalCardBasic from "@/components/DigitalCard/DigitalCardBasic";
 import { TVisitorAgent } from "@/types/visitor";
-
+import TagCertificated from "@/components/tag-certificated";
 export interface IndexProps {
   data: TVisitorAgent;
 }
@@ -11,23 +11,29 @@ const VisitorSummary = ({ data }: IndexProps) => {
     <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-56 h-56 bg-gray-3 rounded-full">
+          <View className="w-60 h-60 bg-gray-3 rounded-full">
             {!!data.avatarUrl && (
               <Image
                 src={data.avatarUrl}
                 mode="aspectFill"
-                className="w-56 h-56 bg-gray-3 rounded-full"
+                className="w-60 h-60 bg-gray-3 rounded-full"
               ></Image>
             )}
           </View>
         </View>
         <View className="flex flex-col gap-8">
-          <DigitalCardBasic
-            name={data.name}
-            position={data.position ?? ""}
-            company={'---'}
-            certificated={data.isEnt}
-          />
+          <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]">{}</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> 轮对话

+ 22 - 1
src/pages/dashboard-visited-detail/index.module.less

@@ -2,4 +2,25 @@
   padding: 0 16px;
   height: 100%;
   flex: 1;
-}
+}
+
+
+.gutterLine{
+  margin: 0 4px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.dot{
+  width: 8px;
+  height: 8px;
+  border-radius: 8px;
+  background: #FFFFFF;
+  border: 2px solid #DEE2EC; 
+}
+.line{
+  width: 2px;
+  height: 100%;
+  background: #DEE2EC;
+}
+

+ 83 - 23
src/pages/dashboard-visited-detail/index.tsx

@@ -1,4 +1,4 @@
-import { View, ScrollView } from "@tarojs/components";
+import { View, ScrollView, Text } from "@tarojs/components";
 import Taro, { useDidShow, useRouter } from "@tarojs/taro";
 import NavBarNormal from "@/components/NavBarNormal/index";
 import PageCustom from "@/components/page-custom/index";
@@ -6,14 +6,15 @@ import IconArrowDownRounded from "@/components/icon/IconArrowDownRounded";
 import { useEffect, useState } from "react";
 import { useAgentStore } from "@/store/agentStore";
 import { isSuccess } from "@/utils";
-import ChatMessage from "@/components/chat-message";
+import ChatRecordItem from "@/components/ChatRecordItem";
 import { getVisitorInfo } from "@/service/visitor";
-import { TVisitorAgent, TVisitorMessage } from "@/types/visitor";
-import type { TMessage, TRobotMessage } from "@/store/textChat";
+import { TSessionItem, TVisitorAgent, TVisitorMessage } from "@/types/visitor";
 import VisitorSummary from "./components/VisitorSummary";
 
-import { useVisitorMessages } from "./visitedDetail";
+import { getVisitorSessions } from "@/service/visitor";
+
 import style from "./index.module.less";
+import { useLoadMore } from "@/utils/loadMore";
 
 export default () => {
   const router = useRouter();
@@ -23,9 +24,8 @@ export default () => {
   }
 
   const [visitor, setVisitor] = useState<TVisitorAgent>();
-  const [list, setList] = useState<
-    (TMessage & TRobotMessage & TVisitorMessage)[]
-  >([]);
+  const [list, setList] = useState<TSessionItem[]>([]);
+  const [totalCount, setTotalCount] = useState(1);
 
   const fetchData = async () => {
     if (visitorId) {
@@ -36,7 +36,39 @@ export default () => {
     }
   };
 
-  const { data, loadMore } = useVisitorMessages(visitorId);
+  const fetcher = async ([_url, nextId, page, pageSize]) => {
+    const res = await getVisitorSessions({
+      startId: nextId,
+      pageSize: 5,
+      visitorId,
+    });
+    const _totalCount = res.data.totalCount;
+
+    if (_totalCount && res.data.data) {
+      setTotalCount(_totalCount);
+      const data = res.data;
+      data.data = data.data.map((item: TSessionItem) => {
+        return { ...item, visitTimes: _totalCount - page };
+      });
+      return data;
+    }
+
+    const data = res.data;
+    data.data = data.data.map((item: TSessionItem) => {
+      return { ...item, visitTimes: totalCount - page };
+    });
+
+    return data;
+  };
+
+  const { data, loadMore } = useLoadMore<{
+    data?: TSessionItem[];
+    nextId?: string;
+    totalCount?: number;
+  }>({
+    url: `api/v1/my/visitor/sessions${visitorId}`,
+    fetcher,
+  });
 
   const onScrollToLower = () => {
     loadMore();
@@ -53,12 +85,14 @@ export default () => {
     }
   }, [data]);
 
+  
+
   return (
     <PageCustom fullPage style={{ overflow: "hidden" }}>
-      <NavBarNormal backText="访问详情"></NavBarNormal>
+      <NavBarNormal backText="数据"></NavBarNormal>
       {visitor ? <VisitorSummary data={visitor} /> : <></>}
       <View className="rounded-container-header"></View>
-      <View className="flex-1 overflow-hidden">
+      <View className="flex-1 overflow-hidden w-full">
         <ScrollView
           scrollY
           onScrollToLower={onScrollToLower}
@@ -68,20 +102,46 @@ export default () => {
           }}
         >
           <View>
-            <View className="flex flex-col gap-16 px-16">
-              {list.map((message) => {
+            <View className="flex flex-col gap-16 px-16 w-full">
+              {list.map((item) => {
                 return (
-                  <>
-                    <View className="text-12 text-gray-45 leading-20 text-center">
-                      {message?.msgTime}
+                  <View className="w-full">
+                    <View className="text-12 text-black leading-16">
+                      {item?.msgTime.slice(0, 10)}
+                    </View>
+                    <View className="flex h-full w-full">
+                      <View className="text-14 font-normal text-black leading-20 flex flex-col items-end">
+                        <View>{item?.msgTime.slice(10, 16)} </View>
+                      </View>
+                      <View className="flex flex-1 w-full">
+                        <View className={style.gutterLine}>
+                          <View className={style.dot}></View>
+                          <View className={style.line}></View>
+                          <View className={style.dot}></View>
+                        </View>
+                        <View className="w-full h-full flex flex-col gap-8">
+                          <View className="text-14 leading-24 text-title">
+                            第{" "}
+                            <Text className="text-primary">
+                              {item?.visitTimes}
+                            </Text>{" "}
+                            次访问你的智能体
+                          </View>
+                          <View className="text-12 text-gray-45">
+                            访问时长: {item.chatSecondsDesc}
+                          </View>
+                          <View className="text-12 text-gray-45">
+                            共进行了 {item.chatRoundCnt} 轮对话{" "}
+                          </View>
+                          <ChatRecordItem
+                            sessionId={item.sessionId}
+                            visitorId={visitorId}
+                            showMoreButton
+                          ></ChatRecordItem>
+                        </View>
+                      </View>
                     </View>
-                    <ChatMessage
-                      message={message}
-                      key={message.msgUk}
-                      role={message.role}
-                      text={message.content}
-                    ></ChatMessage>
-                  </>
+                  </View>
                 );
               })}
             </View>

+ 0 - 25
src/pages/dashboard-visited-detail/visitedDetail.ts

@@ -1,25 +0,0 @@
-import { getVisitorMessages } from "@/service/visitor";
-import { TVisitorMessage } from "@/types/visitor";
-import { useLoadMore } from "@/utils/loadMore";
-
-export const useVisitorMessages = (visitorId: string|number) => {
-  const fetcher = async ([_url, nextId, page, pageSize, _keyword]) => {
-    const res = await getVisitorMessages({ startId: nextId, pageSize, visitorId });
-    return res.data;
-  };
-
-  const { data, loadMore, refetch } = useLoadMore<{
-    data?: TVisitorMessage[]
-    nextId?: string,
-    totalCount?: number
-  }>({
-    url: `api/v1/my/visitor/messages/${visitorId}`,
-    fetcher,
-  });
-
-  return {
-    data,
-    loadMore,
-    refetch
-  }
-}

+ 63 - 35
src/pages/dashboard-visitor-message-editor/index.tsx

@@ -25,24 +25,26 @@ import { uploadFile } from "@/utils/http";
 import { EUploadFileScene } from "@/consts/enum";
 
 import Taro, { useRouter } from "@tarojs/taro";
-import { getKnowledgeQa, updateKnowledgeQa } from "@/service/knowledge";
 import { isSuccess } from "@/utils";
+import { editVisitorDislikeAnswer, getVisitorMessagesByMsgId } from "@/service/visitor";
 
-type TFormdata = {q:string, a: string, links: string[], mediaList: TMediaType[]}
+import { TVisitorChat } from "@/types/visitor";
 
+type TFormdata = {content:string, correctionAnswer: string, links: string[], mediaList: TMediaType[]}
 
-interface IProps {
-  initialData?: TFormdata
-}
 export default function Index() {
 
   const router = useRouter()
-  const { knowledgeId, qaId, knowledgeTitle } = router.params
+  const { msgId, visitorId, agentId } = router.params as {msgId: string, visitorId: string, agentId: string}
+
+  console.log(msgId, visitorId, agentId, 8888)
   
+  const [visitorQ, setQVisitor] = useState<TVisitorChat|null>(null)
+  const [visitor, setVisitor] = useState<TVisitorChat|null>(null)
   const [formData, setFormData] = useState<TFormdata>(
     {
-      q: '',
-      a: '',
+      content: '',
+      correctionAnswer: '',
       links: [],
       mediaList: [] //{fileType: 'image',url: 'https://cdn.wehome.cn/cmn/png/53/META-H8UKWHWU-2JNUAG2BARJF55VHU9QS3-YBQGHDAM-IW.png'}
     }
@@ -51,13 +53,13 @@ export default function Index() {
   const handleInput = (value: string) => {
     setFormData({
       ...formData,
-      q: value,
+      content: value,
     });
   };
   const handleValueAInput = (value: string) => {
     setFormData({
       ...formData,
-      a: value,
+      correctionAnswer: value,
     });
   };
 
@@ -98,33 +100,47 @@ export default function Index() {
   };
 
   const handleSubmit = async () => {
-    if(!knowledgeId || !qaId){
+    if(!msgId || !visitorId || !visitor){
       return
     }
-
     const dataToSubmit = {
-      answer: formData.a,
-      questions: [formData.q],
-      qaId: parseInt(qaId),
+      questions : [visitorQ?.content],
+      visitorId: visitorId,
+      answer: formData.correctionAnswer,
+      content: formData.content,
+      agentId: agentId,
+      msgId: msgId,
+      correctionId: visitor.correctionId,
       links: formData.links.filter(link => link.trim() !== ''),
-      pics: formData.mediaList.map( item => item.url)
+      pics: formData.mediaList.map( item => item.url),
     }
     console.log(dataToSubmit)
-    const {status} = await updateKnowledgeQa(knowledgeId, qaId, dataToSubmit)
+    
+    const {status} = await editVisitorDislikeAnswer(dataToSubmit)
     if(isSuccess(status)){
       Taro.showToast({title: '保存成功', icon: 'success'})
     }
   }
-  const getQaDetail = async (knowledgeId: string, qaId: string)=> {
-    const {status, data} = await getKnowledgeQa(knowledgeId, qaId)
-    if(isSuccess(status)){
+  const getDetail = async () => {
+    const {status, data} = await getVisitorMessagesByMsgId({
+      msgId,
+      visitorId,
+      size: 2,
+    })
+    
+    if(isSuccess(status), data[0]){
+      const _visitor = data[0]
+      setVisitor(_visitor)
+      if(data[1]){
+        setQVisitor(data[1])
+      }
       setFormData({
-        q: data.questions[0],
-        a: data.answer,
-        links: data.links,
-        mediaList: data.pics.map( pic => {
+        content: _visitor.content,
+        correctionAnswer: _visitor.correctionAnswer,
+        links: _visitor.correctionLinks ?? [],
+        mediaList: _visitor.correctionPics?.map( pic => {
           return {fileType: 'image', url: pic}
-        }),
+        }) ?? [],
       })
     }
   }
@@ -150,32 +166,44 @@ export default function Index() {
   }
 
   useEffect(()=> {
-    if(knowledgeId && qaId){
-        getQaDetail(knowledgeId, qaId)
+    if(visitorId && msgId){
+        getDetail()
     }
     
-  }, [knowledgeId, qaId])
+  }, [visitorId, msgId])
 
   
 
   return (
     <PageCustom>
-      <NavBarNormal scrollFadeIn backText={knowledgeTitle ?? '...'}></NavBarNormal>
+      <NavBarNormal scrollFadeIn backText={'差评记录'}></NavBarNormal>
       <View className="w-full pb-120">
         <View className="p-16">
+          <View className="text-gray-45 text-14 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">
                 <View className="flex-center h-28">
                   <IconQ />
                 </View>
-                <View className="flex-1 text-14 leading-28">问题描述</View>
+                <View className="flex-1 text-14 leading-28">提问</View>
+              </View>
+              <View className="p-16 bg-white rounded-12">
+                {visitorQ?.content}
+              </View>
+            </View>
+            <View className="flex flex-col">
+              <View className="flex items-start gap-8 mb-6">
+                <View className="flex-center h-28">
+                  <IconA />
+                </View>
+                <View className="flex-1 text-14 leading-28">原回答</View>
               </View>
               <View className="">
                 <WemetaTextarea
-                  value={formData.q}
+                  value={formData.content}
+                  disabled
                   onInput={handleInput}
-                  placeholder="描述你想要生成的画面和动作。例如:职场精英在点头微笑"
                 />
               </View>
             </View>
@@ -186,13 +214,13 @@ export default function Index() {
                 <View className="flex-center h-28">
                   <IconA />
                 </View>
-                <View className="flex-1 text-14 leading-28">回答</View>
+                <View className="flex-1 text-14 leading-28">纠错回答</View>
               </View>
               <View>
                 <WemetaTextarea
-                  value={formData.a}
+                  value={formData.correctionAnswer}
                   onInput={handleValueAInput}
-                  placeholder="描述你想要生成的画面和动作。例如:职场精英在点头微笑"
+                  placeholder="描述正确的回答"
                 />
               </View>
             </View>

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

@@ -38,7 +38,6 @@ const Index = ({ data }: IndexProps) => {
             name={data.name}
             position={data.position ?? ""}
             company={data.company}
-            certificated
           />
           <View className="text-14 font-medium leading-22">
             第 <Text className="text-yellow">{data.visitTimes}</Text>{" "}

+ 1 - 1
src/pages/knowledge/components/CompanyList/index.tsx

@@ -89,7 +89,7 @@ const Index = ({currentEnt, setCurrentEnt, extraEnt = []}: IProps) => {
     <PickerSingleColumn
       options={options}
       selected={selected}
-      onChange={handleChange}
+      onPicked={handleChange}
       showPicker={showPicker}
       setShowPicker={setShowPicker}
     >

+ 4 - 2
src/pages/knowledge/components/CompanyTab/components/ScrollList.tsx

@@ -27,7 +27,7 @@ const Index = ({entId}:Iprops) => {
     const res = await getEntKnowledgeList({ startId: nextId, pageSize, entId });
     return res.data;
   };
-  const { data, loadMore, refetch } = useLoadMore<TKnowledgeItem[]>({
+  const { data, loadMore, refetch, page } = useLoadMore<TKnowledgeItem[]>({
     url: `getEntKnowledgeList ${entId}`,
     fetcher,
     params: [entId]
@@ -42,13 +42,15 @@ const Index = ({entId}:Iprops) => {
   })
   useEffect(() => {
     if (data?.data) {
-      setList([...list, ...data.data]);
+      const result = page === 1 ? data.data : [...list, ...data.data]
+      setList(result);
       setScrollTop(prev => prev + 1)
     }
   }, [data]);
 
   useEffect(() => {
     loadMore();
+    refetch
   }, [entId]);
   
 

+ 8 - 4
src/pages/knowledge/components/CompanyTab/components/ScrollListChat.tsx

@@ -31,7 +31,7 @@ const ViewStyleChatEnt = ({ entId }: Iprops) => {
     const res = await getEntKnowledgeStream({ startId: nextId, pageSize, entId });
     return res.data;
   };
-  const { data, loadMore, refetch } = useLoadMore<TKnowledgeStreamResponseData[]>({
+  const { data, loadMore, page, refetch } = useLoadMore<TKnowledgeStreamResponseData[]>({
     url: `getEntKnowledgeStream ${entId}`,
     fetcher,
     params: [entId]
@@ -51,13 +51,17 @@ const ViewStyleChatEnt = ({ entId }: Iprops) => {
 
   useEffect(() => {
     if (data?.data) {
-      setList([...list, ...data.data]);
-      setScrollTop(prev => prev + 1)
+      const result = page === 1 ? data.data : [...list, ...data.data]
+      setList(result);
+      if(page === 1){
+        setScrollTop(prev => prev + 1)
+      }
     }
   }, [data]);
 
   useEffect(() => {
-    loadMore();
+    setList([])
+    refetch();
   }, [entId]);
 
   return (

+ 8 - 44
src/pages/knowledge/components/CorrectionList/index.tsx

@@ -19,10 +19,11 @@ import { TCorrectionItem } from "@/types/correction";
 type TListStyle = "card" | "list";
 
 const Index = () => {
-  const [checked, setChecked] = useState(false);
-  const [showPopup, setShowPopup] = useState(false);
+  // const [checked, setChecked] = useState(false);
+  // const [showPopup, setShowPopup] = useState(false);
   const [listStyle, setListStyle] = useState<TListStyle>("card");
-  const [current, setCurrent] = useState<TEntItem | string>("");
+  // const [current, setCurrent] = useState<TEntItem | string>("");
+  const [ent, setEnt] = useState<TEntItem|null>(null)
   const [list, setList] = useState<TCorrectionItem[]>([]);
 
   const extraEnt: TEntItem[] = [{
@@ -35,12 +36,11 @@ const Index = () => {
 
   // 渲染数据内容
   const renderScrollContent = () => {
-    const entId = typeof current === "string" ? undefined : current.entId;
     if (listStyle === "card") {
       return (
         <ViewStyleListCorrection
           setData={setList}
-          entId={entId}
+          entId={ent?.entId}
           viewStyle="card"
         />
       );
@@ -48,12 +48,12 @@ const Index = () => {
     return (
       <ViewStyleListCorrection
         setData={setList}
-        entId={entId}
+        entId={ent?.entId}
         viewStyle="list"
       />
     );
   };
-
+  console.log(list,1112)
   // 渲染主体
   const renderEmpty = () => {
     // 空数据
@@ -78,46 +78,10 @@ const Index = () => {
   return (
     <>
       <View className="px-16 h-full">
-        <CompanyList extraEnt={extraEnt}></CompanyList>
+        <CompanyList currentEnt={ent} setCurrentEnt={setEnt} extraEnt={extraEnt}></CompanyList>
         {renderEmpty()}
         {renderScrollContent()}
       </View>
-
-      {/* <Popup setShow={setShowPopup} show={showPopup} title="展示样式">
-        <View
-          className={`rounded-card ${
-            listStyle === "card" ? "rounded-card-actived" : ""
-          }`}
-          onClick={() => {
-            handleListStyleChange("card");
-          }}
-        >
-          <View className="border-bottom1-gray mb-12">
-            <View className="mb-8 text-14 font-medium leading-22">
-              对话信息流
-            </View>
-          </View>
-          <View className="flex items-center">
-            <WemetaSwitch
-              checked={checked}
-              onChange={(checked) => setChecked(checked)}
-            ></WemetaSwitch>
-          </View>
-        </View>
-        <View
-          className={`rounded-card ${
-            listStyle === "list" ? "rounded-card-actived" : ""
-          }`}
-          onClick={() => {
-            handleListStyleChange("list");
-          }}
-        >
-          <View className="mb-8 text-14 font-medium leading-22">列表形式</View>
-          <View className="mb-12 text-12 leading-20 text-gray-45">
-            将知识点以简洁列表呈现,清晰快速地提供信息。
-          </View>
-        </View>
-      </Popup> */}
     </>
   );
 };

+ 1 - 1
src/pages/knowledge/components/PersonalTab/components/ScrollList.tsx

@@ -34,7 +34,7 @@ const Index = ({types}: IProps) => {
     const res = await getKnowledgeList({ startId: nextId, pageSize, types });
     return res.data;
   };
-  const { data, loadMore } = useLoadMore<TKnowledgeItem[]>({
+  const { data, loadMore, page } = useLoadMore<TKnowledgeItem[]>({
     url: `getKnowledgeList${types}`,
     fetcher,
     params: [types]

+ 1 - 1
src/pages/knowledge/components/PersonalTab/components/ScrollListChat.tsx

@@ -32,7 +32,7 @@ const ViewStyleChat = () => {
     const res = await getMyKnowledgeStream({ startId: nextId, pageSize });
     return res.data;
   };
-  const { data, loadMore } = useLoadMore<TKnowledgeStreamResponseData[]>({
+  const { data, loadMore, page } = useLoadMore<TKnowledgeStreamResponseData[]>({
     url: `getMyKnowledgeStream`,
     fetcher,
   });

+ 24 - 14
src/pages/knowledge/components/view-style/ViewStyleListCorrection.tsx

@@ -24,29 +24,39 @@ const Index = ({viewStyle, entId, setData}:Iprops) => {
   const { showModal } = useModalStore();
 
   const fetcher = async ([_url, nextId, page, pageSize, _entId]) => {
+    if(_entId === -1){
+      _entId = undefined
+    }
     const res = await getCorrectionList({ startId: nextId, pageSize, entId: _entId});
     return res.data;
   };
   
-  const { data, loadMore, refetch } = useLoadMore<TCorrectionItem[]>({
+  const { data, loadMore, refetch, page } = useLoadMore<TCorrectionItem[]>({
     url: `api/v1/my/correction/list${entId}`,
     fetcher,
-    params: [entId]
+    params: [entId],
+    
   });  
 
   const onScrollToUpper = async () => {
     console.log('toUpper')
     loadMore()
   }
-  useDidShow(()=> {
-    refetch()
-    console.log(333)
-  })
+  
+  useEffect(()=> {
+    setList([])
+    setData([]);
+    refetch();
+  }, [entId])
+
   useEffect(() => {
-    if (data?.data) {
-      const result = [...list, ...data.data]
+    if (data?.data?.length) {
+      // 如果是切换 entId,list 已经被 setList([]) 清空
+      // 如果 list 为空,说明是第一页,直接覆盖
+      // 如果 list 不为空,说明是加载更多,追加
+      const result = page === 1 ? data.data : [...list, ...data.data];
       setList(result);
-      setData(result)
+      setData(result);
     }
   }, [data]);
 
@@ -75,10 +85,10 @@ const Index = ({viewStyle, entId, setData}:Iprops) => {
 
   const createCardOptions = (item: TCorrectionItem) => {
     return [
-      <View onClick={() => handleDeleteItem(item.id)}>
-        删除
-      </View>,
-      <View onClick={() => handleEdit(item.id)}>编辑</View>,
+      // <View onClick={() => handleDeleteItem(item.id)}>
+      //   删除
+      // </View>,
+      // <View onClick={() => handleEdit(item.id)}>编辑</View>,
     ]
   }
   return (
@@ -92,7 +102,7 @@ const Index = ({viewStyle, entId, setData}:Iprops) => {
     >
     {list.map((item) => {
       return (
-        <View className="flex flex-col gap-16 px-16 mb-16">
+        <View className="flex flex-col gap-16 mb-16">
           <CardEditable
             buttons={createCardOptions(item)}
           >

+ 5 - 5
src/pages/knowledge/index.tsx

@@ -35,11 +35,11 @@ export default function Index() {
       label: "企业知识",
       children: renderTabContainer(<CompanyTab />),
     },
-    // {
-    //   key: "3",
-    //   label: "纠错记录",
-    //   children: renderTabContainer(<CorrectionList />),
-    // },
+    {
+      key: "3",
+      label: "纠错记录",
+      children: renderTabContainer(<CorrectionList />),
+    },
   ];
   return (
     <PageCustom>

+ 133 - 130
src/service/visitor.ts

@@ -1,169 +1,172 @@
-import {
-  bluebookAiAgent,
-} from '@/xiaolanbenlib/api/index'
-import request from '@/xiaolanbenlib/module/axios.js'
-
-import { TVisitorAgent, TVisitorMessage, TVisitorDetail } from '@/types/visitor'
-
+import { bluebookAiAgent } from "@/xiaolanbenlib/api/index";
+import request from "@/xiaolanbenlib/module/axios.js";
 
+import {
+  TVisitorAgent,
+  TVisitorMessage,
+  TVisitorChat,
+  TSessionItem,
+} from "@/types/visitor";
 
 // 编辑差评记录的答案消息--编辑后则自动标识为已处理
-export const editVisitorDislikeAnswer = (data: TVisitorDetail) => {
-  return request.put(`${bluebookAiAgent}api/v1/my/visitor/message/answer`, data)
-}
+export const editVisitorDislikeAnswer = (data: {
+  agentId: string,
+  answer: string ,
+  links: string[],
+  msgId: string,
+  pics: string[],
+  questions : string[],
+  visitorId: string
+}) => {
+  return request.put(
+    `${bluebookAiAgent}api/v1/my/visitor/message/answer`,
+    data
+  );
+};
 
 // 删除指定的差评待处理记录
 export const deleteVisitorDislikeAnswer = (data: {
-  "visitorId": string,
-  "msgId": string,
+  visitorId: string|number;
+  msgId: string|number;
 }) => {
-  return request.delete(`${bluebookAiAgent}api/v1/my/visitor/dislike/message`, {params: data})
-}
+  return request.delete(`${bluebookAiAgent}api/v1/my/visitor/dislike/message`, {
+    params: data,
+  });
+};
 
 // 获取未处理的差评记录列表
 export type TVisitorDislikeMessagesResponse = {
-  "data": [
-    TVisitorDetail[]
-  ],
-  "nextId": string,
-  "totalCount": number
-}
+  data: [TVisitorChat[]];
+  nextId: string;
+  totalCount: number;
+};
 
 export const getVisitorDislikeMessages = (data: {
-  "agentId": string,
-  "startId": string,
-  "pageSize": number,
+  agentId: string;
+  startId: string;
+  pageSize: number;
 }) => {
-  return request.get<TVisitorDislikeMessagesResponse>(`${bluebookAiAgent}api/v1/my/visitor/dislike/messages`, {params: data})
-}
-
-
-
+  return request.get<TVisitorDislikeMessagesResponse>(
+    `${bluebookAiAgent}api/v1/my/visitor/dislike/messages`,
+    { params: data }
+  );
+};
 
 // 访客访问详情--访客信息
 export type TVisotorInfoResponse = {
-  "agentId": string,
-  "agentStatus": string,
-  "avatarUrl": string,
-  "chatRound": number,
-  "dislikeCnt": number,
-  "isEnt": false,
-  "lastChatTime": "2025-05-21T07:09:45.814Z",
-  "myAgentId": string,
-  "myAgentName": string,
-  "name": string,
-  "position": string,
-  "visitTimes": number,
-  "visitorId": number
-}
-export const getVisitorInfo = (visitorId: number|string) => {
-  return request.get<TVisotorInfoResponse>(`${bluebookAiAgent}api/v1/my/visitor/info`, {params: {visitorId}})
-}
+  agentId: string;
+  agentStatus: string;
+  avatarUrl: string;
+  chatRound: number;
+  dislikeCnt: number;
+  isEnt: false;
+  lastChatTime: "2025-05-21T07:09:45.814Z";
+  myAgentId: string;
+  myAgentName: string;
+  name: string;
+  position: string;
+  visitTimes: number;
+  visitorId: number;
+};
+export const getVisitorInfo = (visitorId: number | string) => {
+  return request.get<TVisotorInfoResponse>(
+    `${bluebookAiAgent}api/v1/my/visitor/info`,
+    { params: { visitorId } }
+  );
+};
 
 // 获取好评记录列表--包含已读未读
 export type TVisitorLikeMessagesResponse = {
-  "data": TVisitorMessage[],
-  "nextId": string,
-  "totalCount": number
-}
+  data: TVisitorMessage[];
+  nextId: string;
+  totalCount: number;
+};
 export const getVisitorLikeMessages = (data: {
-  visitorId: string,
-  startId: string,
-  pageSize: number
+  visitorId: string;
+  startId: string;
+  pageSize: number;
 }) => {
-  return request.get<TVisitorLikeMessagesResponse>(`${bluebookAiAgent}api/v1/my/visitor/like/messages`, {params: data})
-}
+  return request.get<TVisitorLikeMessagesResponse>(
+    `${bluebookAiAgent}api/v1/my/visitor/like/messages`,
+    { params: data }
+  );
+};
 
 // 访客数据列表--列表会按我的智能体明细展示
 export type TVisitorListResponse = {
-  "data": [
-    
-  ],
-  "nextId": string,
-  "totalCount": number
-}
+  data: [];
+  nextId: string;
+  totalCount: number;
+};
 export const getVisitorList = (data: {
-  "agentId": string,
-  "startId": string,
-  "pageSize": string,
+  agentId: string;
+  startId: string;
+  pageSize: string;
 }) => {
-  return request.get<TVisitorListResponse>(`${bluebookAiAgent}api/v1/my/visitor/list`, {params: data})
-}
-
+  return request.get<TVisitorListResponse>(
+    `${bluebookAiAgent}api/v1/my/visitor/list`,
+    { params: data }
+  );
+};
 
 // 访客访问详情--访客聊天记录
 export type TVisitorMessagesResponse = {
-  "data": TVisitorAgent[],
-  "nextId": string,
-  "totalCount": number
-}
+  data: TVisitorChat[];
+  nextId: string;
+  totalCount: number;
+};
 export const getVisitorMessages = (data: {
-  "visitorId": string|number,
-  "startId": string,
-  "pageSize": string,
+  visitorId: string | number;
+  startId?: string;
+  sessionId: string;
+  pageSize: number;
+}) => {
+  return request.get<TVisitorMessagesResponse>(
+    `${bluebookAiAgent}api/v1/my/visitor/session/messages`,
+    { params: data }
+  );
+};
+
+// 访客访问详情--获取访问的会话列表, 仅在 startId 为空时返回 totalCount
+
+export const getVisitorSessions = (data: {
+  visitorId: string | number;
+  startId: string;
+  pageSize: number;
 }) => {
-  return request.get<TVisitorListResponse>(`${bluebookAiAgent}api/v1/my/visitor/messages`, {params: data})
-}
+  return request.get<{
+    data: TSessionItem[];
+    nextId: string;
+    totalCount: number;
+  }>(`${bluebookAiAgent}api/v1/my/visitor/sessions`, { params: data });
+};
 
 // 访客聊天记录 获取指定 msgId 前后各N条;用于查看好差评记录的访客详情
-export type TVisitorMessagesByMsgIdResponse = [
-  {
-    "agentId": string,
-    "visitorId": string,
-    "content": string,
-    "dislikeReason": string,
-    "isDislike": false,
-    "isLike": false,
-    "isStreaming": false,
-    "msgId": number,
-    "msgTime": "2025-05-21T07:09:45.828Z",
-    "msgUk": string,
-    "originalAgentId": string,
-    "role": string
-  }
-]
 export const getVisitorMessagesByMsgId = (data: {
-  "visitorId": string,
-  "agentId": string,
-  "msgId": string,
-  "size": number,
+  visitorId: string;
+  msgId: string;
+  size: number;
 }) => {
-  return request.get<TVisitorMessagesByMsgIdResponse>(`${bluebookAiAgent}api/v1/my/visitor/messages/byMsgId`, {params: data})
-}
-
+  return request.get<TVisitorChat[]>(
+    `${bluebookAiAgent}api/v1/my/visitor/messages/byMsgId`,
+    { params: data }
+  );
+};
 
 // 访问数据汇总
 export type TVisitorSummary = {
-  sumChatUv?: number// 总聊天UV ,
-  sumPv?: number// 总PV ,
-  sumUv?: number// 总UV ,
-  todayChatUv?: number// 今日聊天UV ,
-  todayPv?: number// 今日PV ,
-  todayUv?: number// 今日UV ,
-  unprocessedDislikeCnt?: number// 未处理差评记录数 ,
-  unreadLikeCnt?: number// 未查看点赞记录数
-}
+  sumChatUv?: number; // 总聊天UV ,
+  sumPv?: number; // 总PV ,
+  sumUv?: number; // 总UV ,
+  todayChatUv?: number; // 今日聊天UV ,
+  todayPv?: number; // 今日PV ,
+  todayUv?: number; // 今日UV ,
+  unprocessedDislikeCnt?: number; // 未处理差评记录数 ,
+  unreadLikeCnt?: number; // 未查看点赞记录数
+};
 export const getVisitorSummary = (agentId?: string) => {
-  return request.get<TVisitorSummary>(`${bluebookAiAgent}api/v1/my/visitor/summary`, {params: {agentId}})
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+  return request.get<TVisitorSummary>(
+    `${bluebookAiAgent}api/v1/my/visitor/summary`,
+    { params: { agentId } }
+  );
+};

+ 1 - 1
src/types/user.ts

@@ -13,7 +13,7 @@ export type TUserInfo = {
 // isExpired (boolean, optional): 是否已到期 ,
 // knowledgeCnt (integer, optional): 企业知识库统计数
 export type TEntItem = {
-  entId: number | string;
+  entId?: number | string;
   entName: string;
   expireTime?: string;
   isExpired?: boolean;

+ 11 - 1
src/types/visitor.ts

@@ -3,7 +3,7 @@
 
 
 // 访客的会话详情 
-export type TVisitorDetail = {
+export type TVisitorChat = {
   agentId: string ,
   content: string  // 对方消息内容 ,
   contentType: string // 消息类型:text/plain; application/json; aiseek/audio_chunk; aiseek/thinking; aiseek/function_call; aiseek/multimodal; aiseek/qa; ,
@@ -58,3 +58,13 @@ export type TVisitorAgent = {
   visitTimes: number,// visitTimes (integer, optional): 访问访问我的指定智能体次数 ,
   visitorId: number// visitorId (integer, optional): 访客ID
 }
+
+
+export type TSessionItem = {
+  chatRoundCnt: number,
+  msgTime: string,
+  chatSecondsDesc: string
+  chatSeconds: number
+  sessionId: string
+  visitTimes?: number
+}

+ 1 - 0
tailwind.config.js

@@ -35,6 +35,7 @@ module.exports = {
       'black-3': '#333333',
       'black-6': '#666666',
       'black-9': '#999999',
+      'title': '#111A34',
       'harsh': '#F94F17',
       'purple': '#7e5bef',
       'pink': '#ff49db',