refactor(archive-service): 重构员工会话存档统计逻辑,优化查询性能
1. 新增StaffMapper分页查询与计数方法,替换原MyBatis-Plus分页写法 2. 新增批量统计方法,合并多轮单员工查询为批量SQL查询 3. 重构员工列表查询逻辑,减少数据库交互次数 4. 拆分基础VO转换与统计填充方法,优化代码结构
This commit is contained in:
parent
c4d993a9f5
commit
9f86fc9f76
@ -106,6 +106,21 @@ public interface ArchiveMessageMapper extends BaseMapper<ArchiveMessage> {
|
||||
@Select("SELECT DISTINCT from_user FROM archive_messages WHERE corp_id = #{corpId} AND from_role = 'INTERNAL'")
|
||||
List<String> selectStaffIdsWithArchive(@Param("corpId") String corpId);
|
||||
|
||||
@Select("<script>" +
|
||||
"SELECT from_user AS staff_id, COUNT(*) AS msg_count, " +
|
||||
"SUM(CASE WHEN msgtime >= UNIX_TIMESTAMP(CURDATE()) * 1000 " +
|
||||
" AND msgtime < UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL 1 DAY)) * 1000 THEN 1 ELSE 0 END) AS today_msg_count, " +
|
||||
"MAX(msgtime) AS last_msg_time " +
|
||||
"FROM archive_messages " +
|
||||
"WHERE corp_id = #{corpId} AND from_user IN " +
|
||||
"<foreach collection='staffIds' item='id' open='(' separator=',' close=')'>" +
|
||||
"#{id}" +
|
||||
"</foreach> " +
|
||||
"GROUP BY from_user" +
|
||||
"</script>")
|
||||
List<Map<String, Object>> selectStaffArchiveStats(@Param("corpId") String corpId,
|
||||
@Param("staffIds") List<String> staffIds);
|
||||
|
||||
/**
|
||||
* 查询尚未上传到 COS 的媒体消息
|
||||
*/
|
||||
|
||||
@ -6,6 +6,9 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 客户数据访问层
|
||||
*/
|
||||
@ -14,4 +17,17 @@ public interface CustomerMapper extends BaseMapper<Customer> {
|
||||
|
||||
@Select("SELECT * FROM customers WHERE customer_id = #{customerId} AND corp_id = #{corpId} LIMIT 1")
|
||||
Customer selectByCustomerId(@Param("customerId") String customerId, @Param("corpId") String corpId);
|
||||
|
||||
@Select("<script>" +
|
||||
"SELECT s.staff_id, COUNT(*) AS customer_count " +
|
||||
"FROM customers c " +
|
||||
"JOIN (" +
|
||||
" <foreach collection='staffIds' item='id' separator=' UNION ALL '>" +
|
||||
" SELECT #{id} AS staff_id" +
|
||||
" </foreach>" +
|
||||
") s ON c.corp_id = #{corpId} AND JSON_CONTAINS(c.staff_ids, JSON_QUOTE(s.staff_id)) " +
|
||||
"GROUP BY s.staff_id" +
|
||||
"</script>")
|
||||
List<Map<String, Object>> countCustomersByStaffIds(@Param("corpId") String corpId,
|
||||
@Param("staffIds") List<String> staffIds);
|
||||
}
|
||||
|
||||
@ -6,9 +6,43 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface StaffMapper extends BaseMapper<Staff> {
|
||||
|
||||
@Select("SELECT * FROM staffs WHERE staff_id = #{staffId} AND corp_id = #{corpId} LIMIT 1")
|
||||
Staff selectByStaffId(@Param("staffId") String staffId, @Param("corpId") String corpId);
|
||||
|
||||
@Select("<script>" +
|
||||
"SELECT s.* FROM staffs s " +
|
||||
"WHERE s.corp_id = #{corpId} " +
|
||||
"<if test='keyword != null and keyword != \"\"'>" +
|
||||
" AND (s.staff_id LIKE CONCAT('%', #{keyword}, '%') OR s.name LIKE CONCAT('%', #{keyword}, '%')) " +
|
||||
"</if>" +
|
||||
"<if test='hasArchive'>" +
|
||||
" AND EXISTS (SELECT 1 FROM archive_messages m WHERE m.corp_id = s.corp_id AND m.from_user = s.staff_id LIMIT 1) " +
|
||||
"</if>" +
|
||||
"ORDER BY s.created_at DESC " +
|
||||
"LIMIT #{offset}, #{size}" +
|
||||
"</script>")
|
||||
List<Staff> selectStaffPage(@Param("corpId") String corpId,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("hasArchive") boolean hasArchive,
|
||||
@Param("offset") int offset,
|
||||
@Param("size") int size);
|
||||
|
||||
@Select("<script>" +
|
||||
"SELECT COUNT(*) FROM staffs s " +
|
||||
"WHERE s.corp_id = #{corpId} " +
|
||||
"<if test='keyword != null and keyword != \"\"'>" +
|
||||
" AND (s.staff_id LIKE CONCAT('%', #{keyword}, '%') OR s.name LIKE CONCAT('%', #{keyword}, '%')) " +
|
||||
"</if>" +
|
||||
"<if test='hasArchive'>" +
|
||||
" AND EXISTS (SELECT 1 FROM archive_messages m WHERE m.corp_id = s.corp_id AND m.from_user = s.staff_id LIMIT 1) " +
|
||||
"</if>" +
|
||||
"</script>")
|
||||
Long countStaffPage(@Param("corpId") String corpId,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("hasArchive") boolean hasArchive);
|
||||
}
|
||||
|
||||
@ -51,24 +51,17 @@ public class ArchiveSessionService {
|
||||
* 员工列表
|
||||
*/
|
||||
public PageResult<StaffSessionVO> listStaffs(String keyword, int page, int size, boolean hasArchive) {
|
||||
LambdaQueryWrapper<Staff> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(Staff::getCorpId, corpId);
|
||||
if (keyword != null && !keyword.isEmpty()) {
|
||||
wrapper.and(w -> w.like(Staff::getStaffId, keyword).or().like(Staff::getName, keyword));
|
||||
int offset = (page - 1) * size;
|
||||
Long total = staffMapper.countStaffPage(corpId, keyword, hasArchive);
|
||||
if (total == null || total == 0) {
|
||||
return PageResult.of(page, size, 0L, Collections.emptyList());
|
||||
}
|
||||
// 只展示有会话存档的员工
|
||||
if (hasArchive) {
|
||||
List<String> archiveStaffIds = archiveMessageMapper.selectStaffIdsWithArchive(corpId);
|
||||
if (archiveStaffIds == null || archiveStaffIds.isEmpty()) {
|
||||
return PageResult.of(page, size, 0L, Collections.emptyList());
|
||||
}
|
||||
wrapper.in(Staff::getStaffId, archiveStaffIds);
|
||||
}
|
||||
wrapper.orderByDesc(Staff::getCreatedAt);
|
||||
|
||||
Page<Staff> pageResult = staffMapper.selectPage(new Page<>(page, size), wrapper);
|
||||
List<StaffSessionVO> list = pageResult.getRecords().stream().map(this::convertStaffVO).collect(Collectors.toList());
|
||||
return PageResult.of(page, size, pageResult.getTotal(), list);
|
||||
List<Staff> staffList = staffMapper.selectStaffPage(corpId, keyword, hasArchive, offset, size);
|
||||
List<StaffSessionVO> list = staffList.stream().map(this::toBaseStaffVO).collect(Collectors.toList());
|
||||
List<String> staffIds = staffList.stream().map(Staff::getStaffId).collect(Collectors.toList());
|
||||
fillStaffStats(list, staffIds);
|
||||
return PageResult.of(page, size, total, list);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,6 +221,12 @@ public class ArchiveSessionService {
|
||||
// ============ 私有方法 ============
|
||||
|
||||
private StaffSessionVO convertStaffVO(Staff staff) {
|
||||
StaffSessionVO vo = toBaseStaffVO(staff);
|
||||
fillStaffStats(Collections.singletonList(vo), Collections.singletonList(staff.getStaffId()));
|
||||
return vo;
|
||||
}
|
||||
|
||||
private StaffSessionVO toBaseStaffVO(Staff staff) {
|
||||
StaffSessionVO vo = new StaffSessionVO();
|
||||
vo.setStaffId(staff.getStaffId());
|
||||
vo.setName(staff.getName());
|
||||
@ -237,26 +236,43 @@ public class ArchiveSessionService {
|
||||
vo.setStatus(staff.getStatus());
|
||||
vo.setCreatedAt(staff.getCreatedAt());
|
||||
vo.setUpdatedAt(staff.getUpdatedAt());
|
||||
|
||||
// 查询统计
|
||||
try {
|
||||
Long msgCount = archiveMessageMapper.selectCount(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ArchiveMessage>()
|
||||
.eq(ArchiveMessage::getCorpId, corpId)
|
||||
.eq(ArchiveMessage::getFromUser, staff.getStaffId())
|
||||
);
|
||||
vo.setMsgCount(msgCount != null ? msgCount.intValue() : 0);
|
||||
vo.setTodayMsgCount(archiveMessageMapper.countTodayMsgByStaff(staff.getStaffId(), corpId));
|
||||
vo.setCustomerCount(archiveMessageMapper.countCustomersByStaff(staff.getStaffId(), corpId));
|
||||
Long lastMsgTime = archiveMessageMapper.selectLastMsgTimeByUser(staff.getStaffId(), corpId);
|
||||
vo.setLastMsgTime(lastMsgTime);
|
||||
vo.setLastMsgTimeStr(formatTime(lastMsgTime));
|
||||
} catch (Exception e) {
|
||||
log.debug("查询员工统计失败: {}", e.getMessage());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
private void fillStaffStats(List<StaffSessionVO> vos, List<String> staffIds) {
|
||||
if (vos == null || vos.isEmpty() || staffIds == null || staffIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<Map<String, Object>> statsList = archiveMessageMapper.selectStaffArchiveStats(corpId, staffIds);
|
||||
Map<String, Map<String, Object>> statsMap = statsList.stream()
|
||||
.collect(Collectors.toMap(m -> (String) m.get("staff_id"), m -> m, (a, b) -> a));
|
||||
|
||||
List<Map<String, Object>> custList = customerMapper.countCustomersByStaffIds(corpId, staffIds);
|
||||
Map<String, Integer> custMap = custList.stream()
|
||||
.collect(Collectors.toMap(m -> (String) m.get("staff_id"), m -> ((Number) m.get("customer_count")).intValue(), (a, b) -> a));
|
||||
|
||||
for (StaffSessionVO vo : vos) {
|
||||
Map<String, Object> stats = statsMap.get(vo.getStaffId());
|
||||
if (stats != null) {
|
||||
vo.setMsgCount(((Number) stats.get("msg_count")).intValue());
|
||||
vo.setTodayMsgCount(((Number) stats.get("today_msg_count")).intValue());
|
||||
Long lastMsgTime = stats.get("last_msg_time") instanceof Number ? ((Number) stats.get("last_msg_time")).longValue() : null;
|
||||
vo.setLastMsgTime(lastMsgTime);
|
||||
vo.setLastMsgTimeStr(formatTime(lastMsgTime));
|
||||
} else {
|
||||
vo.setMsgCount(0);
|
||||
vo.setTodayMsgCount(0);
|
||||
vo.setLastMsgTime(null);
|
||||
vo.setLastMsgTimeStr(formatTime(null));
|
||||
}
|
||||
vo.setCustomerCount(custMap.getOrDefault(vo.getStaffId(), 0));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询员工统计失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private CustomerSessionVO convertCustomerVO(Customer customer) {
|
||||
CustomerSessionVO vo = new CustomerSessionVO();
|
||||
vo.setCustomerId(customer.getCustomerId());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user