yangyin
2024-12-11 4c173b743e256132e27096d38f8c9d436c13ee45
src/layout/component/sidebar/components/ChatRecord.vue
@@ -1,26 +1,49 @@
<template>
   <div class="w100 h100 flex items-center flex-column box-border pr-1">
      <div class="w100 box-border px-[18px] py-0 flex-0">
         <el-button
            @click="newChatRoomClick"
            icon="ele-Plus"
            color="#1c86ff"
            class="flex items-center box-border mb-3 justify-center add_room cursor-pointer w-[124px] h-[32.88px] rounded-s-md text-white opacity-100"
         >
            新建聊天室
         </el-button>
         <div class="flex items-center justify-between">
            <el-button
               @click="newChatRoomClick"
               icon="ele-Plus"
               class="flex items-center box-border mb-3 justify-center add_room cursor-pointer w-[124px] h-[32.88px] rounded-s-md text-white opacity-100 bg-[var(--color-bg-avatar)]"
            >
               新建对话
            </el-button>
            <el-popover placement="right-start" :width="136" trigger="hover">
               <template #reference>
                  <div class="nav__chat">
                     <div class="nav__chat-icon">
                        <span class="chat_img ywifont ywicon-shouji !text-[20px] text-[#fff]"></span>
                     </div>
                  </div>
               </template>
               <template #default>
                  <div class="relative">
                     <div class="p-0 box-shadow-none rounded-[10px]">
                        <p class="text-center text-[#5e6772] m-0 p-0 leading-5 text-[12px]">请使用手机浏览器扫描二维码</p>
                        <p class="text-center text-[red] m-0 p-0 leading-5 text-[12px]">(不支持微信扫描)</p>
                        <div ref="setPhoneQRCode" class="mt-[8px] mb-[8px]"></div>
                        <p class="text-center text-[#5e6772] m-0 p-0 leading-5">
                           扫码下载 <br />
                           WI 水务智能助手
                        </p>
                     </div>
                  </div>
               </template>
            </el-popover>
         </div>
      </div>
      <div
         class="flex flex-col flex-auto w-[210.98px] rounded-t-lg box-border mb-3 relative opacity-100 shadow-lg shadow-[[#0e0e0f]-500/50"
      >
         <div class="group flex-0 relative w100 h-[34px] bg-[#2b2c30]">
         <div class="group flex-0 relative w100 h-[34px] bg-[var(--color-bg-base-exr)]">
            <el-input clearable v-model="queryParams.title" placeholder="搜索" class="set-input">
               <template #prefix>
                  <el-icon><search /></el-icon>
               </template>
            </el-input>
            <div
               class="absolute hidden top-[100%] w-[84px] z-[1001] left-0 group-hover:block overflow-hidden rounded-md text-sm text-gray-500 bg-[#fff] py-1.5"
               class="absolute hidden top-[100%] w-[84px] z-[1001] left-0 group-hover:block overflow-hidden rounded-md text-gray-500 bg-[#fff] py-1.5"
            >
               <div
                  class="w100 relative hover:bg-[#e6f1ff]"
@@ -40,20 +63,19 @@
         <div class="flex-auto text-[#ccc] flex flex-col items-center mt-6 overflow-y-auto set-scroll" ref="chatRoomRef">
            <div
               :class="{ 'bg-[#41424a]': item.id === activeRoomId }"
               :class="{ 'text-btn-base': item.id === activeRoomId }"
               class="group flex items-center w-full h-10 rounded-md cursor-pointer px-2 py-2 flex-0"
               v-for="(item, index) in queryData"
               :key="index"
               @click="roomClick(item)"
            >
               <div class="ywicon icon-xiaoxi flex-0 mr-2.5"></div>
               <div class="flex-auto text-ellipsis text-nowrap text-sm group-hover:text-[#0084ff]">{{ item.title }}</div>
               <div class="ywifont ywicon-xiaoxi1 flex-0 mr-2.5"></div>
               <div class="flex-auto text-ellipsis text-nowrap group-hover:text-btn-base">{{ item.title }}</div>
               <div class="text-gray-100 flex items-center space-x-2 ml-1">
                  <div class="ywicon invisible icon-bianji group-hover:visible !text-sm"></div>
                  <div class="ywifont invisible ywicon-bianji group-hover:visible !" @click.stop="editChat(item)"></div>
                  <el-popconfirm title="确定删除聊天记录?" @confirm.stop="confirmDeleteChatRoom(item)" width="180">
                     <template #reference>
                        <div class="ywicon invisible icon-shanchu3 group-hover:visible"></div>
                        <div class="ywifont invisible ywicon-shanchu3 group-hover:visible"></div>
                     </template>
                  </el-popconfirm>
               </div>
@@ -65,60 +87,25 @@
<script setup lang="ts">
import { Search } from '@element-plus/icons-vue';
import { computed, onMounted, reactive, ref, watch } from 'vue';
import type { ChatRoomItem } from './types';
import { CreateHistoryGroup, DeleteHistoryGroups, GetHistoryGroups } from '/@/api/ai/chat';
import router from '/@/router';
import { activeRoomId, chatRoomList } from '/@/stores/chatRoom';
import { DateFilter, dateFilterMap } from '/@/model/types/date';
import { debounce, getRecentDateRange } from '/@/utils/util';
import { ElMessage, ElMessageBox } from 'element-plus';
import moment from 'moment';
import QRCode from 'qrcodejs2-fixes';
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import type { ChatRoomItem } from './types';
import { DeleteHistoryGroups, setHistoryGroupTitle } from '/@/api/ai/chat';
import { SERVE_URL } from '/@/constants';
import { useSearch } from '/@/hooks/useSearch';
import { DateFilter, dateFilterMap } from '/@/model/types/date';
import { activeRoomId, chatRoomList, gotoAnswerPage, newChatRoomClick, selectFirstRoom } from '/@/stores/chatRoom';
import { debounce, getRecentDateRange } from '/@/utils/util';
const chatRoomRef = ref<HTMLDivElement>(null);
const queryParams = ref({
   title: '',
});
const gotoAnswerPage = (room: ChatRoomItem) => {
   if (room.isInitial) {
      router.push({
         name: 'Home',
      });
   } else {
      router.push({
         name: 'AskAnswer',
         query: {
            id: room.id,
         },
      });
   }
   setTimeout(() => {
      activeRoomId.value = room.id;
   }, 0);
};
const newChatRoomClick = async () => {
   const res = await CreateHistoryGroup({
      group_title: 'chat room',
   });
   const newRoom = {
      id: res.history_group_id,
      isInitial: true,
      title: 'chat room',
   };
   if (!chatRoomList.value) {
      chatRoomList.value = [newRoom];
   } else {
      chatRoomList.value.unshift(newRoom);
   }
   gotoAnswerPage(newRoom);
};
const roomClick = (room: ChatRoomItem) => {
   activeRoomId.value = room.id;
   gotoAnswerPage(room);
};
@@ -136,7 +123,32 @@
   roomClick(chatRoomList.value[0]);
   chatRoomRef.value.firstElementChild?.scrollIntoView();
};
const editChat = (room: ChatRoomItem) => {
   ElMessageBox.prompt('', '重命名', {
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/,
      inputValue: room.title,
      inputErrorMessage: '请输入新的名称',
   })
      .then(async (edit) => {
         const res = await setHistoryGroupTitle({
            history_group_id: room.id,
            title: edit.value,
         });
         if (res.json_ok) {
            const foundIndex = chatRoomList.value.findIndex((item) => item.id === room.id);
            chatRoomList.value[foundIndex].title = edit.value;
            chatRoomRef.value.firstElementChild?.scrollIntoView();
         }
      })
      .catch(({ value }) => {
         ElMessage({
            type: 'info',
            message: '取消修改',
         });
      });
};
//#region ====================== 日期筛选 ======================
const activeDateFilter = ref<DateFilter>(DateFilter.All);
@@ -170,7 +182,7 @@
//#endregion
//#region ====================== 搜索聊天室 ======================
const { query,queryData } = useSearch(filteredChatRoomList, queryParams);
const { query, queryData } = useSearch(filteredChatRoomList, queryParams);
const debounceQuery = debounce(query);
@@ -181,24 +193,27 @@
   }
);
//#endregion
onMounted(async () => {
   const res = await GetHistoryGroups();
   const resData = (res?.groups || []) as any[];
   chatRoomList.value = resData?.map((item) => {
      return {
         id: item.group_id,
         title: item.group_title,
         createTime: item.create_time,
         isInitial: false,
      };
//#region ====================== 扫码手机端下载 ======================
const setPhoneQRCode = ref<HTMLElement | null>(null);
// 初始化生成二维码
const initQrcode = () => {
   let currentTime = new Date().getTime();
   const url = `${SERVE_URL}ai_html/views/mobileDownload/index.html?v=${currentTime}`;
   nextTick(() => {
      (<HTMLElement>setPhoneQRCode.value).innerHTML = '';
      new QRCode(setPhoneQRCode.value, {
         text: url,
         width: 126,
         height: 126,
         colorDark: '#000000',
         colorLight: '#ffffff',
      });
   });
   if (!chatRoomList.value || chatRoomList.value.length === 0) {
      newChatRoomClick();
   } else {
      roomClick(chatRoomList.value[0]);
   }
};
//#endregion
onMounted(async () => {
   selectFirstRoom();
   initQrcode();
});
</script>
<style scoped lang="scss">
@@ -233,4 +248,36 @@
   width: 0;
   color: transparent;
}
.nav__chat {
   width: 40px;
   height: 40px;
   border-radius: 12px;
   margin-bottom: 10px;
   cursor: pointer;
   &:hover {
      background-color: #41424a;
   }
   .nav__chat-icon {
      background-position: 8px 8px;
      font-size: 25px;
      line-height: 40px;
      text-align: center;
      color: #fff;
      &:hover {
         color: #0084ff;
      }
      .chat_img {
         display: inline-flex;
         align-items: center;
         color: inherit;
         font-style: normal;
         line-height: 0;
         text-align: center;
         text-transform: none;
         height: 40px;
         text-rendering: optimizeLegibility;
         -webkit-font-smoothing: antialiased;
      }
   }
}
</style>