diff --git a/.DS_Store b/.DS_Store index c2dd2d8c..fcc8bf48 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnterpriseBaseInfoController.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnterpriseBaseInfoController.java new file mode 100644 index 00000000..39680a36 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnterpriseBaseInfoController.java @@ -0,0 +1,146 @@ +package com.ruoyi.info.collection.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.PageDomain; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.page.TableSupport; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoAddDTO; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel; +import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO; +import com.ruoyi.info.collection.domain.vo.EnterpriseBaseInfoImportFailureVO; +import com.ruoyi.info.collection.domain.vo.ImportResultVO; +import com.ruoyi.info.collection.domain.vo.ImportStatusVO; +import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoImportService; +import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoService; +import com.ruoyi.info.collection.utils.EasyExcelUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; + +/** + * 实体库管理 Controller + * + * @author ruoyi + * @date 2026-04-17 + */ +@Tag(name = "实体库管理") +@RestController +@RequestMapping("/ccdi/enterpriseBaseInfo") +public class CcdiEnterpriseBaseInfoController extends BaseController { + + @Resource + private ICcdiEnterpriseBaseInfoService enterpriseBaseInfoService; + + @Resource + private ICcdiEnterpriseBaseInfoImportService enterpriseBaseInfoImportService; + + @Operation(summary = "查询实体库列表") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:list')") + @GetMapping("/list") + public TableDataInfo list(CcdiEnterpriseBaseInfoQueryDTO queryDTO) { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Page page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()); + Page result = enterpriseBaseInfoService.selectEnterpriseBaseInfoPage(page, queryDTO); + return getDataTable(result.getRecords(), result.getTotal()); + } + + @Operation(summary = "获取实体库详细信息") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:query')") + @GetMapping("/{socialCreditCode}") + public AjaxResult getInfo(@PathVariable String socialCreditCode) { + return success(enterpriseBaseInfoService.selectEnterpriseBaseInfoById(socialCreditCode)); + } + + @Operation(summary = "新增实体库信息") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:add')") + @Log(title = "实体库管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody CcdiEnterpriseBaseInfoAddDTO addDTO) { + return toAjax(enterpriseBaseInfoService.insertEnterpriseBaseInfo(addDTO)); + } + + @Operation(summary = "修改实体库信息") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:edit')") + @Log(title = "实体库管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody CcdiEnterpriseBaseInfoEditDTO editDTO) { + return toAjax(enterpriseBaseInfoService.updateEnterpriseBaseInfo(editDTO)); + } + + @Operation(summary = "删除实体库信息") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:remove')") + @Log(title = "实体库管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{socialCreditCodes}") + public AjaxResult remove(@PathVariable String[] socialCreditCodes) { + return toAjax(enterpriseBaseInfoService.deleteEnterpriseBaseInfoByIds(socialCreditCodes)); + } + + @Operation(summary = "下载导入模板") + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiEnterpriseBaseInfoExcel.class, "实体库管理"); + } + + @Operation(summary = "导入实体库信息") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:import')") + @Log(title = "实体库管理", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) throws Exception { + List list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiEnterpriseBaseInfoExcel.class); + if (list == null || list.isEmpty()) { + return error("至少需要一条数据"); + } + + String taskId = enterpriseBaseInfoService.importEnterpriseBaseInfo(list); + ImportResultVO result = new ImportResultVO(); + result.setTaskId(taskId); + result.setStatus("PROCESSING"); + result.setMessage("导入任务已提交,正在后台处理"); + return AjaxResult.success("导入任务已提交,正在后台处理", result); + } + + @Operation(summary = "查询导入状态") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:import')") + @GetMapping("/importStatus/{taskId}") + public AjaxResult getImportStatus(@PathVariable String taskId) { + ImportStatusVO status = enterpriseBaseInfoImportService.getImportStatus(taskId); + return success(status); + } + + @Operation(summary = "查询导入失败记录") + @PreAuthorize("@ss.hasPermi('ccdi:enterpriseBaseInfo:import')") + @GetMapping("/importFailures/{taskId}") + public TableDataInfo getImportFailures(@PathVariable String taskId, + @RequestParam(defaultValue = "1") Integer pageNum, + @RequestParam(defaultValue = "10") Integer pageSize) { + List failures = enterpriseBaseInfoImportService.getImportFailures(taskId); + int fromIndex = (pageNum - 1) * pageSize; + if (fromIndex >= failures.size()) { + return getDataTable(new ArrayList<>(), failures.size()); + } + int toIndex = Math.min(fromIndex + pageSize, failures.size()); + return getDataTable(failures.subList(fromIndex, toIndex), failures.size()); + } +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnumController.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnumController.java index 8acffc0e..3317623e 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnumController.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnumController.java @@ -138,4 +138,30 @@ public class CcdiEnumController { } return AjaxResult.success(options); } + + /** + * 获取实体风险等级选项 + */ + @Operation(summary = "获取实体风险等级选项") + @GetMapping("/enterpriseRiskLevel") + public AjaxResult getEnterpriseRiskLevelOptions() { + List options = new ArrayList<>(); + for (EnterpriseRiskLevel level : EnterpriseRiskLevel.values()) { + options.add(new EnumOptionVO(level.getCode(), level.getDesc())); + } + return AjaxResult.success(options); + } + + /** + * 获取企业来源选项 + */ + @Operation(summary = "获取企业来源选项") + @GetMapping("/enterpriseSource") + public AjaxResult getEnterpriseSourceOptions() { + List options = new ArrayList<>(); + for (EnterpriseSource source : EnterpriseSource.values()) { + options.add(new EnumOptionVO(source.getCode(), source.getDesc())); + } + return AjaxResult.success(options); + } } diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiIntermediaryEnterpriseRelation.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiIntermediaryEnterpriseRelation.java new file mode 100644 index 00000000..47c2a5a3 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiIntermediaryEnterpriseRelation.java @@ -0,0 +1,46 @@ +package com.ruoyi.info.collection.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 中介关联机构关系对象 ccdi_intermediary_enterprise_relation + */ +@Data +@TableName("ccdi_intermediary_enterprise_relation") +public class CcdiIntermediaryEnterpriseRelation implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + private Long id; + + private String intermediaryBizId; + + private String socialCreditCode; + + private String relationPersonPost; + + private String remark; + + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoAddDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoAddDTO.java new file mode 100644 index 00000000..9cf5ef22 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoAddDTO.java @@ -0,0 +1,107 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 实体库管理新增 DTO + * + * @author ruoyi + * @date 2026-04-17 + */ +@Data +@Schema(description = "实体库管理新增DTO") +public class CcdiEnterpriseBaseInfoAddDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "统一社会信用代码") + @NotBlank(message = "统一社会信用代码不能为空") + @Pattern(regexp = "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$", message = "统一社会信用代码格式不正确") + private String socialCreditCode; + + @Schema(description = "企业名称") + @NotBlank(message = "企业名称不能为空") + @Size(max = 200, message = "企业名称长度不能超过200个字符") + private String enterpriseName; + + @Schema(description = "企业类型") + @Size(max = 50, message = "企业类型长度不能超过50个字符") + private String enterpriseType; + + @Schema(description = "企业性质") + @Size(max = 50, message = "企业性质长度不能超过50个字符") + private String enterpriseNature; + + @Schema(description = "行业分类") + @Size(max = 100, message = "行业分类长度不能超过100个字符") + private String industryClass; + + @Schema(description = "所属行业") + @Size(max = 100, message = "所属行业长度不能超过100个字符") + private String industryName; + + @Schema(description = "成立日期") + private Date establishDate; + + @Schema(description = "注册地址") + @Size(max = 500, message = "注册地址长度不能超过500个字符") + private String registerAddress; + + @Schema(description = "法定代表人") + @Size(max = 100, message = "法定代表人长度不能超过100个字符") + private String legalRepresentative; + + @Schema(description = "法定代表人证件类型") + @Size(max = 50, message = "法定代表人证件类型长度不能超过50个字符") + private String legalCertType; + + @Schema(description = "法定代表人证件号码") + @Size(max = 50, message = "法定代表人证件号码长度不能超过50个字符") + private String legalCertNo; + + @Schema(description = "股东1") + @Size(max = 100, message = "股东1长度不能超过100个字符") + private String shareholder1; + + @Schema(description = "股东2") + @Size(max = 100, message = "股东2长度不能超过100个字符") + private String shareholder2; + + @Schema(description = "股东3") + @Size(max = 100, message = "股东3长度不能超过100个字符") + private String shareholder3; + + @Schema(description = "股东4") + @Size(max = 100, message = "股东4长度不能超过100个字符") + private String shareholder4; + + @Schema(description = "股东5") + @Size(max = 100, message = "股东5长度不能超过100个字符") + private String shareholder5; + + @Schema(description = "经营状态") + @NotBlank(message = "经营状态不能为空") + @Size(max = 50, message = "经营状态长度不能超过50个字符") + private String status; + + @Schema(description = "风险等级") + @NotBlank(message = "风险等级不能为空") + private String riskLevel; + + @Schema(description = "企业来源") + @NotBlank(message = "企业来源不能为空") + private String entSource; + + @Schema(description = "数据来源") + @NotBlank(message = "数据来源不能为空") + private String dataSource; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoEditDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoEditDTO.java new file mode 100644 index 00000000..dc015fea --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoEditDTO.java @@ -0,0 +1,107 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 实体库管理编辑 DTO + * + * @author ruoyi + * @date 2026-04-17 + */ +@Data +@Schema(description = "实体库管理编辑DTO") +public class CcdiEnterpriseBaseInfoEditDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "统一社会信用代码") + @NotBlank(message = "统一社会信用代码不能为空") + @Pattern(regexp = "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$", message = "统一社会信用代码格式不正确") + private String socialCreditCode; + + @Schema(description = "企业名称") + @NotBlank(message = "企业名称不能为空") + @Size(max = 200, message = "企业名称长度不能超过200个字符") + private String enterpriseName; + + @Schema(description = "企业类型") + @Size(max = 50, message = "企业类型长度不能超过50个字符") + private String enterpriseType; + + @Schema(description = "企业性质") + @Size(max = 50, message = "企业性质长度不能超过50个字符") + private String enterpriseNature; + + @Schema(description = "行业分类") + @Size(max = 100, message = "行业分类长度不能超过100个字符") + private String industryClass; + + @Schema(description = "所属行业") + @Size(max = 100, message = "所属行业长度不能超过100个字符") + private String industryName; + + @Schema(description = "成立日期") + private Date establishDate; + + @Schema(description = "注册地址") + @Size(max = 500, message = "注册地址长度不能超过500个字符") + private String registerAddress; + + @Schema(description = "法定代表人") + @Size(max = 100, message = "法定代表人长度不能超过100个字符") + private String legalRepresentative; + + @Schema(description = "法定代表人证件类型") + @Size(max = 50, message = "法定代表人证件类型长度不能超过50个字符") + private String legalCertType; + + @Schema(description = "法定代表人证件号码") + @Size(max = 50, message = "法定代表人证件号码长度不能超过50个字符") + private String legalCertNo; + + @Schema(description = "股东1") + @Size(max = 100, message = "股东1长度不能超过100个字符") + private String shareholder1; + + @Schema(description = "股东2") + @Size(max = 100, message = "股东2长度不能超过100个字符") + private String shareholder2; + + @Schema(description = "股东3") + @Size(max = 100, message = "股东3长度不能超过100个字符") + private String shareholder3; + + @Schema(description = "股东4") + @Size(max = 100, message = "股东4长度不能超过100个字符") + private String shareholder4; + + @Schema(description = "股东5") + @Size(max = 100, message = "股东5长度不能超过100个字符") + private String shareholder5; + + @Schema(description = "经营状态") + @NotBlank(message = "经营状态不能为空") + @Size(max = 50, message = "经营状态长度不能超过50个字符") + private String status; + + @Schema(description = "风险等级") + @NotBlank(message = "风险等级不能为空") + private String riskLevel; + + @Schema(description = "企业来源") + @NotBlank(message = "企业来源不能为空") + private String entSource; + + @Schema(description = "数据来源") + @NotBlank(message = "数据来源不能为空") + private String dataSource; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoQueryDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoQueryDTO.java new file mode 100644 index 00000000..c9cd7e80 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoQueryDTO.java @@ -0,0 +1,45 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 实体库管理查询 DTO + * + * @author ruoyi + * @date 2026-04-17 + */ +@Data +@Schema(description = "实体库管理查询DTO") +public class CcdiEnterpriseBaseInfoQueryDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "统一社会信用代码") + private String socialCreditCode; + + @Schema(description = "企业类型") + private String enterpriseType; + + @Schema(description = "企业性质") + private String enterpriseNature; + + @Schema(description = "行业分类") + private String industryClass; + + @Schema(description = "经营状态") + private String status; + + @Schema(description = "风险等级") + private String riskLevel; + + @Schema(description = "企业来源") + private String entSource; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryEnterpriseRelationAddDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryEnterpriseRelationAddDTO.java new file mode 100644 index 00000000..4b71a070 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryEnterpriseRelationAddDTO.java @@ -0,0 +1,33 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 中介关联机构新增DTO + */ +@Data +@Schema(description = "中介关联机构新增DTO") +public class CcdiIntermediaryEnterpriseRelationAddDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "统一社会信用代码") + @NotBlank(message = "统一社会信用代码不能为空") + @Size(max = 18, message = "统一社会信用代码长度不能超过18个字符") + private String socialCreditCode; + + @Schema(description = "关联角色/职务") + @Size(max = 100, message = "关联角色/职务长度不能超过100个字符") + private String relationPersonPost; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryEnterpriseRelationEditDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryEnterpriseRelationEditDTO.java new file mode 100644 index 00000000..2a10c201 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryEnterpriseRelationEditDTO.java @@ -0,0 +1,38 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 中介关联机构编辑DTO + */ +@Data +@Schema(description = "中介关联机构编辑DTO") +public class CcdiIntermediaryEnterpriseRelationEditDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + @NotNull(message = "主键ID不能为空") + private Long id; + + @Schema(description = "统一社会信用代码") + @NotBlank(message = "统一社会信用代码不能为空") + @Size(max = 18, message = "统一社会信用代码长度不能超过18个字符") + private String socialCreditCode; + + @Schema(description = "关联角色/职务") + @Size(max = 100, message = "关联角色/职务长度不能超过100个字符") + private String relationPersonPost; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryRelativeAddDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryRelativeAddDTO.java new file mode 100644 index 00000000..3b8681da --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryRelativeAddDTO.java @@ -0,0 +1,72 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 中介亲属新增DTO + */ +@Data +@Schema(description = "中介亲属新增DTO") +public class CcdiIntermediaryRelativeAddDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "姓名") + @NotBlank(message = "姓名不能为空") + @Size(max = 100, message = "姓名长度不能超过100个字符") + private String name; + + @Schema(description = "人员类型") + private String personType; + + @Schema(description = "亲属关系") + @NotBlank(message = "亲属关系不能为空") + @Size(max = 50, message = "亲属关系长度不能超过50个字符") + private String personSubType; + + @Schema(description = "性别") + private String gender; + + @Schema(description = "证件类型") + private String idType; + + @Schema(description = "证件号码") + @NotBlank(message = "证件号码不能为空") + @Size(max = 50, message = "证件号码长度不能超过50个字符") + private String personId; + + @Schema(description = "手机号码") + @Size(max = 20, message = "手机号码长度不能超过20个字符") + private String mobile; + + @Schema(description = "微信号") + @Size(max = 50, message = "微信号长度不能超过50个字符") + private String wechatNo; + + @Schema(description = "联系地址") + @Size(max = 200, message = "联系地址长度不能超过200个字符") + private String contactAddress; + + @Schema(description = "所在公司") + @Size(max = 200, message = "所在公司长度不能超过200个字符") + private String company; + + @Schema(description = "企业统一信用码") + @Size(max = 50, message = "企业统一信用码长度不能超过50个字符") + private String socialCreditCode; + + @Schema(description = "职位") + @Size(max = 100, message = "职位长度不能超过100个字符") + private String position; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryRelativeEditDTO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryRelativeEditDTO.java new file mode 100644 index 00000000..12d5903a --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiIntermediaryRelativeEditDTO.java @@ -0,0 +1,75 @@ +package com.ruoyi.info.collection.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 中介亲属编辑DTO + */ +@Data +@Schema(description = "中介亲属编辑DTO") +public class CcdiIntermediaryRelativeEditDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "人员ID") + @NotBlank(message = "人员ID不能为空") + private String bizId; + + @Schema(description = "姓名") + @NotBlank(message = "姓名不能为空") + @Size(max = 100, message = "姓名长度不能超过100个字符") + private String name; + + @Schema(description = "人员类型") + private String personType; + + @Schema(description = "亲属关系") + @NotBlank(message = "亲属关系不能为空") + @Size(max = 50, message = "亲属关系长度不能超过50个字符") + private String personSubType; + + @Schema(description = "性别") + private String gender; + + @Schema(description = "证件类型") + private String idType; + + @Schema(description = "证件号码") + @Size(max = 50, message = "证件号码长度不能超过50个字符") + private String personId; + + @Schema(description = "手机号码") + @Size(max = 20, message = "手机号码长度不能超过20个字符") + private String mobile; + + @Schema(description = "微信号") + @Size(max = 50, message = "微信号长度不能超过50个字符") + private String wechatNo; + + @Schema(description = "联系地址") + @Size(max = 200, message = "联系地址长度不能超过200个字符") + private String contactAddress; + + @Schema(description = "所在公司") + @Size(max = 200, message = "所在公司长度不能超过200个字符") + private String company; + + @Schema(description = "企业统一信用码") + @Size(max = 50, message = "企业统一信用码长度不能超过50个字符") + private String socialCreditCode; + + @Schema(description = "职位") + @Size(max = 100, message = "职位长度不能超过100个字符") + private String position; + + @Schema(description = "备注") + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiEnterpriseBaseInfoExcel.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiEnterpriseBaseInfoExcel.java new file mode 100644 index 00000000..9ea0f78a --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiEnterpriseBaseInfoExcel.java @@ -0,0 +1,106 @@ +package com.ruoyi.info.collection.domain.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.ruoyi.common.annotation.DictDropdown; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 实体库管理 Excel 导入模板对象 + * + * @author ruoyi + * @date 2026-04-17 + */ +@Data +public class CcdiEnterpriseBaseInfoExcel implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "统一社会信用代码*", index = 0) + @ColumnWidth(24) + private String socialCreditCode; + + @ExcelProperty(value = "企业名称*", index = 1) + @ColumnWidth(30) + private String enterpriseName; + + @ExcelProperty(value = "企业类型", index = 2) + @ColumnWidth(18) + @DictDropdown(dictType = "ccdi_entity_type") + private String enterpriseType; + + @ExcelProperty(value = "企业性质", index = 3) + @ColumnWidth(18) + @DictDropdown(dictType = "ccdi_enterprise_nature") + private String enterpriseNature; + + @ExcelProperty(value = "行业分类", index = 4) + @ColumnWidth(18) + private String industryClass; + + @ExcelProperty(value = "所属行业", index = 5) + @ColumnWidth(18) + private String industryName; + + @ExcelProperty(value = "成立日期", index = 6) + @ColumnWidth(16) + private Date establishDate; + + @ExcelProperty(value = "注册地址", index = 7) + @ColumnWidth(36) + private String registerAddress; + + @ExcelProperty(value = "法定代表人", index = 8) + @ColumnWidth(18) + private String legalRepresentative; + + @ExcelProperty(value = "法定代表人证件类型", index = 9) + @ColumnWidth(22) + @DictDropdown(dictType = "ccdi_certificate_type") + private String legalCertType; + + @ExcelProperty(value = "法定代表人证件号码", index = 10) + @ColumnWidth(24) + private String legalCertNo; + + @ExcelProperty(value = "股东1", index = 11) + @ColumnWidth(18) + private String shareholder1; + + @ExcelProperty(value = "股东2", index = 12) + @ColumnWidth(18) + private String shareholder2; + + @ExcelProperty(value = "股东3", index = 13) + @ColumnWidth(18) + private String shareholder3; + + @ExcelProperty(value = "股东4", index = 14) + @ColumnWidth(18) + private String shareholder4; + + @ExcelProperty(value = "股东5", index = 15) + @ColumnWidth(18) + private String shareholder5; + + @ExcelProperty(value = "经营状态*", index = 16) + @ColumnWidth(16) + private String status; + + @ExcelProperty(value = "风险等级*", index = 17) + @ColumnWidth(16) + private String riskLevel; + + @ExcelProperty(value = "企业来源*", index = 18) + @ColumnWidth(18) + private String entSource; + + @ExcelProperty(value = "数据来源*", index = 19) + @ColumnWidth(18) + private String dataSource; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiEnterpriseBaseInfoVO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiEnterpriseBaseInfoVO.java new file mode 100644 index 00000000..e0d5e06f --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiEnterpriseBaseInfoVO.java @@ -0,0 +1,85 @@ +package com.ruoyi.info.collection.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 实体库管理 VO + * + * @author ruoyi + * @date 2026-04-17 + */ +@Data +@Schema(description = "实体库管理VO") +public class CcdiEnterpriseBaseInfoVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "统一社会信用代码") + private String socialCreditCode; + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "企业类型") + private String enterpriseType; + + @Schema(description = "企业性质") + private String enterpriseNature; + + @Schema(description = "行业分类") + private String industryClass; + + @Schema(description = "所属行业") + private String industryName; + + @Schema(description = "成立日期") + private Date establishDate; + + @Schema(description = "注册地址") + private String registerAddress; + + @Schema(description = "法定代表人") + private String legalRepresentative; + + @Schema(description = "法定代表人证件类型") + private String legalCertType; + + @Schema(description = "法定代表人证件号码") + private String legalCertNo; + + @Schema(description = "股东1") + private String shareholder1; + + @Schema(description = "股东2") + private String shareholder2; + + @Schema(description = "股东3") + private String shareholder3; + + @Schema(description = "股东4") + private String shareholder4; + + @Schema(description = "股东5") + private String shareholder5; + + @Schema(description = "经营状态") + private String status; + + @Schema(description = "风险等级") + private String riskLevel; + + @Schema(description = "企业来源") + private String entSource; + + @Schema(description = "数据来源") + private String dataSource; + + @Schema(description = "创建时间") + private Date createTime; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiIntermediaryEnterpriseRelationVO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiIntermediaryEnterpriseRelationVO.java new file mode 100644 index 00000000..841561ef --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiIntermediaryEnterpriseRelationVO.java @@ -0,0 +1,48 @@ +package com.ruoyi.info.collection.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 中介关联机构VO + */ +@Data +@Schema(description = "中介关联机构VO") +public class CcdiIntermediaryEnterpriseRelationVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "所属中介ID") + private String intermediaryBizId; + + @Schema(description = "所属中介姓名") + private String intermediaryName; + + @Schema(description = "所属中介证件号") + private String intermediaryPersonId; + + @Schema(description = "统一社会信用代码") + private String socialCreditCode; + + @Schema(description = "机构名称") + private String enterpriseName; + + @Schema(description = "关联角色/职务") + private String relationPersonPost; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiIntermediaryRelativeVO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiIntermediaryRelativeVO.java new file mode 100644 index 00000000..dcc60cfe --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiIntermediaryRelativeVO.java @@ -0,0 +1,69 @@ +package com.ruoyi.info.collection.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 中介亲属VO + */ +@Data +@Schema(description = "中介亲属VO") +public class CcdiIntermediaryRelativeVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "人员ID") + private String bizId; + + @Schema(description = "所属中介ID") + private String relatedNumId; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "人员类型") + private String personType; + + @Schema(description = "亲属关系") + private String personSubType; + + @Schema(description = "性别") + private String gender; + + @Schema(description = "证件类型") + private String idType; + + @Schema(description = "证件号码") + private String personId; + + @Schema(description = "手机号码") + private String mobile; + + @Schema(description = "微信号") + private String wechatNo; + + @Schema(description = "联系地址") + private String contactAddress; + + @Schema(description = "所在公司") + private String company; + + @Schema(description = "企业统一信用码") + private String socialCreditCode; + + @Schema(description = "职位") + private String position; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/EnterpriseBaseInfoImportFailureVO.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/EnterpriseBaseInfoImportFailureVO.java new file mode 100644 index 00000000..5f70bf6f --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/EnterpriseBaseInfoImportFailureVO.java @@ -0,0 +1,51 @@ +package com.ruoyi.info.collection.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 实体库导入失败记录 VO + * + * @author ruoyi + * @date 2026-04-17 + */ +@Data +@Schema(description = "实体库导入失败记录") +public class EnterpriseBaseInfoImportFailureVO { + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "统一社会信用代码") + private String socialCreditCode; + + @Schema(description = "企业类型") + private String enterpriseType; + + @Schema(description = "企业性质") + private String enterpriseNature; + + @Schema(description = "行业分类") + private String industryClass; + + @Schema(description = "所属行业") + private String industryName; + + @Schema(description = "法定代表人") + private String legalRepresentative; + + @Schema(description = "经营状态") + private String status; + + @Schema(description = "风险等级") + private String riskLevel; + + @Schema(description = "企业来源") + private String entSource; + + @Schema(description = "数据来源") + private String dataSource; + + @Schema(description = "错误信息") + private String errorMessage; +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseRiskLevel.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseRiskLevel.java new file mode 100644 index 00000000..be808f2e --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseRiskLevel.java @@ -0,0 +1,56 @@ +package com.ruoyi.info.collection.enums; + +/** + * 实体风险等级枚举 + * + * @author ruoyi + */ +public enum EnterpriseRiskLevel { + + HIGH("1", "高风险"), + MEDIUM("2", "中风险"), + LOW("3", "低风险"); + + private final String code; + private final String desc; + + EnterpriseRiskLevel(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public String getCode() { + return code; + } + + public String getDesc() { + return desc; + } + + public static String getDescByCode(String code) { + for (EnterpriseRiskLevel value : values()) { + if (value.code.equals(code)) { + return value.desc; + } + } + return null; + } + + public static boolean contains(String code) { + for (EnterpriseRiskLevel value : values()) { + if (value.code.equals(code)) { + return true; + } + } + return false; + } + + public static String resolveCode(String value) { + for (EnterpriseRiskLevel item : values()) { + if (item.code.equals(value) || item.desc.equals(value)) { + return item.code; + } + } + return null; + } +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseSource.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseSource.java new file mode 100644 index 00000000..b778173d --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseSource.java @@ -0,0 +1,58 @@ +package com.ruoyi.info.collection.enums; + +/** + * 企业来源枚举 + * + * @author ruoyi + */ +public enum EnterpriseSource { + + GENERAL("GENERAL", "一般企业"), + EMP_RELATION("EMP_RELATION", "员工关系人"), + CREDIT_CUSTOMER("CREDIT_CUSTOMER", "信贷客户"), + INTERMEDIARY("INTERMEDIARY", "中介"), + BOTH("BOTH", "兼有"); + + private final String code; + private final String desc; + + EnterpriseSource(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public String getCode() { + return code; + } + + public String getDesc() { + return desc; + } + + public static String getDescByCode(String code) { + for (EnterpriseSource value : values()) { + if (value.code.equals(code)) { + return value.desc; + } + } + return null; + } + + public static boolean contains(String code) { + for (EnterpriseSource value : values()) { + if (value.code.equals(code)) { + return true; + } + } + return false; + } + + public static String resolveCode(String value) { + for (EnterpriseSource item : values()) { + if (item.code.equals(value) || item.desc.equals(value)) { + return item.code; + } + } + return null; + } +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapper.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapper.java index 0fe7552e..7d714546 100644 --- a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapper.java +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapper.java @@ -1,7 +1,10 @@ package com.ruoyi.info.collection.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO; +import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -16,6 +19,16 @@ import java.util.List; @Mapper public interface CcdiEnterpriseBaseInfoMapper extends BaseMapper { + /** + * 分页查询实体库列表 + * + * @param page 分页参数 + * @param queryDTO 查询条件 + * @return 分页结果 + */ + Page selectEnterpriseBaseInfoPage(Page page, + @Param("queryDTO") CcdiEnterpriseBaseInfoQueryDTO queryDTO); + /** * 批量插入实体中介 * diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiIntermediaryEnterpriseRelationMapper.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiIntermediaryEnterpriseRelationMapper.java new file mode 100644 index 00000000..9bc27ff7 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiIntermediaryEnterpriseRelationMapper.java @@ -0,0 +1,23 @@ +package com.ruoyi.info.collection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ruoyi.info.collection.domain.CcdiIntermediaryEnterpriseRelation; +import com.ruoyi.info.collection.domain.vo.CcdiIntermediaryEnterpriseRelationVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 中介关联机构关系Mapper + */ +@Mapper +public interface CcdiIntermediaryEnterpriseRelationMapper extends BaseMapper { + + List selectByIntermediaryBizId(@Param("bizId") String bizId); + + CcdiIntermediaryEnterpriseRelationVO selectDetailById(@Param("id") Long id); + + boolean existsByIntermediaryBizIdAndSocialCreditCode(@Param("bizId") String bizId, + @Param("socialCreditCode") String socialCreditCode); +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoImportService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoImportService.java new file mode 100644 index 00000000..d84e8e4e --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoImportService.java @@ -0,0 +1,29 @@ +package com.ruoyi.info.collection.service; + +import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo; +import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel; +import com.ruoyi.info.collection.domain.vo.EnterpriseBaseInfoImportFailureVO; +import com.ruoyi.info.collection.domain.vo.ImportStatusVO; + +import java.util.List; +import java.util.Set; + +/** + * 实体库管理导入 Service 接口 + * + * @author ruoyi + * @date 2026-04-17 + */ +public interface ICcdiEnterpriseBaseInfoImportService { + + void importEnterpriseBaseInfoAsync(List excelList, String taskId, String userName); + + ImportStatusVO getImportStatus(String taskId); + + List getImportFailures(String taskId); + + CcdiEnterpriseBaseInfo validateAndBuildEntity(CcdiEnterpriseBaseInfoExcel excel, + Set existingCreditCodes, + Set processedCreditCodes, + String userName); +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoService.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoService.java new file mode 100644 index 00000000..f0c7dbb7 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoService.java @@ -0,0 +1,34 @@ +package com.ruoyi.info.collection.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoAddDTO; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel; +import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO; + +import java.util.List; + +/** + * 实体库管理 Service 接口 + * + * @author ruoyi + * @date 2026-04-17 + */ +public interface ICcdiEnterpriseBaseInfoService { + + Page selectEnterpriseBaseInfoPage(Page page, + CcdiEnterpriseBaseInfoQueryDTO queryDTO); + + CcdiEnterpriseBaseInfoVO selectEnterpriseBaseInfoById(String socialCreditCode); + + int insertEnterpriseBaseInfo(CcdiEnterpriseBaseInfoAddDTO addDTO); + + int updateEnterpriseBaseInfo(CcdiEnterpriseBaseInfoEditDTO editDTO); + + int deleteEnterpriseBaseInfoByIds(String[] socialCreditCodes); + + List selectEnterpriseBaseInfoListForExport(CcdiEnterpriseBaseInfoQueryDTO queryDTO); + + String importEnterpriseBaseInfo(List excelList); +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoImportServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoImportServiceImpl.java new file mode 100644 index 00000000..81bdd562 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoImportServiceImpl.java @@ -0,0 +1,225 @@ +package com.ruoyi.info.collection.service.impl; + +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo; +import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel; +import com.ruoyi.info.collection.domain.vo.EnterpriseBaseInfoImportFailureVO; +import com.ruoyi.info.collection.domain.vo.ImportResult; +import com.ruoyi.info.collection.domain.vo.ImportStatusVO; +import com.ruoyi.info.collection.enums.DataSource; +import com.ruoyi.info.collection.enums.EnterpriseRiskLevel; +import com.ruoyi.info.collection.enums.EnterpriseSource; +import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper; +import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoImportService; +import jakarta.annotation.Resource; +import org.springframework.beans.BeanUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 实体库管理导入 Service 实现 + * + * @author ruoyi + * @date 2026-04-17 + */ +@Service +@EnableAsync +public class CcdiEnterpriseBaseInfoImportServiceImpl implements ICcdiEnterpriseBaseInfoImportService { + + @Resource + private CcdiEnterpriseBaseInfoMapper enterpriseBaseInfoMapper; + + @Resource + private RedisTemplate redisTemplate; + + @Override + @Async + public void importEnterpriseBaseInfoAsync(List excelList, String taskId, String userName) { + List successRecords = new ArrayList<>(); + List failures = new ArrayList<>(); + Set existingCreditCodes = getExistingCreditCodes(excelList); + Set processedCreditCodes = new HashSet<>(); + + for (CcdiEnterpriseBaseInfoExcel excel : excelList) { + try { + CcdiEnterpriseBaseInfo entity = validateAndBuildEntity(excel, existingCreditCodes, processedCreditCodes, userName); + successRecords.add(entity); + processedCreditCodes.add(entity.getSocialCreditCode()); + } catch (Exception e) { + EnterpriseBaseInfoImportFailureVO failureVO = new EnterpriseBaseInfoImportFailureVO(); + BeanUtils.copyProperties(excel, failureVO); + failureVO.setErrorMessage(e.getMessage()); + failures.add(failureVO); + } + } + + if (!successRecords.isEmpty()) { + saveBatch(successRecords, 500); + } + + if (!failures.isEmpty()) { + redisTemplate.opsForValue().set(buildFailuresKey(taskId), failures, 7, TimeUnit.DAYS); + } + + ImportResult result = new ImportResult(); + result.setTotalCount(excelList.size()); + result.setSuccessCount(successRecords.size()); + result.setFailureCount(failures.size()); + updateImportStatus(taskId, failures.isEmpty() ? "SUCCESS" : "PARTIAL_SUCCESS", result); + } + + @Override + public ImportStatusVO getImportStatus(String taskId) { + String key = buildStatusKey(taskId); + Boolean exists = redisTemplate.hasKey(key); + if (Boolean.FALSE.equals(exists)) { + throw new RuntimeException("任务不存在或已过期"); + } + + Map statusMap = redisTemplate.opsForHash().entries(key); + ImportStatusVO statusVO = new ImportStatusVO(); + statusVO.setTaskId((String) statusMap.get("taskId")); + statusVO.setStatus((String) statusMap.get("status")); + statusVO.setTotalCount((Integer) statusMap.get("totalCount")); + statusVO.setSuccessCount((Integer) statusMap.get("successCount")); + statusVO.setFailureCount((Integer) statusMap.get("failureCount")); + statusVO.setProgress((Integer) statusMap.get("progress")); + statusVO.setStartTime((Long) statusMap.get("startTime")); + statusVO.setEndTime((Long) statusMap.get("endTime")); + statusVO.setMessage((String) statusMap.get("message")); + return statusVO; + } + + @Override + public List getImportFailures(String taskId) { + Object failuresObj = redisTemplate.opsForValue().get(buildFailuresKey(taskId)); + if (failuresObj == null) { + return Collections.emptyList(); + } + return JSON.parseArray(JSON.toJSONString(failuresObj), EnterpriseBaseInfoImportFailureVO.class); + } + + @Override + public CcdiEnterpriseBaseInfo validateAndBuildEntity(CcdiEnterpriseBaseInfoExcel excel, + Set existingCreditCodes, + Set processedCreditCodes, + String userName) { + if (excel == null) { + throw new RuntimeException("导入数据不能为空"); + } + if (StringUtils.isEmpty(excel.getEnterpriseName())) { + throw new RuntimeException("企业名称不能为空"); + } + if (StringUtils.isEmpty(excel.getSocialCreditCode())) { + throw new RuntimeException("统一社会信用代码不能为空"); + } + if (!excel.getSocialCreditCode().matches("^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$")) { + throw new RuntimeException("统一社会信用代码格式不正确"); + } + if (StringUtils.isEmpty(excel.getStatus())) { + throw new RuntimeException("经营状态不能为空"); + } + + String riskLevel = EnterpriseRiskLevel.resolveCode(StringUtils.trim(excel.getRiskLevel())); + if (riskLevel == null) { + throw new RuntimeException("风险等级不在允许范围内"); + } + String entSource = EnterpriseSource.resolveCode(StringUtils.trim(excel.getEntSource())); + if (entSource == null) { + throw new RuntimeException("企业来源不在允许范围内"); + } + String dataSource = resolveDataSourceCode(StringUtils.trim(excel.getDataSource())); + if (dataSource == null) { + throw new RuntimeException("数据来源不在允许范围内"); + } + + if (existingCreditCodes.contains(excel.getSocialCreditCode())) { + throw new RuntimeException(String.format("统一社会信用代码[%s]已存在,请勿重复导入", excel.getSocialCreditCode())); + } + if (processedCreditCodes.contains(excel.getSocialCreditCode())) { + throw new RuntimeException(String.format("统一社会信用代码[%s]在导入文件中重复,已跳过此条记录", excel.getSocialCreditCode())); + } + + CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo(); + BeanUtils.copyProperties(excel, entity); + entity.setRiskLevel(riskLevel); + entity.setEntSource(entSource); + entity.setDataSource(dataSource); + entity.setStatus(StringUtils.trim(excel.getStatus())); + entity.setCreatedBy(userName); + entity.setUpdatedBy(userName); + return entity; + } + + private Set getExistingCreditCodes(List excelList) { + List creditCodes = excelList.stream() + .map(CcdiEnterpriseBaseInfoExcel::getSocialCreditCode) + .filter(StringUtils::isNotEmpty) + .collect(Collectors.toList()); + if (creditCodes.isEmpty()) { + return Collections.emptySet(); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(CcdiEnterpriseBaseInfo::getSocialCreditCode, creditCodes); + return enterpriseBaseInfoMapper.selectList(wrapper).stream() + .map(CcdiEnterpriseBaseInfo::getSocialCreditCode) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + private int saveBatch(List list, int batchSize) { + int total = 0; + for (int i = 0; i < list.size(); i += batchSize) { + int end = Math.min(i + batchSize, list.size()); + total += enterpriseBaseInfoMapper.insertBatch(list.subList(i, end)); + } + return total; + } + + private void updateImportStatus(String taskId, String status, ImportResult result) { + Map statusData = new HashMap<>(); + statusData.put("status", status); + statusData.put("successCount", result.getSuccessCount()); + statusData.put("failureCount", result.getFailureCount()); + statusData.put("progress", 100); + statusData.put("endTime", System.currentTimeMillis()); + if ("SUCCESS".equals(status)) { + statusData.put("message", "全部成功!共导入" + result.getTotalCount() + "条数据"); + } else { + statusData.put("message", "成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "条"); + } + redisTemplate.opsForHash().putAll(buildStatusKey(taskId), statusData); + } + + private String resolveDataSourceCode(String value) { + for (DataSource source : DataSource.values()) { + if (source.getCode().equals(value) || source.getDesc().equals(value)) { + return source.getCode(); + } + } + return null; + } + + private String buildStatusKey(String taskId) { + return "import:enterpriseBaseInfo:" + taskId; + } + + private String buildFailuresKey(String taskId) { + return "import:enterpriseBaseInfo:" + taskId + ":failures"; + } +} diff --git a/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoServiceImpl.java b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoServiceImpl.java new file mode 100644 index 00000000..70820e81 --- /dev/null +++ b/ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoServiceImpl.java @@ -0,0 +1,182 @@ +package com.ruoyi.info.collection.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoAddDTO; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoEditDTO; +import com.ruoyi.info.collection.domain.dto.CcdiEnterpriseBaseInfoQueryDTO; +import com.ruoyi.info.collection.domain.excel.CcdiEnterpriseBaseInfoExcel; +import com.ruoyi.info.collection.domain.vo.CcdiEnterpriseBaseInfoVO; +import com.ruoyi.info.collection.enums.DataSource; +import com.ruoyi.info.collection.enums.EnterpriseRiskLevel; +import com.ruoyi.info.collection.enums.EnterpriseSource; +import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper; +import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoImportService; +import com.ruoyi.info.collection.service.ICcdiEnterpriseBaseInfoService; +import jakarta.annotation.Resource; +import org.springframework.beans.BeanUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * 实体库管理 Service 实现 + * + * @author ruoyi + * @date 2026-04-17 + */ +@Service +public class CcdiEnterpriseBaseInfoServiceImpl implements ICcdiEnterpriseBaseInfoService { + + @Resource + private CcdiEnterpriseBaseInfoMapper enterpriseBaseInfoMapper; + + @Resource + private ICcdiEnterpriseBaseInfoImportService enterpriseBaseInfoImportService; + + @Resource + private RedisTemplate redisTemplate; + + @Override + public Page selectEnterpriseBaseInfoPage(Page page, + CcdiEnterpriseBaseInfoQueryDTO queryDTO) { + return enterpriseBaseInfoMapper.selectEnterpriseBaseInfoPage(page, queryDTO); + } + + @Override + public CcdiEnterpriseBaseInfoVO selectEnterpriseBaseInfoById(String socialCreditCode) { + CcdiEnterpriseBaseInfo entity = enterpriseBaseInfoMapper.selectById(socialCreditCode); + if (entity == null) { + return null; + } + CcdiEnterpriseBaseInfoVO vo = new CcdiEnterpriseBaseInfoVO(); + BeanUtils.copyProperties(entity, vo); + return vo; + } + + @Override + @Transactional + public int insertEnterpriseBaseInfo(CcdiEnterpriseBaseInfoAddDTO addDTO) { + if (enterpriseBaseInfoMapper.selectById(addDTO.getSocialCreditCode()) != null) { + throw new RuntimeException("该统一社会信用代码已存在"); + } + validateEnumFields(addDTO.getStatus(), addDTO.getRiskLevel(), addDTO.getEntSource(), addDTO.getDataSource()); + + CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo(); + BeanUtils.copyProperties(addDTO, entity); + return enterpriseBaseInfoMapper.insert(entity); + } + + @Override + @Transactional + public int updateEnterpriseBaseInfo(CcdiEnterpriseBaseInfoEditDTO editDTO) { + CcdiEnterpriseBaseInfo existing = enterpriseBaseInfoMapper.selectById(editDTO.getSocialCreditCode()); + if (existing == null) { + throw new RuntimeException("实体库记录不存在"); + } + validateEnumFields(editDTO.getStatus(), editDTO.getRiskLevel(), editDTO.getEntSource(), editDTO.getDataSource()); + + CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo(); + BeanUtils.copyProperties(editDTO, entity); + return enterpriseBaseInfoMapper.updateById(entity); + } + + @Override + @Transactional + public int deleteEnterpriseBaseInfoByIds(String[] socialCreditCodes) { + if (socialCreditCodes == null || socialCreditCodes.length == 0) { + return 0; + } + return enterpriseBaseInfoMapper.deleteBatchIds(List.of(socialCreditCodes)); + } + + @Override + public List selectEnterpriseBaseInfoListForExport(CcdiEnterpriseBaseInfoQueryDTO queryDTO) { + LambdaQueryWrapper wrapper = buildQueryWrapper(queryDTO); + return enterpriseBaseInfoMapper.selectList(wrapper).stream().map(entity -> { + CcdiEnterpriseBaseInfoExcel excel = new CcdiEnterpriseBaseInfoExcel(); + BeanUtils.copyProperties(entity, excel); + return excel; + }).toList(); + } + + @Override + @Transactional + public String importEnterpriseBaseInfo(List excelList) { + String taskId = UUID.randomUUID().toString(); + String statusKey = "import:enterpriseBaseInfo:" + taskId; + + Map statusData = new HashMap<>(); + statusData.put("taskId", taskId); + statusData.put("status", "PROCESSING"); + statusData.put("totalCount", excelList.size()); + statusData.put("successCount", 0); + statusData.put("failureCount", 0); + statusData.put("progress", 0); + statusData.put("startTime", System.currentTimeMillis()); + statusData.put("message", "正在处理..."); + + redisTemplate.opsForHash().putAll(statusKey, statusData); + redisTemplate.expire(statusKey, 7, TimeUnit.DAYS); + + enterpriseBaseInfoImportService.importEnterpriseBaseInfoAsync(excelList, taskId, SecurityUtils.getUsername()); + return taskId; + } + + private LambdaQueryWrapper buildQueryWrapper(CcdiEnterpriseBaseInfoQueryDTO queryDTO) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (queryDTO == null) { + return wrapper.orderByDesc(CcdiEnterpriseBaseInfo::getCreateTime); + } + wrapper.like(StringUtils.isNotEmpty(queryDTO.getEnterpriseName()), + CcdiEnterpriseBaseInfo::getEnterpriseName, queryDTO.getEnterpriseName()); + wrapper.eq(StringUtils.isNotEmpty(queryDTO.getSocialCreditCode()), + CcdiEnterpriseBaseInfo::getSocialCreditCode, queryDTO.getSocialCreditCode()); + wrapper.eq(StringUtils.isNotEmpty(queryDTO.getEnterpriseType()), + CcdiEnterpriseBaseInfo::getEnterpriseType, queryDTO.getEnterpriseType()); + wrapper.eq(StringUtils.isNotEmpty(queryDTO.getEnterpriseNature()), + CcdiEnterpriseBaseInfo::getEnterpriseNature, queryDTO.getEnterpriseNature()); + wrapper.like(StringUtils.isNotEmpty(queryDTO.getIndustryClass()), + CcdiEnterpriseBaseInfo::getIndustryClass, queryDTO.getIndustryClass()); + wrapper.eq(StringUtils.isNotEmpty(queryDTO.getStatus()), + CcdiEnterpriseBaseInfo::getStatus, queryDTO.getStatus()); + wrapper.eq(StringUtils.isNotEmpty(queryDTO.getRiskLevel()), + CcdiEnterpriseBaseInfo::getRiskLevel, queryDTO.getRiskLevel()); + wrapper.eq(StringUtils.isNotEmpty(queryDTO.getEntSource()), + CcdiEnterpriseBaseInfo::getEntSource, queryDTO.getEntSource()); + return wrapper.orderByDesc(CcdiEnterpriseBaseInfo::getCreateTime); + } + + private void validateEnumFields(String status, String riskLevel, String entSource, String dataSource) { + if (StringUtils.isEmpty(status)) { + throw new RuntimeException("经营状态不能为空"); + } + if (!EnterpriseRiskLevel.contains(riskLevel)) { + throw new RuntimeException("风险等级不在允许范围内"); + } + if (!EnterpriseSource.contains(entSource)) { + throw new RuntimeException("企业来源不在允许范围内"); + } + if (!containsDataSource(dataSource)) { + throw new RuntimeException("数据来源不在允许范围内"); + } + } + + private boolean containsDataSource(String code) { + for (DataSource source : DataSource.values()) { + if (source.getCode().equals(code)) { + return true; + } + } + return false; + } +} diff --git a/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiEnterpriseBaseInfoMapper.xml b/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiEnterpriseBaseInfoMapper.xml index 22b32dbb..68502958 100644 --- a/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiEnterpriseBaseInfoMapper.xml +++ b/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiEnterpriseBaseInfoMapper.xml @@ -4,6 +4,83 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO ccdi_enterprise_base_info ( @@ -21,7 +98,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{item.legalRepresentative}, #{item.legalCertType}, #{item.legalCertNo}, #{item.shareholder1}, #{item.shareholder2}, #{item.shareholder3}, #{item.shareholder4}, #{item.shareholder5}, #{item.status}, #{item.riskLevel}, #{item.entSource}, #{item.dataSource}, - #{item.createdBy}, #{item.updatedBy}, #{item.createTime}, #{item.updateTime} + #{item.createdBy}, #{item.updatedBy}, NOW(), NOW() ) @@ -43,7 +120,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{item.legalRepresentative}, #{item.legalCertType}, #{item.legalCertNo}, #{item.shareholder1}, #{item.shareholder2}, #{item.shareholder3}, #{item.shareholder4}, #{item.shareholder5}, #{item.status}, #{item.riskLevel}, #{item.entSource}, #{item.dataSource}, - #{item.createdBy}, #{item.updatedBy}, #{item.createTime}, #{item.updateTime} + #{item.createdBy}, #{item.updatedBy}, NOW(), NOW() ) ON DUPLICATE KEY UPDATE @@ -67,7 +144,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ent_source = VALUES(ent_source), data_source = VALUES(data_source), updated_by = VALUES(updated_by), - update_time = VALUES(update_time) + update_time = NOW() @@ -95,7 +172,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ent_source = #{item.entSource}, data_source = #{item.dataSource}, updated_by = #{item.updatedBy}, - update_time = #{item.updateTime} + update_time = NOW() WHERE social_credit_code = #{item.socialCreditCode} diff --git a/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiIntermediaryEnterpriseRelationMapper.xml b/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiIntermediaryEnterpriseRelationMapper.xml new file mode 100644 index 00000000..7c143fad --- /dev/null +++ b/ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiIntermediaryEnterpriseRelationMapper.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/plans/backend/2026-04-17-enterprise-base-info-management-backend-implementation.md b/docs/plans/backend/2026-04-17-enterprise-base-info-management-backend-implementation.md new file mode 100644 index 00000000..7e65b012 --- /dev/null +++ b/docs/plans/backend/2026-04-17-enterprise-base-info-management-backend-implementation.md @@ -0,0 +1,188 @@ +# 实体库管理后端实施计划 + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 新增独立的实体库管理后端链路,基于 `ccdi_enterprise_base_info` 支持分页查询、详情、新增、编辑、删除、异步导入、导入状态查询和失败记录查询。 + +**Architecture:** 复用现有 `CcdiEnterpriseBaseInfo` 实体与 Mapper,新增独立的 Controller、Service、DTO、VO、Excel 与导入服务,接口风格与员工信息维护保持一致。`riskLevel`、`entSource`、`dataSource` 统一通过枚举接口对外提供选项,导入采用严格新增策略,数据库重复和 Excel 内重复统一记为失败。 + +**Tech Stack:** Java 21, Spring Boot 3, MyBatis Plus, Redis, EasyExcel, JUnit 5, MySQL, Markdown + +--- + +## 文件结构与职责 + +**后端源码** + +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnterpriseBaseInfoController.java` + 实体库管理对外接口入口,提供 CRUD、导入模板、导入任务状态和失败记录查询。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoService.java` + 定义实体库管理服务接口。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoImportService.java` + 定义异步导入状态与失败记录查询接口。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoServiceImpl.java` + 承接分页查询、详情、增删改和导入任务提交。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoImportServiceImpl.java` + 处理异步导入、校验、失败记录落 Redis 与状态回写。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoQueryDTO.java` + 定义查询条件。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoAddDTO.java` + 定义新增入参和校验规则。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoEditDTO.java` + 定义编辑入参与主键不可变约束。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiEnterpriseBaseInfoVO.java` + 承接列表和详情返回。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/EnterpriseBaseInfoImportFailureVO.java` + 承接导入失败记录回显。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiEnterpriseBaseInfoExcel.java` + 定义导入模板列、导入字段和字典下拉。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseRiskLevel.java` + 新增实体风险等级枚举。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseSource.java` + 新增企业来源枚举。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnumController.java` + 新增风险等级与企业来源选项接口。 +- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapper.java` + 补充分页查询与批量导入方法声明。 +- `ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiEnterpriseBaseInfoMapper.xml` + 补充分页查询、结果映射、批量插入 SQL。 + +**SQL** + +- `sql/migration/2026-04-17-add-enterprise-base-info-menu.sql` + 新增“实体库管理”菜单和功能权限。 +- `sql/migration/2026-04-17-add-enterprise-base-info-dict-or-enum-seed.sql` + 如需初始化与导入模板一致的固定值说明,可在脚本中补充注释性或字典性数据;若最终走纯枚举接口,则只保留菜单 SQL。 + +**测试** + +- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiEnterpriseBaseInfoServiceImplTest.java` + 校验新增、编辑、删除、详情和枚举值校验。 +- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiEnterpriseBaseInfoImportServiceImplTest.java` + 校验导入重复失败、Excel 内重复失败和状态回写。 +- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapperTest.java` + 校验分页 SQL 和结果映射关键片段。 +- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/controller/CcdiEnumControllerTest.java` + 校验新增的枚举选项接口。 + +## 实施任务 + +### Task 1: 搭建实体库管理 DTO / VO / Excel 契约 + +**Files:** + +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoQueryDTO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoAddDTO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiEnterpriseBaseInfoEditDTO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiEnterpriseBaseInfoVO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/EnterpriseBaseInfoImportFailureVO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiEnterpriseBaseInfoExcel.java` +- Reference: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiEnterpriseBaseInfo.java` +- Reference: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiIntermediaryEntityExcel.java` + +- [x] 定义 QueryDTO,包含 `enterpriseName`、`socialCreditCode`、`enterpriseType`、`enterpriseNature`、`industryClass`、`status`、`riskLevel`、`entSource`。 +- [x] 定义 AddDTO / EditDTO,完整覆盖单表维护字段,并给 `socialCreditCode`、`enterpriseName`、`status`、`riskLevel`、`entSource`、`dataSource` 加基础校验。 +- [x] 在 EditDTO 中保持主键为必填,不新增改主键语义字段。 +- [x] 定义 VO,补齐列表和详情所需字段,并预留 `createTime` 供前端表格展示。 +- [x] 定义 Excel 对象,列顺序与页面表单一致,并为 `enterpriseType`、`enterpriseNature`、`legalCertType` 使用现有字典下拉;`riskLevel`、`entSource`、`dataSource` 保持文本列,后续由导入服务做枚举校验。 + +### Task 2: 补齐风险等级与企业来源枚举出口 + +**Files:** + +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseRiskLevel.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/enums/EnterpriseSource.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnumController.java` + +- [x] 新增 `EnterpriseRiskLevel` 枚举,口径固定为 `1/2/3` 对应高/中/低风险,并提供 `getCode()`、`getDesc()`、`getDescByCode()`、`contains()`。 +- [x] 新增 `EnterpriseSource` 枚举,口径固定为 `GENERAL`、`EMP_RELATION`、`CREDIT_CUSTOMER`、`INTERMEDIARY`、`BOTH`,并提供与现有 `DataSource` 一致的方法。 +- [x] 在 `CcdiEnumController` 中新增 `/enterpriseRiskLevel` 与 `/enterpriseSource` 两个接口,返回 `EnumOptionVO` 列表。 +- [x] 保持现有 `/dataSource` 不变,避免前端重复造轮子。 + +### Task 3: 实现分页查询与 CRUD 服务链路 + +**Files:** + +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapper.java` +- Modify: `ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiEnterpriseBaseInfoMapper.xml` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoService.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoServiceImpl.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnterpriseBaseInfoController.java` +- Reference: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java` +- Reference: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java` + +- [x] 在 Mapper 中新增分页查询方法,按 QueryDTO 动态拼装筛选条件。 +- [x] 在 Mapper XML 中新增结果映射和 `selectEnterpriseBaseInfoPage` SQL,输出 `create_time`、`risk_level`、`ent_source`、`data_source` 等字段。 +- [x] 在 Service 接口中定义分页、详情、新增、编辑、删除、导出列表、导入任务提交方法。 +- [x] 在 ServiceImpl 中实现主键唯一校验、编辑存在性校验、枚举值校验和删除批量处理。 +- [x] 新建 Controller,接口路径统一使用 `/ccdi/enterpriseBaseInfo`,返回风格完全对齐员工信息维护。 +- [x] 导入模板下载复用 `EasyExcelUtil.importTemplateWithDictDropdown`。 + +### Task 4: 实现异步导入与失败记录查询 + +**Files:** + +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiEnterpriseBaseInfoImportService.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoImportServiceImpl.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiEnterpriseBaseInfoServiceImpl.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiEnterpriseBaseInfoController.java` +- Reference: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java` +- Reference: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiIntermediaryEntityImportServiceImpl.java` + +- [x] 在 ServiceImpl 中提交导入任务,Redis key 建议使用 `import:enterpriseBaseInfo:{taskId}`。 +- [x] 在导入服务中实现 Excel 行校验,数据库重复与 Excel 内重复统一生成失败记录。 +- [x] 新增 `riskLevel`、`entSource`、`dataSource` 枚举校验,拒绝非法值。 +- [x] 成功记录分批批量插入;导入不支持更新,不提供 `updateSupport` 分支逻辑。 +- [x] 失败记录写入 Redis,状态统一支持 `PROCESSING`、`SUCCESS`、`PARTIAL_SUCCESS`。 +- [x] Controller 补 `/importData`、`/importStatus/{taskId}`、`/importFailures/{taskId}` 三个接口,分页失败记录方式与员工信息维护一致。 + +### Task 5: 补菜单 SQL 和权限口径 + +**Files:** + +- Create: `sql/migration/2026-04-17-add-enterprise-base-info-menu.sql` +- Reference: `sql/ccdi_staff_fmy_relation_menu.sql` +- Reference: `sql/migration/2026-04-13-add-ccdi-account-info-menu.sql` + +- [x] 在“信息维护”目录下新增“实体库管理”菜单。 +- [x] 菜单 path 固定为 `enterpriseBaseInfo`,component 固定为 `ccdiEnterpriseBaseInfo/index`。 +- [x] 功能权限至少包含 `list`、`query`、`add`、`edit`、`remove`、`import`。 +- [x] SQL 保持幂等写法,避免重复插入菜单。 + +### Task 6: 补后端测试与验证命令 + +**Files:** + +- Create: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiEnterpriseBaseInfoServiceImplTest.java` +- Create: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiEnterpriseBaseInfoImportServiceImplTest.java` +- Create: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/mapper/CcdiEnterpriseBaseInfoMapperTest.java` +- Create: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/controller/CcdiEnumControllerTest.java` + +- [x] 为新增、编辑、删除、详情和枚举值校验补服务测试。 +- [x] 为导入数据库重复失败、Excel 内重复失败补导入服务测试。 +- [x] 为 Mapper XML 的分页查询关键 SQL 补测试或最小断言。 +- [x] 为新增枚举接口补 Controller 测试。 +- [x] 执行后端验证命令并记录结果。 + +## 验证命令 + +```bash +mvn -pl ccdi-info-collection -Dtest=CcdiEnterpriseBaseInfoServiceImplTest,CcdiEnterpriseBaseInfoImportServiceImplTest,CcdiEnterpriseBaseInfoMapperTest,CcdiEnumControllerTest test +mvn -pl ccdi-info-collection -DskipTests compile +``` + +## 执行结果 + +- 实际测试命令:`mvn -pl ccdi-info-collection -am -Dsurefire.failIfNoSpecifiedTests=false -Dtest=CcdiEnterpriseBaseInfoServiceImplTest,CcdiEnterpriseBaseInfoImportServiceImplTest,CcdiEnterpriseBaseInfoMapperTest,CcdiEnumControllerTest test` +- 测试结果:`BUILD SUCCESS`,共执行 11 个测试,`Failures: 0, Errors: 0, Skipped: 0` +- 实际编译命令:`mvn -pl ccdi-info-collection -am -DskipTests compile` +- 编译结果:`BUILD SUCCESS` + +## 完成标准 + +- 后端新增独立 `/ccdi/enterpriseBaseInfo` 管理接口 +- 列表、详情、新增、编辑、删除链路可用 +- 导入严格新增,数据库重复与 Excel 内重复都进入失败记录 +- `riskLevel`、`entSource`、`dataSource` 均有统一选项口径 +- 菜单 SQL 与权限标识已补齐 +- 后端定向测试与编译验证已执行并记录结果 diff --git a/docs/plans/frontend/2026-04-17-enterprise-base-info-management-frontend-implementation.md b/docs/plans/frontend/2026-04-17-enterprise-base-info-management-frontend-implementation.md new file mode 100644 index 00000000..023d7149 --- /dev/null +++ b/docs/plans/frontend/2026-04-17-enterprise-base-info-management-frontend-implementation.md @@ -0,0 +1,126 @@ +# 实体库管理前端实施计划 + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 新增独立的实体库管理前端页面,打通查询、新增、查看、编辑、删除、导入、导入状态轮询与失败记录查看。 + +**Architecture:** 继续沿用员工信息维护的单页大文件实现方式,新建 `ccdiEnterpriseBaseInfo` 页面和独立 API 文件,不改造现有中介页面。选项数据统一从 `ccdiEnum` 拉取,列表、弹窗、导入和失败记录交互整体对齐员工信息维护,避免页面内再维护一套业务语义。 + +**Tech Stack:** Vue 2, Element UI, JavaScript, npm, nvm, Markdown + +--- + +## 文件结构与职责 + +**前端源码** + +- `ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue` + 实体库管理主页面,负责搜索、表格、编辑弹窗、详情弹窗、导入和失败记录。 +- `ruoyi-ui/src/api/ccdiEnterpriseBaseInfo.js` + 新增实体库管理接口封装。 +- `ruoyi-ui/src/api/ccdiEnum.js` + 补风险等级与企业来源选项请求方法。 + +**依赖参考** + +- `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` + 作为页面结构、导入轮询、失败记录和工具栏交互模板。 +- `ruoyi-ui/src/views/ccdiIntermediary/index.vue` + 参考实体导入失败记录展示字段。 +- `ruoyi-ui/src/api/ccdiBaseStaff.js` + 参考单表管理 API 风格。 + +## 实施任务 + +### Task 1: 搭建实体库管理 API 与选项加载 + +**Files:** + +- Create: `ruoyi-ui/src/api/ccdiEnterpriseBaseInfo.js` +- Modify: `ruoyi-ui/src/api/ccdiEnum.js` + +- [x] 在新 API 文件中定义 `listEnterpriseBaseInfo`、`getEnterpriseBaseInfo`、`addEnterpriseBaseInfo`、`updateEnterpriseBaseInfo`、`delEnterpriseBaseInfo`、`importTemplate`、`importData`、`getImportStatus`、`getImportFailures`。 +- [x] 在 `ccdiEnum.js` 中新增 `getEnterpriseRiskLevelOptions` 与 `getEnterpriseSourceOptions`。 +- [x] 继续复用现有 `getCorpTypeOptions`、`getCorpNatureOptions`、`getCertTypeOptions`、`getDataSourceOptions`。 + +### Task 2: 搭建页面骨架与查询表单 + +**Files:** + +- Create: `ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue` +- Reference: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` + +- [x] 初始化页面数据结构,至少包含 `loading`、`enterpriseBaseInfoList`、`queryParams`、`form`、`rules`、`open`、`detailOpen`、`upload`、`showFailureButton`。 +- [x] 查询区按设计文档落 `enterpriseName`、`socialCreditCode`、`enterpriseType`、`enterpriseNature`、`industryClass`、`status`、`riskLevel`、`entSource`。 +- [x] 在 `created` 或首屏初始化流程中并发拉取主体类型、企业性质、证件类型、风险等级、企业来源、数据来源选项。 +- [x] 搜索、重置、分页方法命名保持员工页一致,降低后续维护成本。 + +### Task 3: 完成列表、详情与编辑弹窗 + +**Files:** + +- Modify: `ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue` + +- [x] 列表区展示企业名称、统一社会信用代码、企业类型、企业性质、行业分类、所属行业、法定代表人、经营状态、风险等级、企业来源、数据来源、创建时间。 +- [x] 通过格式化方法把 `riskLevel`、`entSource`、`dataSource` 展示成中文描述,不直接露出编码。 +- [x] 实现详情弹窗,只读展示与表单同口径字段。 +- [x] 实现新增/编辑弹窗,编辑态禁用统一社会信用代码输入框。 +- [x] 表单中补齐 `status`、`riskLevel`、`entSource`、`dataSource` 四个可维护字段。 +- [x] 提交时保持最短路径,不做额外参数转换层,只在需要时把空字符串标准化。 + +### Task 4: 完成删除、导入与失败记录流程 + +**Files:** + +- Modify: `ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue` + +- [x] 删除逻辑对齐员工页,支持单条删除和批量删除。 +- [x] 新增导入弹窗配置,上传地址指向 `/ccdi/enterpriseBaseInfo/importData`。 +- [x] 导入完成后缓存最近一次任务号,建议 key 使用 `enterprise_base_info_import_last_task`。 +- [x] 增加导入状态轮询逻辑,状态结束后刷新列表并按结果决定是否显示“查看导入失败记录”按钮。 +- [x] 新增失败记录弹窗,至少展示企业名称、统一社会信用代码、企业类型、企业性质、风险等级、企业来源、失败原因。 +- [x] 提供“清除历史记录”能力,行为与员工页保持一致。 + +### Task 5: 补页面校验和展示细节 + +**Files:** + +- Modify: `ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue` + +- [x] 为统一社会信用代码增加 18 位格式校验。 +- [x] 为企业名称、经营状态、风险等级、企业来源、数据来源增加必填校验。 +- [x] 新增 `formatRiskLevel`、`formatEnterpriseSource`、`formatDataSource`、`formatStatus` 等展示方法。 +- [x] 详情和列表统一复用格式化方法,避免页面出现双口径文本。 + +### Task 6: 执行前端构建验证 + +**Files:** + +- Modify: `docs/plans/frontend/2026-04-17-enterprise-base-info-management-frontend-implementation.md` + 在执行阶段补实际验证结果。 + +- [x] 使用 `nvm` 切换 Node 版本,优先使用当前仓库已验证可构建的版本。 +- [x] 执行生产构建,确认页面编译通过。 +- [x] 若有构建阻塞,记录真实错误,不引入额外兼容方案。 + +## 验证命令 + +```bash +cd /Users/wkc/Desktop/ccdi/ccdi/ruoyi-ui +source ~/.nvm/nvm.sh && nvm use 14.21.3 +npm run build:prod +``` + +## 执行结果 + +- 实际执行命令:`cd /Users/wkc/Desktop/ccdi/ccdi/ruoyi-ui && source ~/.nvm/nvm.sh && nvm use 14.21.3 && npm run build:prod` +- 构建结果:`BUILD SUCCESS` +- 备注:构建过程中仅有既有包体积告警(asset size / entrypoint size limit),未出现语法或模块解析错误 + +## 完成标准 + +- 前端新增独立“实体库管理”页面与 API 文件 +- 查询、分页、详情、新增、编辑、删除链路可用 +- 风险等级、企业来源、数据来源全部以统一选项口径展示和提交 +- 导入轮询、失败记录、历史任务缓存可用 +- 已使用 `nvm` 切换 Node 版本并完成前端构建验证 diff --git a/ruoyi-ui/src/api/ccdiEnterpriseBaseInfo.js b/ruoyi-ui/src/api/ccdiEnterpriseBaseInfo.js new file mode 100644 index 00000000..5afab2bd --- /dev/null +++ b/ruoyi-ui/src/api/ccdiEnterpriseBaseInfo.js @@ -0,0 +1,78 @@ +import request from '@/utils/request' + +// 查询实体库列表 +export function listEnterpriseBaseInfo(query) { + return request({ + url: '/ccdi/enterpriseBaseInfo/list', + method: 'get', + params: query + }) +} + +// 查询实体库详细 +export function getEnterpriseBaseInfo(socialCreditCode) { + return request({ + url: '/ccdi/enterpriseBaseInfo/' + socialCreditCode, + method: 'get' + }) +} + +// 新增实体库 +export function addEnterpriseBaseInfo(data) { + return request({ + url: '/ccdi/enterpriseBaseInfo', + method: 'post', + data: data + }) +} + +// 修改实体库 +export function updateEnterpriseBaseInfo(data) { + return request({ + url: '/ccdi/enterpriseBaseInfo', + method: 'put', + data: data + }) +} + +// 删除实体库 +export function delEnterpriseBaseInfo(socialCreditCodes) { + return request({ + url: '/ccdi/enterpriseBaseInfo/' + socialCreditCodes, + method: 'delete' + }) +} + +// 下载导入模板 +export function importTemplate() { + return request({ + url: '/ccdi/enterpriseBaseInfo/importTemplate', + method: 'post' + }) +} + +// 导入实体库 +export function importData(data) { + return request({ + url: '/ccdi/enterpriseBaseInfo/importData', + method: 'post', + data: data + }) +} + +// 查询导入状态 +export function getImportStatus(taskId) { + return request({ + url: '/ccdi/enterpriseBaseInfo/importStatus/' + taskId, + method: 'get' + }) +} + +// 查询导入失败记录 +export function getImportFailures(taskId, pageNum, pageSize) { + return request({ + url: '/ccdi/enterpriseBaseInfo/importFailures/' + taskId, + method: 'get', + params: { pageNum, pageSize } + }) +} diff --git a/ruoyi-ui/src/api/ccdiEnum.js b/ruoyi-ui/src/api/ccdiEnum.js index d7f39aba..e2661d18 100644 --- a/ruoyi-ui/src/api/ccdiEnum.js +++ b/ruoyi-ui/src/api/ccdiEnum.js @@ -89,3 +89,23 @@ export function getDataSourceOptions() { method: 'get' }) } + +/** + * 查询实体风险等级选项 + */ +export function getEnterpriseRiskLevelOptions() { + return request({ + url: '/ccdi/enum/enterpriseRiskLevel', + method: 'get' + }) +} + +/** + * 查询企业来源选项 + */ +export function getEnterpriseSourceOptions() { + return request({ + url: '/ccdi/enum/enterpriseSource', + method: 'get' + }) +} diff --git a/ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue b/ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue new file mode 100644 index 00000000..19940105 --- /dev/null +++ b/ruoyi-ui/src/views/ccdiEnterpriseBaseInfo/index.vue @@ -0,0 +1,977 @@ + + + + + diff --git a/ruoyi-ui/src/views/ccdiIntermediary/components/EnterpriseRelationEditDialog.vue b/ruoyi-ui/src/views/ccdiIntermediary/components/EnterpriseRelationEditDialog.vue new file mode 100644 index 00000000..856128cc --- /dev/null +++ b/ruoyi-ui/src/views/ccdiIntermediary/components/EnterpriseRelationEditDialog.vue @@ -0,0 +1,87 @@ + + + diff --git a/ruoyi-ui/src/views/ccdiIntermediary/components/RelativeEditDialog.vue b/ruoyi-ui/src/views/ccdiIntermediary/components/RelativeEditDialog.vue new file mode 100644 index 00000000..f4a82cd9 --- /dev/null +++ b/ruoyi-ui/src/views/ccdiIntermediary/components/RelativeEditDialog.vue @@ -0,0 +1,192 @@ + + + diff --git a/sql/migration/2026-04-17-add-enterprise-base-info-menu.sql b/sql/migration/2026-04-17-add-enterprise-base-info-menu.sql new file mode 100644 index 00000000..1520a6f4 --- /dev/null +++ b/sql/migration/2026-04-17-add-enterprise-base-info-menu.sql @@ -0,0 +1,199 @@ +-- 实体库管理菜单 +-- 挂载到“信息维护”目录下,可重复执行 + +SET @parent_menu_id = ( + SELECT menu_id + FROM sys_menu + WHERE menu_name = '信息维护' + AND parent_id = 0 + LIMIT 1 +); + +INSERT INTO sys_menu ( + menu_name, + parent_id, + order_num, + path, + component, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + create_by, + create_time, + update_by, + update_time, + remark +) +SELECT + '实体库管理', + @parent_menu_id, + 12, + 'enterpriseBaseInfo', + 'ccdiEnterpriseBaseInfo/index', + 1, + 0, + 'C', + '0', + '0', + 'ccdi:enterpriseBaseInfo:list', + 'documentation', + 'admin', + NOW(), + '', + NULL, + '实体库管理菜单' +FROM dual +WHERE @parent_menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM sys_menu + WHERE parent_id = @parent_menu_id + AND path = 'enterpriseBaseInfo' + ); + +SET @menu_id = ( + SELECT menu_id + FROM sys_menu + WHERE parent_id = @parent_menu_id + AND path = 'enterpriseBaseInfo' + LIMIT 1 +); + +INSERT INTO sys_menu ( + menu_name, + parent_id, + order_num, + path, + component, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + create_by, + create_time, + remark +) +SELECT '实体库查询', @menu_id, 1, '', '', 1, 0, 'F', '0', '0', 'ccdi:enterpriseBaseInfo:query', '#', 'admin', NOW(), '' +FROM dual +WHERE @menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM sys_menu + WHERE parent_id = @menu_id + AND perms = 'ccdi:enterpriseBaseInfo:query' + ); + +INSERT INTO sys_menu ( + menu_name, + parent_id, + order_num, + path, + component, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + create_by, + create_time, + remark +) +SELECT '实体库新增', @menu_id, 2, '', '', 1, 0, 'F', '0', '0', 'ccdi:enterpriseBaseInfo:add', '#', 'admin', NOW(), '' +FROM dual +WHERE @menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM sys_menu + WHERE parent_id = @menu_id + AND perms = 'ccdi:enterpriseBaseInfo:add' + ); + +INSERT INTO sys_menu ( + menu_name, + parent_id, + order_num, + path, + component, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + create_by, + create_time, + remark +) +SELECT '实体库修改', @menu_id, 3, '', '', 1, 0, 'F', '0', '0', 'ccdi:enterpriseBaseInfo:edit', '#', 'admin', NOW(), '' +FROM dual +WHERE @menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM sys_menu + WHERE parent_id = @menu_id + AND perms = 'ccdi:enterpriseBaseInfo:edit' + ); + +INSERT INTO sys_menu ( + menu_name, + parent_id, + order_num, + path, + component, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + create_by, + create_time, + remark +) +SELECT '实体库删除', @menu_id, 4, '', '', 1, 0, 'F', '0', '0', 'ccdi:enterpriseBaseInfo:remove', '#', 'admin', NOW(), '' +FROM dual +WHERE @menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM sys_menu + WHERE parent_id = @menu_id + AND perms = 'ccdi:enterpriseBaseInfo:remove' + ); + +INSERT INTO sys_menu ( + menu_name, + parent_id, + order_num, + path, + component, + is_frame, + is_cache, + menu_type, + visible, + status, + perms, + icon, + create_by, + create_time, + remark +) +SELECT '实体库导入', @menu_id, 5, '', '', 1, 0, 'F', '0', '0', 'ccdi:enterpriseBaseInfo:import', '#', 'admin', NOW(), '' +FROM dual +WHERE @menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 + FROM sys_menu + WHERE parent_id = @menu_id + AND perms = 'ccdi:enterpriseBaseInfo:import' + ); diff --git a/sql/migration/2026-04-17-create-intermediary-enterprise-relation.sql b/sql/migration/2026-04-17-create-intermediary-enterprise-relation.sql new file mode 100644 index 00000000..d6678cff --- /dev/null +++ b/sql/migration/2026-04-17-create-intermediary-enterprise-relation.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS `ccdi_intermediary_enterprise_relation` ( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `intermediary_biz_id` VARCHAR(64) NOT NULL COMMENT '所属中介biz_id', + `social_credit_code` VARCHAR(18) NOT NULL COMMENT '统一社会信用代码', + `relation_person_post` VARCHAR(100) DEFAULT NULL COMMENT '关联角色/职务', + `remark` VARCHAR(500) DEFAULT NULL COMMENT '备注', + `created_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_intermediary_enterprise` (`intermediary_biz_id`, `social_credit_code`), + KEY `idx_intermediary_biz_id` (`intermediary_biz_id`), + KEY `idx_social_credit_code` (`social_credit_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='中介关联机构关系表'; diff --git a/sql/migration/2026-04-17-fix-intermediary-person-sub-type-dict.sql b/sql/migration/2026-04-17-fix-intermediary-person-sub-type-dict.sql new file mode 100644 index 00000000..d3d2b68a --- /dev/null +++ b/sql/migration/2026-04-17-fix-intermediary-person-sub-type-dict.sql @@ -0,0 +1,4 @@ +-- 如当前环境通过数据字典维护 person_sub_type,请补齐以下固定值: +-- 本人、配偶、子女、父母、兄弟姐妹、其他 +-- +-- 具体 dict_type 请按现网实际配置填写后执行。 diff --git a/tongweb_62318.properties b/tongweb_62318.properties new file mode 100644 index 00000000..153ab7f7 --- /dev/null +++ b/tongweb_62318.properties @@ -0,0 +1,15 @@ +#TongTech License properties +#Fri Apr 17 16:39:03 CST 2026 +application.location=/Users/wkc/Desktop/ccdi/ccdi +license.create.date=2024-12-10 +license.customer.name=\u6D59\u6C5F\u519C\u6751\u5546\u4E1A\u8054\u5408\u94F6\u884C\u80A1\u4EFD\u6709\u9650\u516C\u53F8 +license.end.date=-1 +license.extern.properties.name=validateType,order_number,license_info +license.extern.properties.value=file,2024-2121,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\n +license.file.content=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\n +license.file.path=classpath\:license.dat +license.max.number=-1 +license.project.name=\u6D59\u6C5F\u519C\u6751\u5546\u4E1A\u8054\u5408\u94F6\u884C\u80A1\u4EFD\u6709\u9650\u516C\u53F8\u5173\u4E8E\u56FD\u4EA7\u5316\u5E94\u7528\u670D\u52A1\u5668\u4E2D\u95F4\u4EF6\u91C7\u8D2D +license.type=release +license.validate.type=file +server.number=7.0.E.7