From e429c291995f3f20184079e480031533ae5c03e6 Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期五, 18 九月 2026 17:24:28 +0800
Subject: [PATCH] refactor(全项目): 综合优化全端业务与修复各类问题
---
tcm-training-admin-backend/src/test/java/com/tcm/training/admin/member/service/UserAppServiceTest.java | 195 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 195 insertions(+), 0 deletions(-)
diff --git a/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/member/service/UserAppServiceTest.java b/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/member/service/UserAppServiceTest.java
index 21d910b..2c96067 100644
--- a/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/member/service/UserAppServiceTest.java
+++ b/tcm-training-admin-backend/src/test/java/com/tcm/training/admin/member/service/UserAppServiceTest.java
@@ -6,7 +6,10 @@
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tcm.training.admin.common.PageResponse;
+import com.tcm.training.admin.live.entity.Clinic;
import com.tcm.training.admin.live.mapper.ClinicMapper;
+import com.tcm.training.admin.member.dto.UserBatchClinicUpdateRequest;
+import com.tcm.training.admin.member.dto.UserUpdateRequest;
import com.tcm.training.admin.member.entity.AppUser;
import com.tcm.training.admin.member.mapper.UserMapper;
import com.tcm.training.admin.member.row.UserDetailRow;
@@ -17,6 +20,9 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
@@ -24,7 +30,9 @@
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.time.LocalDateTime;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -133,4 +141,191 @@
assertTrue(wrapperCaptor.getValue().getParamNameValuePairs().values().stream().allMatch(value -> value == null));
assertEquals(Long.valueOf(12L), result.getId());
}
+
+ @ParameterizedTest
+ @CsvSource({"10, 100", "20, 100", "20, "})
+ void updateShouldSynchronizeClinicBindingIncludingStaleRelations(Long oldClinicId, Long oldDoctorId) {
+ AppUser user = prepareUserUpdate(0);
+ user.setClinicId(oldClinicId);
+ user.setSuperiorClinicUserId(oldDoctorId);
+ prepareClinicAccounts(1);
+
+ userAppService.update(12L, updateRequest(20L));
+
+ verify(userMapper).updateById(user);
+ assertClinicBinding(Collections.singletonList(12L), 20L, 200L);
+ }
+
+ @Test
+ void updateShouldExplicitlyClearBothClinicFields() {
+ AppUser user = prepareUserUpdate(0);
+ user.setClinicId(10L);
+ user.setSuperiorClinicUserId(100L);
+
+ userAppService.update(12L, updateRequest(null));
+
+ assertClinicBinding(Collections.singletonList(12L), null, null);
+ verify(clinicMapper, never()).selectById(any());
+ }
+
+ @Test
+ void updateShouldPreserveDoctorAccountClinic() {
+ AppUser user = prepareUserUpdate(1);
+ user.setClinicId(10L);
+
+ userAppService.update(12L, updateRequest(null));
+
+ assertEquals(Long.valueOf(10L), user.getClinicId());
+ verify(userMapper).updateById(user);
+ verify(userMapper, never()).update(any(), any());
+ }
+
+ @Test
+ void batchUpdateShouldSynchronizeBothClinicFields() {
+ prepareClinicAccounts(1);
+ when(userMapper.selectCount(any())).thenReturn(2L);
+
+ userAppService.batchUpdateClinic(batchRequest());
+
+ assertClinicBinding(Arrays.asList(12L, 13L), 20L, 200L);
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, 2})
+ void updateShouldRejectMissingOrAmbiguousClinicAccount(int accountCount) {
+ AppUser user = new AppUser();
+ user.setId(12L);
+ user.setType(0);
+ when(userMapper.selectOne(any())).thenReturn(user);
+ prepareClinicAccounts(accountCount);
+
+ IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
+ () -> userAppService.update(12L, updateRequest(20L)));
+
+ assertEquals(accountCount == 0 ? "目标诊所尚未关联诊所账号,无法绑定患者"
+ : "目标诊所关联多个账号,请先确认患者归属", error.getMessage());
+ assertNoUserWrite();
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, 2})
+ void batchUpdateShouldRejectMissingOrAmbiguousClinicAccount(int accountCount) {
+ prepareClinicAccounts(accountCount);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> userAppService.batchUpdateClinic(batchRequest()));
+
+ assertNoUserWrite();
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ void batchUpdateShouldRejectMissingOrDeletedClinic(boolean deleted) {
+ if (deleted) {
+ Clinic clinic = new Clinic();
+ clinic.setId(20L);
+ clinic.setDeleted(1);
+ when(clinicMapper.selectById(20L)).thenReturn(clinic);
+ }
+
+ IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
+ () -> userAppService.batchUpdateClinic(batchRequest()));
+
+ assertEquals("绑定诊所不存在", error.getMessage());
+ assertNoUserWrite();
+ }
+
+ @Test
+ void batchUpdateShouldRejectUsersOutsidePersonalUserScope() {
+ prepareClinicAccounts(1);
+ when(userMapper.selectCount(any())).thenAnswer(invocation -> {
+ com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AppUser> query =
+ invocation.getArgument(0);
+ assertTrue(query.getSqlSegment().contains("type ="));
+ assertTrue(query.getParamNameValuePairs().containsValue(0));
+ return 1L;
+ });
+
+ IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
+ () -> userAppService.batchUpdateClinic(batchRequest()));
+
+ assertEquals("部分用户不存在或不是普通用户", error.getMessage());
+ assertNoUserWrite();
+ }
+
+ private AppUser prepareUserUpdate(int type) {
+ AppUser user = new AppUser();
+ user.setId(12L);
+ user.setType(type);
+ user.setDeleted(0);
+ // 第一次查询用户,第二次检查手机号冲突。
+ when(userMapper.selectOne(any())).thenReturn(user, null);
+ UserDetailRow detail = new UserDetailRow();
+ detail.setId(12L);
+ when(userMapper.selectUserDetail(12L)).thenReturn(detail);
+ return user;
+ }
+
+ private void prepareClinicAccounts(int count) {
+ Clinic clinic = new Clinic();
+ clinic.setId(20L);
+ clinic.setDeleted(0);
+ when(clinicMapper.selectById(20L)).thenReturn(clinic);
+ AppUser doctor = new AppUser();
+ doctor.setId(200L);
+ doctor.setType(1);
+ doctor.setClinicId(20L);
+ when(userMapper.selectList(any())).thenAnswer(invocation -> {
+ com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AppUser> query =
+ invocation.getArgument(0);
+ String sql = query.getSqlSegment();
+ assertTrue(sql.contains("clinic_id =") && sql.contains("type =") && sql.contains("deleted ="));
+ assertTrue(query.getParamNameValuePairs().values().containsAll(Arrays.asList(20L, 1, 0)));
+ return Collections.nCopies(count, doctor);
+ });
+ }
+
+ private UserUpdateRequest updateRequest(Long clinicId) {
+ UserUpdateRequest request = new UserUpdateRequest();
+ request.setNickname("测试用户");
+ request.setPhone("13800000000");
+ request.setStatus(1);
+ request.setClinicId(clinicId);
+ return request;
+ }
+
+ private UserBatchClinicUpdateRequest batchRequest() {
+ UserBatchClinicUpdateRequest request = new UserBatchClinicUpdateRequest();
+ request.setUserIds(Arrays.asList(12L, 13L));
+ request.setClinicId(20L);
+ return request;
+ }
+
+ private void assertNoUserWrite() {
+ verify(userMapper, never()).updateById(any(AppUser.class));
+ verify(userMapper, never()).update(any(), any());
+ }
+
+ private void assertClinicBinding(List<Long> userIds, Long clinicId, Long doctorId) {
+ ArgumentCaptor<LambdaUpdateWrapper<AppUser>> captor = ArgumentCaptor.forClass(LambdaUpdateWrapper.class);
+ verify(userMapper).update(isNull(), captor.capture());
+ LambdaUpdateWrapper<AppUser> update = captor.getValue();
+ // 按列名核对绑定参数,避免诊所 ID 和诊所账号 ID 被误用。
+ String[] assignments = update.getSqlSet().split(",");
+ assertEquals(2, assignments.length);
+ assertAssignment(update, assignments[0], "clinic_id", clinicId);
+ assertAssignment(update, assignments[1], "superior_clinic_user_id", doctorId);
+ String sql = update.getSqlSegment();
+ assertTrue(sql.contains("id IN") && sql.contains("type =") && sql.contains("deleted ="));
+ assertTrue(update.getParamNameValuePairs().values().containsAll(userIds));
+ assertTrue(update.getParamNameValuePairs().containsValue(0));
+ }
+
+ private void assertAssignment(LambdaUpdateWrapper<AppUser> update, String assignment,
+ String column, Long expectedValue) {
+ assertTrue(assignment.startsWith(column + "="));
+ String parameter = assignment.substring(assignment.lastIndexOf('.') + 1, assignment.length() - 1);
+ assertTrue(update.getParamNameValuePairs().containsKey(parameter));
+ assertEquals(expectedValue, update.getParamNameValuePairs().get(parameter));
+ }
}
--
Gitblit v1.7.1