399 lines
11 KiB
Vue
399 lines
11 KiB
Vue
<template>
|
|
<view style="display: flex;flex-direction: column;background-color: #ececec;">
|
|
<u-status-bar bgColor="transparent"></u-status-bar>
|
|
<uni-search-bar class="search_bar"
|
|
:focus="true"
|
|
bgColor="#fff"
|
|
cancelButton="always"
|
|
:placeholder="getPlaceholder"
|
|
v-model="searchValue"
|
|
@confirm="search"
|
|
@input="input"
|
|
@cancel="cancel"
|
|
@clear="clear">
|
|
</uni-search-bar>
|
|
<u-tabs :list="searchTypeList" :current="currentTabIndex" @change="changeSearchType"></u-tabs>
|
|
<scroll-view scroll-y="true" class="scroll-view">
|
|
<!-- 加载状态 -->
|
|
<view v-if="status === 'loading'" class="empty-container">
|
|
<u-loading-icon mode="spinner" size="40"></u-loading-icon>
|
|
<text class="empty-text">搜索中...</text>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view v-else-if="status === 'done' && isEmpty" class="empty-container">
|
|
<text class="empty-text">暂无搜索结果</text>
|
|
</view>
|
|
|
|
<!-- 等待搜索状态 -->
|
|
<view v-else-if="status === 'wait'" class="empty-container">
|
|
<text class="empty-text">请输入关键词进行搜索</text>
|
|
</view>
|
|
|
|
<!-- 搜索结果 -->
|
|
<view v-else>
|
|
<!-- 会话搜索结果 -->
|
|
<ConversationItem
|
|
v-if="currentSearchType === 'conversation'"
|
|
:source="conversation"
|
|
:key="index"
|
|
v-for="(conversation,index) in conversationList"
|
|
></ConversationItem>
|
|
|
|
<!-- 好友搜索结果 -->
|
|
<user-item
|
|
v-if="currentSearchType === 'friend'"
|
|
@itemClick="userClick"
|
|
@updateCheck="()=>{}"
|
|
:checked="false"
|
|
:disabled="false"
|
|
:checkVisible="false"
|
|
v-for="cell in friendList"
|
|
:item="cell"
|
|
:key="cell.userID"
|
|
/>
|
|
|
|
<!-- 消息搜索结果 -->
|
|
<view v-if="['message', 'file', 'location'].includes(currentSearchType)">
|
|
<view
|
|
v-for="(resultItem, resultIndex) in messageList"
|
|
:key="resultIndex"
|
|
class="conversation-group"
|
|
>
|
|
<view class="conversation-header" @click="goToConversation(resultItem)">
|
|
<my-avatar
|
|
:src="resultItem.faceURL"
|
|
:desc="resultItem.showName"
|
|
:isGroup="resultItem.conversationType === 2"
|
|
size="36"
|
|
/>
|
|
<text class="conversation-title">{{ resultItem.showName }}</text>
|
|
<text class="message-count">{{ resultItem.messageCount }}条相关消息</text>
|
|
</view>
|
|
<message-search-item
|
|
v-for="(message, msgIndex) in resultItem.messageList"
|
|
:key="msgIndex"
|
|
:message="message"
|
|
:conversation="resultItem"
|
|
@click="messageClick"
|
|
></message-search-item>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import {mapGetters} from "vuex";
|
|
import ConversationItem from "@/pages/conversation/conversationList/components/ConversationItem.vue";
|
|
import UserItem from "@/components/UserItem/index.vue";
|
|
import MessageSearchItem from "./components/MessageSearchItem.vue";
|
|
import MyAvatar from "@/components/MyAvatar/index.vue";
|
|
import IMSDK,{MessageType, SessionType} from "openim-uniapp-polyfill";
|
|
import {prepareConversationState, navigateToDesignatedConversation} from "@/util/imCommon";
|
|
|
|
export default {
|
|
components:{
|
|
ConversationItem,
|
|
UserItem,
|
|
MessageSearchItem,
|
|
MyAvatar
|
|
},
|
|
data() {
|
|
return {
|
|
searchValue:"",
|
|
currentSearchType:"message", // conversation, friend, message, file, location
|
|
searchTypeList:[
|
|
{
|
|
name: '会话',
|
|
value: 'conversation'
|
|
},
|
|
{
|
|
name: '好友',
|
|
value: 'friend'
|
|
},
|
|
{
|
|
name: '消息',
|
|
value: 'message'
|
|
},
|
|
{
|
|
name: '文件',
|
|
value: 'file'
|
|
},
|
|
{
|
|
name: '位置',
|
|
value: 'location'
|
|
}
|
|
],
|
|
conversationList:[],
|
|
friendList:[],
|
|
messageList:[],
|
|
status:"wait", // wait, loading, done
|
|
conversationID:"",
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters([
|
|
"storeConversationList",
|
|
"storeFriendList",
|
|
]),
|
|
currentTabIndex() {
|
|
const index = this.searchTypeList.findIndex(item => item.value === this.currentSearchType);
|
|
return index >= 0 ? index : 2;
|
|
},
|
|
getPlaceholder() {
|
|
const placeholders = {
|
|
conversation: "搜索会话名称",
|
|
friend: "搜索好友昵称或备注",
|
|
message: "搜索消息内容",
|
|
file: "搜索文件",
|
|
location: "搜索位置"
|
|
};
|
|
return placeholders[this.currentSearchType] || "请输入您要搜索的内容";
|
|
},
|
|
isEmpty() {
|
|
if (this.currentSearchType === 'conversation') {
|
|
return this.conversationList.length === 0;
|
|
} else if (this.currentSearchType === 'friend') {
|
|
return this.friendList.length === 0;
|
|
} else if (['message', 'file', 'location'].includes(this.currentSearchType)) {
|
|
return this.messageList.length === 0;
|
|
}
|
|
return true;
|
|
}
|
|
},
|
|
onLoad(opt) {
|
|
if(opt.type){
|
|
this.currentSearchType = opt.type;
|
|
}
|
|
if(opt.conversationID){
|
|
this.conversationID = opt.conversationID;
|
|
}
|
|
},
|
|
methods: {
|
|
clear(){
|
|
this.searchValue = "";
|
|
this.status = "wait";
|
|
this.conversationList = [];
|
|
this.friendList = [];
|
|
this.messageList = [];
|
|
},
|
|
cancel(){
|
|
uni.navigateBack();
|
|
},
|
|
input(){
|
|
// 可以在这里实现实时搜索
|
|
},
|
|
async search(){
|
|
if(!this.searchValue || this.searchValue.trim() === ''){
|
|
uni.showToast({
|
|
title: '请输入搜索关键词',
|
|
icon: 'none'
|
|
});
|
|
return;
|
|
}
|
|
|
|
this.status = 'loading';
|
|
try {
|
|
if(this.currentSearchType === 'conversation'){
|
|
await this.searchConversation();
|
|
} else if(this.currentSearchType === 'friend'){
|
|
await this.searchFriend();
|
|
} else if(['message', 'file', 'location'].includes(this.currentSearchType)){
|
|
await this.searchMessage();
|
|
}
|
|
} catch(e) {
|
|
console.error('搜索失败:', e);
|
|
uni.showToast({
|
|
title: '搜索失败,请重试',
|
|
icon: 'none'
|
|
});
|
|
} finally {
|
|
this.status = 'done';
|
|
}
|
|
},
|
|
changeSearchType(e){
|
|
//console.log(e,this.searchTypeList[e]);
|
|
this.currentSearchType = e.value;//this.searchTypeList[index].value;
|
|
this.search();
|
|
// 切换类型时清空之前的搜索结果
|
|
//this.clear();
|
|
},
|
|
userClick(item){
|
|
// 跳转到用户详情或聊天页面
|
|
uni.navigateTo({
|
|
url: `/pages/common/userCard/index?sourceID=${item.userID}`
|
|
});
|
|
},
|
|
messageClick(item){
|
|
// 跳转到对应的聊天页面
|
|
const conversation = item.conversation;
|
|
if(conversation){
|
|
prepareConversationState(conversation);
|
|
}
|
|
},
|
|
goToConversation(resultItem){
|
|
// 根据会话类型跳转
|
|
const sessionType = resultItem.conversationType === 2 ? SessionType.WorkingGroup : SessionType.Single;
|
|
|
|
// 从 conversationID 中解析 sourceID,或者从 store 中获取
|
|
let sourceID = resultItem.groupID || resultItem.userID;
|
|
|
|
if(!sourceID){
|
|
// 从 conversationID 解析:si_userID1_userID2 或 g_groupID
|
|
const convID = resultItem.conversationID || '';
|
|
if(convID.startsWith('si_')) {
|
|
// 单聊:si_userID1_userID2,取第二个 userID(对方)
|
|
const parts = convID.split('_');
|
|
if(parts.length >= 3){
|
|
const selfID = this.$store.getters.storeCurrentUserID;
|
|
sourceID = parts[1] === selfID ? parts[2] : parts[1];
|
|
}
|
|
} else if(convID.startsWith('g_')) {
|
|
// 群聊:g_groupID
|
|
sourceID = convID.substring(2);
|
|
}
|
|
}
|
|
|
|
// 如果还是没有,尝试从 store 中获取
|
|
if(!sourceID){
|
|
const allConversations = this.storeConversationList || [];
|
|
const conv = allConversations.find(c => c.conversationID === resultItem.conversationID);
|
|
if(conv){
|
|
sourceID = conv.groupID || conv.userID;
|
|
}
|
|
}
|
|
|
|
if(sourceID){
|
|
navigateToDesignatedConversation(sourceID, sessionType).catch(() => {
|
|
uni.showToast({
|
|
title: '跳转失败',
|
|
icon: 'none'
|
|
});
|
|
});
|
|
} else {
|
|
uni.showToast({
|
|
title: '无法跳转,会话信息不完整',
|
|
icon: 'none'
|
|
});
|
|
}
|
|
},
|
|
// 搜索会话
|
|
searchConversation(){
|
|
const keyword = this.searchValue.toLowerCase();
|
|
const allConversations = this.storeConversationList || [];
|
|
this.conversationList = allConversations.filter(conversation => {
|
|
const showName = (conversation.showName || '').toLowerCase();
|
|
return showName.includes(keyword);
|
|
});
|
|
},
|
|
// 搜索好友
|
|
searchFriend(){
|
|
const keyword = this.searchValue.toLowerCase();
|
|
const allFriends = this.storeFriendList || [];
|
|
this.friendList = allFriends.filter(friend => {
|
|
const nickname = (friend.nickname || '').toLowerCase();
|
|
const remark = (friend.remark || '').toLowerCase();
|
|
const userID = (friend.userID || '').toLowerCase();
|
|
return nickname.includes(keyword) || remark.includes(keyword) || userID.includes(keyword);
|
|
});
|
|
},
|
|
// 搜索消息(包括文件、位置)
|
|
async searchMessage(){
|
|
const _this = this;
|
|
|
|
// 根据搜索类型确定消息类型
|
|
let messageTypeList = [];
|
|
if(this.currentSearchType === 'file'){
|
|
messageTypeList = [MessageType.FileMessage];
|
|
} else if(this.currentSearchType === 'location'){
|
|
messageTypeList = [MessageType.LocationMessage];
|
|
} else {
|
|
// 消息搜索:文本消息
|
|
messageTypeList = [MessageType.TextMessage];
|
|
}
|
|
|
|
try {
|
|
const result = await IMSDK.asyncApi('searchLocalMessages', IMSDK.uuid(), {
|
|
conversationID: _this.conversationID || '',
|
|
keywordList: [_this.searchValue],
|
|
keywordListMatchType: 0,
|
|
senderUserIDList: [],
|
|
messageTypeList: messageTypeList,
|
|
searchTimePosition: 0,
|
|
searchTimePeriod: 0,
|
|
pageIndex: 1,
|
|
count: 50,
|
|
});
|
|
|
|
if(result && result.errCode === 0 && result.data){
|
|
// 直接使用返回的 searchResultItems,它们已经包含了会话信息和消息列表
|
|
this.messageList = result.data.searchResultItems || [];
|
|
|
|
// 如果需要补充更多会话信息,可以从store中获取
|
|
const allConversations = this.storeConversationList || [];
|
|
this.messageList.forEach(item => {
|
|
const conv = allConversations.find(c => c.conversationID === item.conversationID);
|
|
if(conv){
|
|
// 补充会话信息(如果返回的数据不完整)
|
|
item.userID = item.userID || conv.userID;
|
|
item.groupID = item.groupID || conv.groupID;
|
|
}
|
|
});
|
|
} else {
|
|
this.messageList = [];
|
|
}
|
|
} catch(e) {
|
|
console.error('搜索消息失败:', e);
|
|
this.messageList = [];
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.scroll-view{
|
|
flex: 1;
|
|
height: 0;
|
|
::v-deep .uni-scroll-view-content{
|
|
background-color: #fff;
|
|
}
|
|
}
|
|
.empty-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 200rpx 0;
|
|
.empty-text {
|
|
margin-top: 24rpx;
|
|
font-size: 28rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
.conversation-group {
|
|
background-color: #fff;
|
|
margin-bottom: 20rpx;
|
|
.conversation-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24rpx 44rpx;
|
|
background-color: #f5f5f5;
|
|
border-bottom: 1px solid #eee;
|
|
.conversation-title {
|
|
flex: 1;
|
|
margin-left: 24rpx;
|
|
font-size: 30rpx;
|
|
font-weight: 500;
|
|
color: #333;
|
|
}
|
|
.message-count {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
</style> |