u
This commit is contained in:
1 parent
6fd3bf5138
commit
28678fb4df
13 files changed
+358
-136
No files matched your search
@@ -19,5 +19,8 @@ public interface ImFriendMapper extends BaseMapper<ImFriend> {
|
||||
@Param("id") Long id
|
||||
);
|
||||
|
||||
Long selectFriendTotal(@Param("userId") Long userId);
|
||||
Long selectFriendTotal(
|
||||
@Param("userId") Long userId,
|
||||
@Param("name") String name
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,24 @@
|
||||
package cn.link56.im.mapper;
|
||||
|
||||
import cn.link56.im.model.po.ImGroup;
|
||||
import cn.link56.im.model.vo.QueryFriendVO;
|
||||
import cn.link56.im.model.vo.QueryGroupVO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ImGroupMapper extends BaseMapper<ImGroup> {
|
||||
List<QueryGroupVO> selectGroup(
|
||||
@Param("offset") int offset,
|
||||
@Param("limit") int limit,
|
||||
@Param("userId") Long userId,
|
||||
@Param("name") String name,
|
||||
@Param("id") Long id
|
||||
);
|
||||
|
||||
Long selectGroupTotal(@Param("userId") Long userId,
|
||||
@Param("name") String name);
|
||||
}
|
||||
@@ -22,8 +22,8 @@ public class ImGroupUser {
|
||||
@TableField("b_join_time")
|
||||
private Date joinTime;
|
||||
|
||||
@TableField("b_last_active_time")
|
||||
private Date lastActiveTime;
|
||||
@TableField("b_last_message_id")
|
||||
private Integer lastMessageId;
|
||||
|
||||
@TableField("b_unread_count")
|
||||
private Integer unreadCount;
|
||||
|
||||
@@ -10,8 +10,6 @@ import java.util.Date;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class QueryFriendVO {
|
||||
private Long id;
|
||||
|
||||
private Long friendId;
|
||||
private String friendName;
|
||||
private String friendAvatar;
|
||||
|
||||
@@ -8,9 +8,9 @@ import lombok.NoArgsConstructor;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class QueryGroupVO {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String avatar;
|
||||
private Long groupId;
|
||||
private String groupName;
|
||||
private String groupAvatar;
|
||||
|
||||
private Integer unreadCount;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public class ImFriendService extends ServiceImpl<ImFriendMapper, ImFriend> {
|
||||
item.setIsOnline(SessionManager.isOnline(friendId));
|
||||
});
|
||||
// 查询总数
|
||||
Long total = imFriendMapper.selectFriendTotal(userId);
|
||||
Long total = imFriendMapper.selectFriendTotal(userId,name);
|
||||
|
||||
BasePageVO<QueryFriendVO> basePageVO = new BasePageVO<>();
|
||||
basePageVO.setRecords(queryFriendVOS);
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package cn.link56.im.service;
|
||||
|
||||
import cn.link56.common.BasePageVO;
|
||||
import cn.link56.common.context.UserContext;
|
||||
import cn.link56.im.mapper.ImGroupMapper;
|
||||
import cn.link56.im.model.dto.QueryGroupDTO;
|
||||
import cn.link56.im.model.po.ImGroup;
|
||||
import cn.link56.im.model.vo.QueryFriendVO;
|
||||
import cn.link56.im.model.vo.QueryGroupVO;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class ImGroupService extends ServiceImpl<ImGroupMapper, ImGroup>{
|
||||
@@ -16,13 +19,17 @@ public class ImGroupService extends ServiceImpl<ImGroupMapper, ImGroup>{
|
||||
private ImGroupMapper imGroupMapper;
|
||||
|
||||
public BasePageVO<QueryGroupVO> queryGroup(QueryGroupDTO dto) {
|
||||
Long userId = UserContext.getUserId();
|
||||
|
||||
String name = dto.getName();
|
||||
Long id = dto.getId();
|
||||
|
||||
int offset = (dto.getCurrentPage() - 1) * dto.getPageSize() + 1;
|
||||
int limit = dto.getCurrentPage() * dto.getPageSize();
|
||||
|
||||
List<QueryGroupVO> queryFriendVOS = imGroupMapper.selectGroup(offset, limit, userId, name, id);
|
||||
Long total = imGroupMapper.selectGroupTotal(userId, name);
|
||||
|
||||
return new BasePageVO<>();
|
||||
return new BasePageVO<>(total,queryFriendVOS);
|
||||
}
|
||||
}
|
||||
+24
-17
@@ -9,34 +9,41 @@
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
f.b_id AS id,
|
||||
f.b_friend_id AS friendId,
|
||||
u.b_name AS friendName,
|
||||
u.b_avatar AS friendAvatar,
|
||||
f.b_unread_count AS unreadCount,
|
||||
m.b_id AS lastMessageId,
|
||||
m.b_send_time AS lastMessageTime,
|
||||
m.b_type AS lastMessageType,
|
||||
m.b_content AS lastMessageContent,
|
||||
ROW_NUMBER() OVER (
|
||||
ORDER BY
|
||||
<if test="id != null and id != 0">
|
||||
CASE WHEN f.b_id = #{id} THEN 0 ELSE 1 END,
|
||||
</if>
|
||||
m.b_send_time DESC
|
||||
) AS rn
|
||||
f.b_id AS id,
|
||||
f.b_friend_id AS friendId,
|
||||
u.b_name AS friendName,
|
||||
u.b_avatar AS friendAvatar,
|
||||
f.b_unread_count AS unreadCount,
|
||||
m.b_id AS lastMessageId,
|
||||
m.b_send_time AS lastMessageTime,
|
||||
m.b_type AS lastMessageType,
|
||||
m.b_content AS lastMessageContent,
|
||||
ROW_NUMBER() OVER (
|
||||
ORDER BY
|
||||
<if test="id != null and id != 0">
|
||||
CASE WHEN f.b_id = #{id} THEN 0 ELSE 1 END,
|
||||
</if>
|
||||
m.b_send_time DESC
|
||||
) AS rn
|
||||
FROM b_im_friend f
|
||||
LEFT JOIN b_company_user u ON f.b_friend_id = u.b_id
|
||||
LEFT JOIN b_im_private_message m ON f.b_last_message_id = m.b_id
|
||||
WHERE f.b_user_id = #{userId}
|
||||
) AS t
|
||||
<if test="name != null and name != ''">
|
||||
AND u.b_name LIKE '%' + #{name} + '%'
|
||||
</if>
|
||||
) t
|
||||
WHERE t.rn BETWEEN #{offset} AND #{limit}
|
||||
</select>
|
||||
|
||||
<select id="selectFriendTotal" resultType="java.lang.Long">
|
||||
SELECT COUNT(*)
|
||||
FROM b_im_friend f
|
||||
LEFT JOIN b_company_user u ON f.b_friend_id = u.b_id
|
||||
WHERE f.b_user_id = #{userId}
|
||||
<if test="name != null and name != ''">
|
||||
AND u.b_name LIKE '%' + #{name} + '%'
|
||||
</if>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+27
-14
@@ -9,35 +9,48 @@
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
g.b_id AS id,
|
||||
g.b_name AS name,
|
||||
g.b_avatar AS avatar,
|
||||
g.b_id AS groupId,
|
||||
g.b_name AS groupName,
|
||||
g.b_avatar AS groupAvatar,
|
||||
gu.b_unread_count AS unreadCount,
|
||||
|
||||
m.b_id AS lastMessageId,
|
||||
m.b_send_time AS lastMessageTime,
|
||||
m.b_type AS lastMessageType,
|
||||
m.b_content AS lastMessageContent,
|
||||
ROW_NUMBER() OVER (
|
||||
ORDER BY
|
||||
|
||||
u.b_id AS lastMessageSenderId,
|
||||
u.b_name AS lastMessageSenderName,
|
||||
u.b_avatar AS lastMessageSenderAvatar,
|
||||
|
||||
ROW_NUMBER() OVER (
|
||||
ORDER BY
|
||||
<if test="id != null and id != 0">
|
||||
CASE WHEN g.b_id = #{id} THEN 0 ELSE 1 END,
|
||||
</if>
|
||||
m.b_send_time DESC
|
||||
) AS rn
|
||||
FROM b_im_group g
|
||||
INNER JOIN b_im_group_user gu ON g.b_id = gu.b_group_id
|
||||
LEFT JOIN b_im_group_message m ON gu.b_last_message_id = m.b_id
|
||||
WHERE gu.b_user_id = #{userId}
|
||||
) AS t
|
||||
m.b_send_time DESC
|
||||
) AS rn
|
||||
FROM b_im_group g
|
||||
INNER JOIN b_im_group_user gu ON g.b_id = gu.b_group_id
|
||||
LEFT JOIN b_im_group_message m ON gu.b_last_message_id = m.b_id
|
||||
LEFT JOIN b_company_user u ON m.b_sender_id = u.b_id
|
||||
WHERE gu.b_user_id = #{userId}
|
||||
<if test="name != null and name != ''">
|
||||
AND g.b_name LIKE '%' + #{name} + '%'
|
||||
</if>
|
||||
) t
|
||||
WHERE t.rn BETWEEN #{offset} AND #{limit}
|
||||
</select>
|
||||
|
||||
|
||||
<select id="selectGroupTotal" resultType="java.lang.Long">
|
||||
SELECT COUNT(DISTINCT g.b_id)
|
||||
FROM b_im_group g
|
||||
INNER JOIN b_im_group_user gu ON g.b_id = gu.b_group_id
|
||||
INNER JOIN b_im_group_user gu ON g.b_id = gu.b_group_id
|
||||
WHERE gu.b_user_id = #{userId}
|
||||
<if test="name != null and name != ''">
|
||||
AND g.b_name LIKE '%' + #{name} + '%'
|
||||
</if>
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CreateFriendParams, ImFriend, QueryFriendParams } from '@/types/im'
|
||||
import type { CreateFriendParams, ImFriend, ImGroup, QueryFriendParams, QueryGroupParams } from '@/types/im'
|
||||
import { httpPostJson } from '@/request/utils'
|
||||
|
||||
export function createFriendApi(params: CreateFriendParams) {
|
||||
@@ -8,3 +8,7 @@ export function createFriendApi(params: CreateFriendParams) {
|
||||
export function queryFriendApi(params: QueryFriendParams) {
|
||||
return httpPostJson<BasePageResult<ImFriend>>('/im/friend/query', params)
|
||||
}
|
||||
|
||||
export function queryGroupApi(params: QueryGroupParams) {
|
||||
return httpPostJson<BasePageResult<ImGroup>>('/im/group/query', params)
|
||||
}
|
||||
@@ -40,7 +40,7 @@ const router = createRouter({
|
||||
component: () => import('@/views/company/detail.vue'),
|
||||
},
|
||||
{
|
||||
path: '/im',
|
||||
path: '/im/:type?/:id?',
|
||||
component: () => import('@/views/im/index.vue'),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -62,3 +62,24 @@ export interface ImFriend {
|
||||
|
||||
isOnline: boolean
|
||||
}
|
||||
|
||||
export interface QueryGroupParams {
|
||||
currentPage: number
|
||||
pageSize: number
|
||||
|
||||
name: string
|
||||
id: number | null
|
||||
}
|
||||
|
||||
export interface ImGroup {
|
||||
groupId: number
|
||||
groupName: string
|
||||
groupAvatar: string
|
||||
|
||||
unreadCount: number
|
||||
|
||||
lastMessageId: number
|
||||
lastMessageTime: number
|
||||
lastMessageType: number
|
||||
lastMessageContent: string
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ImFriend } from '@/types/im'
|
||||
import type { ImFriend, ImGroup } from '@/types/im'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { queryFriendApi } from '@/request/api/im'
|
||||
import { queryFriendApi, queryGroupApi } from '@/request/api/im'
|
||||
import { useWebSocket } from '@/store/websocket'
|
||||
import { MessageType } from '@/types/im'
|
||||
import { formatImTime } from '@/utils/time'
|
||||
@@ -13,30 +12,92 @@ const route = useRoute()
|
||||
const websocket = useWebSocket()
|
||||
|
||||
// 当前聊天对象
|
||||
const activeChatTab = ref<'private' | 'group'>('private')
|
||||
const searchName = ref('')
|
||||
|
||||
const initialFriendId = ref<number | null>(
|
||||
route.params.friendId ? Number(route.params.friendId) : null,
|
||||
type ChatType = 'private' | 'group'
|
||||
|
||||
const initialChat = ref<{
|
||||
type: ChatType
|
||||
id: number
|
||||
} | null>(null)
|
||||
|
||||
type CurrentChat
|
||||
= | {
|
||||
type: 'private'
|
||||
id: number
|
||||
data?: ImFriend
|
||||
}
|
||||
| {
|
||||
type: 'group'
|
||||
id: number
|
||||
data?: ImGroup
|
||||
}
|
||||
|
||||
const currentChat = ref<CurrentChat | null>(null)
|
||||
|
||||
watch(
|
||||
() => initialChat.value,
|
||||
(chat) => {
|
||||
if (!chat)
|
||||
return
|
||||
|
||||
currentChat.value = {
|
||||
type: chat.type,
|
||||
id: chat.id,
|
||||
}
|
||||
|
||||
initialChat.value = null
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 聊天列表
|
||||
interface ImListState<T> {
|
||||
list: T[]
|
||||
page: number
|
||||
pageSize: number
|
||||
total: number
|
||||
loading: boolean
|
||||
hasMore: boolean
|
||||
}
|
||||
|
||||
// 好友列表
|
||||
const friends = ref<ImFriend[]>([])
|
||||
const friendsPage = ref({
|
||||
const friendState = ref<ImListState<ImFriend>>({
|
||||
list: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
hasMore: true,
|
||||
})
|
||||
// 群组列表
|
||||
const groupState = ref<ImListState<ImGroup>>({
|
||||
list: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
loading: false,
|
||||
hasMore: true,
|
||||
})
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
const type = route.params.type as ChatType | undefined
|
||||
const id = route.params.id ? Number(route.params.id) : null
|
||||
|
||||
if (type && id) {
|
||||
initialChat.value = { type, id }
|
||||
}
|
||||
|
||||
loadGroups()
|
||||
loadFriends()
|
||||
|
||||
websocket.onMessage((msg) => {
|
||||
const { type, from } = msg
|
||||
|
||||
// 更新在线状态
|
||||
const updateOnlineStatus = (isOnline: boolean) => {
|
||||
const friend = friends.value.find(item => item.friendId === from)
|
||||
const friend = friendState.value.list.find(item => item.friendId === from)
|
||||
if (friend)
|
||||
friend.isOnline = isOnline
|
||||
}
|
||||
@@ -52,57 +113,118 @@ onMounted(() => {
|
||||
|
||||
// 加载好友列表
|
||||
async function loadFriends() {
|
||||
if (friendsPage.value.loading)
|
||||
const state = friendState.value
|
||||
if (state.loading || !state.hasMore)
|
||||
return
|
||||
friendsPage.value.loading = true
|
||||
|
||||
state.loading = true
|
||||
try {
|
||||
const res = await queryFriendApi({
|
||||
currentPage: friendsPage.value.page,
|
||||
pageSize: friendsPage.value.pageSize,
|
||||
name: '',
|
||||
id: initialFriendId.value,
|
||||
currentPage: state.page,
|
||||
pageSize: state.pageSize,
|
||||
name: searchName.value,
|
||||
id: currentChat.value?.type === 'private' ? currentChat.value.id : null,
|
||||
})
|
||||
|
||||
if (res.isSuccess) {
|
||||
const { records, total } = res.data
|
||||
if (!res.isSuccess)
|
||||
throw new Error(res.message)
|
||||
|
||||
if (friendsPage.value.page === 1) {
|
||||
friends.value = records
|
||||
}
|
||||
else {
|
||||
// 合并并去重
|
||||
const merged = friends.value.concat(records)
|
||||
const map = new Map<number, typeof merged[0]>()
|
||||
for (const f of merged) {
|
||||
map.set(f.id, f)
|
||||
}
|
||||
friends.value = Array.from(map.values())
|
||||
}
|
||||
const { records, total } = res.data
|
||||
|
||||
// 设置当前聊天对象
|
||||
if (initialFriendId.value) {
|
||||
const friend = friends.value.find(f => f.id === initialFriendId.value)
|
||||
if (friend) {
|
||||
// openPrivateChat(friend)
|
||||
}
|
||||
initialFriendId.value = null
|
||||
}
|
||||
state.list
|
||||
= state.page === 1
|
||||
? records
|
||||
: [...state.list, ...records]
|
||||
|
||||
friendsPage.value.total = total
|
||||
}
|
||||
else {
|
||||
ElMessage.error(res.message || '加载好友列表失败,请稍后再试')
|
||||
}
|
||||
state.total = total
|
||||
state.hasMore = state.list.length < total
|
||||
state.page++
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err)
|
||||
ElMessage.error('加载好友列表失败,请稍后再试')
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
finally {
|
||||
friendsPage.value.loading = false
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载群组列表
|
||||
async function loadGroups() {
|
||||
const state = groupState.value
|
||||
if (state.loading || !state.hasMore)
|
||||
return
|
||||
|
||||
state.loading = true
|
||||
try {
|
||||
const res = await queryGroupApi({
|
||||
currentPage: state.page,
|
||||
pageSize: state.pageSize,
|
||||
name: searchName.value,
|
||||
id: currentChat.value?.type === 'group' ? currentChat.value.id : null,
|
||||
})
|
||||
|
||||
if (!res.isSuccess)
|
||||
throw new Error(res.message)
|
||||
|
||||
const { records, total } = res.data
|
||||
|
||||
state.list
|
||||
= state.page === 1
|
||||
? records
|
||||
: [...state.list, ...records]
|
||||
|
||||
state.total = total
|
||||
state.hasMore = state.list.length < total
|
||||
state.page++
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
function resetList<T>(state: ImListState<T>) {
|
||||
state.page = 1
|
||||
state.total = 0
|
||||
state.hasMore = true
|
||||
state.list = []
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
resetList(friendState.value)
|
||||
resetList(groupState.value)
|
||||
|
||||
loadFriends()
|
||||
loadGroups()
|
||||
}
|
||||
|
||||
function onPrivateChat(friend: ImFriend) {
|
||||
// 将 friend 的未读置0
|
||||
const hadUnread = friend.unreadCount > 0
|
||||
friend.unreadCount = 0
|
||||
// 设置当前聊天
|
||||
currentChat.value = {
|
||||
id: friend.friendId,
|
||||
type: 'private',
|
||||
data: friend,
|
||||
}
|
||||
// 初始化分页
|
||||
}
|
||||
|
||||
function onGroupChat(group: ImGroup) {
|
||||
// 将 friend 的未读置0
|
||||
const hadUnread = group.unreadCount > 0
|
||||
group.unreadCount = 0
|
||||
// 设置当前聊天
|
||||
currentChat.value = {
|
||||
id: group.groupId,
|
||||
type: 'group',
|
||||
data: group,
|
||||
}
|
||||
// 初始化分页
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -137,49 +259,16 @@ async function loadFriends() {
|
||||
<div class="im__body">
|
||||
<div class="im__list">
|
||||
<div class="im__list-search">
|
||||
<el-input placeholder="请根据名称搜索" :prefix-icon="Search" />
|
||||
<el-input
|
||||
v-model="searchName"
|
||||
placeholder="请根据名称搜索"
|
||||
:prefix-icon="Search"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
@clear="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
<el-tabs v-model="activeChatTab" class="im__list-tabs">
|
||||
<el-tab-pane label="单聊" name="private" />
|
||||
<el-tab-pane label="群聊" name="group" />
|
||||
</el-tabs>
|
||||
<div class="im__list-item">
|
||||
<div class="im__list-body">
|
||||
<div
|
||||
v-for="item in friends" :key="item.id" class="im__chat-item"
|
||||
>
|
||||
<el-badge
|
||||
is-dot
|
||||
:color="item.isOnline ? '#24e68a' : '#bfbfbf'"
|
||||
:badge-style="{
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
}"
|
||||
:offset="[-4, 34]"
|
||||
>
|
||||
<SafeImage class="im__chat-item-avatar" :url="item.friendAvatar" :size="40" round />
|
||||
</el-badge>
|
||||
<div class="im__chat-item-info">
|
||||
<div class="im__chat-item-main">
|
||||
<div class="im__chat-item-name">
|
||||
{{ item.friendName }}
|
||||
</div>
|
||||
<div class="im__chat-item-last-time">
|
||||
{{ formatImTime(item.lastMessageTime, 'list') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="im__chat-item-message">
|
||||
<div class="im__chat-item-last-message">
|
||||
{{ item.lastMessageContent }}
|
||||
</div>
|
||||
<el-badge :value="item.unreadCount || 0" :show-zero="false" :max="99" class="im__chat-item-unread-count" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="im__list-item">
|
||||
<div class="im__list-header">
|
||||
<SvgIcon icon="tabler:message-circle" :size="16" />
|
||||
<span class="im__list-header-title">
|
||||
@@ -188,7 +277,12 @@ async function loadFriends() {
|
||||
</div>
|
||||
<div class="im__list-body">
|
||||
<div
|
||||
v-for="item in friends" :key="item.id" class="im__chat-item"
|
||||
v-for="item in friendState.list" :key="item.id" class="im__chat-item"
|
||||
:class="{
|
||||
'im__chat-item--selected':
|
||||
currentChat?.type === 'private' && item.friendId === currentChat.id,
|
||||
}"
|
||||
@click="onPrivateChat(item)"
|
||||
>
|
||||
<el-badge
|
||||
is-dot
|
||||
@@ -199,7 +293,7 @@ async function loadFriends() {
|
||||
}"
|
||||
:offset="[-4, 34]"
|
||||
>
|
||||
<SafeImage class="im__chat-item-avatar" :url="item.friendAvatar" :size="40" round />
|
||||
<SafeImage :size="40" :url="item.friendAvatar" round class="im__chat-item-avatar" />
|
||||
</el-badge>
|
||||
<div class="im__chat-item-info">
|
||||
<div class="im__chat-item-main">
|
||||
@@ -220,7 +314,68 @@ async function loadFriends() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="im__list-item">
|
||||
<div class="im__list-header">
|
||||
<SvgIcon icon="bi:people" :size="16" />
|
||||
<span class="im__list-header-title">
|
||||
群聊
|
||||
</span>
|
||||
</div>
|
||||
<div class="im__list-body">
|
||||
<div
|
||||
v-for="item in groupState.list" :key="item.groupId" class="im__chat-item"
|
||||
>
|
||||
<SafeImage :size="40" :url="item.groupAvatar" round class="im__chat-item-avatar" />
|
||||
|
||||
<div class="im__chat-item-info">
|
||||
<div class="im__chat-item-main">
|
||||
<div class="im__chat-item-name">
|
||||
{{ item.groupName }}
|
||||
</div>
|
||||
<div class="im__chat-item-last-time">
|
||||
{{ formatImTime(item.lastMessageTime, 'list') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="im__chat-item-message">
|
||||
<div v-if="item.lastMessageId" class="im__chat-item-last-message">
|
||||
<!-- {{ item. }}: {{ item.lastMessageContent }} -->
|
||||
</div>
|
||||
|
||||
<el-badge :value="item.unreadCount || 0" :show-zero="false" :max="99" class="im__chat-item-unread-count" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="currentChat" class="im__window">
|
||||
<div class="im__window-header">
|
||||
<div class="im__window-peer">
|
||||
<div class="im__window-peer-info">
|
||||
<div class="im__window-peer-name">
|
||||
{{ currentChat.type === 'private' ? currentChat.data?.friendName : currentChat.data?.groupName }}
|
||||
</div>
|
||||
<div v-if="currentChat.type === 'private'" class="im__window-peer-desc">
|
||||
<div
|
||||
class="im__window-peer-status"
|
||||
:class="currentChat.data?.isOnline ? 'im__window-peer-status--online' : 'im__window-peer-status--offline'"
|
||||
>
|
||||
<span>[ </span>
|
||||
<div class="im__window-peer-status-dot" />
|
||||
<span>{{ currentChat.data?.isOnline ? '在线' : '离线' }}</span>
|
||||
<span> ]</span>
|
||||
</div>
|
||||
<span>
|
||||
公司描述等等等...
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="im__window-actions" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -258,8 +413,7 @@ async function loadFriends() {
|
||||
|
||||
.im__container {
|
||||
width: 1300px;
|
||||
height: 80%;
|
||||
min-height: 700px;
|
||||
min-height: 750px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 2px;
|
||||
|
||||
Reference in new issue
Block a user