新增权限点增加
parent
8a7ee5f066
commit
c6b695169e
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.unis.crm.service.impl;
|
package com.unis.crm.service.impl;
|
||||||
|
|
||||||
import com.unis.crm.common.BusinessException;
|
import com.unis.crm.common.BusinessException;
|
||||||
|
import com.unis.crm.common.UnauthorizedException;
|
||||||
import com.unis.crm.dto.expansion.ChannelExpansionItemDTO;
|
import com.unis.crm.dto.expansion.ChannelExpansionItemDTO;
|
||||||
import com.unis.crm.dto.expansion.ChannelExpansionContactRequest;
|
import com.unis.crm.dto.expansion.ChannelExpansionContactRequest;
|
||||||
import com.unis.crm.dto.expansion.ChannelRelatedProjectSummaryDTO;
|
import com.unis.crm.dto.expansion.ChannelRelatedProjectSummaryDTO;
|
||||||
|
|
@ -18,6 +19,7 @@ import com.unis.crm.dto.expansion.UpdateChannelExpansionRequest;
|
||||||
import com.unis.crm.dto.expansion.UpdateSalesExpansionRequest;
|
import com.unis.crm.dto.expansion.UpdateSalesExpansionRequest;
|
||||||
import com.unis.crm.mapper.ExpansionMapper;
|
import com.unis.crm.mapper.ExpansionMapper;
|
||||||
import com.unis.crm.service.ExpansionService;
|
import com.unis.crm.service.ExpansionService;
|
||||||
|
import com.unisbase.security.PermissionService;
|
||||||
import com.unisbase.security.SpringSecurityTenantProvider;
|
import com.unisbase.security.SpringSecurityTenantProvider;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
|
@ -47,16 +49,22 @@ public class ExpansionServiceImpl implements ExpansionService {
|
||||||
private static final String CERTIFICATION_LEVEL_TYPE_CODE = "tz_rzjb";
|
private static final String CERTIFICATION_LEVEL_TYPE_CODE = "tz_rzjb";
|
||||||
private static final String CHANNEL_ATTRIBUTE_TYPE_CODE = "tz_qdsx";
|
private static final String CHANNEL_ATTRIBUTE_TYPE_CODE = "tz_qdsx";
|
||||||
private static final String INTERNAL_ATTRIBUTE_TYPE_CODE = "tz_xhsnbsx";
|
private static final String INTERNAL_ATTRIBUTE_TYPE_CODE = "tz_xhsnbsx";
|
||||||
|
private static final String CREATE_PERMISSION = "expansion:create";
|
||||||
private static final String MULTI_VALUE_CUSTOM_PREFIX = "__custom__:";
|
private static final String MULTI_VALUE_CUSTOM_PREFIX = "__custom__:";
|
||||||
private static final DateTimeFormatter FOLLOW_UP_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
private static final DateTimeFormatter FOLLOW_UP_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||||
private static final Logger log = LoggerFactory.getLogger(ExpansionServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(ExpansionServiceImpl.class);
|
||||||
|
|
||||||
private final ExpansionMapper expansionMapper;
|
private final ExpansionMapper expansionMapper;
|
||||||
private final SpringSecurityTenantProvider tenantProvider;
|
private final SpringSecurityTenantProvider tenantProvider;
|
||||||
|
private final PermissionService permissionService;
|
||||||
|
|
||||||
public ExpansionServiceImpl(ExpansionMapper expansionMapper, SpringSecurityTenantProvider tenantProvider) {
|
public ExpansionServiceImpl(
|
||||||
|
ExpansionMapper expansionMapper,
|
||||||
|
SpringSecurityTenantProvider tenantProvider,
|
||||||
|
PermissionService permissionService) {
|
||||||
this.expansionMapper = expansionMapper;
|
this.expansionMapper = expansionMapper;
|
||||||
this.tenantProvider = tenantProvider;
|
this.tenantProvider = tenantProvider;
|
||||||
|
this.permissionService = permissionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -148,6 +156,7 @@ public class ExpansionServiceImpl implements ExpansionService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createSalesExpansion(Long userId, CreateSalesExpansionRequest request) {
|
public Long createSalesExpansion(Long userId, CreateSalesExpansionRequest request) {
|
||||||
|
requirePermission(CREATE_PERMISSION, "无权新增拓展");
|
||||||
fillSalesDefaults(request);
|
fillSalesDefaults(request);
|
||||||
ensureUniqueEmployeeNo(userId, request.getEmployeeNo(), null);
|
ensureUniqueEmployeeNo(userId, request.getEmployeeNo(), null);
|
||||||
expansionMapper.insertSalesExpansion(userId, request);
|
expansionMapper.insertSalesExpansion(userId, request);
|
||||||
|
|
@ -160,6 +169,7 @@ public class ExpansionServiceImpl implements ExpansionService {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Long createChannelExpansion(Long userId, CreateChannelExpansionRequest request) {
|
public Long createChannelExpansion(Long userId, CreateChannelExpansionRequest request) {
|
||||||
|
requirePermission(CREATE_PERMISSION, "无权新增拓展");
|
||||||
fillChannelDefaults(request);
|
fillChannelDefaults(request);
|
||||||
ensureUniqueChannelName(userId, request.getChannelName(), null);
|
ensureUniqueChannelName(userId, request.getChannelName(), null);
|
||||||
expansionMapper.insertChannelExpansion(userId, request);
|
expansionMapper.insertChannelExpansion(userId, request);
|
||||||
|
|
@ -675,4 +685,10 @@ public class ExpansionServiceImpl implements ExpansionService {
|
||||||
throw new BusinessException("无权操作该拓展记录");
|
throw new BusinessException("无权操作该拓展记录");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void requirePermission(String perm, String message) {
|
||||||
|
if (!permissionService.hasPermi(perm)) {
|
||||||
|
throw new UnauthorizedException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.unis.crm.common.BusinessException;
|
import com.unis.crm.common.BusinessException;
|
||||||
|
import com.unis.crm.common.UnauthorizedException;
|
||||||
import com.unis.crm.dto.opportunity.CurrentUserAccountDTO;
|
import com.unis.crm.dto.opportunity.CurrentUserAccountDTO;
|
||||||
import com.unis.crm.dto.opportunity.CreateOpportunityFollowUpRequest;
|
import com.unis.crm.dto.opportunity.CreateOpportunityFollowUpRequest;
|
||||||
import com.unis.crm.dto.opportunity.CreateOpportunityRequest;
|
import com.unis.crm.dto.opportunity.CreateOpportunityRequest;
|
||||||
|
|
@ -23,6 +24,7 @@ import com.unis.crm.mapper.OpportunityMapper;
|
||||||
import com.unis.crm.service.OmsClient;
|
import com.unis.crm.service.OmsClient;
|
||||||
import com.unis.crm.service.OpportunityService;
|
import com.unis.crm.service.OpportunityService;
|
||||||
import com.unisbase.dto.DataScopeRuleDTO;
|
import com.unisbase.dto.DataScopeRuleDTO;
|
||||||
|
import com.unisbase.security.PermissionService;
|
||||||
import com.unisbase.service.DataScopeService;
|
import com.unisbase.service.DataScopeService;
|
||||||
import com.unisbase.spi.UnisBaseTenantProvider;
|
import com.unisbase.spi.UnisBaseTenantProvider;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -50,6 +52,7 @@ public class OpportunityServiceImpl implements OpportunityService {
|
||||||
private static final String OPPORTUNITY_TYPE_CODE = "sj_jslx";
|
private static final String OPPORTUNITY_TYPE_CODE = "sj_jslx";
|
||||||
private static final String CONFIDENCE_TYPE_CODE = "sj_xmbwd";
|
private static final String CONFIDENCE_TYPE_CODE = "sj_xmbwd";
|
||||||
private static final String SYS_IS_TYPE_CODE = "sys_is";
|
private static final String SYS_IS_TYPE_CODE = "sys_is";
|
||||||
|
private static final String CREATE_PERMISSION = "opportunity:create";
|
||||||
private static final String ARCHIVED_OPPORTUNITY_EDIT_MESSAGE = "已签单商机不允许编辑";
|
private static final String ARCHIVED_OPPORTUNITY_EDIT_MESSAGE = "已签单商机不允许编辑";
|
||||||
private static final String ARCHIVED_OPPORTUNITY_PUSH_MESSAGE = "已签单商机不允许推送";
|
private static final String ARCHIVED_OPPORTUNITY_PUSH_MESSAGE = "已签单商机不允许推送";
|
||||||
private static final String REPORT_ATTACHMENT_METADATA_PREFIX = "[[WORK_REPORT_ATTACHMENTS]]";
|
private static final String REPORT_ATTACHMENT_METADATA_PREFIX = "[[WORK_REPORT_ATTACHMENTS]]";
|
||||||
|
|
@ -62,18 +65,21 @@ public class OpportunityServiceImpl implements OpportunityService {
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
private final DataScopeService dataScopeService;
|
private final DataScopeService dataScopeService;
|
||||||
private final UnisBaseTenantProvider tenantProvider;
|
private final UnisBaseTenantProvider tenantProvider;
|
||||||
|
private final PermissionService permissionService;
|
||||||
|
|
||||||
public OpportunityServiceImpl(
|
public OpportunityServiceImpl(
|
||||||
OpportunityMapper opportunityMapper,
|
OpportunityMapper opportunityMapper,
|
||||||
OmsClient omsClient,
|
OmsClient omsClient,
|
||||||
ObjectMapper objectMapper,
|
ObjectMapper objectMapper,
|
||||||
DataScopeService dataScopeService,
|
DataScopeService dataScopeService,
|
||||||
UnisBaseTenantProvider tenantProvider) {
|
UnisBaseTenantProvider tenantProvider,
|
||||||
|
PermissionService permissionService) {
|
||||||
this.opportunityMapper = opportunityMapper;
|
this.opportunityMapper = opportunityMapper;
|
||||||
this.omsClient = omsClient;
|
this.omsClient = omsClient;
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
this.dataScopeService = dataScopeService;
|
this.dataScopeService = dataScopeService;
|
||||||
this.tenantProvider = tenantProvider;
|
this.tenantProvider = tenantProvider;
|
||||||
|
this.permissionService = permissionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -169,6 +175,7 @@ public class OpportunityServiceImpl implements OpportunityService {
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Long createOpportunity(Long userId, CreateOpportunityRequest request) {
|
public Long createOpportunity(Long userId, CreateOpportunityRequest request) {
|
||||||
|
requirePermission(CREATE_PERMISSION, "无权新增商机");
|
||||||
fillDefaults(request);
|
fillDefaults(request);
|
||||||
Long customerId = resolveOrCreateOwnedCustomerId(userId, request.getCustomerName().trim(), request.getSource());
|
Long customerId = resolveOrCreateOwnedCustomerId(userId, request.getCustomerName().trim(), request.getSource());
|
||||||
|
|
||||||
|
|
@ -997,6 +1004,12 @@ public class OpportunityServiceImpl implements OpportunityService {
|
||||||
|| normalizedOperator.contains("dls");
|
|| normalizedOperator.contains("dls");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void requirePermission(String perm, String message) {
|
||||||
|
if (!permissionService.hasPermi(perm)) {
|
||||||
|
throw new UnauthorizedException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private OmsPreSalesOptionDTO resolveSelectedPreSales(
|
private OmsPreSalesOptionDTO resolveSelectedPreSales(
|
||||||
OpportunityOmsPushDataDTO pushData,
|
OpportunityOmsPushDataDTO pushData,
|
||||||
PushOpportunityToOmsRequest request,
|
PushOpportunityToOmsRequest request,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.unis.crm.common.BusinessException;
|
import com.unis.crm.common.BusinessException;
|
||||||
|
import com.unis.crm.common.UnauthorizedException;
|
||||||
import com.unis.crm.dto.expansion.ChannelExpansionContactRequest;
|
import com.unis.crm.dto.expansion.ChannelExpansionContactRequest;
|
||||||
import com.unis.crm.dto.expansion.CreateChannelExpansionRequest;
|
import com.unis.crm.dto.expansion.CreateChannelExpansionRequest;
|
||||||
import com.unis.crm.dto.expansion.CreateSalesExpansionRequest;
|
import com.unis.crm.dto.expansion.CreateSalesExpansionRequest;
|
||||||
|
|
@ -17,6 +18,7 @@ import com.unis.crm.dto.expansion.SalesExpansionItemDTO;
|
||||||
import com.unis.crm.dto.expansion.UpdateChannelExpansionRequest;
|
import com.unis.crm.dto.expansion.UpdateChannelExpansionRequest;
|
||||||
import com.unis.crm.dto.expansion.UpdateSalesExpansionRequest;
|
import com.unis.crm.dto.expansion.UpdateSalesExpansionRequest;
|
||||||
import com.unis.crm.mapper.ExpansionMapper;
|
import com.unis.crm.mapper.ExpansionMapper;
|
||||||
|
import com.unisbase.security.PermissionService;
|
||||||
import com.unisbase.security.SpringSecurityTenantProvider;
|
import com.unisbase.security.SpringSecurityTenantProvider;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
@ -36,12 +38,16 @@ class ExpansionServiceImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
private SpringSecurityTenantProvider tenantProvider;
|
private SpringSecurityTenantProvider tenantProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PermissionService permissionService;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private ExpansionServiceImpl expansionService;
|
private ExpansionServiceImpl expansionService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createSalesExpansion_shouldRejectDuplicateEmployeeNo() {
|
void createSalesExpansion_shouldRejectDuplicateEmployeeNo() {
|
||||||
CreateSalesExpansionRequest request = buildCreateSalesRequest();
|
CreateSalesExpansionRequest request = buildCreateSalesRequest();
|
||||||
|
when(permissionService.hasPermi("expansion:create")).thenReturn(true);
|
||||||
when(expansionMapper.countSalesExpansionByEmployeeNo("EMP001")).thenReturn(1);
|
when(expansionMapper.countSalesExpansionByEmployeeNo("EMP001")).thenReturn(1);
|
||||||
|
|
||||||
BusinessException exception = assertThrows(
|
BusinessException exception = assertThrows(
|
||||||
|
|
@ -52,6 +58,19 @@ class ExpansionServiceImplTest {
|
||||||
verify(expansionMapper, never()).insertSalesExpansion(any(), any());
|
verify(expansionMapper, never()).insertSalesExpansion(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createSalesExpansion_shouldRejectWhenPermissionMissing() {
|
||||||
|
CreateSalesExpansionRequest request = buildCreateSalesRequest();
|
||||||
|
when(permissionService.hasPermi("expansion:create")).thenReturn(false);
|
||||||
|
|
||||||
|
UnauthorizedException exception = assertThrows(
|
||||||
|
UnauthorizedException.class,
|
||||||
|
() -> expansionService.createSalesExpansion(1L, request));
|
||||||
|
|
||||||
|
assertEquals("无权新增拓展", exception.getMessage());
|
||||||
|
verify(expansionMapper, never()).insertSalesExpansion(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateSalesExpansion_shouldSkipDuplicateEmployeeNoCheck() {
|
void updateSalesExpansion_shouldSkipDuplicateEmployeeNoCheck() {
|
||||||
UpdateSalesExpansionRequest request = buildUpdateSalesRequest();
|
UpdateSalesExpansionRequest request = buildUpdateSalesRequest();
|
||||||
|
|
@ -67,6 +86,7 @@ class ExpansionServiceImplTest {
|
||||||
@Test
|
@Test
|
||||||
void createChannelExpansion_shouldRejectDuplicateChannelName() {
|
void createChannelExpansion_shouldRejectDuplicateChannelName() {
|
||||||
CreateChannelExpansionRequest request = buildCreateChannelRequest();
|
CreateChannelExpansionRequest request = buildCreateChannelRequest();
|
||||||
|
when(permissionService.hasPermi("expansion:create")).thenReturn(true);
|
||||||
when(expansionMapper.countChannelExpansionByChannelName("渠道A")).thenReturn(1);
|
when(expansionMapper.countChannelExpansionByChannelName("渠道A")).thenReturn(1);
|
||||||
|
|
||||||
BusinessException exception = assertThrows(
|
BusinessException exception = assertThrows(
|
||||||
|
|
@ -77,6 +97,19 @@ class ExpansionServiceImplTest {
|
||||||
verify(expansionMapper, never()).insertChannelExpansion(any(), any());
|
verify(expansionMapper, never()).insertChannelExpansion(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createChannelExpansion_shouldRejectWhenPermissionMissing() {
|
||||||
|
CreateChannelExpansionRequest request = buildCreateChannelRequest();
|
||||||
|
when(permissionService.hasPermi("expansion:create")).thenReturn(false);
|
||||||
|
|
||||||
|
UnauthorizedException exception = assertThrows(
|
||||||
|
UnauthorizedException.class,
|
||||||
|
() -> expansionService.createChannelExpansion(1L, request));
|
||||||
|
|
||||||
|
assertEquals("无权新增拓展", exception.getMessage());
|
||||||
|
verify(expansionMapper, never()).insertChannelExpansion(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateChannelExpansion_shouldSkipDuplicateChannelNameCheck() {
|
void updateChannelExpansion_shouldSkipDuplicateChannelNameCheck() {
|
||||||
UpdateChannelExpansionRequest request = buildUpdateChannelRequest();
|
UpdateChannelExpansionRequest request = buildUpdateChannelRequest();
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.unis.crm.common.BusinessException;
|
import com.unis.crm.common.BusinessException;
|
||||||
|
import com.unis.crm.common.UnauthorizedException;
|
||||||
import com.unis.crm.dto.opportunity.CurrentUserAccountDTO;
|
import com.unis.crm.dto.opportunity.CurrentUserAccountDTO;
|
||||||
import com.unis.crm.dto.opportunity.CreateOpportunityRequest;
|
import com.unis.crm.dto.opportunity.CreateOpportunityRequest;
|
||||||
import com.unis.crm.dto.opportunity.OmsPreSalesOptionDTO;
|
import com.unis.crm.dto.opportunity.OmsPreSalesOptionDTO;
|
||||||
|
|
@ -24,6 +25,7 @@ import com.unis.crm.dto.opportunity.UpdateOpportunityIntegrationRequest;
|
||||||
import com.unis.crm.mapper.OpportunityMapper;
|
import com.unis.crm.mapper.OpportunityMapper;
|
||||||
import com.unis.crm.service.OmsClient;
|
import com.unis.crm.service.OmsClient;
|
||||||
import com.unisbase.dto.DataScopeRuleDTO;
|
import com.unisbase.dto.DataScopeRuleDTO;
|
||||||
|
import com.unisbase.security.PermissionService;
|
||||||
import com.unisbase.service.DataScopeService;
|
import com.unisbase.service.DataScopeService;
|
||||||
import com.unisbase.spi.UnisBaseTenantProvider;
|
import com.unisbase.spi.UnisBaseTenantProvider;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
@ -53,6 +55,9 @@ class OpportunityServiceImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
private UnisBaseTenantProvider tenantProvider;
|
private UnisBaseTenantProvider tenantProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PermissionService permissionService;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private OpportunityServiceImpl opportunityService;
|
private OpportunityServiceImpl opportunityService;
|
||||||
|
|
||||||
|
|
@ -84,6 +89,7 @@ class OpportunityServiceImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createOpportunity_shouldRejectWhenCustomerDoesNotExist() {
|
void createOpportunity_shouldRejectWhenCustomerDoesNotExist() {
|
||||||
|
when(permissionService.hasPermi("opportunity:create")).thenReturn(true);
|
||||||
when(opportunityMapper.selectOwnedCustomerIdByName(1L, "客户A")).thenReturn(null);
|
when(opportunityMapper.selectOwnedCustomerIdByName(1L, "客户A")).thenReturn(null);
|
||||||
when(opportunityMapper.insertOpportunity(eq(1L), any(), any(CreateOpportunityRequest.class))).thenAnswer(invocation -> {
|
when(opportunityMapper.insertOpportunity(eq(1L), any(), any(CreateOpportunityRequest.class))).thenAnswer(invocation -> {
|
||||||
CreateOpportunityRequest request = invocation.getArgument(2);
|
CreateOpportunityRequest request = invocation.getArgument(2);
|
||||||
|
|
@ -102,6 +108,18 @@ class OpportunityServiceImplTest {
|
||||||
verify(opportunityMapper).insertCustomer(any(), eq(1L), eq("客户A"), any());
|
verify(opportunityMapper).insertCustomer(any(), eq(1L), eq("客户A"), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createOpportunity_shouldRejectWhenPermissionMissing() {
|
||||||
|
when(permissionService.hasPermi("opportunity:create")).thenReturn(false);
|
||||||
|
|
||||||
|
UnauthorizedException exception = assertThrows(
|
||||||
|
UnauthorizedException.class,
|
||||||
|
() -> opportunityService.createOpportunity(1L, updateRequest("客户A")));
|
||||||
|
|
||||||
|
assertEquals("无权新增商机", exception.getMessage());
|
||||||
|
verify(opportunityMapper, never()).insertOpportunity(any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateOpportunity_shouldKeepCurrentCustomerWhenCustomerNameUnchanged() {
|
void updateOpportunity_shouldKeepCurrentCustomerWhenCustomerNameUnchanged() {
|
||||||
when(opportunityMapper.countOwnedOpportunity(1L, 10L)).thenReturn(1);
|
when(opportunityMapper.countOwnedOpportunity(1L, 10L)).thenReturn(1);
|
||||||
|
|
@ -172,6 +190,7 @@ class OpportunityServiceImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createOpportunity_shouldPersistEditableSnapshotFields() {
|
void createOpportunity_shouldPersistEditableSnapshotFields() {
|
||||||
|
when(permissionService.hasPermi("opportunity:create")).thenReturn(true);
|
||||||
when(opportunityMapper.selectOwnedCustomerIdByName(1L, "客户A")).thenReturn(200L);
|
when(opportunityMapper.selectOwnedCustomerIdByName(1L, "客户A")).thenReturn(200L);
|
||||||
when(opportunityMapper.insertOpportunity(eq(1L), eq(200L), any(CreateOpportunityRequest.class))).thenAnswer(invocation -> {
|
when(opportunityMapper.insertOpportunity(eq(1L), eq(200L), any(CreateOpportunityRequest.class))).thenAnswer(invocation -> {
|
||||||
CreateOpportunityRequest request = invocation.getArgument(2);
|
CreateOpportunityRequest request = invocation.getArgument(2);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,16 @@ export interface UserRole {
|
||||||
roleName?: string;
|
roleName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserPermission {
|
||||||
|
permId?: number;
|
||||||
|
parentId?: number;
|
||||||
|
name?: string;
|
||||||
|
code: string;
|
||||||
|
permType?: string;
|
||||||
|
status?: number;
|
||||||
|
isVisible?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AdminUserSummary {
|
export interface AdminUserSummary {
|
||||||
userId: number;
|
userId: number;
|
||||||
username: string;
|
username: string;
|
||||||
|
|
@ -808,6 +818,7 @@ const LOGIN_PATH = "/login";
|
||||||
const USER_CONTEXT_CACHE_TTL_MS = 2 * 60 * 1000;
|
const USER_CONTEXT_CACHE_TTL_MS = 2 * 60 * 1000;
|
||||||
const CURRENT_USER_CACHE_KEY = "auth-cache:current-user";
|
const CURRENT_USER_CACHE_KEY = "auth-cache:current-user";
|
||||||
const PROFILE_OVERVIEW_CACHE_KEY = "auth-cache:profile-overview";
|
const PROFILE_OVERVIEW_CACHE_KEY = "auth-cache:profile-overview";
|
||||||
|
const MY_PERMISSIONS_CACHE_KEY = "auth-cache:my-permissions";
|
||||||
const memoryRequestCache = new Map<string, { expiresAt: number; value: unknown }>();
|
const memoryRequestCache = new Map<string, { expiresAt: number; value: unknown }>();
|
||||||
const inFlightRequestCache = new Map<string, Promise<unknown>>();
|
const inFlightRequestCache = new Map<string, Promise<unknown>>();
|
||||||
let authExpiryTimer: number | null = null;
|
let authExpiryTimer: number | null = null;
|
||||||
|
|
@ -1235,6 +1246,29 @@ export async function refreshCurrentUser() {
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function listMyPermissions() {
|
||||||
|
return getCachedAuthedRequest<UserPermission[]>(
|
||||||
|
MY_PERMISSIONS_CACHE_KEY,
|
||||||
|
() => request<UserPermission[]>("/api/sys/api/permissions/me", undefined, true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canUsePermission(perm: string, codes: string[]) {
|
||||||
|
if (!perm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!codes.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasMenuCodes = codes.some((code) => code.startsWith("menu:"));
|
||||||
|
const hasButtonCodes = codes.some((code) => !code.startsWith("menu:") && code.includes(":"));
|
||||||
|
if (perm.startsWith("menu:")) {
|
||||||
|
return !hasMenuCodes || codes.includes(perm);
|
||||||
|
}
|
||||||
|
return !hasButtonCodes || codes.includes(perm);
|
||||||
|
}
|
||||||
|
|
||||||
export async function getDashboardHome() {
|
export async function getDashboardHome() {
|
||||||
return request<DashboardHome>("/api/dashboard/home", undefined, true);
|
return request<DashboardHome>("/api/dashboard/home", undefined, true);
|
||||||
}
|
}
|
||||||
|
|
@ -1650,7 +1684,7 @@ function writeCachedValue<T>(cacheKey: string, value: T, ttlMs = USER_CONTEXT_CA
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearCachedAuthContext() {
|
function clearCachedAuthContext() {
|
||||||
[CURRENT_USER_CACHE_KEY, PROFILE_OVERVIEW_CACHE_KEY].forEach((cacheKey) => {
|
[CURRENT_USER_CACHE_KEY, PROFILE_OVERVIEW_CACHE_KEY, MY_PERMISSIONS_CACHE_KEY].forEach((cacheKey) => {
|
||||||
memoryRequestCache.delete(cacheKey);
|
memoryRequestCache.delete(cacheKey);
|
||||||
inFlightRequestCache.delete(cacheKey);
|
inFlightRequestCache.delete(cacheKey);
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Search, Plus, Download, MapPin, Building2, User, Phone, X, Clock, FileT
|
||||||
import { motion, AnimatePresence } from "motion/react";
|
import { motion, AnimatePresence } from "motion/react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
|
canUsePermission,
|
||||||
checkChannelExpansionDuplicate,
|
checkChannelExpansionDuplicate,
|
||||||
checkSalesExpansionDuplicate,
|
checkSalesExpansionDuplicate,
|
||||||
createChannelExpansion,
|
createChannelExpansion,
|
||||||
|
|
@ -13,6 +14,7 @@ import {
|
||||||
getExpansionOverview,
|
getExpansionOverview,
|
||||||
getOpportunityMeta,
|
getOpportunityMeta,
|
||||||
getStoredCurrentUserId,
|
getStoredCurrentUserId,
|
||||||
|
listMyPermissions,
|
||||||
updateChannelExpansion,
|
updateChannelExpansion,
|
||||||
updateSalesExpansion,
|
updateSalesExpansion,
|
||||||
type ChannelExpansionContact,
|
type ChannelExpansionContact,
|
||||||
|
|
@ -138,6 +140,7 @@ function createEmptyChannelContact(): ChannelExpansionContact {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHANNEL_REVENUE_LABEL = "年度营业额(万元)";
|
const CHANNEL_REVENUE_LABEL = "年度营业额(万元)";
|
||||||
|
const EXPANSION_CREATE_PERMISSION = "expansion:create";
|
||||||
const EXPANSION_EXPORT_PREFERENCES_STORAGE_KEY = "crm:expansion-export-preferences";
|
const EXPANSION_EXPORT_PREFERENCES_STORAGE_KEY = "crm:expansion-export-preferences";
|
||||||
|
|
||||||
const defaultSalesForm: CreateSalesExpansionPayload = {
|
const defaultSalesForm: CreateSalesExpansionPayload = {
|
||||||
|
|
@ -1353,6 +1356,7 @@ export default function Expansion() {
|
||||||
const [exporting, setExporting] = useState(false);
|
const [exporting, setExporting] = useState(false);
|
||||||
const [exportFilterOpen, setExportFilterOpen] = useState(false);
|
const [exportFilterOpen, setExportFilterOpen] = useState(false);
|
||||||
const [exportFilters, setExportFilters] = useState<ExpansionExportFilters>(() => loadExpansionExportPreferences());
|
const [exportFilters, setExportFilters] = useState<ExpansionExportFilters>(() => loadExpansionExportPreferences());
|
||||||
|
const [permissionCodes, setPermissionCodes] = useState<string[] | null>(null);
|
||||||
const [salesDuplicateChecking, setSalesDuplicateChecking] = useState(false);
|
const [salesDuplicateChecking, setSalesDuplicateChecking] = useState(false);
|
||||||
const [channelDuplicateChecking, setChannelDuplicateChecking] = useState(false);
|
const [channelDuplicateChecking, setChannelDuplicateChecking] = useState(false);
|
||||||
const [createError, setCreateError] = useState("");
|
const [createError, setCreateError] = useState("");
|
||||||
|
|
@ -1375,6 +1379,7 @@ export default function Expansion() {
|
||||||
const [editSalesForm, setEditSalesForm] = useState<CreateSalesExpansionPayload>(defaultSalesForm);
|
const [editSalesForm, setEditSalesForm] = useState<CreateSalesExpansionPayload>(defaultSalesForm);
|
||||||
const [editChannelForm, setEditChannelForm] = useState<CreateChannelExpansionPayload>(defaultChannelForm);
|
const [editChannelForm, setEditChannelForm] = useState<CreateChannelExpansionPayload>(defaultChannelForm);
|
||||||
const hasForegroundModal = createOpen || editOpen || exportFilterOpen;
|
const hasForegroundModal = createOpen || editOpen || exportFilterOpen;
|
||||||
|
const canCreateExpansion = permissionCodes !== null && canUsePermission(EXPANSION_CREATE_PERMISSION, permissionCodes);
|
||||||
|
|
||||||
const loadMeta = useCallback(async () => {
|
const loadMeta = useCallback(async () => {
|
||||||
const data = await getExpansionMeta();
|
const data = await getExpansionMeta();
|
||||||
|
|
@ -1388,6 +1393,33 @@ export default function Expansion() {
|
||||||
return data;
|
return data;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
async function loadPermissions() {
|
||||||
|
try {
|
||||||
|
const permissions = await listMyPermissions();
|
||||||
|
if (!cancelled) {
|
||||||
|
setPermissionCodes(
|
||||||
|
permissions
|
||||||
|
.filter((permission) => permission.status !== 0)
|
||||||
|
.map((permission) => permission.code)
|
||||||
|
.filter(Boolean),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
if (!cancelled) {
|
||||||
|
setPermissionCodes(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadPermissions();
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
|
|
@ -2516,13 +2548,15 @@ export default function Expansion() {
|
||||||
<Download className="crm-icon-md" />
|
<Download className="crm-icon-md" />
|
||||||
<span className="hidden sm:inline">{exporting ? "导出中..." : "导出"}</span>
|
<span className="hidden sm:inline">{exporting ? "导出中..." : "导出"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
{canCreateExpansion ? (
|
||||||
onClick={handleOpenCreate}
|
<button
|
||||||
className={cn("crm-btn-sm crm-btn-primary flex items-center gap-2", disableMobileMotion ? "active:scale-100" : "active:scale-95")}
|
onClick={handleOpenCreate}
|
||||||
>
|
className={cn("crm-btn-sm crm-btn-primary flex items-center gap-2", disableMobileMotion ? "active:scale-100" : "active:scale-95")}
|
||||||
<Plus className="crm-icon-md" />
|
>
|
||||||
<span className="hidden sm:inline">新增</span>
|
<Plus className="crm-icon-md" />
|
||||||
</button>
|
<span className="hidden sm:inline">新增</span>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { useLocation } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
checkChannelExpansionDuplicate,
|
checkChannelExpansionDuplicate,
|
||||||
checkSalesExpansionDuplicate,
|
checkSalesExpansionDuplicate,
|
||||||
|
canUsePermission,
|
||||||
createChannelExpansion,
|
createChannelExpansion,
|
||||||
createOpportunity,
|
createOpportunity,
|
||||||
createSalesExpansion,
|
createSalesExpansion,
|
||||||
|
|
@ -17,6 +18,7 @@ import {
|
||||||
getOpportunityOmsPreSalesOptions,
|
getOpportunityOmsPreSalesOptions,
|
||||||
getOpportunityOverview,
|
getOpportunityOverview,
|
||||||
getStoredCurrentUserId,
|
getStoredCurrentUserId,
|
||||||
|
listMyPermissions,
|
||||||
pushOpportunityToOms,
|
pushOpportunityToOms,
|
||||||
updateOpportunity,
|
updateOpportunity,
|
||||||
type ChannelExpansionContact,
|
type ChannelExpansionContact,
|
||||||
|
|
@ -68,6 +70,7 @@ const OPPORTUNITY_EXPANSION_OPTION_LIMIT = 20;
|
||||||
const OPPORTUNITY_EXPANSION_SEARCH_DEBOUNCE_MS = 300;
|
const OPPORTUNITY_EXPANSION_SEARCH_DEBOUNCE_MS = 300;
|
||||||
const OPPORTUNITY_NEXT_PLAN_LABEL = "下一步销售计划";
|
const OPPORTUNITY_NEXT_PLAN_LABEL = "下一步销售计划";
|
||||||
const LEGACY_OPPORTUNITY_NEXT_PLAN_LABEL = "后续规划";
|
const LEGACY_OPPORTUNITY_NEXT_PLAN_LABEL = "后续规划";
|
||||||
|
const OPPORTUNITY_CREATE_PERMISSION = "opportunity:create";
|
||||||
const OPPORTUNITY_EXPORT_PREFERENCES_STORAGE_KEY = "crm:opportunity-export-preferences";
|
const OPPORTUNITY_EXPORT_PREFERENCES_STORAGE_KEY = "crm:opportunity-export-preferences";
|
||||||
|
|
||||||
const COMPETITOR_OPTIONS = [
|
const COMPETITOR_OPTIONS = [
|
||||||
|
|
@ -1854,6 +1857,7 @@ export default function Opportunities() {
|
||||||
const [exporting, setExporting] = useState(false);
|
const [exporting, setExporting] = useState(false);
|
||||||
const [exportFilterOpen, setExportFilterOpen] = useState(false);
|
const [exportFilterOpen, setExportFilterOpen] = useState(false);
|
||||||
const [exportFilters, setExportFilters] = useState<OpportunityExportFilters>(() => loadOpportunityExportPreferences());
|
const [exportFilters, setExportFilters] = useState<OpportunityExportFilters>(() => loadOpportunityExportPreferences());
|
||||||
|
const [permissionCodes, setPermissionCodes] = useState<string[] | null>(null);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [exportError, setExportError] = useState("");
|
const [exportError, setExportError] = useState("");
|
||||||
const [items, setItems] = useState<OpportunityItem[]>([]);
|
const [items, setItems] = useState<OpportunityItem[]>([]);
|
||||||
|
|
@ -1898,12 +1902,40 @@ export default function Opportunities() {
|
||||||
const [loadingChannelExpansionOptions, setLoadingChannelExpansionOptions] = useState(false);
|
const [loadingChannelExpansionOptions, setLoadingChannelExpansionOptions] = useState(false);
|
||||||
const hasLoadedOpportunityExpansionOptionsRef = useRef(false);
|
const hasLoadedOpportunityExpansionOptionsRef = useRef(false);
|
||||||
const hasForegroundModal = createOpen || editOpen || pushConfirmOpen || exportFilterOpen || quickCreateOpen;
|
const hasForegroundModal = createOpen || editOpen || pushConfirmOpen || exportFilterOpen || quickCreateOpen;
|
||||||
|
const canCreateOpportunity = permissionCodes !== null && canUsePermission(OPPORTUNITY_CREATE_PERMISSION, permissionCodes);
|
||||||
|
|
||||||
const fetchOpportunityExpansionOptions = async (query?: string) => getOpportunityExpansionOptions({
|
const fetchOpportunityExpansionOptions = async (query?: string) => getOpportunityExpansionOptions({
|
||||||
keyword: query,
|
keyword: query,
|
||||||
limit: OPPORTUNITY_EXPANSION_OPTION_LIMIT,
|
limit: OPPORTUNITY_EXPANSION_OPTION_LIMIT,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
async function loadPermissions() {
|
||||||
|
try {
|
||||||
|
const permissions = await listMyPermissions();
|
||||||
|
if (!cancelled) {
|
||||||
|
setPermissionCodes(
|
||||||
|
permissions
|
||||||
|
.filter((permission) => permission.status !== 0)
|
||||||
|
.map((permission) => permission.code)
|
||||||
|
.filter(Boolean),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
if (!cancelled) {
|
||||||
|
setPermissionCodes(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadPermissions();
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
|
|
@ -2867,13 +2899,15 @@ export default function Opportunities() {
|
||||||
<Download className="crm-icon-md" />
|
<Download className="crm-icon-md" />
|
||||||
<span className="hidden sm:inline">{exporting ? "导出中..." : "导出"}</span>
|
<span className="hidden sm:inline">{exporting ? "导出中..." : "导出"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
{canCreateOpportunity ? (
|
||||||
onClick={handleOpenCreate}
|
<button
|
||||||
className={cn("crm-btn-sm crm-btn-primary flex items-center gap-2", disableMobileMotion ? "active:scale-100" : "active:scale-95")}
|
onClick={handleOpenCreate}
|
||||||
>
|
className={cn("crm-btn-sm crm-btn-primary flex items-center gap-2", disableMobileMotion ? "active:scale-100" : "active:scale-95")}
|
||||||
<Plus className="crm-icon-md" />
|
>
|
||||||
<span className="hidden sm:inline">新增商机</span>
|
<Plus className="crm-icon-md" />
|
||||||
</button>
|
<span className="hidden sm:inline">新增商机</span>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>UnisBase - 智能会议系统</title>
|
<title>UnisBase - 智能会议系统</title>
|
||||||
<script type="module" crossorigin src="/assets/index-CibjLtv7.js"></script>
|
<script type="module" crossorigin src="/assets/index-DNoKV8lp.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CaWPk49l.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CaWPk49l.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,12 @@ function isPlatformOnlyMenu(item: SysPermission) {
|
||||||
|| item.path === "/platform-settings";
|
|| item.path === "/platform-settings";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPermissionOnlyMenu(item: SysPermission) {
|
||||||
|
return item.code === "crm"
|
||||||
|
|| item.code === "menu:expansion"
|
||||||
|
|| item.code === "menu:opportunities";
|
||||||
|
}
|
||||||
|
|
||||||
function resolveSelectedMenuPath(pathname: string): string {
|
function resolveSelectedMenuPath(pathname: string): string {
|
||||||
if (pathname.startsWith("/dashboard-analytics-settings/cards/")) {
|
if (pathname.startsWith("/dashboard-analytics-settings/cards/")) {
|
||||||
return "/dashboard-analytics-settings";
|
return "/dashboard-analytics-settings";
|
||||||
|
|
@ -143,6 +149,7 @@ export default function AppLayout() {
|
||||||
|
|
||||||
const filtered = data
|
const filtered = data
|
||||||
.filter((item) => isPlatformMode || !isPlatformOnlyMenu(item))
|
.filter((item) => isPlatformMode || !isPlatformOnlyMenu(item))
|
||||||
|
.filter((item) => !isPermissionOnlyMenu(item))
|
||||||
.filter((item) => (item.permType === "menu" || item.permType === "directory") && item.isVisible === 1 && item.status === 1)
|
.filter((item) => (item.permType === "menu" || item.permType === "directory") && item.isVisible === 1 && item.status === 1)
|
||||||
.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0));
|
.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0));
|
||||||
setMenus(filtered);
|
setMenus(filtered);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
-- 20260630
|
||||||
|
-- 修复/补齐前台拓展管理“新增”按钮权限点:expansion:create
|
||||||
|
-- 执行后可在 frontend1 角色管理的功能权限树中看到:CRM业务 / 拓展 / 新增拓展。
|
||||||
|
-- 可重复执行;CRM业务与拓展节点仅用于权限管理,不在后台侧边栏显示。
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to public;
|
||||||
|
|
||||||
|
do $$
|
||||||
|
declare
|
||||||
|
v_business_parent_id bigint;
|
||||||
|
v_expansion_menu_perm_id bigint;
|
||||||
|
v_expansion_create_perm_id bigint;
|
||||||
|
v_has_role_permission_tenant boolean;
|
||||||
|
begin
|
||||||
|
perform setval('sys_permission_perm_id_seq', coalesce((select max(perm_id) from sys_permission), 0) + 1, false);
|
||||||
|
perform setval('sys_role_permission_id_seq', coalesce((select max(id) from sys_role_permission), 0) + 1, false);
|
||||||
|
|
||||||
|
select exists (
|
||||||
|
select 1
|
||||||
|
from information_schema.columns
|
||||||
|
where table_schema = current_schema()
|
||||||
|
and table_name = 'sys_role_permission'
|
||||||
|
and column_name = 'tenant_id'
|
||||||
|
) into v_has_role_permission_tenant;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_business_parent_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'crm'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_business_parent_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
null, 'CRM业务', 'crm', 'directory', 1, null, null, 'AppstoreOutlined',
|
||||||
|
10, 0, 1, 'CRM前台业务权限分组,仅用于权限管理,不在后台侧边栏显示', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_business_parent_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set name = 'CRM业务',
|
||||||
|
perm_type = 'directory',
|
||||||
|
level = 1,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = coalesce(nullif(icon, ''), 'AppstoreOutlined'),
|
||||||
|
sort_order = coalesce(sort_order, 10),
|
||||||
|
is_visible = 0,
|
||||||
|
status = 1,
|
||||||
|
description = 'CRM前台业务权限分组,仅用于权限管理,不在后台侧边栏显示',
|
||||||
|
meta = coalesce(meta, '{}'::jsonb),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_business_parent_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_expansion_menu_perm_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'menu:expansion'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_expansion_menu_perm_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
v_business_parent_id, '拓展', 'menu:expansion', 'menu', 2,
|
||||||
|
null, null, 'TeamOutlined', 20, 0, 1,
|
||||||
|
'CRM前台拓展管理页面权限分组,仅用于权限管理,不在后台侧边栏显示', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_expansion_menu_perm_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set parent_id = v_business_parent_id,
|
||||||
|
name = '拓展',
|
||||||
|
perm_type = 'menu',
|
||||||
|
level = 2,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = coalesce(nullif(icon, ''), 'TeamOutlined'),
|
||||||
|
sort_order = coalesce(sort_order, 20),
|
||||||
|
is_visible = 0,
|
||||||
|
status = 1,
|
||||||
|
description = 'CRM前台拓展管理页面权限分组,仅用于权限管理,不在后台侧边栏显示',
|
||||||
|
meta = coalesce(meta, '{}'::jsonb),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_expansion_menu_perm_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_expansion_create_perm_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'expansion:create'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_expansion_create_perm_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
v_expansion_menu_perm_id, '新增拓展', 'expansion:create', 'button', 3,
|
||||||
|
null, null, null, 1, 1, 1, '控制CRM前台拓展管理页面的新增按钮和销售/渠道拓展创建接口', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_expansion_create_perm_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set parent_id = v_expansion_menu_perm_id,
|
||||||
|
name = '新增拓展',
|
||||||
|
perm_type = 'button',
|
||||||
|
level = 3,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = null,
|
||||||
|
sort_order = 1,
|
||||||
|
is_visible = 1,
|
||||||
|
status = 1,
|
||||||
|
description = '控制CRM前台拓展管理页面的新增按钮和销售/渠道拓展创建接口',
|
||||||
|
meta = '{}'::jsonb,
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_expansion_create_perm_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if v_has_role_permission_tenant then
|
||||||
|
insert into sys_role_permission (role_id, perm_id, tenant_id, is_deleted, created_at, updated_at)
|
||||||
|
select distinct r.role_id, permission_source.perm_id, r.tenant_id, 0, now(), now()
|
||||||
|
from sys_role r
|
||||||
|
cross join (
|
||||||
|
select unnest(array[v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id]) as perm_id
|
||||||
|
) permission_source
|
||||||
|
where coalesce(r.is_deleted, 0) = 0
|
||||||
|
and permission_source.perm_id is not null
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
)
|
||||||
|
and not exists (
|
||||||
|
select 1
|
||||||
|
from sys_role_permission rp
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id = permission_source.perm_id
|
||||||
|
);
|
||||||
|
|
||||||
|
update sys_role_permission rp
|
||||||
|
set tenant_id = coalesce(rp.tenant_id, r.tenant_id),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
from sys_role r
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id in (v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id)
|
||||||
|
and coalesce(r.is_deleted, 0) = 0
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
);
|
||||||
|
else
|
||||||
|
insert into sys_role_permission (role_id, perm_id, is_deleted, created_at, updated_at)
|
||||||
|
select distinct r.role_id, permission_source.perm_id, 0, now(), now()
|
||||||
|
from sys_role r
|
||||||
|
cross join (
|
||||||
|
select unnest(array[v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id]) as perm_id
|
||||||
|
) permission_source
|
||||||
|
where coalesce(r.is_deleted, 0) = 0
|
||||||
|
and permission_source.perm_id is not null
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
)
|
||||||
|
and not exists (
|
||||||
|
select 1
|
||||||
|
from sys_role_permission rp
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id = permission_source.perm_id
|
||||||
|
);
|
||||||
|
|
||||||
|
update sys_role_permission rp
|
||||||
|
set is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
from sys_role r
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id in (v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id)
|
||||||
|
and coalesce(r.is_deleted, 0) = 0
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
);
|
||||||
|
end if;
|
||||||
|
end $$;
|
||||||
|
|
||||||
|
commit;
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
-- 20260630
|
||||||
|
-- 新增前台业务按钮权限点:
|
||||||
|
-- opportunity:create 新增商机
|
||||||
|
-- expansion:create 新增拓展
|
||||||
|
-- 执行后可在 frontend1 权限管理与角色权限绑定中维护这些权限。
|
||||||
|
-- 可重复执行;已执行过旧版本的环境,重新执行本脚本会修复父子关系和管理员授权。
|
||||||
|
|
||||||
|
begin;
|
||||||
|
|
||||||
|
set search_path to public;
|
||||||
|
|
||||||
|
do $$
|
||||||
|
declare
|
||||||
|
v_business_parent_id bigint;
|
||||||
|
v_expansion_menu_perm_id bigint;
|
||||||
|
v_expansion_create_perm_id bigint;
|
||||||
|
v_menu_perm_id bigint;
|
||||||
|
v_create_perm_id bigint;
|
||||||
|
v_has_role_permission_tenant boolean;
|
||||||
|
begin
|
||||||
|
perform setval('sys_permission_perm_id_seq', coalesce((select max(perm_id) from sys_permission), 0) + 1, false);
|
||||||
|
perform setval('sys_role_permission_id_seq', coalesce((select max(id) from sys_role_permission), 0) + 1, false);
|
||||||
|
|
||||||
|
select exists (
|
||||||
|
select 1
|
||||||
|
from information_schema.columns
|
||||||
|
where table_schema = current_schema()
|
||||||
|
and table_name = 'sys_role_permission'
|
||||||
|
and column_name = 'tenant_id'
|
||||||
|
) into v_has_role_permission_tenant;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_business_parent_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'crm'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_business_parent_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
null, 'CRM业务', 'crm', 'directory', 1, null, null, 'AppstoreOutlined',
|
||||||
|
10, 0, 1, 'CRM前台业务权限分组,仅用于权限管理,不在后台侧边栏显示', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_business_parent_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set name = 'CRM业务',
|
||||||
|
perm_type = 'directory',
|
||||||
|
level = 1,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = coalesce(nullif(icon, ''), 'AppstoreOutlined'),
|
||||||
|
sort_order = coalesce(sort_order, 10),
|
||||||
|
is_visible = 0,
|
||||||
|
status = 1,
|
||||||
|
description = 'CRM前台业务权限分组,仅用于权限管理,不在后台侧边栏显示',
|
||||||
|
meta = coalesce(meta, '{}'::jsonb),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_business_parent_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_expansion_menu_perm_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'menu:expansion'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_expansion_menu_perm_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
v_business_parent_id, '拓展', 'menu:expansion', 'menu', 2,
|
||||||
|
null, null, 'TeamOutlined', 20, 0, 1,
|
||||||
|
'CRM前台拓展管理页面权限分组,仅用于权限管理,不在后台侧边栏显示', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_expansion_menu_perm_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set parent_id = v_business_parent_id,
|
||||||
|
name = '拓展',
|
||||||
|
perm_type = 'menu',
|
||||||
|
level = 2,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = coalesce(nullif(icon, ''), 'TeamOutlined'),
|
||||||
|
sort_order = coalesce(sort_order, 20),
|
||||||
|
is_visible = 0,
|
||||||
|
status = 1,
|
||||||
|
description = 'CRM前台拓展管理页面权限分组,仅用于权限管理,不在后台侧边栏显示',
|
||||||
|
meta = coalesce(meta, '{}'::jsonb),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_expansion_menu_perm_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_expansion_create_perm_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'expansion:create'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_expansion_create_perm_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
v_expansion_menu_perm_id, '新增拓展', 'expansion:create', 'button', 3,
|
||||||
|
null, null, null, 1, 1, 1, '控制CRM前台拓展管理页面的新增按钮和销售/渠道拓展创建接口', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_expansion_create_perm_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set parent_id = v_expansion_menu_perm_id,
|
||||||
|
name = '新增拓展',
|
||||||
|
perm_type = 'button',
|
||||||
|
level = 3,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = null,
|
||||||
|
sort_order = 1,
|
||||||
|
is_visible = 1,
|
||||||
|
status = 1,
|
||||||
|
description = '控制CRM前台拓展管理页面的新增按钮和销售/渠道拓展创建接口',
|
||||||
|
meta = '{}'::jsonb,
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_expansion_create_perm_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_menu_perm_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'menu:opportunities'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_menu_perm_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
v_business_parent_id, '商机', 'menu:opportunities', 'menu', 2,
|
||||||
|
null, null, 'BriefcaseOutlined', 30, 0, 1,
|
||||||
|
'CRM前台商机储备页面权限分组,仅用于权限管理,不在后台侧边栏显示', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_menu_perm_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set parent_id = v_business_parent_id,
|
||||||
|
name = '商机',
|
||||||
|
perm_type = 'menu',
|
||||||
|
level = 2,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = coalesce(nullif(icon, ''), 'BriefcaseOutlined'),
|
||||||
|
sort_order = coalesce(sort_order, 30),
|
||||||
|
is_visible = 0,
|
||||||
|
status = 1,
|
||||||
|
description = 'CRM前台商机储备页面权限分组,仅用于权限管理,不在后台侧边栏显示',
|
||||||
|
meta = coalesce(meta, '{}'::jsonb),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_menu_perm_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select perm_id
|
||||||
|
into v_create_perm_id
|
||||||
|
from sys_permission
|
||||||
|
where code = 'opportunity:create'
|
||||||
|
order by perm_id
|
||||||
|
limit 1;
|
||||||
|
|
||||||
|
if v_create_perm_id is null then
|
||||||
|
insert into sys_permission (
|
||||||
|
parent_id, name, code, perm_type, level, path, component, icon,
|
||||||
|
sort_order, is_visible, status, description, meta, is_deleted, created_at, updated_at
|
||||||
|
) values (
|
||||||
|
v_menu_perm_id, '新增商机', 'opportunity:create', 'button', 3,
|
||||||
|
null, null, null, 1, 1, 1, '控制CRM前台商机储备页面的新增商机按钮和创建接口', '{}'::jsonb, 0, now(), now()
|
||||||
|
)
|
||||||
|
returning perm_id into v_create_perm_id;
|
||||||
|
else
|
||||||
|
update sys_permission
|
||||||
|
set parent_id = v_menu_perm_id,
|
||||||
|
name = '新增商机',
|
||||||
|
perm_type = 'button',
|
||||||
|
level = 3,
|
||||||
|
path = null,
|
||||||
|
component = null,
|
||||||
|
icon = null,
|
||||||
|
sort_order = 1,
|
||||||
|
is_visible = 1,
|
||||||
|
status = 1,
|
||||||
|
description = '控制CRM前台商机储备页面的新增商机按钮和创建接口',
|
||||||
|
meta = '{}'::jsonb,
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
where perm_id = v_create_perm_id;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if v_has_role_permission_tenant then
|
||||||
|
insert into sys_role_permission (role_id, perm_id, tenant_id, is_deleted, created_at, updated_at)
|
||||||
|
select distinct r.role_id, permission_source.perm_id, r.tenant_id, 0, now(), now()
|
||||||
|
from sys_role r
|
||||||
|
cross join (
|
||||||
|
select unnest(array[v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id, v_menu_perm_id, v_create_perm_id]) as perm_id
|
||||||
|
) permission_source
|
||||||
|
where coalesce(r.is_deleted, 0) = 0
|
||||||
|
and permission_source.perm_id is not null
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
)
|
||||||
|
and not exists (
|
||||||
|
select 1
|
||||||
|
from sys_role_permission rp
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id = permission_source.perm_id
|
||||||
|
);
|
||||||
|
|
||||||
|
update sys_role_permission rp
|
||||||
|
set tenant_id = coalesce(rp.tenant_id, r.tenant_id),
|
||||||
|
is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
from sys_role r
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id in (v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id, v_menu_perm_id, v_create_perm_id)
|
||||||
|
and coalesce(r.is_deleted, 0) = 0
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
);
|
||||||
|
else
|
||||||
|
insert into sys_role_permission (role_id, perm_id, is_deleted, created_at, updated_at)
|
||||||
|
select distinct r.role_id, permission_source.perm_id, 0, now(), now()
|
||||||
|
from sys_role r
|
||||||
|
cross join (
|
||||||
|
select unnest(array[v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id, v_menu_perm_id, v_create_perm_id]) as perm_id
|
||||||
|
) permission_source
|
||||||
|
where coalesce(r.is_deleted, 0) = 0
|
||||||
|
and permission_source.perm_id is not null
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
)
|
||||||
|
and not exists (
|
||||||
|
select 1
|
||||||
|
from sys_role_permission rp
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id = permission_source.perm_id
|
||||||
|
);
|
||||||
|
|
||||||
|
update sys_role_permission rp
|
||||||
|
set is_deleted = 0,
|
||||||
|
updated_at = now()
|
||||||
|
from sys_role r
|
||||||
|
where rp.role_id = r.role_id
|
||||||
|
and rp.perm_id in (v_business_parent_id, v_expansion_menu_perm_id, v_expansion_create_perm_id, v_menu_perm_id, v_create_perm_id)
|
||||||
|
and coalesce(r.is_deleted, 0) = 0
|
||||||
|
and (
|
||||||
|
r.role_code in ('TENANT_ADMIN', 'ADMIN', 'SYS_ADMIN', 'PLATFORM_ADMIN', 'SUPER_ADMIN')
|
||||||
|
or r.role_name ilike '%管理员%'
|
||||||
|
or r.role_name ilike '%admin%'
|
||||||
|
);
|
||||||
|
end if;
|
||||||
|
end $$;
|
||||||
|
|
||||||
|
commit;
|
||||||
Loading…
Reference in New Issue