Merge branch 'feature/REQ-3457' into 'master'

Feature/req 3457

See merge request universal/infrastructure/backend/im-center!54
This commit is contained in:
金海洋 2025-01-21 03:14:05 +00:00
commit 767eac8ef7
16 changed files with 798 additions and 3 deletions

View File

@ -0,0 +1,42 @@
package cn.axzo.im.center.api.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.im.center.api.vo.req.chatuser.BatchCreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.CreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.QueryChatUserHistoryReq;
import cn.axzo.im.center.api.vo.resp.chatuser.QueryChatUserHistoryResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* 私聊
*
* @author xudawei@axzo.cn
* @date 2024/11/04
*/
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}")
public interface ChatUserApi {
/**
* 创建聊天用户记录
*/
@PostMapping("api/im/chat/user/createChatUserHistory")
ApiResult<Void> createChatUserHistory(@RequestBody @Validated CreateChatUserHistoryReq req);
/**
* 批量-创建历史聊天用户
*/
@PostMapping("api/im/chat/user/batchCreateChatUserHistory")
ApiResult<Void> batchCreateChatUserHistory(@RequestBody @Validated BatchCreateChatUserHistoryReq req);
/**
* 获取聊天用户记录
*/
@PostMapping("api/im/chat/user/searchChatUserHistory")
ApiResult<List<QueryChatUserHistoryResp>> searchChatUserHistory(@RequestBody @Validated QueryChatUserHistoryReq req);
}

View File

@ -0,0 +1,25 @@
package cn.axzo.im.center.api.vo.req.chatuser;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* 创建聊天用户记录
* @author xudawei
* @date 2024/12/27
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BatchCreateChatUserHistoryReq {
@NotEmpty(message = "集合不能为空")
private List<CreateChatUserHistoryReq> reqList;
}

View File

@ -0,0 +1,74 @@
package cn.axzo.im.center.api.vo.req.chatuser;
import cn.axzo.im.center.api.vo.req.ComplaintCreateReq;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.WorkspaceOrOuEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 创建聊天用户记录
* @author xudawei
* @date 2024/12/27
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CreateChatUserHistoryReq {
/**
* 发送人IM账号
*/
private String senderImAccount;
/**
* 发送人PersonId
*/
private Long senderPersonId;
/**
* 发送人单位Id
*/
private Long senderOuId;
private AppTypeEnum imSenderAccountAppType;
/**
* 接收人IM账号
*/
private String receiverImAccount;
/**
* 接收人personId
*/
private Long receiverPersonId;
/**
* 接收人单位Id
*/
private Long receiverOuId;
/**
* 接收人项目Id
*/
private Long receiverWorkspaceId;
/**
* 接收人类型WORKSPACE:项目OU:单位
*/
private WorkspaceOrOuEnum receiverType;
/**
* 类型,PRIVATE:私聊,GROUP:群聊
*/
private ComplaintCreateReq.ChatTypeEnum chatType;
/**
* 创建人
*/
private Long creator;
}

View File

@ -0,0 +1,39 @@
package cn.axzo.im.center.api.vo.req.chatuser;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
/**
* 聊天用户历史记录
* @author xudawei
* @date 2024/12/27
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class QueryChatUserHistoryReq {
/**
* 发送人IM账号
*/
@NotBlank(message = "发送人IM账号不能为空")
private String senderImAccount;
/**
* 接收人项目Id
*/
private Long receiverWorkspaceId;
/**
* 接收人单位Id
*/
private Long receiverOuId;
/**
* 接收人Id
*/
private Long receiverPersonId;
}

View File

@ -0,0 +1,56 @@
package cn.axzo.im.center.api.vo.resp.chatuser;
import cn.axzo.im.center.api.vo.req.ComplaintCreateReq;
import cn.axzo.im.center.common.enums.WorkspaceOrOuEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 聊天用户历史记录
* @author xudawei
* @date 2024/12/27
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class QueryChatUserHistoryResp {
/**
* 发送人IM账号
*/
private String senderImAccount;
/**
* 发送人PersonId
*/
private Long senderPersonId;
/**
* 发送人单位Id
*/
private Long senderOuId;
/**
* 接收人personId
*/
private Long receiverPersonId;
/**
* 接收人单位Id
*/
private Long receiverOuId;
/**
* 接收人项目Id
*/
private Long receiverWorkspaceId;
/**
* 类型,PRIVATE:私聊,GROUP:群聊
*/
private ComplaintCreateReq.ChatTypeEnum chatType;
}

View File

@ -0,0 +1,31 @@
package cn.axzo.im.center.common.enums;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 项目或者单位
* @author xudawei@axzo.cn
* @date 2024/12/30
*/
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum WorkspaceOrOuEnum {
/**
* 项目
*/
WORKSPACE("workspace", "项目"),
/**
* 单位
*/
OU("ou", "单位")
;
private final String code;
private final String message;
}

View File

@ -0,0 +1,58 @@
package cn.axzo.im.controller;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.im.center.api.feign.ChatUserApi;
import cn.axzo.im.center.api.vo.req.chatuser.BatchCreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.CreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.QueryChatUserHistoryReq;
import cn.axzo.im.center.api.vo.resp.chatuser.QueryChatUserHistoryResp;
import cn.axzo.im.service.ChatUserHistoryService;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 私聊
* @author xudawei@axzo.cn
* @date 2024/12/27
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RefreshScope
public class ChatUserController implements ChatUserApi {
private final ChatUserHistoryService chatUserHistoryService;
/**
* 创建历史聊天用户
*/
@Override
public ApiResult<Void> createChatUserHistory(CreateChatUserHistoryReq req) {
chatUserHistoryService.create(req);
return ApiResult.ok();
}
/**
* 批量-创建历史聊天用户
*/
@Override
public ApiResult<Void> batchCreateChatUserHistory(BatchCreateChatUserHistoryReq req) {
log.info("batchCreateChatUserHistory,params:{}", JSON.toJSONString(req));
chatUserHistoryService.batchCreate(req);
return ApiResult.ok();
}
/**
* 查询历史聊天用户
*/
@Override
public ApiResult<List<QueryChatUserHistoryResp>> searchChatUserHistory(QueryChatUserHistoryReq req) {
List<QueryChatUserHistoryResp> list = chatUserHistoryService.searchChatUserHistory(req, 10);
return ApiResult.ok(list);
}
}

View File

@ -0,0 +1,33 @@
package cn.axzo.im.dao.mapper;
import cn.axzo.im.center.api.vo.req.chatuser.CreateChatUserHistoryReq;
import cn.axzo.im.entity.ChatUserHistory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author xudawei@axzo.cn
* @date 2024/11/05
* @desc 历史聊天用户
*/
public interface ChatUserHistoryMapper extends BaseMapper<ChatUserHistory> {
@Select("<script>SELECT *\n" +
"FROM im_chat_user_history\n" +
"WHERE " +
" is_delete=0 and \n" +
" (sender_im_account,receiver_person_id,receiver_ou_id,receiver_workspace_id) in\n" +
" <foreach collection='reqList' item='item' separator=',' open='(' close=')'>\n" +
" (#{item.senderImAccount},#{item.receiverPersonId},#{item.receiverOuId},#{item.receiverWorkspaceId})\n" +
" </foreach>\n" +
"ORDER BY update_at DESC\n" +
"\n" +
"</script>")
List<ChatUserHistory> findBySenderReceiver(
@Param("reqList") List<CreateChatUserHistoryReq> reqList);
}

View File

@ -0,0 +1,24 @@
package cn.axzo.im.dao.repository;
import cn.axzo.im.dao.mapper.ChatUserHistoryMapper;
import cn.axzo.im.dao.mapper.MessageHistoryMapper;
import cn.axzo.im.entity.ChatUserHistory;
import cn.axzo.im.entity.MessageHistory;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import java.util.Collections;
import java.util.List;
/**
* im-center
*
* @author xudawei@axzo.cn
* @date 2025/01/08
*/
@Repository("chatUserHistoryDao")
public class ChatUserHistoryDao extends ServiceImpl<ChatUserHistoryMapper, ChatUserHistory> {
}

View File

@ -0,0 +1,123 @@
package cn.axzo.im.entity;
import cn.axzo.im.center.api.vo.req.ComplaintCreateReq;
import cn.axzo.im.center.api.vo.req.chatuser.CreateChatUserHistoryReq;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.io.Serializable;
import java.util.Date;
/**
* 历史聊天用户
* @author xudawei@axzo.cn
* @date 2024/12/27
*/
@TableName("im_chat_user_history")
@Data
@SuperBuilder
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ChatUserHistory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Long id;
/**
* 发送人IM账号
*/
@TableField("sender_im_account")
private String senderImAccount;
/**
* 发送人PersonId
*/
@TableField("sender_person_id")
private Long senderPersonId;
/**
* 发送人单位Id
*/
@TableField("sender_ou_id")
private Long senderOuId;
/**
* 接收人personId
*/
@TableField("receiver_person_id")
private Long receiverPersonId;
/**
* 接收人单位Id
*/
@TableField("receiver_ou_id")
private Long receiverOuId;
/**
* 接收人项目Id
*/
@TableField("receiver_workspace_id")
private Long receiverWorkspaceId;
/**
* 类型,PRIVATE:私聊,GROUP:群聊
*/
@TableField("chat_type")
private ComplaintCreateReq.ChatTypeEnum chatType;
/**
* 备注
*/
@TableField("remark")
private String remark;
/**
* 创建人
*/
@TableField("creator")
private Long creator;
/**
* 是否删除
*/
@TableField("is_delete")
private Long isDelete;
/**
* 创建时间
*/
@TableField("create_at")
private Date createAt;
/**
* 更新时间
*/
@TableField("update_at")
private Date updateAt;
/**
* 创建对象
*/
public static ChatUserHistory create(CreateChatUserHistoryReq req) {
return ChatUserHistory.builder()
.senderImAccount(req.getSenderImAccount())
.senderPersonId(req.getSenderPersonId())
.senderOuId(req.getSenderOuId())
.receiverPersonId(req.getReceiverPersonId())
.receiverOuId(req.getReceiverOuId())
.receiverWorkspaceId(req.getReceiverWorkspaceId())
.chatType(req.getChatType())
.creator(req.getCreator())
.isDelete(0L).build();
}
}

View File

@ -0,0 +1,90 @@
package cn.axzo.im.event.payload;
import cn.axzo.basics.profiles.common.enums.IdentityType;
import cn.axzo.tyr.client.model.enums.SaasJobTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SaasRoleUserRelation implements Serializable {
/**
* 身份Id
*/
private Long identityId;
/**
* 身份类型 1:工人 2:从业人员 3:班组长 4:运营人员 5:政务人员
*/
private IdentityType identityType;
/**
* 角色Id
*/
private Long roleId;
/**
* 自然人Id
*/
private Long naturalPersonId;
/**
* 创建者
*/
private Long createBy;
/**
* 更新者
*/
private Long updateBy;
/**
* 所属单位Id 用户在当前工作台的所属单位
*/
private Long ouId;
/**
* 工作台Id
*/
private Long workspaceId;
/**
* 资源类型
*/
private Integer resourceType;
/**
* 资源Id
*/
private Long resourceId;
/**
* 岗位类型 1:主岗 2:兼岗
* 一个人在一个工作台内除非 特殊的角色(超管,无权限角色等)必定有且只有一个主岗可以有N个兼岗
*/
private SaasJobTypeEnum jobType;
/**
* id
*/
private Long id;
/**
* 创建时间
*/
private Date createAt;
/**
* 修改时间
*/
private Date updateAt;
/**
* 是否删除 0正常1删除
*/
private Long isDelete = 0L;
}

View File

@ -1,6 +1,5 @@
package cn.axzo.im.event.payload; package cn.axzo.im.event.payload;
import cn.axzo.basics.auth.dto.SaasRoleUserRelation;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;

View File

@ -1,6 +1,5 @@
package cn.axzo.im.event.payload; package cn.axzo.im.event.payload;
import cn.axzo.basics.auth.dto.SaasRoleUserRelation;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO; import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;

View File

@ -1,6 +1,5 @@
package cn.axzo.im.handler.chatgroup; package cn.axzo.im.handler.chatgroup;
import cn.axzo.basics.auth.dto.SaasRoleUserRelation;
import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer; import cn.axzo.framework.rocketmq.EventConsumer;
@ -11,6 +10,7 @@ import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum; import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum;
import cn.axzo.im.entity.ChatGroup; import cn.axzo.im.entity.ChatGroup;
import cn.axzo.im.event.inner.EventTypeEnum; import cn.axzo.im.event.inner.EventTypeEnum;
import cn.axzo.im.event.payload.SaasRoleUserRelation;
import cn.axzo.im.event.payload.SaasRoleUserRelationUpsertPayload; import cn.axzo.im.event.payload.SaasRoleUserRelationUpsertPayload;
import cn.axzo.im.gateway.TyrApiGateway; import cn.axzo.im.gateway.TyrApiGateway;
import cn.axzo.im.service.ChatGroupService; import cn.axzo.im.service.ChatGroupService;

View File

@ -0,0 +1,33 @@
package cn.axzo.im.service;
import cn.axzo.im.center.api.vo.req.chatuser.BatchCreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.CreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.QueryChatUserHistoryReq;
import cn.axzo.im.center.api.vo.resp.chatuser.QueryChatUserHistoryResp;
import cn.axzo.im.entity.ChatUserHistory;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author xudawei@axzo.cn
* @date 2024/12/27
* @desc 历史聊天用户
*/
public interface ChatUserHistoryService extends IService<ChatUserHistory> {
/**
* 创建历史聊天用户
*/
Boolean create(CreateChatUserHistoryReq req);
/**
* 批量创建历史聊天用户
*/
Boolean batchCreate(BatchCreateChatUserHistoryReq req);
/**
* 查询历史聊天用户
*/
List<QueryChatUserHistoryResp> searchChatUserHistory(QueryChatUserHistoryReq req, int limitSize);
}

View File

@ -0,0 +1,169 @@
package cn.axzo.im.service.impl;
import cn.axzo.im.center.api.vo.req.AccountAbsentQuery;
import cn.axzo.im.center.api.vo.req.chatuser.BatchCreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.CreateChatUserHistoryReq;
import cn.axzo.im.center.api.vo.req.chatuser.QueryChatUserHistoryReq;
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
import cn.axzo.im.center.api.vo.resp.chatuser.QueryChatUserHistoryResp;
import cn.axzo.im.dao.mapper.ChatUserHistoryMapper;
import cn.axzo.im.dao.repository.ChatUserHistoryDao;
import cn.axzo.im.entity.ChatUserHistory;
import cn.axzo.im.service.AccountService;
import cn.axzo.im.service.ChatUserHistoryService;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author xudawei@axzo.cn
* @date 2024/11/05
* @desc 历史聊天用户
*/
@Slf4j
@Service
@RefreshScope
@RequiredArgsConstructor
public class ChatUserHistoryServiceImpl extends ServiceImpl<ChatUserHistoryMapper, ChatUserHistory>
implements ChatUserHistoryService {
private final ChatUserHistoryDao chatUserHistoryDao;
private final AccountService accountService;
/**
* 创建历史聊天用户
*/
@Override
public Boolean create(CreateChatUserHistoryReq req) {
return this.saveOrUpdate(ChatUserHistory.create(req));
}
/**
* 批量创建历史聊天用户
*/
@Override
public Boolean batchCreate(BatchCreateChatUserHistoryReq req) {
if (CollectionUtils.isEmpty(req.getReqList())) {
return false;
}
List<ChatUserHistory> historyList = this.buildHistory(req);
log.info("batchCreate-historyList:{}", JSON.toJSONString(historyList));
try {
return this.saveOrUpdateBatch(historyList);
} catch (Exception e) {
log.warn("batchCreateChatUserHistory-expcetion,req:{}", JSON.toJSONString(req), e);
}
return false;
}
/**
* 构建历史聊天用户
*/
private List<ChatUserHistory> buildHistory(BatchCreateChatUserHistoryReq req) {
// 非空校验
if (Objects.isNull(req) || CollectionUtils.isEmpty(req.getReqList())) {
return Lists.newArrayList();
}
//根据Req构建entity对象
List<ChatUserHistory> historyList = req.getReqList().stream()
.map(item -> {
//im账号为空则重新设置Im账号
this.rechangeSenderImAccount(item);
//创建历史聊天对象
return ChatUserHistory.create(item);
})
.collect(Collectors.toList());
//从db中获取历史聊天用户
List<ChatUserHistory> bySenderReceiver = chatUserHistoryDao.getBaseMapper().findBySenderReceiver(req.getReqList());
if (CollectionUtils.isEmpty(bySenderReceiver)) {
return historyList;
}
//db已经有聊天用户记录的则重新设置id更新时间
//db没有聊天用户记录的则插入记录
Map<String, Long> imAccountMap = bySenderReceiver.stream()
.collect(Collectors.toMap((this::buildChatHistoryKey), (v -> v.getId()), (x, y) -> x));
for (ChatUserHistory history : historyList) {
Long id = imAccountMap.get(this.buildChatHistoryKey(history));
if (Objects.nonNull(id)) {
history.setId(id);
history.setUpdateAt(new Date());
}
}
return historyList;
}
/**
* 重新设置IM账号
*/
private void rechangeSenderImAccount(CreateChatUserHistoryReq req) {
if (!StringUtils.hasText(req.getSenderImAccount())) {
String senderImAccount = this.registerAccountIfAbsent(req.getImSenderAccountAppType().getCode(), req.getSenderPersonId(), req.getSenderOuId());
req.setSenderImAccount(senderImAccount);
}
}
/**
* 注册IM账号(支持幂等性)
*/
private String registerAccountIfAbsent(String appType, Long personId, Long ouId) {
AccountAbsentQuery query = new AccountAbsentQuery();
query.setAppType(appType);
query.setPersonId(personId.toString());
query.setOuId(ouId);
//1 注册IM账号
List<UserAccountResp> userAccountResps = accountService.registerAccountIfAbsent(query);
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(userAccountResps)) {
return userAccountResps.get(0).getImAccount();
}
return "";
}
/**
* 构建Key
*/
private String buildChatHistoryKey(ChatUserHistory history) {
if (Objects.isNull(history)) {
return "";
}
StringBuilder builder = new StringBuilder();
builder.append(StringUtils.hasText(history.getSenderImAccount()) ? history.getSenderImAccount() : "-")
.append(Objects.nonNull(history.getReceiverPersonId()) ? history.getReceiverPersonId() : "-")
.append(Objects.nonNull(history.getReceiverOuId()) ? history.getReceiverOuId() : "-")
.append(Objects.nonNull(history.getReceiverWorkspaceId()) ? history.getReceiverWorkspaceId() : "-");
return builder.toString();
}
/**
* 查询历史聊天用户
*/
@Override
public List<QueryChatUserHistoryResp> searchChatUserHistory(QueryChatUserHistoryReq req, int limitSize) {
List<ChatUserHistory> list = this.lambdaQuery()
.eq(StringUtils.hasText(req.getSenderImAccount()), ChatUserHistory::getSenderImAccount, req.getSenderImAccount())
.eq(Objects.nonNull(req.getReceiverOuId()), ChatUserHistory::getReceiverOuId, req.getReceiverOuId())
.eq(Objects.nonNull(req.getReceiverWorkspaceId()), ChatUserHistory::getReceiverWorkspaceId, req.getReceiverWorkspaceId())
.eq(Objects.nonNull(req.getReceiverPersonId()), ChatUserHistory::getReceiverPersonId, req.getReceiverPersonId())
.orderByDesc(ChatUserHistory::getUpdateAt)
.last(" limit " + limitSize)
.list();
return BeanUtil.copyToList(list, QueryChatUserHistoryResp.class);
}
}