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

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

View File

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

View File

@ -127,7 +127,7 @@
// useZPaging(zPaging) // useZPaging(zPaging)
import searchItem from './searchItem.vue' 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']) 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) => { const inputSearchText = (e) => {
if (e.trim() != state.searchText.trim()) { if (e.trim() != state.searchText.trim()) {
@ -419,6 +429,7 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// zPaging.value?.complete([data]) // zPaging.value?.complete([data])
} }
} }
// const resp = props.apiRequest(params) // const resp = props.apiRequest(params)
// resp.then(({ code, data }) => { // resp.then(({ code, data }) => {
// console.log(data) // console.log(data)
@ -493,10 +504,10 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// if (pageNum === 1) { // if (pageNum === 1) {
// // // //
// state.searchResult = null // state.searchResult = null
// zPaging.value?.complete([]) // // zPaging.value?.complete([])
// } else { // } else {
// // // //
// zPaging.value?.complete(state.searchResult ? [state.searchResult] : []) // // zPaging.value?.complete(state.searchResult ? [state.searchResult] : [])
// } // }
// } else { // } else {
// if (props.isPagination) { // if (props.isPagination) {
@ -534,20 +545,20 @@ const queryAllSearch = (pageNum, searchResultPageSize) => {
// total = data.group_record_count // total = data.group_record_count
// } // }
// } // }
// zPaging.value?.completeByTotal([data], total) // // zPaging.value?.completeByTotal([data], total)
// } else { // } else {
// state.searchResult = data // state.searchResult = data
// zPaging.value?.complete([data]) // // zPaging.value?.complete([data])
// } // }
// } // }
// } else { // } else {
// if (pageNum === 1) { // if (pageNum === 1) {
// // // //
// state.searchResult = null // state.searchResult = null
// zPaging.value?.complete([]) // // zPaging.value?.complete([])
// } else { // } 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) { // if (pageNum === 1) {
// // // //
// state.searchResult = null // state.searchResult = null
// zPaging.value?.complete([]) // // zPaging.value?.complete([])
// } else { // } 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 { .result-has-more {
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid #f8f8f8; border-bottom: 1px solid #f8f8f8;
cursor: pointer;
span { span {
color: #191919; color: #191919;
line-height: 20px; line-height: 20px;
} }
} }
.result-has-more:hover {
background-color: #f8f8f8;
}
} }
} }
} }

View File

@ -18,7 +18,7 @@ export function isLoggedIn() {
*/ */
export function getAccessToken() { export function getAccessToken() {
// return storage.get(AccessToken) || '' // 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> <script lang="ts" setup>
import { reactive, computed,watch } from 'vue' import { reactive, computed, watch } from 'vue'
import { NDrawer } from 'naive-ui' import { NDrawer } from 'naive-ui'
import { useUserStore, useDialogueStore, useUploadsStore } from '@/store' import { useUserStore, useDialogueStore, useUploadsStore } from '@/store'
import PanelHeader from './panel/PanelHeader.vue' import PanelHeader from './panel/PanelHeader.vue'
@ -44,10 +44,13 @@ const events = {
} }
} }
watch(() => talkParams, (newValue, oldValue) => { watch(
console.log(newValue); () => talkParams,
(newValue, oldValue) => {
},{deep:true,immediate:true}) console.log(newValue)
},
{ deep: true, immediate: true }
)
// Header // Header
const onPanelHeaderEvent = (eventType: string) => { const onPanelHeaderEvent = (eventType: string) => {
@ -130,7 +133,11 @@ const onPanelHeaderEvent = (eventType: string) => {
show-mask="transparent" show-mask="transparent"
to="#drawer-container" 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> </n-drawer>
</template> </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 flTree from '@/components/flnlayout/tree/flnindex.vue'
import { processError, processSuccess } from '@/utils/helper/message.js' import { processError, processSuccess } from '@/utils/helper/message.js'
import chatAppSearchList from '@/components/search/searchList.vue' import chatAppSearchList from '@/components/search/searchList.vue'
import { ServeSeachQueryAll, ServeQueryTalkRecord } from '@/api/search'
const currentInstance = getCurrentInstance() const currentInstance = getCurrentInstance()
const $request = currentInstance?.appContext.config.globalProperties?.$request const $request = currentInstance?.appContext.config.globalProperties?.$request
@ -79,24 +80,36 @@ const renderChatAppSearch = () => {
console.log(searchText, searchResultKey, talk_type, receiver_id) console.log(searchText, searchResultKey, talk_type, receiver_id)
const result = JSON.parse(decodeURIComponent(res)) const result = JSON.parse(decodeURIComponent(res))
console.log(result) 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({ const state = reactive({
isShowAddressBookModal: false, // isShowAddressBookModal: false, //
customModalStyle: { customModalStyle: {
@ -225,7 +238,16 @@ const state = reactive({
type: 'render', type: 'render',
render: renderChatAppSearch render: renderChatAppSearch
} }
] // ], //
isShowSearchRecordModal: false, //
customSearchRecordModalStyle: {
width: '997px',
height: '740px',
backgroundColor: '#F9F9FD'
}, //
searchRecordText: '', //
ServeQueryTalkRecordParams: '', //
ServeQueryTalkRecordDetailParams: '' //
}) })
const items = computed((): ISession[] => { const items = computed((): ISession[] => {
@ -645,6 +667,62 @@ const handleGroupChatListPaginationSize = (value) => {
</div> </div>
</template> </template>
</customModal> </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> </template>
<style lang="less" scoped> <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> </style>

View File

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