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
|
@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;
|
package cn.link56.im.mapper;
|
||||||
|
|
||||||
import cn.link56.im.model.po.ImGroup;
|
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 com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ImGroupMapper extends BaseMapper<ImGroup> {
|
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")
|
@TableField("b_join_time")
|
||||||
private Date joinTime;
|
private Date joinTime;
|
||||||
|
|
||||||
@TableField("b_last_active_time")
|
@TableField("b_last_message_id")
|
||||||
private Date lastActiveTime;
|
private Integer lastMessageId;
|
||||||
|
|
||||||
@TableField("b_unread_count")
|
@TableField("b_unread_count")
|
||||||
private Integer unreadCount;
|
private Integer unreadCount;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import java.util.Date;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class QueryFriendVO {
|
public class QueryFriendVO {
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private Long friendId;
|
private Long friendId;
|
||||||
private String friendName;
|
private String friendName;
|
||||||
private String friendAvatar;
|
private String friendAvatar;
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import lombok.NoArgsConstructor;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class QueryGroupVO {
|
public class QueryGroupVO {
|
||||||
private Long id;
|
private Long groupId;
|
||||||
private String name;
|
private String groupName;
|
||||||
private String avatar;
|
private String groupAvatar;
|
||||||
|
|
||||||
private Integer unreadCount;
|
private Integer unreadCount;
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class ImFriendService extends ServiceImpl<ImFriendMapper, ImFriend> {
|
|||||||
item.setIsOnline(SessionManager.isOnline(friendId));
|
item.setIsOnline(SessionManager.isOnline(friendId));
|
||||||
});
|
});
|
||||||
// 查询总数
|
// 查询总数
|
||||||
Long total = imFriendMapper.selectFriendTotal(userId);
|
Long total = imFriendMapper.selectFriendTotal(userId,name);
|
||||||
|
|
||||||
BasePageVO<QueryFriendVO> basePageVO = new BasePageVO<>();
|
BasePageVO<QueryFriendVO> basePageVO = new BasePageVO<>();
|
||||||
basePageVO.setRecords(queryFriendVOS);
|
basePageVO.setRecords(queryFriendVOS);
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
package cn.link56.im.service;
|
package cn.link56.im.service;
|
||||||
|
|
||||||
import cn.link56.common.BasePageVO;
|
import cn.link56.common.BasePageVO;
|
||||||
|
import cn.link56.common.context.UserContext;
|
||||||
import cn.link56.im.mapper.ImGroupMapper;
|
import cn.link56.im.mapper.ImGroupMapper;
|
||||||
import cn.link56.im.model.dto.QueryGroupDTO;
|
import cn.link56.im.model.dto.QueryGroupDTO;
|
||||||
import cn.link56.im.model.po.ImGroup;
|
import cn.link56.im.model.po.ImGroup;
|
||||||
|
import cn.link56.im.model.vo.QueryFriendVO;
|
||||||
import cn.link56.im.model.vo.QueryGroupVO;
|
import cn.link56.im.model.vo.QueryGroupVO;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ImGroupService extends ServiceImpl<ImGroupMapper, ImGroup>{
|
public class ImGroupService extends ServiceImpl<ImGroupMapper, ImGroup>{
|
||||||
@@ -16,13 +19,17 @@ public class ImGroupService extends ServiceImpl<ImGroupMapper, ImGroup>{
|
|||||||
private ImGroupMapper imGroupMapper;
|
private ImGroupMapper imGroupMapper;
|
||||||
|
|
||||||
public BasePageVO<QueryGroupVO> queryGroup(QueryGroupDTO dto) {
|
public BasePageVO<QueryGroupVO> queryGroup(QueryGroupDTO dto) {
|
||||||
|
Long userId = UserContext.getUserId();
|
||||||
|
|
||||||
String name = dto.getName();
|
String name = dto.getName();
|
||||||
Long id = dto.getId();
|
Long id = dto.getId();
|
||||||
|
|
||||||
int offset = (dto.getCurrentPage() - 1) * dto.getPageSize() + 1;
|
int offset = (dto.getCurrentPage() - 1) * dto.getPageSize() + 1;
|
||||||
int limit = dto.getCurrentPage() * dto.getPageSize();
|
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 *
|
SELECT *
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
f.b_id AS id,
|
f.b_id AS id,
|
||||||
f.b_friend_id AS friendId,
|
f.b_friend_id AS friendId,
|
||||||
u.b_name AS friendName,
|
u.b_name AS friendName,
|
||||||
u.b_avatar AS friendAvatar,
|
u.b_avatar AS friendAvatar,
|
||||||
f.b_unread_count AS unreadCount,
|
f.b_unread_count AS unreadCount,
|
||||||
m.b_id AS lastMessageId,
|
m.b_id AS lastMessageId,
|
||||||
m.b_send_time AS lastMessageTime,
|
m.b_send_time AS lastMessageTime,
|
||||||
m.b_type AS lastMessageType,
|
m.b_type AS lastMessageType,
|
||||||
m.b_content AS lastMessageContent,
|
m.b_content AS lastMessageContent,
|
||||||
ROW_NUMBER() OVER (
|
ROW_NUMBER() OVER (
|
||||||
ORDER BY
|
ORDER BY
|
||||||
<if test="id != null and id != 0">
|
<if test="id != null and id != 0">
|
||||||
CASE WHEN f.b_id = #{id} THEN 0 ELSE 1 END,
|
CASE WHEN f.b_id = #{id} THEN 0 ELSE 1 END,
|
||||||
</if>
|
</if>
|
||||||
m.b_send_time DESC
|
m.b_send_time DESC
|
||||||
) AS rn
|
) AS rn
|
||||||
FROM b_im_friend f
|
FROM b_im_friend f
|
||||||
LEFT JOIN b_company_user u ON f.b_friend_id = u.b_id
|
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
|
LEFT JOIN b_im_private_message m ON f.b_last_message_id = m.b_id
|
||||||
WHERE f.b_user_id = #{userId}
|
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}
|
WHERE t.rn BETWEEN #{offset} AND #{limit}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectFriendTotal" resultType="java.lang.Long">
|
<select id="selectFriendTotal" resultType="java.lang.Long">
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM b_im_friend f
|
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}
|
WHERE f.b_user_id = #{userId}
|
||||||
|
<if test="name != null and name != ''">
|
||||||
|
AND u.b_name LIKE '%' + #{name} + '%'
|
||||||
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
+27
-14
@@ -9,35 +9,48 @@
|
|||||||
SELECT *
|
SELECT *
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
g.b_id AS id,
|
g.b_id AS groupId,
|
||||||
g.b_name AS name,
|
g.b_name AS groupName,
|
||||||
g.b_avatar AS avatar,
|
g.b_avatar AS groupAvatar,
|
||||||
gu.b_unread_count AS unreadCount,
|
gu.b_unread_count AS unreadCount,
|
||||||
|
|
||||||
m.b_id AS lastMessageId,
|
m.b_id AS lastMessageId,
|
||||||
m.b_send_time AS lastMessageTime,
|
m.b_send_time AS lastMessageTime,
|
||||||
m.b_type AS lastMessageType,
|
m.b_type AS lastMessageType,
|
||||||
m.b_content AS lastMessageContent,
|
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">
|
<if test="id != null and id != 0">
|
||||||
CASE WHEN g.b_id = #{id} THEN 0 ELSE 1 END,
|
CASE WHEN g.b_id = #{id} THEN 0 ELSE 1 END,
|
||||||
</if>
|
</if>
|
||||||
m.b_send_time DESC
|
m.b_send_time DESC
|
||||||
) AS rn
|
) AS rn
|
||||||
FROM b_im_group g
|
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
|
||||||
LEFT JOIN b_im_group_message m ON gu.b_last_message_id = m.b_id
|
LEFT JOIN b_im_group_message m ON gu.b_last_message_id = m.b_id
|
||||||
WHERE gu.b_user_id = #{userId}
|
LEFT JOIN b_company_user u ON m.b_sender_id = u.b_id
|
||||||
) AS t
|
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}
|
WHERE t.rn BETWEEN #{offset} AND #{limit}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<select id="selectGroupTotal" resultType="java.lang.Long">
|
<select id="selectGroupTotal" resultType="java.lang.Long">
|
||||||
SELECT COUNT(DISTINCT g.b_id)
|
SELECT COUNT(DISTINCT g.b_id)
|
||||||
FROM b_im_group g
|
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}
|
WHERE gu.b_user_id = #{userId}
|
||||||
|
<if test="name != null and name != ''">
|
||||||
|
AND g.b_name LIKE '%' + #{name} + '%'
|
||||||
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</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'
|
import { httpPostJson } from '@/request/utils'
|
||||||
|
|
||||||
export function createFriendApi(params: CreateFriendParams) {
|
export function createFriendApi(params: CreateFriendParams) {
|
||||||
@@ -8,3 +8,7 @@ export function createFriendApi(params: CreateFriendParams) {
|
|||||||
export function queryFriendApi(params: QueryFriendParams) {
|
export function queryFriendApi(params: QueryFriendParams) {
|
||||||
return httpPostJson<BasePageResult<ImFriend>>('/im/friend/query', params)
|
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'),
|
component: () => import('@/views/company/detail.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/im',
|
path: '/im/:type?/:id?',
|
||||||
component: () => import('@/views/im/index.vue'),
|
component: () => import('@/views/im/index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,3 +62,24 @@ export interface ImFriend {
|
|||||||
|
|
||||||
isOnline: boolean
|
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>
|
<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 { Search } from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { onMounted, ref } from 'vue'
|
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { queryFriendApi } from '@/request/api/im'
|
import { queryFriendApi, queryGroupApi } from '@/request/api/im'
|
||||||
import { useWebSocket } from '@/store/websocket'
|
import { useWebSocket } from '@/store/websocket'
|
||||||
import { MessageType } from '@/types/im'
|
import { MessageType } from '@/types/im'
|
||||||
import { formatImTime } from '@/utils/time'
|
import { formatImTime } from '@/utils/time'
|
||||||
@@ -13,30 +12,92 @@ const route = useRoute()
|
|||||||
const websocket = useWebSocket()
|
const websocket = useWebSocket()
|
||||||
|
|
||||||
// 当前聊天对象
|
// 当前聊天对象
|
||||||
const activeChatTab = ref<'private' | 'group'>('private')
|
const searchName = ref('')
|
||||||
|
|
||||||
const initialFriendId = ref<number | null>(
|
type ChatType = 'private' | 'group'
|
||||||
route.params.friendId ? Number(route.params.friendId) : null,
|
|
||||||
|
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 friendState = ref<ImListState<ImFriend>>({
|
||||||
const friendsPage = ref({
|
list: [],
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
hasMore: true,
|
||||||
|
})
|
||||||
|
// 群组列表
|
||||||
|
const groupState = ref<ImListState<ImGroup>>({
|
||||||
|
list: [],
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
loading: false,
|
||||||
|
hasMore: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
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()
|
loadFriends()
|
||||||
|
|
||||||
websocket.onMessage((msg) => {
|
websocket.onMessage((msg) => {
|
||||||
const { type, from } = msg
|
const { type, from } = msg
|
||||||
|
|
||||||
|
// 更新在线状态
|
||||||
const updateOnlineStatus = (isOnline: boolean) => {
|
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)
|
if (friend)
|
||||||
friend.isOnline = isOnline
|
friend.isOnline = isOnline
|
||||||
}
|
}
|
||||||
@@ -52,57 +113,118 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 加载好友列表
|
// 加载好友列表
|
||||||
async function loadFriends() {
|
async function loadFriends() {
|
||||||
if (friendsPage.value.loading)
|
const state = friendState.value
|
||||||
|
if (state.loading || !state.hasMore)
|
||||||
return
|
return
|
||||||
friendsPage.value.loading = true
|
|
||||||
|
|
||||||
|
state.loading = true
|
||||||
try {
|
try {
|
||||||
const res = await queryFriendApi({
|
const res = await queryFriendApi({
|
||||||
currentPage: friendsPage.value.page,
|
currentPage: state.page,
|
||||||
pageSize: friendsPage.value.pageSize,
|
pageSize: state.pageSize,
|
||||||
name: '',
|
name: searchName.value,
|
||||||
id: initialFriendId.value,
|
id: currentChat.value?.type === 'private' ? currentChat.value.id : null,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.isSuccess) {
|
if (!res.isSuccess)
|
||||||
const { records, total } = res.data
|
throw new Error(res.message)
|
||||||
|
|
||||||
if (friendsPage.value.page === 1) {
|
const { records, total } = res.data
|
||||||
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())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置当前聊天对象
|
state.list
|
||||||
if (initialFriendId.value) {
|
= state.page === 1
|
||||||
const friend = friends.value.find(f => f.id === initialFriendId.value)
|
? records
|
||||||
if (friend) {
|
: [...state.list, ...records]
|
||||||
// openPrivateChat(friend)
|
|
||||||
}
|
|
||||||
initialFriendId.value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
friendsPage.value.total = total
|
state.total = total
|
||||||
}
|
state.hasMore = state.list.length < total
|
||||||
else {
|
state.page++
|
||||||
ElMessage.error(res.message || '加载好友列表失败,请稍后再试')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (e) {
|
||||||
console.log(err)
|
console.error(e)
|
||||||
ElMessage.error('加载好友列表失败,请稍后再试')
|
|
||||||
}
|
}
|
||||||
finally {
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -137,49 +259,16 @@ async function loadFriends() {
|
|||||||
<div class="im__body">
|
<div class="im__body">
|
||||||
<div class="im__list">
|
<div class="im__list">
|
||||||
<div class="im__list-search">
|
<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>
|
</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-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">
|
<div class="im__list-header">
|
||||||
<SvgIcon icon="tabler:message-circle" :size="16" />
|
<SvgIcon icon="tabler:message-circle" :size="16" />
|
||||||
<span class="im__list-header-title">
|
<span class="im__list-header-title">
|
||||||
@@ -188,7 +277,12 @@ async function loadFriends() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="im__list-body">
|
<div class="im__list-body">
|
||||||
<div
|
<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
|
<el-badge
|
||||||
is-dot
|
is-dot
|
||||||
@@ -199,7 +293,7 @@ async function loadFriends() {
|
|||||||
}"
|
}"
|
||||||
:offset="[-4, 34]"
|
: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>
|
</el-badge>
|
||||||
<div class="im__chat-item-info">
|
<div class="im__chat-item-info">
|
||||||
<div class="im__chat-item-main">
|
<div class="im__chat-item-main">
|
||||||
@@ -220,7 +314,68 @@ async function loadFriends() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -258,8 +413,7 @@ async function loadFriends() {
|
|||||||
|
|
||||||
.im__container {
|
.im__container {
|
||||||
width: 1300px;
|
width: 1300px;
|
||||||
height: 80%;
|
min-height: 750px;
|
||||||
min-height: 700px;
|
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
|||||||
Reference in new issue
Block a user