Commit fe2e63069a6353b94bf39b50dfb7311f16f78391

Authored by zichun
1 parent c6c415dc

feat(usr): UserMapper.xml searchUsers REQ-USR-003

backend/src/main/java/com/xly/erp/module/usr/mapper/UserMapper.java
1 1 package com.xly.erp.module.usr.mapper;
2 2  
3 3 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import com.xly.erp.module.usr.dto.UserQueryDTO;
4 6 import com.xly.erp.module.usr.entity.UserEntity;
  7 +import com.xly.erp.module.usr.vo.UserListItemVO;
  8 +import org.apache.ibatis.annotations.Param;
5 9  
6 10 public interface UserMapper extends BaseMapper<UserEntity> {
  11 +
  12 + /** REQ-USR-003 用户列表查询:跨表 JOIN tStaff,按 query 过滤 + 分页。XML 实现。 */
  13 + IPage<UserListItemVO> searchUsers(IPage<UserListItemVO> page, @Param("query") UserQueryDTO query);
7 14 }
... ...
backend/src/main/resources/mapper/usr/UserMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="com.xly.erp.module.usr.mapper.UserMapper">
  4 +
  5 + <!-- REQ-USR-003 用户列表查询:LEFT JOIN tStaff + 动态 WHERE。
  6 + query.column 由 service 层白名单映射,绝不接受用户原始输入。 -->
  7 + <select id="searchUsers" resultType="com.xly.erp.module.usr.vo.UserListItemVO">
  8 + SELECT
  9 + u.iIncrement, u.sUserName, s.sStaffName, u.sUserNo,
  10 + s.sDepartment, u.sUserType, u.sLanguage, u.bDeleted,
  11 + u.tLastLoginDate, u.sCreatedBy, u.tCreateDate
  12 + FROM tUser u
  13 + LEFT JOIN tStaff s ON u.iStaffId = s.iIncrement AND s.bDeleted = 0
  14 + <where>
  15 + <if test="query.queryField != 'deleted'">
  16 + u.bDeleted = 0
  17 + </if>
  18 + <if test="query.column != null and query.column != '' and query.queryValue != null and query.queryValue != ''">
  19 + AND
  20 + <choose>
  21 + <when test="query.matchType == 'equals'">
  22 + ${query.column} = #{query.queryValue}
  23 + </when>
  24 + <when test="query.matchType == 'notContains'">
  25 + ${query.column} NOT LIKE CONCAT('%', #{query.queryValue}, '%')
  26 + </when>
  27 + <otherwise>
  28 + ${query.column} LIKE CONCAT('%', #{query.queryValue}, '%')
  29 + </otherwise>
  30 + </choose>
  31 + </if>
  32 + </where>
  33 + ORDER BY u.tCreateDate DESC, u.iIncrement DESC
  34 + </select>
  35 +</mapper>
... ...
backend/src/test/java/com/xly/erp/module/usr/mapper/UserMapperSearchIT.java 0 → 100644
  1 +package com.xly.erp.module.usr.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.metadata.IPage;
  4 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5 +import com.xly.erp.module.usr.dto.UserQueryDTO;
  6 +import com.xly.erp.module.usr.entity.StaffEntity;
  7 +import com.xly.erp.module.usr.entity.UserEntity;
  8 +import com.xly.erp.module.usr.vo.UserListItemVO;
  9 +import org.junit.jupiter.api.Test;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.boot.test.context.SpringBootTest;
  12 +import org.springframework.test.annotation.Rollback;
  13 +import org.springframework.test.context.ActiveProfiles;
  14 +import org.springframework.transaction.annotation.Transactional;
  15 +
  16 +import java.time.LocalDateTime;
  17 +
  18 +import static org.assertj.core.api.Assertions.assertThat;
  19 +
  20 +@SpringBootTest
  21 +@ActiveProfiles("test")
  22 +@Transactional
  23 +@Rollback
  24 +class UserMapperSearchIT {
  25 +
  26 + @Autowired UserMapper userMapper;
  27 + @Autowired StaffMapper staffMapper;
  28 +
  29 + private Integer insertStaff(String name) {
  30 + StaffEntity s = new StaffEntity();
  31 + s.setSStaffNo("st_" + System.nanoTime());
  32 + s.setSStaffName(name);
  33 + s.setSDepartment("研发部");
  34 + s.setBDeleted(false);
  35 + s.setTCreateDate(LocalDateTime.now());
  36 + staffMapper.insert(s);
  37 + return s.getIIncrement();
  38 + }
  39 +
  40 + private Integer insertUser(String userName, Integer staffId) {
  41 + UserEntity u = new UserEntity();
  42 + u.setSUserNo("uno_" + System.nanoTime());
  43 + u.setSUserName(userName);
  44 + u.setIStaffId(staffId);
  45 + u.setSUserType("普通用户");
  46 + u.setSLanguage("zh");
  47 + u.setBCanModifyDocs(false);
  48 + u.setSPasswordHash("$2a$10$x");
  49 + u.setBDeleted(false);
  50 + u.setTCreateDate(LocalDateTime.now());
  51 + userMapper.insert(u);
  52 + return u.getIIncrement();
  53 + }
  54 +
  55 + @Test
  56 + void searchUsers_emptyFilter_returnsAllUndeletedAsPage() {
  57 + Integer staffId = insertStaff("张三");
  58 + insertUser("alice_" + System.nanoTime(), staffId);
  59 + insertUser("bob_" + System.nanoTime(), null);
  60 +
  61 + UserQueryDTO query = new UserQueryDTO();
  62 + IPage<UserListItemVO> result = userMapper.searchUsers(new Page<>(1, 50), query);
  63 +
  64 + assertThat(result.getTotal()).isGreaterThanOrEqualTo(2L);
  65 + assertThat(result.getRecords()).extracting(UserListItemVO::getSUserName)
  66 + .anyMatch(n -> n.startsWith("alice_") || n.startsWith("bob_"));
  67 + }
  68 +
  69 + @Test
  70 + void searchUsers_filterByUserName_filtersCorrectly() {
  71 + String alicePrefix = "ali_" + System.nanoTime();
  72 + insertUser(alicePrefix + "_alice", null);
  73 + insertUser("bob_unmatch_" + System.nanoTime(), null);
  74 +
  75 + UserQueryDTO query = new UserQueryDTO();
  76 + query.setQueryField("username");
  77 + query.setColumn("u.sUserName");
  78 + query.setMatchType("contains");
  79 + query.setQueryValue(alicePrefix);
  80 +
  81 + IPage<UserListItemVO> result = userMapper.searchUsers(new Page<>(1, 50), query);
  82 +
  83 + assertThat(result.getRecords()).hasSize(1);
  84 + assertThat(result.getRecords().get(0).getSUserName()).startsWith(alicePrefix);
  85 + }
  86 +}
... ...