修改聊天设置弹窗,新增单聊的聊天设置;新增搜索聊天记录的弹窗,接入部分接口数据,调整样式

This commit is contained in:
wangyifeng 2025-05-14 17:22:25 +08:00
parent 701d878f7d
commit ed0737b5e3
11 changed files with 254 additions and 45 deletions

11
src/api/search.js Normal file
View File

@ -0,0 +1,11 @@
import { post, get, upload } from '@/utils/request'
//ES搜索-主页搜索什么都有、指定用户、指定群、群与用户概览
export const ServeSeachQueryAll = (data = {}) => {
return post('/api/v1/elasticsearch/query-all', data)
}
//ES搜索聊天记录-主页搜索什么都有、聊天记录
export const ServeQueryTalkRecord = (data = {}) => {
return post('/api/v1/elasticsearch/query-talk-record', data)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { reactive, computed, watch, ref } from 'vue'
import { NEmpty, NPopover, NPopconfirm } from 'naive-ui'
import { NEmpty, NPopover, NPopconfirm, NSwitch } from 'naive-ui'
import { useUserStore } from '@/store'
import GroupLaunch from './GroupLaunch.vue'
import GroupManage from './manage/index.vue'
@ -22,6 +22,11 @@ const props = defineProps({
gid: {
type: Number,
default: 0
},
talkType: {
// 1: 2:
type: Number,
default: 0
}
})
@ -53,7 +58,7 @@ const state = reactive({
actionBtns: {
confirmBtn: true,
cancelBtn: true
}, //
} //
})
const members = ref<any[]>([])
@ -198,9 +203,10 @@ const showChatSettingOperateModal = (type: string) => {
</script>
<template>
<section class="el-container is-vertical section">
<header class="el-header header bdr-b">
<div class="left-icon" @click="emit('to-talk')">
<n-icon size="21" :component="Comment" />
<header class="el-header header">
<!-- <div class="left-icon" @click="emit('to-talk')"> -->
<div class="left-icon" style="cursor: unset;">
<!-- <n-icon size="21" :component="Comment" /> -->
</div>
<div class="center-text">
<!-- <span>群信息</span> -->
@ -213,7 +219,29 @@ const showChatSettingOperateModal = (type: string) => {
</header>
<main class="el-main main me-scrollbar me-scrollbar-thumb">
<div class="info-box">
<div class="info-box" v-if="talkType === 1">
<div class="b-box b-box-bottomBorder">
<div class="block">
<div class="title">查找聊天记录</div>
<img class="icon-right" src="@/assets/image/icon/arrow-right-grey.png" alt="" />
</div>
</div>
<div class="b-box">
<div class="block">
<div class="title">置顶会话</div>
<n-switch />
</div>
</div>
<div class="b-box">
<div class="block">
<div class="title">消息免打扰</div>
<n-switch />
</div>
</div>
</div>
<div class="info-box" v-if="talkType === 2">
<div class="b-box">
<div class="block">
<div class="title">群成员</div>
@ -284,7 +312,7 @@ const showChatSettingOperateModal = (type: string) => {
</div>
</div>
<div class="member-box">
<div class="member-box" v-if="talkType === 2">
<div class="flex">
<n-input placeholder="搜索" v-model:value="state.keywords" :clearable="true" round>
<template #prefix>
@ -335,7 +363,7 @@ const showChatSettingOperateModal = (type: string) => {
清空聊天记录
</n-button>
<n-button
v-if="isAdmin || isLeader"
v-if="talkType === 2 && (isAdmin || isLeader)"
class="btn"
type="error"
ghost
@ -343,7 +371,13 @@ const showChatSettingOperateModal = (type: string) => {
>
解散该群
</n-button>
<n-button class="btn" type="error" ghost @click="showChatSettingOperateModal('quit')">
<n-button
v-if="talkType === 2"
class="btn"
type="error"
ghost
@click="showChatSettingOperateModal('quit')"
>
退出群聊
</n-button>
</div>
@ -404,8 +438,11 @@ const showChatSettingOperateModal = (type: string) => {
height: 100%;
.header {
width: 100%;
width: calc(100% - 40px);
height: 60px;
margin: 0 20px;
box-sizing: border-box;
border-bottom: 2px solid #efeff2;
display: flex;
align-items: center;
@ -425,7 +462,7 @@ const showChatSettingOperateModal = (type: string) => {
.left-icon,
.right-icon {
width: 50px;
width: 30px;
height: 100%;
flex-shrink: 0;
cursor: pointer;
@ -437,7 +474,7 @@ const showChatSettingOperateModal = (type: string) => {
}
.main {
padding: 15px;
padding: 15px 20px;
.info-box {
.b-box {
@ -498,6 +535,9 @@ const showChatSettingOperateModal = (type: string) => {
color: #999999;
}
}
.b-box-bottomBorder {
border-bottom: 1px solid #f0f0f2;
}
}
.member-box {
@ -572,7 +612,7 @@ const showChatSettingOperateModal = (type: string) => {
.btn {
width: calc(100% - 50px);
background-color: #fff;
color: #CF3050;
color: #cf3050;
}
}

View File

@ -261,6 +261,7 @@ const resultDetail = computed(() => {
justify-content: flex-start;
padding: 11px 0 12px;
border-bottom: 1px solid #f8f8f8;
cursor: pointer;
.search-item-avatar{
position: relative;
@ -334,4 +335,7 @@ const resultDetail = computed(() => {
.search-item-condition {
border: 0;
}
.search-item:hover {
background-color: #f8f8f8;
}
</style>

View File

@ -127,7 +127,7 @@
// useZPaging(zPaging)
import searchItem from './searchItem.vue'
import { ref, reactive, defineEmits, defineProps, onMounted } from 'vue'
import { ref, reactive, defineEmits, defineProps, onMounted, watch } from 'vue'
const emits = defineEmits(['toMoreResultPage', 'lastIdChange', 'clickSearchItem'])
@ -184,6 +184,16 @@ onMounted(() => {
}
})
watch(
() => [props.searchResultPageSize, props.searchText],
([newPageSize, newText], [oldPageSize, oldText]) => {
console.log(newPageSize, newText, oldPageSize, oldText)
if (newPageSize !== oldPageSize || newText !== oldText) {
queryAllSearch(1, newPageSize)
}
}
)
//
const inputSearchText = (e) => {
if (e.trim() != state.searchText.trim()) {
@ -419,6 +429,7 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// zPaging.value?.complete([data])
}
}
// const resp = props.apiRequest(params)
// resp.then(({ code, data }) => {
// console.log(data)
@ -493,10 +504,10 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// if (pageNum === 1) {
// //
// state.searchResult = null
// zPaging.value?.complete([])
// // zPaging.value?.complete([])
// } else {
// //
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// // zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// }
// } else {
// if (props.isPagination) {
@ -534,20 +545,20 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// total = data.group_record_count
// }
// }
// zPaging.value?.completeByTotal([data], total)
// // zPaging.value?.completeByTotal([data], total)
// } else {
// state.searchResult = data
// zPaging.value?.complete([data])
// // zPaging.value?.complete([data])
// }
// }
// } else {
// if (pageNum === 1) {
// //
// state.searchResult = null
// zPaging.value?.complete([])
// // zPaging.value?.complete([])
// } else {
// //
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// // zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// }
// }
// })
@ -556,10 +567,10 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// if (pageNum === 1) {
// //
// state.searchResult = null
// zPaging.value?.complete([])
// // zPaging.value?.complete([])
// } else {
// //
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// // zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// }
// })
}
@ -731,11 +742,15 @@ const clickSearchItem = (searchResultKey, searchItem) => {
.result-has-more {
padding: 10px 0;
border-bottom: 1px solid #f8f8f8;
cursor: pointer;
span {
color: #191919;
line-height: 20px;
}
}
.result-has-more:hover {
background-color: #f8f8f8;
}
}
}
}

View File

@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b8987a3f4c77465504ba46f90370546f2f3656c248bd63549a43410178becfd0d1888ecbb8e82d291e68cf9da8ec1096e2d8abd4bb9d7edc62d38469e56226683693764f82df03eaa47fe6fd21a9cb83e0e'
return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b89642c979f5ab2d142ebbcb209ce7e7964c143edb27ba9be09900f4f4af311e8f5edee6f6b05af86d24daae9a9fd1d1cf686b1ac565663e192e2598c14c35470c9d760c4badd3a54f9c46c7b779684c7d0'
}
/**

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { reactive, computed,watch } from 'vue'
import { reactive, computed, watch } from 'vue'
import { NDrawer } from 'naive-ui'
import { useUserStore, useDialogueStore, useUploadsStore } from '@/store'
import PanelHeader from './panel/PanelHeader.vue'
@ -44,10 +44,13 @@ const events = {
}
}
watch(() => talkParams, (newValue, oldValue) => {
console.log(newValue);
},{deep:true,immediate:true})
watch(
() => talkParams,
(newValue, oldValue) => {
console.log(newValue)
},
{ deep: true, immediate: true }
)
// Header
const onPanelHeaderEvent = (eventType: string) => {
@ -130,7 +133,11 @@ const onPanelHeaderEvent = (eventType: string) => {
show-mask="transparent"
to="#drawer-container"
>
<GroupPanel :gid="talkParams.receiver_id" @close="state.isShowGroupAside = false" />
<GroupPanel
:gid="talkParams.receiver_id"
@close="state.isShowGroupAside = false"
:talkType="talkParams.type"
/>
</n-drawer>
</template>

View File

@ -36,6 +36,7 @@ import xNDataTable from '@/components/x-naive-ui/x-n-data-table/index.vue'
import flTree from '@/components/flnlayout/tree/flnindex.vue'
import { processError, processSuccess } from '@/utils/helper/message.js'
import chatAppSearchList from '@/components/search/searchList.vue'
import { ServeSeachQueryAll, ServeQueryTalkRecord } from '@/api/search'
const currentInstance = getCurrentInstance()
const $request = currentInstance?.appContext.config.globalProperties?.$request
@ -79,24 +80,36 @@ const renderChatAppSearch = () => {
console.log(searchText, searchResultKey, talk_type, receiver_id)
const result = JSON.parse(decodeURIComponent(res))
console.log(result)
},
onToMoreResultPage: (searchResultKey, searchText) => {
if (searchResultKey === 'general_infos') {
state.ServeQueryTalkRecordParams = encodeURIComponent(
JSON.stringify({
talk_type: 0, //12
receiver_id: 0, //
last_group_id: 0, //id
last_member_id: 0, //id
last_receiver_user_name: '', //
last_receiver_group_name: '' //
})
)
state.ServeQueryTalkRecordDetailParams = encodeURIComponent(
JSON.stringify({
last_group_id: 0,
last_member_id: 0,
receiver_id: 40,
talk_type: 1
})
)
state.isShowSearchRecordModal = true
}
console.log(searchResultKey, searchText)
}
},
{}
)
}
//ES-
const ServeSeachQueryAll = () => {
let url = '/api/v1/elasticsearch/query-all'
let params = {}
let config = {
baseURL: import.meta.env.VITE_BASE_API
}
return $request.HTTP.components.postDataByParams(url, params, config).then((res) => {
console.log(res)
})
}
const state = reactive({
isShowAddressBookModal: false, //
customModalStyle: {
@ -225,7 +238,16 @@ const state = reactive({
type: 'render',
render: renderChatAppSearch
}
] //
], //
isShowSearchRecordModal: false, //
customSearchRecordModalStyle: {
width: '997px',
height: '740px',
backgroundColor: '#F9F9FD'
}, //
searchRecordText: '', //
ServeQueryTalkRecordParams: '', //
ServeQueryTalkRecordDetailParams: '' //
})
const items = computed((): ISession[] => {
@ -645,6 +667,62 @@ const handleGroupChatListPaginationSize = (value) => {
</div>
</template>
</customModal>
<customModal
v-model:show="state.isShowSearchRecordModal"
title="搜索聊天记录"
:style="state.customSearchRecordModalStyle"
:customCloseBtn="true"
:closable="false"
>
<template #content>
<div class="search-record-modal-content">
<n-card style="padding: 0 12px;">
<div class="search-record-input">
<span class="search-record-input-title">搜索</span>
<n-input
type="text"
v-model:value="state.searchRecordText"
placeholder="请输入"
clearable
>
<template #clear-icon>
<img src="@/assets/image/icon/close-btn-grey-line.png" alt="close" />
</template>
</n-input>
</div>
<div class="search-record-card" v-if="state.searchRecordText">
<div class="search-record-list">
<chatAppSearchList
:searchResultPageSize="10"
:listLimit="false"
:apiRequest="ServeQueryTalkRecord"
:apiParams="state.ServeQueryTalkRecordParams"
:searchText="state.searchRecordText || '王'"
:isPagination="true"
searchResultKey="general_infos"
></chatAppSearchList>
</div>
<div class="search-record-detail">
<chatAppSearchList
:searchResultPageSize="10"
:listLimit="false"
:apiRequest="ServeQueryTalkRecord"
:apiParams="state.ServeQueryTalkRecordDetailParams"
:searchText="state.searchRecordText || '王'"
:isPagination="true"
:searchRecordDetail="true"
></chatAppSearchList>
</div>
</div>
<div class="search-record-empty" v-if="!state.searchRecordText">
<img src="@/assets/image/chatList/search-empty.png" alt="" />
<span>暂无搜索内容</span>
</div>
</n-card>
</div>
</template>
</customModal>
</template>
<style lang="less" scoped>
@ -802,4 +880,58 @@ html[theme-mode='dark'] {
}
}
}
.search-record-modal-content {
box-sizing: border-box;
width: 100%;
padding: 0 12px;
:deep(.n-card) {
border: 0;
box-shadow: 0 3px 6px 1px rgba(188, 188, 188, 0.18);
}
.search-record-input {
display: flex;
align-items: center;
justify-content: center;
.search-record-input-title {
width: 78px;
}
}
.search-record-card {
display: flex;
flex-direction: row;
gap: 20px;
padding: 28px 0 0;
.search-record-list {
width: 260px;
height: 517px;
border: 1px solid #efeff5;
overflow-y: scroll;
}
.search-record-detail {
width: 578px;
height: 517px;
border: 1px solid #efeff5;
overflow-y: scroll;
}
}
.search-record-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 28px 0 0;
height: 519px;
img {
width: 160px;
height: 104px;
}
span {
font-size: 14px;
color: #999;
font-weight: 400;
margin: 13px 0 0;
}
}
}
</style>

View File

@ -67,12 +67,12 @@ const onSetMenu = () => {
@click="emit('evnet', 'notice')"
/>
<n-icon
v-show="type == 2"
:component="Peoples"
:size="18"
class="icon"
@click="emit('evnet', 'group')"
/>
>
<img style="width: 20px; height: 20px;" src="@/assets/image/chatList/chat-settings.png" alt="" />
</n-icon>
</div>
</header>
</template>