优化
This commit is contained in:
@@ -12,6 +12,8 @@ import com.baiyue.iam.dto.TenantDtos.ApprovalResponse;
|
||||
import com.baiyue.iam.entity.IamTenantReview;
|
||||
import com.baiyue.iam.service.TenantGuard;
|
||||
import com.baiyue.iam.service.TenantService;
|
||||
import com.baiyue.iam.service.MemberService;
|
||||
import com.baiyue.iam.dto.PlatformCustomerMemberDtos;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
@@ -38,6 +40,8 @@ import java.util.List;
|
||||
public class PlatformTenantController {
|
||||
@Resource
|
||||
private TenantService service;
|
||||
@Resource
|
||||
private MemberService memberService;
|
||||
|
||||
@GetMapping("/tenants")
|
||||
@PreAuthorize("hasAuthority('platform:customer:list')")
|
||||
@@ -69,6 +73,15 @@ public class PlatformTenantController {
|
||||
return ApiResponse.success(service.merchant(tenantId));
|
||||
}
|
||||
|
||||
@GetMapping("/tenants/{tenantId:\\d+}/members")
|
||||
@PreAuthorize("hasAuthority('platform:customer:view')")
|
||||
@Operation(summary = "查询企业客户成员及账号", description = "平台只读查询指定企业的全部成员,包含 OWNER 企业管理员,并返回登录账号。")
|
||||
public ApiResponse<List<PlatformCustomerMemberDtos.MemberResponse>> members(
|
||||
@PathVariable long tenantId, @AuthenticationPrincipal AuthenticatedUser user) {
|
||||
TenantGuard.tenant(user, "PLATFORM");
|
||||
return ApiResponse.success(memberService.platformList(tenantId));
|
||||
}
|
||||
|
||||
@PostMapping("/tenants")
|
||||
@PreAuthorize("hasAuthority('platform:customer:create')")
|
||||
@Operation(summary = "Register enterprise tenant / 创建企业客户草稿", description = "Create a PROFILE_REQUIRED merchant draft only. Saving the customer does not create a review ticket. / 仅创建待完善企业客户草稿,保存客户不会创建审核单。")
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baiyue.iam.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** 平台查看客户企业成员时使用的只读契约,补充认证账号信息。 */
|
||||
public final class PlatformCustomerMemberDtos {
|
||||
private PlatformCustomerMemberDtos() { }
|
||||
|
||||
public record MemberResponse(Long membershipId, Long userId, Long authUserId,
|
||||
String username, String displayName, String phone, String email,
|
||||
String memberType, String memberNo, String status,
|
||||
List<Long> roleIds, List<String> roleNames) { }
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import com.baiyue.iam.entity.IamRole;
|
||||
import com.baiyue.iam.entity.IamUser;
|
||||
import com.baiyue.iam.mapper.IamRoleMapper;
|
||||
import com.baiyue.iam.repository.MemberRepository;
|
||||
import com.baiyue.iam.repository.TenantRepository;
|
||||
import com.baiyue.iam.dto.PlatformCustomerMemberDtos;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import feign.FeignException;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -33,6 +35,8 @@ public class MemberService {
|
||||
@Resource
|
||||
private MemberRepository repository;
|
||||
@Resource
|
||||
private TenantRepository tenantRepository;
|
||||
@Resource
|
||||
private IamRoleMapper roleMapper;
|
||||
@Resource
|
||||
private AuthAccountClient authClient;
|
||||
@@ -43,6 +47,34 @@ public class MemberService {
|
||||
return repository.findByTenant(tenantId).stream().map(m -> response(tenantId, m)).toList();
|
||||
}
|
||||
|
||||
/** 平台只读查询客户成员;显式校验客户主档,并包含 OWNER 管理员。 */
|
||||
public List<PlatformCustomerMemberDtos.MemberResponse> platformList(long tenantId) {
|
||||
var tenant = tenantRepository.findTenant(tenantId);
|
||||
if (tenant == null || !"MERCHANT".equals(tenant.getTenantType())) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "企业客户不存在");
|
||||
}
|
||||
return repository.findByTenant(tenantId).stream().map(m -> platformResponse(tenantId, m)).toList();
|
||||
}
|
||||
|
||||
private PlatformCustomerMemberDtos.MemberResponse platformResponse(long tenantId, IamMembership membership) {
|
||||
IamUser user = requiredUser(membership.getUserId());
|
||||
AuthAccountClient.AccountSummary account = accountSummary(user.getAuthUserId());
|
||||
List<Long> roleIds = repository.findRoleIds(tenantId, membership.getId());
|
||||
List<String> roleNames = roleIds.stream()
|
||||
.map(roleMapper::selectById)
|
||||
.filter(role -> role != null && Long.valueOf(tenantId).equals(role.getTenantId()))
|
||||
.map(IamRole::getRoleName)
|
||||
.toList();
|
||||
return new PlatformCustomerMemberDtos.MemberResponse(membership.getId(), user.getId(),
|
||||
user.getAuthUserId(), account.username(), user.getDisplayName(), user.getPhone(), user.getEmail(),
|
||||
membership.getMemberType(), membership.getMemberNo(), membership.getStatus(),
|
||||
roleIds, roleNames);
|
||||
}
|
||||
|
||||
private AuthAccountClient.AccountSummary accountSummary(Long authUserId) {
|
||||
return data(call(() -> authClient.summary(internalToken, authUserId)));
|
||||
}
|
||||
|
||||
public MemberResponse detail(long tenantId, Long membershipId) {
|
||||
return response(tenantId, required(tenantId, membershipId));
|
||||
}
|
||||
|
||||
@@ -88,6 +88,22 @@ paths:
|
||||
'400': {$ref: '#/components/responses/BadRequest'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
/api/platform/v1/iam/tenants/{tenantId}/members:
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/TenantId'}
|
||||
get:
|
||||
tags: [Platform Tenant / 平台租户]
|
||||
summary: 查询企业客户成员及账号
|
||||
description: 平台只读查询指定客户的全部企业成员,包含 OWNER 企业管理员并返回登录账号;需要 `platform:customer:view` 权限。
|
||||
responses:
|
||||
'200':
|
||||
description: 企业成员查询成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PlatformCustomerMembersApiResponse'
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
'404': {$ref: '#/components/responses/NotFound'}
|
||||
/api/platform/v1/iam/tenants/{tenantId}/submit-review:
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/TenantId'}
|
||||
@@ -802,6 +818,28 @@ components:
|
||||
- type: object
|
||||
properties:
|
||||
data: {$ref: '#/components/schemas/InternalUserResponse'}
|
||||
PlatformCustomerMemberResponse:
|
||||
type: object
|
||||
required: [membershipId, userId, authUserId, username, displayName, memberType, status, roleIds, roleNames]
|
||||
properties:
|
||||
membershipId: {type: string, pattern: '^\d+$'}
|
||||
userId: {type: string, pattern: '^\d+$'}
|
||||
authUserId: {type: string, pattern: '^\d+$'}
|
||||
username: {type: string}
|
||||
displayName: {type: string}
|
||||
phone: {type: string}
|
||||
email: {type: string, format: email}
|
||||
memberType: {type: string, enum: [OWNER, EMPLOYEE]}
|
||||
memberNo: {type: string}
|
||||
status: {type: string, enum: [ACTIVE, DISABLED]}
|
||||
roleIds: {type: array, items: {type: string, pattern: '^\d+$'}}
|
||||
roleNames: {type: array, items: {type: string}}
|
||||
PlatformCustomerMembersApiResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/ApiResponse'}
|
||||
- type: object
|
||||
properties:
|
||||
data: {type: array, items: {$ref: '#/components/schemas/PlatformCustomerMemberResponse'}}
|
||||
PlatformManagedUserPageApiResponse:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/ApiResponse'}
|
||||
|
||||
@@ -7,9 +7,11 @@ import com.baiyue.iam.client.AuthAccountClient;
|
||||
import com.baiyue.iam.dto.MemberDtos.*;
|
||||
import com.baiyue.iam.entity.IamMembership;
|
||||
import com.baiyue.iam.entity.IamRole;
|
||||
import com.baiyue.iam.entity.IamTenant;
|
||||
import com.baiyue.iam.entity.IamUser;
|
||||
import com.baiyue.iam.mapper.IamRoleMapper;
|
||||
import com.baiyue.iam.repository.MemberRepository;
|
||||
import com.baiyue.iam.repository.TenantRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -28,6 +30,7 @@ import static org.mockito.Mockito.*;
|
||||
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
|
||||
class MemberServiceTest {
|
||||
@MockBean private MemberRepository repository;
|
||||
@MockBean private TenantRepository tenantRepository;
|
||||
@MockBean private IamRoleMapper roleMapper;
|
||||
@MockBean private AuthAccountClient auth;
|
||||
@Resource private MemberService service;
|
||||
@@ -52,6 +55,28 @@ class MemberServiceTest {
|
||||
verifyNoInteractions(auth);
|
||||
}
|
||||
|
||||
@Test void shouldReturnOwnerAccountForPlatformCustomerDetail() {
|
||||
IamTenant tenant = new IamTenant();
|
||||
tenant.setId(100L); tenant.setTenantType("MERCHANT");
|
||||
member.setMemberType("OWNER");
|
||||
user.setPhone("13800138000"); user.setEmail("owner@example.com");
|
||||
when(tenantRepository.findTenant(100L)).thenReturn(tenant);
|
||||
when(repository.findByTenant(100L)).thenReturn(List.of(member));
|
||||
IamRole ownerRole = new IamRole();
|
||||
ownerRole.setId(50L); ownerRole.setTenantId(100L); ownerRole.setRoleName("企业管理员");
|
||||
when(roleMapper.selectById(50L)).thenReturn(ownerRole);
|
||||
when(auth.summary("internal-token", 40L)).thenReturn(ApiResponse.success(
|
||||
new AuthAccountClient.AccountSummary(40L, "merchant_owner", "企业管理员", "ACTIVE")));
|
||||
|
||||
var result = service.platformList(100L);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("merchant_owner", result.get(0).username());
|
||||
assertEquals("OWNER", result.get(0).memberType());
|
||||
assertEquals("ACTIVE", result.get(0).status());
|
||||
assertEquals(List.of("企业管理员"), result.get(0).roleNames());
|
||||
}
|
||||
|
||||
@Test void shouldHandleCase02() {
|
||||
when(repository.findByTenantAndId(200L, 20L)).thenReturn(null);
|
||||
assertThrows(BizException.class, () -> service.detail(200L, 20L));
|
||||
|
||||
Reference in New Issue
Block a user