diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java index 0b77935..4a2dba8 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchPartyDto.java @@ -26,7 +26,7 @@ public class ContractLaunchPartyDto implements Serializable { /** 角色名称(我方/相对方) */ private String roleName; - /** 主体编码(前端传值,当前不单独落库,用于拼接 signingSubjectCode/c_weNames) */ + /** 主体编码(我方主体取组织ID,相对方通常为空) */ private String subjectCode; /** 排序号 */ diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchQueryDto.java b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchQueryDto.java index 163b8b6..419cfba 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchQueryDto.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/dto/ContractLaunchQueryDto.java @@ -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; } diff --git a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java index 4825364..b821ba0 100644 --- a/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java +++ b/src/main/java/com/nbport/zgwl/contractlaunch/service/ContractLaunchServiceImpl.java @@ -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 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 page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize()); Page resultPage = (Page) contractLaunchMapper.selectContractPage(page, queryDto); PageResult 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 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); + } + } } /** 校验草稿必填项 */ diff --git a/src/main/java/com/nbport/zgwl/manifest/mapper/ContractTemplateMapper.java b/src/main/java/com/nbport/zgwl/manifest/mapper/ContractTemplateMapper.java index 9015ab2..3bfd73d 100644 --- a/src/main/java/com/nbport/zgwl/manifest/mapper/ContractTemplateMapper.java +++ b/src/main/java/com/nbport/zgwl/manifest/mapper/ContractTemplateMapper.java @@ -21,7 +21,7 @@ public interface ContractTemplateMapper { IPage selectTemplatePage(Page page, @Param("query") ContractTemplateQueryDto queryDto); /** 查询已发布模板列表 */ - List selectPublishedTemplates(); + List selectPublishedTemplates(@Param("visibleOrgIds") List visibleOrgIds); /** 根据主键查询模板详情 */ ContractTemplateDto selectTemplateById(@Param("id") Long id); diff --git a/src/main/java/com/nbport/zgwl/manifest/service/ContractTemplateServiceImpl.java b/src/main/java/com/nbport/zgwl/manifest/service/ContractTemplateServiceImpl.java index 017b05f..521db17 100644 --- a/src/main/java/com/nbport/zgwl/manifest/service/ContractTemplateServiceImpl.java +++ b/src/main/java/com/nbport/zgwl/manifest/service/ContractTemplateServiceImpl.java @@ -67,7 +67,7 @@ public class ContractTemplateServiceImpl implements ContractTemplateService { /** 已发布的模板列表 */ @Override public List queryPublishedTemplates() { - List templates = contractTemplateMapper.selectPublishedTemplates(); + List templates = contractTemplateMapper.selectPublishedTemplates(computeVisibleOrgIds()); contractTemplateDataHandler.fillUiFields(templates); return templates; } diff --git a/src/main/java/com/nbport/zgwl/partner/service/PartnerManageServiceImpl.java b/src/main/java/com/nbport/zgwl/partner/service/PartnerManageServiceImpl.java index 86465f9..57baa68 100644 --- a/src/main/java/com/nbport/zgwl/partner/service/PartnerManageServiceImpl.java +++ b/src/main/java/com/nbport/zgwl/partner/service/PartnerManageServiceImpl.java @@ -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 queryPartnerList(PartnerQueryDto queryDto) { Page page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize()); - queryDto.setOrgId(1L); + queryDto.setOrgId(resolveCurrentOrgId()); Page resultPage = (Page) partnerManageMapper.selectPartnerPage(page, queryDto); PageResult 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; + } + } + /** * 避免为了一个判空再引入新依赖,这里保留一个最小工具。 */ diff --git a/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml b/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml index 7035001..0f3b3ec 100644 --- a/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml +++ b/src/main/resources/mapper/contractlaunch/ContractLaunchMapper.xml @@ -110,6 +110,7 @@ + @@ -237,6 +238,21 @@ select SEQ_SC_AR_ELE.NEXTVAL from dual + @@ -441,13 +490,13 @@ INSERT ALL 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 @@ diff --git a/src/main/resources/mapper/partner/PartnerManageMapper.xml b/src/main/resources/mapper/partner/PartnerManageMapper.xml index a9d6733..56a76f8 100644 --- a/src/main/resources/mapper/partner/PartnerManageMapper.xml +++ b/src/main/resources/mapper/partner/PartnerManageMapper.xml @@ -86,6 +86,9 @@ IS_DELETED = 'N' + + and ORG_ID = #{query.orgId} + and CUSTOMER_NAME_C like CONCAT(CONCAT('%', #{query.customerNameC}), '%') diff --git a/zgwl_contract_launch_party_subject_patch_oracle.sql b/zgwl_contract_launch_party_subject_patch_oracle.sql new file mode 100644 index 0000000..7a699a0 --- /dev/null +++ b/zgwl_contract_launch_party_subject_patch_oracle.sql @@ -0,0 +1,16 @@ +-- 合同方子表补充主体编码字段 +DECLARE + v_count NUMBER := 0; +BEGIN + SELECT COUNT(1) + INTO v_count + FROM USER_TAB_COLUMNS + WHERE TABLE_NAME = 'SEAL_CONTRACT_LAUNCH_PARTY' + AND COLUMN_NAME = 'SUBJECT_CODE'; + + IF v_count = 0 THEN + EXECUTE IMMEDIATE 'ALTER TABLE SEAL_CONTRACT_LAUNCH_PARTY ADD SUBJECT_CODE VARCHAR2(100 CHAR)'; + EXECUTE IMMEDIATE 'COMMENT ON COLUMN SEAL_CONTRACT_LAUNCH_PARTY.SUBJECT_CODE IS ''主体编码(我方主体组织ID,相对方通常为空)'''; + END IF; +END; +/