权限相关修改
This commit is contained in:
@@ -26,7 +26,7 @@ public class ContractLaunchPartyDto implements Serializable {
|
||||
/** 角色名称(我方/相对方) */
|
||||
private String roleName;
|
||||
|
||||
/** 主体编码(前端传值,当前不单独落库,用于拼接 signingSubjectCode/c_weNames) */
|
||||
/** 主体编码(我方主体取组织ID,相对方通常为空) */
|
||||
private String subjectCode;
|
||||
|
||||
/** 排序号 */
|
||||
|
||||
@@ -34,4 +34,21 @@ public class ContractLaunchQueryDto extends BasePageDto implements Serializable
|
||||
|
||||
/** 创建时间范围-结束 yyyy-MM-dd */
|
||||
private String dateEnd;
|
||||
|
||||
// ============== 权限过滤字段(由后端 queryPage 自动注入,前端不传) ==============
|
||||
|
||||
/** 当前登录用户账号(个人级过滤用) */
|
||||
private String currentUserId;
|
||||
|
||||
/** 当前登录人组织ID(公司级/我方主体过滤用,与主表 ORG_ID 同类型 String) */
|
||||
private String currentOrgId;
|
||||
|
||||
/** 当前登录人部门名称(部门级过滤用) */
|
||||
private String currentDeptName;
|
||||
|
||||
/**
|
||||
* 查询范围:personal(个人)/department(部门)/company(公司)/admin(管理员)
|
||||
* 由后端根据角色解析,前端不传
|
||||
*/
|
||||
private String queryScope;
|
||||
}
|
||||
|
||||
+103
-3
@@ -42,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -70,9 +71,30 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
private final SealTokenService sealTokenService;
|
||||
private final SealConfig sealConfig;
|
||||
|
||||
/** 分页查询,附带合同方/文件/履行计划(列表页不查日志) */
|
||||
/**
|
||||
* 分页查询,附带合同方/文件/履行计划(列表页不查日志)。
|
||||
*
|
||||
* 权限过滤说明(对应需求文档"使用角色与权限"章节):
|
||||
* - personal(个人级):只能看自己发起的合同(CREATE_BY = 当前用户)
|
||||
* - department(部门级):本部门合同(INITIATOR_DEPT = 当前部门)
|
||||
* - company(公司级):本公司内部合同,且作为我方/相对方参与的合同也能看到
|
||||
* - admin(管理员级):所有通过平台发起或签署的合同,不加过滤
|
||||
*
|
||||
* "多个我方 + 多个相对方都能看到合同"的闭环:
|
||||
* - 我方:主表 SIGNING_SUBJECT_CODE 存了多个我方主体编码(逗号分割),当前用户 orgId 命中即可见
|
||||
* - 相对方:party 子表 PARTNER_ID 关联 partner 表 LINKED_ORG_ID,当前用户 orgId 命中即可见
|
||||
* (政府/外部客户无 linkedOrgId,不参与本地权限,仅在签章平台签署)
|
||||
*
|
||||
* 当前无角色编码体系,scope 暂写死 admin,后续接入角色后改 resolveQueryScope 即可。
|
||||
*/
|
||||
@Override
|
||||
public PageResult<ContractLaunchDto> queryPage(ContractLaunchQueryDto queryDto) {
|
||||
SysUserEntity currentUser = adminSecurityManage.getUser();
|
||||
String scope = resolveQueryScope(currentUser);
|
||||
queryDto.setQueryScope(scope);
|
||||
queryDto.setCurrentUserId(currentUser.getUsername());
|
||||
queryDto.setCurrentOrgId(currentUser.getSysOrgEntity() == null ? null : currentUser.getSysOrgEntity().getId());
|
||||
queryDto.setCurrentDeptName(currentUser.getSysOrgEntity() == null ? null : currentUser.getSysOrgEntity().getOrgName());
|
||||
Page<ContractLaunchDto> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
|
||||
Page<ContractLaunchDto> resultPage = (Page<ContractLaunchDto>) contractLaunchMapper.selectContractPage(page, queryDto);
|
||||
PageResult<ContractLaunchDto> pageResult = new PageResult<>(resultPage);
|
||||
@@ -80,6 +102,20 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析当前用户的查询范围。
|
||||
*
|
||||
* TODO: 后续接入角色编码后,按角色返回:
|
||||
* - 系统管理员 → admin
|
||||
* - 公司合同管理员(财务部) → company
|
||||
* - 部门合同管理员 → department
|
||||
* - 业务人员 → personal
|
||||
* 当前无角色体系,暂统一返回 admin(即不过滤),保证流程可跑通。
|
||||
*/
|
||||
private String resolveQueryScope(SysUserEntity currentUser) {
|
||||
return "admin";
|
||||
}
|
||||
|
||||
/** 查询详情,含日志 */
|
||||
@Override
|
||||
public ContractLaunchDto getDetail(Long id) {
|
||||
@@ -1004,6 +1040,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
if (contract == null) {
|
||||
throw new ServiceException("合同数据不能为空");
|
||||
}
|
||||
SysUserEntity currentUser = adminSecurityManage.getUser();
|
||||
boolean singleAgreement = isSingleAgreement(contract);
|
||||
contract.setContractName(trim(contract.getContractName()));
|
||||
contract.setContractCode(trim(contract.getContractCode()));
|
||||
@@ -1074,7 +1111,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
contract.setPerformancePlans(new ArrayList<>());
|
||||
}
|
||||
normalizePartyList(contract);
|
||||
contract.setSigningSubjectCode(resolveSigningSubjectCodes(contract));
|
||||
applyAuthoritativeOurPartySubjects(contract, currentUser);
|
||||
contract.setSigningSubjectCode(resolveSigningSubjectCodes(contract, currentUser));
|
||||
}
|
||||
|
||||
private void normalizePartyList(ContractLaunchDto contract) {
|
||||
@@ -1128,6 +1166,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
}
|
||||
|
||||
private String resolveSigningSubjectCodes(ContractLaunchDto contract) {
|
||||
return resolveSigningSubjectCodes(contract, adminSecurityManage.getUser());
|
||||
}
|
||||
|
||||
private String resolveSigningSubjectCodes(ContractLaunchDto contract, SysUserEntity currentUser) {
|
||||
if (contract == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -1145,7 +1187,65 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
if (contract.getSigningSubjectCode() != null && !contract.getSigningSubjectCode().isBlank()) {
|
||||
return trim(contract.getSigningSubjectCode());
|
||||
}
|
||||
return trim(contract.getOrgId());
|
||||
String currentOrgId = currentUser == null || currentUser.getSysOrgEntity() == null
|
||||
? null
|
||||
: trim(currentUser.getSysOrgEntity().getId());
|
||||
return currentOrgId != null ? currentOrgId : trim(contract.getOrgId());
|
||||
}
|
||||
|
||||
private void applyAuthoritativeOurPartySubjects(ContractLaunchDto contract, SysUserEntity currentUser) {
|
||||
if (contract == null || contract.getPartyList() == null || contract.getPartyList().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String currentOrgId = currentUser == null || currentUser.getSysOrgEntity() == null
|
||||
? null
|
||||
: trim(currentUser.getSysOrgEntity().getId());
|
||||
String currentOrgName = currentUser == null || currentUser.getSysOrgEntity() == null
|
||||
? null
|
||||
: trim(currentUser.getSysOrgEntity().getOrgName());
|
||||
List<String> persistedSubjectCodes = Arrays.stream(String.valueOf(contract.getSigningSubjectCode() == null ? "" : contract.getSigningSubjectCode()).split(","))
|
||||
.map(String::trim)
|
||||
.filter(item -> !item.isBlank())
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
int persistedIndex = 0;
|
||||
boolean containsCurrentOrg = false;
|
||||
for (ContractLaunchPartyDto party : contract.getPartyList()) {
|
||||
if (!isOurParty(party)) {
|
||||
party.setSubjectCode(null);
|
||||
continue;
|
||||
}
|
||||
String subjectCode = trim(party.getSubjectCode());
|
||||
String companyName = trim(party.getCompanyName());
|
||||
boolean matchesCurrentOrg = currentOrgId != null
|
||||
&& ((subjectCode != null && Objects.equals(subjectCode, currentOrgId))
|
||||
|| (companyName != null && currentOrgName != null && Objects.equals(companyName, currentOrgName)));
|
||||
if (matchesCurrentOrg) {
|
||||
party.setSubjectCode(currentOrgId);
|
||||
if (currentOrgName != null) {
|
||||
party.setCompanyName(currentOrgName);
|
||||
}
|
||||
containsCurrentOrg = true;
|
||||
continue;
|
||||
}
|
||||
if (subjectCode == null || subjectCode.isBlank()) {
|
||||
if (persistedIndex < persistedSubjectCodes.size()) {
|
||||
subjectCode = persistedSubjectCodes.get(persistedIndex++);
|
||||
} else if (!containsCurrentOrg && currentOrgId != null) {
|
||||
subjectCode = currentOrgId;
|
||||
if (companyName == null || companyName.isBlank()) {
|
||||
companyName = currentOrgName;
|
||||
}
|
||||
containsCurrentOrg = true;
|
||||
}
|
||||
} else if (Objects.equals(subjectCode, currentOrgId)) {
|
||||
containsCurrentOrg = true;
|
||||
}
|
||||
party.setSubjectCode(subjectCode);
|
||||
if ((party.getCompanyName() == null || party.getCompanyName().isBlank()) && companyName != null) {
|
||||
party.setCompanyName(companyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 校验草稿必填项 */
|
||||
|
||||
@@ -21,7 +21,7 @@ public interface ContractTemplateMapper {
|
||||
IPage<ContractTemplateDto> selectTemplatePage(Page<ContractTemplateDto> page, @Param("query") ContractTemplateQueryDto queryDto);
|
||||
|
||||
/** 查询已发布模板列表 */
|
||||
List<ContractTemplateDto> selectPublishedTemplates();
|
||||
List<ContractTemplateDto> selectPublishedTemplates(@Param("visibleOrgIds") List<String> visibleOrgIds);
|
||||
|
||||
/** 根据主键查询模板详情 */
|
||||
ContractTemplateDto selectTemplateById(@Param("id") Long id);
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ContractTemplateServiceImpl implements ContractTemplateService {
|
||||
/** 已发布的模板列表 */
|
||||
@Override
|
||||
public List<ContractTemplateDto> queryPublishedTemplates() {
|
||||
List<ContractTemplateDto> templates = contractTemplateMapper.selectPublishedTemplates();
|
||||
List<ContractTemplateDto> templates = contractTemplateMapper.selectPublishedTemplates(computeVisibleOrgIds());
|
||||
contractTemplateDataHandler.fillUiFields(templates);
|
||||
return templates;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.nbport.zgwl.partner.mapper.PartnerManageMapper;
|
||||
import com.nbport.zgwl.partner.utils.PartnerIdUtils;
|
||||
import com.nbport.zgwl.partner.utils.PartnerManageConstants;
|
||||
import com.nbport.zgwl.partner.utils.PartnerSyncPayloadBuilder;
|
||||
import com.nbport.zgwl.utils.AdminSecurityManage;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -40,11 +41,13 @@ public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
|
||||
private final DataCollectionPushService dataCollectionPushService;
|
||||
|
||||
private final AdminSecurityManage adminSecurityManage;
|
||||
|
||||
/** 分页查询相对方列表(结果中会带上联系人数据) */
|
||||
@Override
|
||||
public PageResult<PartnerManageDto> queryPartnerList(PartnerQueryDto queryDto) {
|
||||
Page<PartnerManageDto> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
|
||||
queryDto.setOrgId(1L);
|
||||
queryDto.setOrgId(resolveCurrentOrgId());
|
||||
Page<PartnerManageDto> resultPage = (Page<PartnerManageDto>) partnerManageMapper.selectPartnerPage(page, queryDto);
|
||||
PageResult<PartnerManageDto> pageResult = new PageResult<>(resultPage);
|
||||
attachContacts(pageResult.getData());
|
||||
@@ -81,7 +84,7 @@ public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
partner.setCreateTime(now);
|
||||
partner.setUpdateBy(PartnerManageConstants.DEFAULT_OPERATOR);
|
||||
partner.setUpdateTime(now);
|
||||
partner.setOrgId(1L);
|
||||
partner.setOrgId(resolveCurrentOrgId());
|
||||
partner.setIsDeleted(PartnerManageConstants.PARTNER_IS_DELETED_NORMAL);
|
||||
|
||||
partnerManageMapper.insertPartner(partner);
|
||||
@@ -115,7 +118,7 @@ public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
partner.setSyncMessage("信息已修改,待重新同步");
|
||||
partner.setUpdateBy(PartnerManageConstants.DEFAULT_OPERATOR);
|
||||
partner.setUpdateTime(now);
|
||||
partner.setOrgId(1L);
|
||||
partner.setOrgId(dbPartner.getOrgId() != null ? dbPartner.getOrgId() : resolveCurrentOrgId());
|
||||
partner.setIsDeleted(PartnerManageConstants.PARTNER_IS_DELETED_NORMAL);
|
||||
partnerManageMapper.updatePartner(partner);
|
||||
partnerManageMapper.markPartnerContactsDeletedByPartnerId(
|
||||
@@ -294,6 +297,22 @@ public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private Long resolveCurrentOrgId() {
|
||||
if (adminSecurityManage.getUser() == null || adminSecurityManage.getUser().getSysOrgEntity() == null) {
|
||||
return null;
|
||||
}
|
||||
String orgId = adminSecurityManage.getUser().getSysOrgEntity().getId();
|
||||
if (!StrUtilHelper.hasText(orgId)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.valueOf(orgId);
|
||||
} catch (NumberFormatException ex) {
|
||||
log.warn("当前登录组织ID不是数字,无法回写相对方orgId: {}", orgId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 避免为了一个判空再引入新依赖,这里保留一个最小工具。
|
||||
*/
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<result property="contractId" column="CONTRACT_ID"/>
|
||||
<result property="roleCode" column="ROLE_CODE"/>
|
||||
<result property="roleName" column="ROLE_NAME"/>
|
||||
<result property="subjectCode" column="SUBJECT_CODE"/>
|
||||
<result property="sortOrder" column="SORT_ORDER"/>
|
||||
<result property="partnerId" column="PARTNER_ID"/>
|
||||
<result property="oppositeId" column="OPPOSITE_ID"/>
|
||||
@@ -237,6 +238,21 @@
|
||||
select SEQ_SC_AR_ELE.NEXTVAL from dual
|
||||
</select>
|
||||
|
||||
<!--
|
||||
权限过滤说明(对应需求文档"使用角色与权限"章节):
|
||||
- admin:不过滤,看所有合同
|
||||
- personal:自己发起的(CREATE_BY) OR 我方主体命中(SIGNING_SUBJECT_CODE包含当前orgId) OR 相对方命中(party关联partner.LINKED_ORG_ID=当前orgId)
|
||||
- department:本部门(INITIATOR_DEPT) OR 我方主体命中 OR 相对方命中
|
||||
- company:本公司(ORG_ID) OR 我方主体命中 OR 相对方命中
|
||||
|
||||
"多个我方 + 多个相对方都能看到合同"的闭环:
|
||||
- 我方:主表 SIGNING_SUBJECT_CODE 存多个我方主体编码(逗号分割),当前用户 orgId 命中即可见
|
||||
- 相对方:party 子表 PARTNER_ID 关联 ILDM_FEE_CUSTOMER_INFO.LINKED_ORG_ID,命中即可见
|
||||
(政府/外部客户无 linkedOrgId,不参与本地权限,仅在签章平台签署)
|
||||
|
||||
类型说明:ORG_ID 为 VARCHAR,LINKED_ORG_ID 为 NUMBER,比较时用 TO_CHAR 统一。
|
||||
我方主体编码逗号分割匹配用 INSTR,避免拆分。
|
||||
-->
|
||||
<select id="selectContractPage" resultMap="ContractLaunchResult">
|
||||
<include refid="mainColumns"/>
|
||||
<where>
|
||||
@@ -259,6 +275,39 @@
|
||||
<if test="query.dateEnd != null and query.dateEnd != ''">
|
||||
and CREATE_TIME <= TO_DATE(#{query.dateEnd} || ' 23:59:59', 'YYYY-MM-DD HH24:MI:SS')
|
||||
</if>
|
||||
<!-- 权限范围过滤:admin 不过滤;其余范围按"自己/部门/公司 + 我方主体命中 + 相对方命中"取并集 -->
|
||||
<if test="query.queryScope != null and query.queryScope != '' and query.queryScope != 'admin'">
|
||||
and (
|
||||
<!-- 个人级:自己发起的合同 -->
|
||||
<choose>
|
||||
<when test="query.queryScope == 'personal'">
|
||||
CREATE_BY = #{query.currentUserId}
|
||||
</when>
|
||||
<when test="query.queryScope == 'department'">
|
||||
INITIATOR_DEPT = #{query.currentDeptName}
|
||||
</when>
|
||||
<when test="query.queryScope == 'company'">
|
||||
ORG_ID = #{query.currentOrgId}
|
||||
</when>
|
||||
</choose>
|
||||
<!-- 我方主体命中:当前用户组织编码在 SIGNING_SUBJECT_CODE 逗号分割列表中 -->
|
||||
<if test="query.currentOrgId != null and query.currentOrgId != ''">
|
||||
or INSTR(',' || SIGNING_SUBJECT_CODE || ',', ',' || #{query.currentOrgId} || ',') > 0
|
||||
</if>
|
||||
<!-- 相对方命中:合同方子表关联的相对方 linked_org_id = 当前用户组织ID -->
|
||||
<if test="query.currentOrgId != null and query.currentOrgId != ''">
|
||||
or ID in (
|
||||
select p.CONTRACT_ID
|
||||
from SEAL_CONTRACT_LAUNCH_PARTY p
|
||||
inner join ILDM_FEE_CUSTOMER_INFO c on p.PARTNER_ID = c.CUSTOMER_SYSID
|
||||
where p.IS_DELETED = 'N'
|
||||
and p.ROLE_CODE = 'OPPOSITE'
|
||||
and c.LINKED_ORG_ID is not null
|
||||
and TO_CHAR(c.LINKED_ORG_ID) = #{query.currentOrgId}
|
||||
)
|
||||
</if>
|
||||
)
|
||||
</if>
|
||||
</where>
|
||||
order by CREATE_TIME desc, ID desc
|
||||
</select>
|
||||
@@ -441,13 +490,13 @@
|
||||
INSERT ALL
|
||||
<foreach collection="list" item="item">
|
||||
INTO SEAL_CONTRACT_LAUNCH_PARTY (
|
||||
ID, CONTRACT_ID, ROLE_CODE, ROLE_NAME, SORT_ORDER, PARTNER_ID, OPPOSITE_ID,
|
||||
ID, CONTRACT_ID, ROLE_CODE, ROLE_NAME, SUBJECT_CODE, SORT_ORDER, PARTNER_ID, OPPOSITE_ID,
|
||||
COMPANY_NAME, COMPANY_TYPE, OPPOSITE_CHARACTER, CONTACT_NAME, CONTACT_PHONE,
|
||||
CONTACT_EMAIL, CONTACT_ADDRESS, REGISTERED_ADDRESS, LEGAL_REPRESENTATIVE,
|
||||
CREDIT_CODE, BANK_NAME, BANK_ACCOUNT, NATURAL_PERSON_ID_TYPE, NATURAL_PERSON_ID_NUMBER,
|
||||
IS_GROUP_INTERNAL, IS_HONG_KONG_MACAO_TAIWAN, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, IS_DELETED, REMARK
|
||||
) VALUES (
|
||||
#{item.id}, #{item.contractId}, #{item.roleCode}, #{item.roleName}, #{item.sortOrder}, #{item.partnerId}, #{item.oppositeId},
|
||||
#{item.id}, #{item.contractId}, #{item.roleCode}, #{item.roleName}, #{item.subjectCode}, #{item.sortOrder}, #{item.partnerId}, #{item.oppositeId},
|
||||
#{item.companyName}, #{item.companyType}, #{item.oppositeCharacter}, #{item.contactName}, #{item.contactPhone},
|
||||
#{item.contactEmail}, #{item.contactAddress}, #{item.registeredAddress}, #{item.legalRepresentative},
|
||||
#{item.creditCode}, #{item.bankName}, #{item.bankAccount}, #{item.naturalPersonIdType}, #{item.naturalPersonIdNumber},
|
||||
@@ -590,7 +639,7 @@
|
||||
</update>
|
||||
|
||||
<select id="selectPartyByContractIds" resultMap="PartyResult">
|
||||
select ID, CONTRACT_ID, ROLE_CODE, ROLE_NAME, SORT_ORDER, PARTNER_ID, OPPOSITE_ID,
|
||||
select ID, CONTRACT_ID, ROLE_CODE, ROLE_NAME, SUBJECT_CODE, SORT_ORDER, PARTNER_ID, OPPOSITE_ID,
|
||||
COMPANY_NAME, COMPANY_TYPE, OPPOSITE_CHARACTER, CONTACT_NAME, CONTACT_PHONE,
|
||||
CONTACT_EMAIL, CONTACT_ADDRESS, REGISTERED_ADDRESS, LEGAL_REPRESENTATIVE,
|
||||
CREDIT_CODE, BANK_NAME, BANK_ACCOUNT, NATURAL_PERSON_ID_TYPE, NATURAL_PERSON_ID_NUMBER,
|
||||
|
||||
@@ -71,6 +71,13 @@
|
||||
<include refid="selectTemplateColumns"/>
|
||||
where del_flag = '0'
|
||||
and status = 'published'
|
||||
<if test="visibleOrgIds != null and visibleOrgIds.size() > 0">
|
||||
and (
|
||||
<foreach collection="visibleOrgIds" item="orgId" separator=" OR ">
|
||||
INSTR(publish_org_ids_json, '"' || #{orgId} || '"') > 0
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
order by updated_time desc, id desc
|
||||
</select>
|
||||
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
<include refid="selectPartnerColumns"/>
|
||||
<where>
|
||||
IS_DELETED = 'N'
|
||||
<if test="query.orgId != null">
|
||||
and ORG_ID = #{query.orgId}
|
||||
</if>
|
||||
<if test="query.customerNameC != null and query.customerNameC != ''">
|
||||
and CUSTOMER_NAME_C like CONCAT(CONCAT('%', #{query.customerNameC}), '%')
|
||||
</if>
|
||||
|
||||
Reference in New Issue
Block a user