| | |
| | | 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> |
| | | <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="flex-0 relative w100 h-[34px] bg-[#2b2c30]"> |
| | | <el-input v-model="state.searchInput" placeholder="搜索" class="set-input"> |
| | | <div class="group flex-0 relative w100 h-[34px] bg-[#2b2c30]"> |
| | | <el-input clearable v-model="queryParams.title" placeholder="搜索" class="set-input"> |
| | | <template #prefix> |
| | | <el-icon @click="selectDateChange"><search /></el-icon> |
| | | <el-icon><search /></el-icon> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | <div class="absolute top-[100%] w-[84px] z-[1001] left-0" v-show="state.isShowDate"> |
| | | <div class="w100 bg-[#fff] px-[0px] py-[5px]" v-for="item in state.selectDateOption" :key="item.value"> |
| | | <div class="w100 relative h-[28px] flex items-center justify-center cursor-pointer">{{ item.label }}</div> |
| | | <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" |
| | | > |
| | | <div |
| | | class="w100 relative hover:bg-[#e6f1ff]" |
| | | v-for="item in Object.keys(dateFilterMap)" |
| | | :key="item" |
| | | @click="filterDateClick(Number(item))" |
| | | > |
| | | <div |
| | | class="size-2 absolute left-2 rounded-full bg-[#2a82e4]" |
| | | :style="{ display: item === activeDateFilter + '' ? 'block' : 'none' }" |
| | | style="top: calc(50% - 0.25rem)" |
| | | ></div> |
| | | <div class="w100 relative h-[28px] flex items-center justify-center cursor-pointer">{{ dateFilterMap[item] }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <div |
| | | :class="{ 'bg-[#41424a]': 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 chatRoomList" |
| | | v-for="(item, index) in queryData" |
| | | :key="index" |
| | | @click="roomClick(item)" |
| | | > |
| | | <div class="ywicon icon-xiaoxi flex-0 mr-2.5"></div> |
| | | <div class="ywifont ywicon-xiaoxi1 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="text-gray-100 flex items-center space-x-2 ml-1"> |
| | | <div class="ywicon invisible icon-bianji visible group-hover:visible !text-sm"></div> |
| | | |
| | | <div class="ywifont invisible ywicon-bianji group-hover:visible !text-sm" @click.stop="editChat(item)"></div> |
| | | <el-popconfirm title="确定删除聊天记录?" @confirm.stop="confirmDeleteChatRoom(item)" width="180"> |
| | | <template #reference> |
| | | <div class="ywicon invisible icon-shanchu3 visible group-hover:visible"></div> |
| | | <div class="ywifont invisible ywicon-shanchu3 group-hover:visible"></div> |
| | | </template> |
| | | </el-popconfirm> |
| | | </div> |
| | |
| | | |
| | | <script setup lang="ts"> |
| | | import { Search } from '@element-plus/icons-vue'; |
| | | import { onMounted, reactive, ref } from 'vue'; |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import moment from 'moment'; |
| | | import { computed, onMounted, 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'; |
| | | let state = reactive({ |
| | | searchInput: '', |
| | | selectDateOption: [ |
| | | { |
| | | label: '全部', |
| | | value: 0, |
| | | }, |
| | | { |
| | | label: '一周内', |
| | | value: 1, |
| | | }, |
| | | { |
| | | label: '一月内', |
| | | value: 2, |
| | | }, |
| | | { |
| | | label: '一月前', |
| | | value: 3, |
| | | }, |
| | | ], |
| | | isShowDate: false, |
| | | import { DeleteHistoryGroups, setHistoryGroupTitle } from '/@/api/ai/chat'; |
| | | 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 chatRoomRef = ref<HTMLDivElement>(null); |
| | | |
| | | const selectDateChange = () => { |
| | | state.isShowDate = !state.isShowDate; |
| | | }; |
| | | |
| | | 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); |
| | | }; |
| | | |
| | |
| | | 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); |
| | | const filterDateClick = (dateFilter: DateFilter) => { |
| | | activeDateFilter.value = dateFilter; |
| | | }; |
| | | |
| | | const filteredChatRoomList = computed(() => { |
| | | if (activeDateFilter.value === DateFilter.All) return chatRoomList.value; |
| | | else { |
| | | let dayCount = null; |
| | | switch (activeDateFilter.value) { |
| | | case DateFilter.AWeek: |
| | | dayCount = 7; |
| | | break; |
| | | |
| | | case DateFilter.AMonth: |
| | | dayCount = 30; |
| | | |
| | | break; |
| | | case DateFilter.ThreeMonth: |
| | | dayCount = 90; |
| | | break; |
| | | } |
| | | |
| | | const [startDay, endDay] = getRecentDateRange(dayCount); |
| | | const data = chatRoomList.value.filter((item) => moment(item.createTime).isBetween(startDay, endDay)); |
| | | return data; |
| | | } |
| | | }); |
| | | //#endregion |
| | | |
| | | //#region ====================== 搜索聊天室 ====================== |
| | | const { query, queryData } = useSearch(filteredChatRoomList, queryParams); |
| | | |
| | | const debounceQuery = debounce(query); |
| | | |
| | | watch( |
| | | () => queryParams.value.title, |
| | | (val) => { |
| | | debounceQuery(); |
| | | } |
| | | ); |
| | | //#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, |
| | | }; |
| | | }); |
| | | if (!chatRoomList.value || chatRoomList.value.length === 0) { |
| | | newChatRoomClick(); |
| | | } else { |
| | | roomClick(chatRoomList.value[0]); |
| | | } |
| | | selectFirstRoom(); |
| | | }); |
| | | </script> |
| | | <style scoped lang="scss"> |
| | |
| | | transition: color 0.2s ease-in-out; |
| | | box-shadow: unset; |
| | | } |
| | | :deep(.el-input__inner) { |
| | | &::placeholder { |
| | | color: white; |
| | | } |
| | | color: white; |
| | | } |
| | | } |
| | | ::-webkit-scrollbar { |
| | | height: 0; |