ソースを参照

feat: 专家问题 - 推荐问题

whh 9 ヶ月 前
コミット
d40548e452

+ 2 - 0
src/api/chat.js

@@ -19,5 +19,7 @@ export const chatApi = {
   getChatSessionTag: params =>http.get('/front/bigModel/chat/generateSessionId', { params }),
 
   getWelcomeRecommend: params => http.get('/front/bigModel/home/recommendQAList/' + params),
+
+  deleteHistory: params => http.delete('/front/bigModel/chat/deleteOneChtById/' + params),
 }
 

+ 0 - 1
src/assets/styles/index.scss

@@ -1,4 +1,3 @@
-// @import "./mixins.scss";
 @import "./variables.scss";
 @import "reset.css";
 @import "common.scss";

+ 4 - 4
src/assets/svgs/tool/bucket-del.svg

@@ -1,6 +1,6 @@
 <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M2.66666 5H13.3333L12.3333 14.6667H3.66666L2.66666 5Z" stroke="#5E5E5E" stroke-linejoin="round"/>
-<path d="M6.66733 8.33411V11.6675" stroke="#5E5E5E" stroke-linecap="round"/>
-<path d="M9.33414 8.33313V11.6657" stroke="#5E5E5E" stroke-linecap="round"/>
-<path d="M4 4.99997L9.4414 1L12 5" stroke="#5E5E5E" stroke-linecap="round" stroke-linejoin="round"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M2.66666 5H13.3333L12.3333 14.6667H3.66666L2.66666 5Z" stroke="currentColor" stroke-linejoin="round"/>
+<path d="M6.66733 8.33411V11.6675" stroke="currentColor" stroke-linecap="round"/>
+<path d="M9.33414 8.33313V11.6657" stroke="currentColor" stroke-linecap="round"/>
+<path d="M4 4.99997L9.4414 1L12 5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
 </svg>

+ 6 - 2
src/components/Chat/ChatAnswer.vue

@@ -56,7 +56,11 @@ const text = computed(() => {
 
 <template>
   <div class="answer-inner">
-    <div class="answer-card">
+    <div :class="[
+        'answer-card', 'px-[20px]', 'py-[20px]',
+        // loading && delayLoading ? 'pb-[20px]' : 'pb-[4px]'
+      ]"
+    >
       <div class="chat-answer_icon relative flex-shrink-0">
         <SvgIcon name="common-logo" class="chat-logo " size="30" :style="{ scale: loading ? 0 : 1 }" />
         <div style="color: #2454FF" class="la-ball-circus la-dark la-sm flex-shrink-0" v-show="loading">
@@ -106,7 +110,7 @@ const text = computed(() => {
 
   .answer-card {
     @include flex(x, start, start);
-    padding: 20px;
+    // padding: 20px 20px 4px 20px;
     border-radius: 8px;
     background: #fff;
   }

+ 3 - 3
src/components/Chat/ChatInput.vue

@@ -10,7 +10,7 @@ const modelLoading = defineModel('loading');
 
 const message = useMessage();
 
-const inpVal = ref(null);
+const inpVal = ref('');
 const inpRef = ref(null);
 
 const isFocusState = ref(false);
@@ -31,8 +31,8 @@ const commonEmitEvent = (eventName) => {
     return message.warning('请输入您的问题或需求');
   }
 
-  if ( len > 500 ) {
-    return message.warning('问题限制500个字以内');
+  if ( len > 2000 ) {
+    return message.warning('问题限制2000个字以内');
   }
 
   if ( modelLoading.value ) {

+ 3 - 7
src/components/ChatWelcome/index.vue

@@ -22,8 +22,8 @@ defineProps({
 
 const emit = defineEmits(['on-click']);
 
-const handleEmit = ({ content: question }) => {
-  emit('on-click', question);
+const handleEmit = ({ content: realQuestion, question }) => {
+  emit('on-click', { realQuestion, question } );
 }
 </script>
 
@@ -52,8 +52,4 @@ const handleEmit = ({ content: question }) => {
       </dd>
     </dl>
   </div>
-</template>
-
-<style setup lang="scss">
-
-</style>
+</template>

+ 1 - 1
src/components/Layout/TheSubMenu.vue

@@ -40,7 +40,7 @@ const handleLoadMore = () => emits('scrollToLower');
       <slot name="top" />
     </div>
 
-    <div class="sub-menu-main w-full h-full">
+    <div class="sub-menu-main w-full h-full" >
       <NInfiniteScroll class="h-full" :distance="10" @load="handleLoadMore">
         <slot></slot>
         <div class="footer-loading w-full h-[50px]" v-show="loading">

+ 12 - 19
src/components/RecodeCardItem/index.vue

@@ -1,6 +1,7 @@
 <script setup>
-import { ref } from 'vue';
+import { ref, computed } from 'vue';
 import { NPopconfirm, useMessage  } from 'naive-ui';
+import { chatApi } from "@/api/chat";
 import { SvgIcon } from '@/components';
 
 const props = defineProps({
@@ -18,39 +19,27 @@ const props = defineProps({
   }
 });
 
+const isOff = ref(false);
+
 const emit = defineEmits(['on-delete', 'on-click']);
 
 const message = useMessage();
 
-const handlePositiveClick = () => {
-  message.success('删除成功');
-}
-
 const handleCardClick = () => {
   emit('on-click', props.dataItem);
 }
 
-const handleDelete = () => {
-  console.log('点击了 del');
+const handleDelete = async () => {
+  emit('on-delete', props.dataItem.id);
 }
 </script>
 
 <template>
   <div class="recode-card-item" @click="handleCardClick">
     <p class="content">{{ title }}</p>
-    <p class="time flex item-center justify-between w-full mt-[2px]">
-      <span>{{ time }}</span>
+    <p class="time flex item-center justify-between w-full mt-[2px] hover:color-[red]">
+      <span class="hover:color-[red]">{{ time }}</span>
       <SvgIcon name="tool-bucket-del" size="16" class="del-icon cursor-pointer hidden" @click.stop="handleDelete"></SvgIcon>
-      <!-- <NPopconfirm
-        negative-text="取消"
-        positive-text="删除"
-        @positive-click="handlePositiveClick"
-      >
-        <template #trigger>
-          
-        </template>
-        删除后无法恢复,是否继续删除?
-      </NPopconfirm> -->
     </p>
   </div>
 </template>
@@ -80,6 +69,10 @@ const handleDelete = () => {
 
     .del-icon {
       display: block;
+
+      &:hover {
+        color: red;
+      }
     }
 
     &::before {

+ 24 - 5
src/composables/useInfinite.js

@@ -1,27 +1,33 @@
-import { ref, unref, onMounted } from "vue";
+import { ref, unref, onMounted, computed } from "vue";
 import { chatApi } from '@/api/chat';
 
 export const useInfinite = props => {
-  const pageParams = { page: 1, pageSize: 10 };
+  const pageParams = { page: 1, pageSize: 20 };
 
   const recordList = ref([]);
   const isFetching = ref(false);
+  const counter = ref(0);
   const noMore = ref(false);
 
+  const isMore = computed(() => recordList.value.length < counter.value);
+
   const addHistoryRecord = record => {
     recordList.value.unshift(...record);
   }
 
   const onScrolltolower = async () => {
+
     if(unref(isFetching) || unref(noMore)) return;
 
     isFetching.value = true;
 
-    const { rows, total } = await chatApi.getAnswerHistoryList({ ...props, ...pageParams });
+    const { rows, total } = await initRecordData();
     
-    recordList.value.push(...rows);
+    counter.value = total;
 
-    if (pageParams.page * pageParams.pageSize < total) {
+    recordList.value.push(...rows);
+ 
+    if (unref(isMore)) {
       pageParams.page ++;
     } else {
       noMore.value = true;
@@ -30,12 +36,25 @@ export const useInfinite = props => {
     isFetching.value = false;
   }
 
+  const onReset = async () => {
+    const { rows, total } = await initRecordData();
+
+    recordList.value = rows;
+    counter.value = total;
+    noMore.value = unref(isMore);
+  }
+
+  const initRecordData = async () => {
+    return await chatApi.getAnswerHistoryList({ ...props, ...pageParams });
+  }
+
   onMounted(() => onScrolltolower());
 
   return {
     recordList,
     isFetching,
     onScrolltolower,
+    onReset,
     addHistoryRecord
   }
 }

+ 34 - 17
src/views/answer/AnswerView.vue

@@ -1,7 +1,7 @@
 <script setup>
 import { ref, unref, computed, onMounted } from 'vue';
 import { useMessage } from 'naive-ui';
-import { SvgIcon, BaseButton, RecodeCardItem, TheSubMenu, TheChatView, ChatWelcome } from '@/components';
+import { BaseButton, RecodeCardItem, TheSubMenu, TheChatView, ChatWelcome } from '@/components';
 import { ChatAsk, ChatAnswer, ChatInput } from '@/components/Chat';
 import { chatApi } from '@/api/chat';
 
@@ -11,7 +11,7 @@ import { useChat } from '@/composables/useChat';
 import { useRecommend } from '@/composables/useRecommend';
 
 // TODO: 如果这里的key不一样,将会在拆一层组件出来 - list
-const { recordList, isFetching, onScrolltolower, addHistoryRecord } = useInfinite({model: 0});
+const { recordList, isFetching, onScrolltolower, onReset, addHistoryRecord } = useInfinite({model: 0});
 const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll();
 const { chatDataSource, addChat, updateChat, clearChat } = useChat();
 const { recommendList } = useRecommend({type: 0});
@@ -22,7 +22,7 @@ const isLoading = ref(false);
 
 const currenSessionId = ref(null);
 
-const isExistInHistory = computed(() => !(recordList.value.findIndex(({ sessionId: sId }) => sId === unref(currenSessionId)) === -1));
+const isExistInHistory = computed(() => (recordList.value.findIndex(({ sessionId: sId }) => sId === unref(currenSessionId)) === -1));
 
 // 新建对话
 const handleCreateDialog = async () => {
@@ -39,24 +39,27 @@ const handleCreateDialog = async () => {
   clearChat();
 }
 
-// 处理推荐问题
-const handleWelcomeRecommend = question => {
-  
-}
-
 // 查询对话详情
 const handleChatDetail = async ({ sessionId }) => {
+  isLoading.value = false;
   const { data } = await chatApi.getAnswerHistoryDetail({ sessionId });
-  chatDataSource.value = data.map(({ createTime, sessionId, question, answer }) => ({ createTime, sessionId, question, answer, loading: false }));
+  chatDataSource.value = data.map(({ createTime, sessionId, question, answer }) => ({ 
+    createTime, 
+    sessionId, 
+    question, 
+    answer, 
+    loading: false 
+  }));
   currenSessionId.value = sessionId;
   scrollToBottom();
 }
 
-const onRegenerate = async ({ question, sessionId }) => {
+const onRegenerate = async ({ question, realQuestion }) => {
+  const sessionId = unref(currenSessionId);
   const params = {
     data: {
       sessionId,
-      question,
+      question: realQuestion || question,
     },
     onDownloadProgress: ({ event }) => {
       const xhr = event.target;
@@ -90,10 +93,9 @@ const onRegenerate = async ({ question, sessionId }) => {
 }
 
 // 提交问题
-const handleSubmit = async (question) => {
+const handleSubmit = async (question, realQuestion = '') => {
   // 用于模拟 - 内容生成前置等待状态
-  const sessionId = unref(currenSessionId);
-
+  
   if (unref(isExistInHistory)) {
     const { data: sessionId } = await chatApi.getChatSessionTag();
     currenSessionId.value = sessionId;
@@ -102,8 +104,9 @@ const handleSubmit = async (question) => {
   isLoading.value = true;
 
   addChat({
-    sessionId,
+    sessionId: unref(currenSessionId),
     question,
+    realQuestion,
     answer: '',
     loading: true,
     delayLoading: true
@@ -111,7 +114,20 @@ const handleSubmit = async (question) => {
 
   scrollToBottom();
 
-  setTimeout(() => onRegenerate({ question, sessionId }), 2 * 1000);
+  setTimeout(() => onRegenerate({ question, realQuestion }), 2 * 1000);
+}
+
+// 处理推荐问题
+const handleWelcomeRecommend = ({ question, realQuestion }) => {
+  handleSubmit( question, realQuestion );
+}
+
+// 删除历史对话
+const handeChatDelete = async (id) => {
+  await chatApi.deleteHistory(id);
+  onReset();
+  clearChat();
+  message.success('删除成功');
 }
 </script>
 
@@ -133,6 +149,7 @@ const handleSubmit = async (question) => {
           :time="item.createTime"
           :data-item="item"
           @on-click="handleChatDetail"
+          @on-delete="handeChatDelete"
         />
       </div>
 
@@ -149,7 +166,7 @@ const handleSubmit = async (question) => {
       />
 
       <div class="conversation-item" v-if="chatDataSource.length">
-        <template v-for="item in chatDataSource" :key="item.sessionId">
+        <template v-for="item in chatDataSource" :key="item.id">
           <ChatAsk :content="item.question"></ChatAsk>
           <ChatAnswer :content="item.answer" :loading="item.loading" :delay-loading="item.delayLoading"></ChatAnswer>
         </template>