新增项目管理员角色权限控制
This commit is contained in:
@@ -6,6 +6,7 @@ import com.ruoyi.ccdi.project.domain.excel.CcdiBankStatementExcel;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementDetailVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiBankStatementService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -39,13 +40,16 @@ public class CcdiBankStatementController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiBankStatementService bankStatementService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 分页查询流水明细
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "分页查询流水明细")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public TableDataInfo list(CcdiBankStatementQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiBankStatementListVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiBankStatementListVO> result = bankStatementService.selectStatementPage(page, queryDTO);
|
||||
@@ -57,8 +61,8 @@ public class CcdiBankStatementController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/options")
|
||||
@Operation(summary = "查询项目级筛选项")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getOptions(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiBankStatementFilterOptionsVO options = bankStatementService.getFilterOptions(projectId);
|
||||
return AjaxResult.success(options);
|
||||
}
|
||||
@@ -68,8 +72,8 @@ public class CcdiBankStatementController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/detail/{bankStatementId}")
|
||||
@Operation(summary = "查询流水详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getDetail(@PathVariable Long bankStatementId) {
|
||||
projectAccessService.assertCanReadByBankStatementId(bankStatementId);
|
||||
CcdiBankStatementDetailVO detail = bankStatementService.getStatementDetail(bankStatementId);
|
||||
return AjaxResult.success(detail);
|
||||
}
|
||||
@@ -81,6 +85,7 @@ public class CcdiBankStatementController extends BaseController {
|
||||
@Operation(summary = "导出流水明细")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:export')")
|
||||
public void export(HttpServletResponse response, CcdiBankStatementQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiBankStatementExcel> list = bankStatementService.selectStatementListForExport(queryDTO);
|
||||
ExcelUtil<CcdiBankStatementExcel> util = new ExcelUtil<>(CcdiBankStatementExcel.class);
|
||||
util.exportExcel(response, list, "流水明细");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ruoyi.ccdi.project.controller;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiBankTagRebuildDTO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiBankTagService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -9,6 +10,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -27,12 +29,17 @@ public class CcdiBankTagController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiBankTagService bankTagService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 手动提交流水标签重算任务
|
||||
*/
|
||||
@Operation(summary = "手动重算项目流水标签")
|
||||
@PostMapping("/rebuild")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult rebuild(@Validated @RequestBody CcdiBankTagRebuildDTO dto) {
|
||||
projectAccessService.assertCanOperate(dto.getProjectId());
|
||||
String operator = SecurityUtils.getUsername();
|
||||
log.info("【流水标签】收到手动重算请求: projectId={}, modelCode={}, operator={}",
|
||||
dto.getProjectId(), dto.getModelCode(), operator);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.ccdi.project.controller;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiEvidenceQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiEvidenceSaveDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiEvidenceVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiEvidenceService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -34,13 +35,17 @@ public class CcdiEvidenceController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiEvidenceService evidenceService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 保存证据
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "保存证据")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult saveEvidence(@Validated @RequestBody CcdiEvidenceSaveDTO dto) {
|
||||
projectAccessService.assertCanOperate(dto.getProjectId());
|
||||
CcdiEvidenceVO vo = evidenceService.saveEvidence(dto, SecurityUtils.getUsername());
|
||||
return AjaxResult.success("证据入库成功", vo);
|
||||
}
|
||||
@@ -50,8 +55,8 @@ public class CcdiEvidenceController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询项目证据列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult listEvidence(CcdiEvidenceQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiEvidenceVO> list = evidenceService.listEvidence(queryDTO);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
@@ -61,8 +66,8 @@ public class CcdiEvidenceController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/{evidenceId}")
|
||||
@Operation(summary = "查询证据详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getEvidence(@PathVariable Long evidenceId) {
|
||||
projectAccessService.assertCanReadByEvidenceId(evidenceId);
|
||||
CcdiEvidenceVO vo = evidenceService.getEvidence(evidenceId);
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiPullBankInfoSubmitDTO;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiFileUploadRecord;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFileUploadStatisticsVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiIdCardParseVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiFileUploadService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -17,6 +18,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -40,17 +42,22 @@ public class CcdiFileUploadController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiFileUploadService fileUploadService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 批量上传文件(异步)
|
||||
*/
|
||||
@PostMapping("/batch")
|
||||
@Operation(summary = "批量上传文件", description = "异步批量上传流水文件")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult batchUpload(@RequestParam Long projectId,
|
||||
@RequestParam MultipartFile[] files) {
|
||||
// 参数校验
|
||||
if (projectId == null) {
|
||||
return AjaxResult.error("项目ID不能为空");
|
||||
}
|
||||
projectAccessService.assertCanOperate(projectId);
|
||||
if (files == null || files.length == 0) {
|
||||
return AjaxResult.error("请选择要上传的文件");
|
||||
}
|
||||
@@ -95,6 +102,7 @@ public class CcdiFileUploadController extends BaseController {
|
||||
*/
|
||||
@PostMapping("/parse-id-card-file")
|
||||
@Operation(summary = "解析身份证文件", description = "解析首个sheet第一列的身份证号")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult parseIdCardFile(@RequestParam MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return AjaxResult.error("身份证文件不能为空");
|
||||
@@ -108,10 +116,12 @@ public class CcdiFileUploadController extends BaseController {
|
||||
*/
|
||||
@PostMapping("/pull-bank-info")
|
||||
@Operation(summary = "拉取本行信息", description = "按身份证号批量提交拉取本行信息任务")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult pullBankInfo(@RequestBody CcdiPullBankInfoSubmitDTO dto) {
|
||||
if (dto == null || dto.getProjectId() == null) {
|
||||
return AjaxResult.error("项目ID不能为空");
|
||||
}
|
||||
projectAccessService.assertCanOperate(dto.getProjectId());
|
||||
if (CollectionUtils.isEmpty(dto.getIdCards())) {
|
||||
return AjaxResult.error("身份证号不能为空");
|
||||
}
|
||||
@@ -138,6 +148,7 @@ public class CcdiFileUploadController extends BaseController {
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询上传记录列表", description = "分页查询文件上传记录")
|
||||
public TableDataInfo list(CcdiFileUploadQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiFileUploadRecord> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiFileUploadRecord> result = fileUploadService.selectPage(page, queryDTO);
|
||||
@@ -150,6 +161,7 @@ public class CcdiFileUploadController extends BaseController {
|
||||
@GetMapping("/statistics/{projectId}")
|
||||
@Operation(summary = "查询上传统计", description = "统计各状态的文件数量")
|
||||
public AjaxResult getStatistics(@PathVariable Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiFileUploadStatisticsVO statistics = fileUploadService.countByStatus(projectId);
|
||||
return AjaxResult.success(statistics);
|
||||
}
|
||||
@@ -160,6 +172,7 @@ public class CcdiFileUploadController extends BaseController {
|
||||
@GetMapping("/detail/{id}")
|
||||
@Operation(summary = "查询记录详情", description = "根据ID查询文件上传记录详情")
|
||||
public AjaxResult getDetail(@PathVariable Long id) {
|
||||
projectAccessService.assertCanReadByFileRecordId(id);
|
||||
CcdiFileUploadRecord record = fileUploadService.getById(id);
|
||||
return AjaxResult.success(record);
|
||||
}
|
||||
@@ -169,7 +182,9 @@ public class CcdiFileUploadController extends BaseController {
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除上传文件", description = "按上传记录ID删除文件并清理流水")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult deleteFile(@PathVariable Long id) {
|
||||
projectAccessService.assertCanOperateByFileRecordId(id);
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
String message = fileUploadService.deleteFileUploadRecord(id, userId);
|
||||
return AjaxResult.success(message);
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiFundGraphService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -38,10 +39,14 @@ public class CcdiFundGraphController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiFundGraphService fundGraphService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "查询资金流图谱主体")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult searchSubjects(CcdiFundGraphQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiFundGraphNodeVO> subjects = fundGraphService.searchSubjects(queryDTO);
|
||||
return AjaxResult.success(subjects);
|
||||
}
|
||||
@@ -50,6 +55,7 @@ public class CcdiFundGraphController extends BaseController {
|
||||
@Operation(summary = "查询一层资金流图谱")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getGraph(CcdiFundGraphQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiFundGraphVO graph = fundGraphService.getFundGraph(queryDTO);
|
||||
return AjaxResult.success(graph);
|
||||
}
|
||||
@@ -58,6 +64,7 @@ public class CcdiFundGraphController extends BaseController {
|
||||
@Operation(summary = "查询资金边流水明细")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public TableDataInfo getEdgeDetail(CcdiFundGraphEdgeDetailQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiFundGraphStatementVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiFundGraphStatementVO> result = fundGraphService.getEdgeDetails(page, queryDTO);
|
||||
@@ -66,9 +73,10 @@ public class CcdiFundGraphController extends BaseController {
|
||||
|
||||
@PostMapping("/manual-edge")
|
||||
@Operation(summary = "新增手工资金流向")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult saveManualEdge(@RequestBody CcdiFundGraphManualEdgeSaveDTO saveDTO) {
|
||||
try {
|
||||
projectAccessService.assertCanOperate(saveDTO == null ? null : saveDTO.getProjectId());
|
||||
CcdiFundGraphEdgeVO edge = fundGraphService.saveManualEdge(saveDTO, SecurityUtils.getUsername());
|
||||
return AjaxResult.success(edge);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
@@ -11,9 +11,11 @@ import com.ruoyi.ccdi.project.domain.dto.ModelParamSaveAllDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.ModelListVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.ModelParamVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiModelParamService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -31,12 +33,17 @@ public class CcdiModelParamController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiModelParamService modelParamService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 查询模型列表
|
||||
*/
|
||||
@Operation(summary = "查询模型列表")
|
||||
@GetMapping("/modelList")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult listModels(@RequestParam(required = false) Long projectId) {
|
||||
assertCanReadProjectParam(projectId);
|
||||
List<ModelListVO> list = modelParamService.selectModelList(projectId);
|
||||
return success(list);
|
||||
}
|
||||
@@ -46,7 +53,9 @@ public class CcdiModelParamController extends BaseController {
|
||||
*/
|
||||
@Operation(summary = "查询模型参数列表")
|
||||
@GetMapping("/list")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult list(@Validated ModelParamQueryDTO queryDTO) {
|
||||
assertCanReadProjectParam(queryDTO.getProjectId());
|
||||
List<ModelParamVO> list = modelParamService.selectParamList(queryDTO);
|
||||
return success(list);
|
||||
}
|
||||
@@ -57,7 +66,9 @@ public class CcdiModelParamController extends BaseController {
|
||||
@Operation(summary = "保存模型参数")
|
||||
@Log(title = "模型参数配置", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/save")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult save(@Validated @RequestBody ModelParamSaveDTO saveDTO) {
|
||||
assertCanOperateProjectParam(saveDTO.getProjectId());
|
||||
modelParamService.saveParams(saveDTO);
|
||||
return success("保存成功");
|
||||
}
|
||||
@@ -67,7 +78,9 @@ public class CcdiModelParamController extends BaseController {
|
||||
*/
|
||||
@Operation(summary = "查询所有模型及其参数")
|
||||
@GetMapping("/listAll")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult listAll(@Validated ModelParamAllQueryDTO queryDTO) {
|
||||
assertCanReadProjectParam(queryDTO.getProjectId());
|
||||
ModelParamAllVO result = modelParamService.selectAllParams(queryDTO.getProjectId());
|
||||
return success(result);
|
||||
}
|
||||
@@ -78,8 +91,24 @@ public class CcdiModelParamController extends BaseController {
|
||||
@Operation(summary = "批量保存所有模型参数")
|
||||
@Log(title = "模型参数配置", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/saveAll")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult saveAll(@Validated @RequestBody ModelParamSaveAllDTO saveAllDTO) {
|
||||
assertCanOperateProjectParam(saveAllDTO.getProjectId());
|
||||
modelParamService.saveAllParams(saveAllDTO);
|
||||
return success("保存成功");
|
||||
}
|
||||
|
||||
private void assertCanReadProjectParam(Long projectId) {
|
||||
if (projectId == null || projectId <= 0) {
|
||||
return;
|
||||
}
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
}
|
||||
|
||||
private void assertCanOperateProjectParam(Long projectId) {
|
||||
if (projectId == null || projectId <= 0) {
|
||||
return;
|
||||
}
|
||||
projectAccessService.assertCanOperate(projectId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ public class CcdiProjectController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/{projectId}")
|
||||
@Operation(summary = "查询项目详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getProject(@PathVariable Long projectId) {
|
||||
CcdiProjectVO vo = projectService.getProjectById(projectId);
|
||||
return AjaxResult.success(vo);
|
||||
@@ -96,7 +95,6 @@ public class CcdiProjectController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询项目列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
|
||||
public TableDataInfo listProject(CcdiProjectQueryDTO queryDTO) {
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiProjectVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
@@ -109,7 +107,6 @@ public class CcdiProjectController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/history")
|
||||
@Operation(summary = "查询历史项目列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
|
||||
public AjaxResult listHistoryProjects(CcdiProjectQueryDTO queryDTO) {
|
||||
List<CcdiProjectHistoryListItemVO> result = projectService.listHistoryProjects(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
@@ -131,7 +128,6 @@ public class CcdiProjectController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/statusCounts")
|
||||
@Operation(summary = "查询项目状态统计")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
|
||||
public AjaxResult getStatusCounts() {
|
||||
CcdiProjectStatusCountsVO counts = projectService.getStatusCounts();
|
||||
return AjaxResult.success(counts);
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionPageVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectTopRiskPeopleVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiProjectOverviewService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
@@ -51,6 +52,9 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiProjectOverviewService overviewService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 查询风险仪表盘
|
||||
*/
|
||||
@@ -58,6 +62,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询风险仪表盘")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getDashboard(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiProjectOverviewDashboardVO dashboard = overviewService.getDashboard(projectId);
|
||||
return AjaxResult.success(dashboard);
|
||||
}
|
||||
@@ -69,6 +74,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询风险人员总览")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getRiskPeople(CcdiProjectRiskPeopleQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectRiskPeopleOverviewVO overview = overviewService.getRiskPeopleOverview(queryDTO);
|
||||
return AjaxResult.success(overview);
|
||||
}
|
||||
@@ -80,6 +86,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询外部人员预警")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExternalPersons(CcdiProjectExternalPersonQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExternalPersonWarningVO warnings = overviewService.getExternalPersonWarnings(queryDTO);
|
||||
return AjaxResult.success(warnings);
|
||||
}
|
||||
@@ -91,6 +98,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询外部人员风险汇总")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExternalRiskSummary(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiProjectExternalRiskSummaryVO summary = overviewService.getExternalRiskSummary(projectId);
|
||||
return AjaxResult.success(summary);
|
||||
}
|
||||
@@ -102,6 +110,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询中高风险人员TOP10")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getTopRiskPeople(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiProjectTopRiskPeopleVO topRiskPeople = overviewService.getTopRiskPeople(projectId);
|
||||
return AjaxResult.success(topRiskPeople);
|
||||
}
|
||||
@@ -113,6 +122,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询风险模型卡片")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getRiskModelCards(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiProjectRiskModelCardsVO cards = overviewService.getRiskModelCards(projectId);
|
||||
return AjaxResult.success(cards);
|
||||
}
|
||||
@@ -124,6 +134,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询风险模型命中人员")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getRiskModelPeople(CcdiProjectRiskModelPeopleQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectRiskModelPeopleVO people = overviewService.getRiskModelPeople(queryDTO);
|
||||
return AjaxResult.success(people);
|
||||
}
|
||||
@@ -135,6 +146,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询外部人员风险模型卡片")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExternalRiskModelCards(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiProjectRiskModelCardsVO cards = overviewService.getExternalRiskModelCards(projectId);
|
||||
return AjaxResult.success(cards);
|
||||
}
|
||||
@@ -146,6 +158,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询外部人员风险模型命中人员")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExternalRiskModelPeople(CcdiProjectExternalRiskModelPeopleQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectRiskModelPeopleVO people = overviewService.getExternalRiskModelPeople(queryDTO);
|
||||
return AjaxResult.success(people);
|
||||
}
|
||||
@@ -157,6 +170,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询项目分析详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectPersonAnalysisDetailVO detail = overviewService.getPersonAnalysisDetail(queryDTO);
|
||||
return AjaxResult.success(detail);
|
||||
}
|
||||
@@ -168,6 +182,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询涉疑交易明细")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getSuspiciousTransactions(CcdiProjectSuspiciousTransactionQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectSuspiciousTransactionPageVO pageVO = overviewService.getSuspiciousTransactions(queryDTO);
|
||||
return AjaxResult.success(pageVO);
|
||||
}
|
||||
@@ -179,6 +194,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询项目员工负面征信")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getEmployeeCreditNegative(CcdiProjectEmployeeCreditNegativeQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectEmployeeCreditNegativePageVO pageVO = overviewService.getEmployeeCreditNegative(queryDTO);
|
||||
return AjaxResult.success(pageVO);
|
||||
}
|
||||
@@ -190,6 +206,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "查询异常账户人员信息")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getAbnormalAccountPeople(CcdiProjectAbnormalAccountQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectAbnormalAccountPageVO pageVO = overviewService.getAbnormalAccountPeople(queryDTO);
|
||||
return AjaxResult.success(pageVO);
|
||||
}
|
||||
@@ -204,6 +221,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
HttpServletResponse response,
|
||||
CcdiProjectSuspiciousTransactionQueryDTO queryDTO
|
||||
) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiProjectSuspiciousTransactionExcel> rows = overviewService.exportSuspiciousTransactions(queryDTO);
|
||||
ExcelUtil<CcdiProjectSuspiciousTransactionExcel> util =
|
||||
new ExcelUtil<>(CcdiProjectSuspiciousTransactionExcel.class);
|
||||
@@ -217,6 +235,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "导出风险人员总览")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public void exportRiskPeople(HttpServletResponse response, Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
List<CcdiProjectRiskPeopleOverviewExcel> rows = overviewService.exportRiskPeopleOverview(projectId);
|
||||
ExcelUtil<CcdiProjectRiskPeopleOverviewExcel> util =
|
||||
new ExcelUtil<>(CcdiProjectRiskPeopleOverviewExcel.class);
|
||||
@@ -230,6 +249,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "导出外部人员预警")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public void exportExternalPersons(HttpServletResponse response, Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
List<CcdiProjectExternalPersonWarningExcel> rows = overviewService.exportExternalPersonWarnings(projectId);
|
||||
ExcelUtil<CcdiProjectExternalPersonWarningExcel> util =
|
||||
new ExcelUtil<>(CcdiProjectExternalPersonWarningExcel.class);
|
||||
@@ -243,6 +263,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "导出风险模型命中人员")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public void exportRiskModelPeople(HttpServletResponse response, CcdiProjectRiskModelPeopleQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiProjectRiskModelPeopleExcel> rows = overviewService.exportRiskModelPeople(queryDTO);
|
||||
ExcelUtil<CcdiProjectRiskModelPeopleExcel> util =
|
||||
new ExcelUtil<>(CcdiProjectRiskModelPeopleExcel.class);
|
||||
@@ -259,6 +280,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
HttpServletResponse response,
|
||||
CcdiProjectExternalRiskModelPeopleQueryDTO queryDTO
|
||||
) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiProjectRiskModelPeopleExcel> rows = overviewService.exportExternalRiskModelPeople(queryDTO);
|
||||
ExcelUtil<CcdiProjectRiskModelPeopleExcel> util =
|
||||
new ExcelUtil<>(CcdiProjectRiskModelPeopleExcel.class);
|
||||
@@ -272,6 +294,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "导出风险明细")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public void exportRiskDetails(HttpServletResponse response, Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
overviewService.exportRiskDetails(response, projectId);
|
||||
}
|
||||
|
||||
@@ -282,6 +305,7 @@ public class CcdiProjectOverviewController extends BaseController {
|
||||
@Operation(summary = "导出结果总览报告")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public void exportOverviewReport(HttpServletResponse response, Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
overviewService.exportOverviewReport(response, projectId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedTransferDetailVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedTransferListVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityDetailVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityListVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiProjectSpecialCheckService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -39,6 +40,9 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiProjectSpecialCheckService specialCheckService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
/**
|
||||
* 查询员工家庭资产负债列表
|
||||
*/
|
||||
@@ -46,6 +50,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询员工家庭资产负债列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getFamilyAssetLiabilityList(@Validated CcdiProjectFamilyAssetLiabilityListQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectFamilyAssetLiabilityListVO result = specialCheckService.getFamilyAssetLiabilityList(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -57,6 +62,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询员工家庭资产负债详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getFamilyAssetLiabilityDetail(@Validated CcdiProjectFamilyAssetLiabilityDetailQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectFamilyAssetLiabilityDetailVO result = specialCheckService.getFamilyAssetLiabilityDetail(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -68,6 +74,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询采购拓展列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExtendedPurchaseList(@Validated CcdiProjectExtendedPurchaseQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExtendedPurchaseListVO result = specialCheckService.getExtendedPurchaseList(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -79,6 +86,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询采购拓展详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExtendedPurchaseDetail(@Validated CcdiProjectExtendedPurchaseDetailQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExtendedPurchaseDetailVO result = specialCheckService.getExtendedPurchaseDetail(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -90,6 +98,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询招聘拓展列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExtendedRecruitmentList(@Validated CcdiProjectExtendedRecruitmentQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExtendedRecruitmentListVO result = specialCheckService.getExtendedRecruitmentList(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -101,6 +110,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询招聘拓展详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExtendedRecruitmentDetail(@Validated CcdiProjectExtendedRecruitmentDetailQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExtendedRecruitmentDetailVO result = specialCheckService.getExtendedRecruitmentDetail(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -112,6 +122,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询调动拓展列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExtendedTransferList(@Validated CcdiProjectExtendedTransferQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExtendedTransferListVO result = specialCheckService.getExtendedTransferList(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
@@ -123,6 +134,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
|
||||
@Operation(summary = "查询调动拓展详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getExtendedTransferDetail(@Validated CcdiProjectExtendedTransferDetailQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiProjectExtendedTransferDetailVO result = specialCheckService.getExtendedTransferDetail(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphSuspectedEnterpriseQue
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphVO;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiRelationGraphService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -29,10 +30,14 @@ public class CcdiRelationGraphController extends BaseController {
|
||||
@Resource
|
||||
private ICcdiRelationGraphService relationGraphService;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "查询关系图谱主体")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult searchSubjects(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
List<CcdiRelationGraphNodeVO> subjects = relationGraphService.searchSubjects(queryDTO);
|
||||
return AjaxResult.success(subjects);
|
||||
}
|
||||
@@ -41,6 +46,7 @@ public class CcdiRelationGraphController extends BaseController {
|
||||
@Operation(summary = "查询一层关系图谱")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getGraph(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiRelationGraphVO graph = relationGraphService.getRelationGraph(queryDTO);
|
||||
return AjaxResult.success(graph);
|
||||
}
|
||||
@@ -49,6 +55,7 @@ public class CcdiRelationGraphController extends BaseController {
|
||||
@Operation(summary = "查询关系图谱疑似同名企业")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getSuspectedEnterprises(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO) {
|
||||
projectAccessService.assertCanRead(queryDTO.getProjectId());
|
||||
CcdiRelationGraphSuspectedEnterpriseVO result = relationGraphService.getSuspectedEnterprises(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.ruoyi.ccdi.project.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 当前登录用户的项目访问范围。
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ProjectAccessScope {
|
||||
|
||||
/** 当前用户名 */
|
||||
private String username;
|
||||
|
||||
/** 是否可查看全部项目 */
|
||||
private boolean viewAllProjects;
|
||||
|
||||
/** 是否超级管理员 */
|
||||
private boolean superAdmin;
|
||||
|
||||
/** 是否项目管理员 */
|
||||
private boolean projectManager;
|
||||
}
|
||||
@@ -10,6 +10,9 @@ import java.math.BigDecimal;
|
||||
@Data
|
||||
public class CcdiFundGraphManualEdgeSaveDTO {
|
||||
|
||||
/** 当前项目ID,仅用于写权限校验,不参与手工资金流归属过滤 */
|
||||
private Long projectId;
|
||||
|
||||
/** 起点主体object_key;为空时默认使用当前查询中心 */
|
||||
private String fromObjectKey;
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ import lombok.Data;
|
||||
@Data
|
||||
public class CcdiRelationGraphSuspectedEnterpriseQueryDTO {
|
||||
|
||||
/** 项目ID */
|
||||
private Long projectId;
|
||||
|
||||
/** 姓名 */
|
||||
private String personName;
|
||||
|
||||
|
||||
@@ -61,4 +61,10 @@ public class CcdiProjectVO {
|
||||
|
||||
/** 创建者姓名(真实姓名) */
|
||||
private String createByName;
|
||||
|
||||
/** 是否当前用户创建 */
|
||||
private Boolean ownedByCurrentUser;
|
||||
|
||||
/** 当前用户是否可操作 */
|
||||
private Boolean canOperate;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.ccdi.project.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.project.domain.CcdiProject;
|
||||
import com.ruoyi.ccdi.project.domain.ProjectAccessScope;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
|
||||
@@ -25,7 +26,9 @@ public interface CcdiProjectMapper extends BaseMapper<CcdiProject> {
|
||||
* @param queryDTO 查询条件
|
||||
* @return 分页结果
|
||||
*/
|
||||
Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, @Param("queryDTO") CcdiProjectQueryDTO queryDTO);
|
||||
Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page,
|
||||
@Param("queryDTO") CcdiProjectQueryDTO queryDTO,
|
||||
@Param("scope") ProjectAccessScope scope);
|
||||
|
||||
/**
|
||||
* 查询历史项目列表
|
||||
@@ -33,7 +36,8 @@ public interface CcdiProjectMapper extends BaseMapper<CcdiProject> {
|
||||
* @param queryDTO 查询条件
|
||||
* @return 历史项目列表
|
||||
*/
|
||||
List<CcdiProjectHistoryListItemVO> selectHistoryProjects(@Param("queryDTO") CcdiProjectQueryDTO queryDTO);
|
||||
List<CcdiProjectHistoryListItemVO> selectHistoryProjects(@Param("queryDTO") CcdiProjectQueryDTO queryDTO,
|
||||
@Param("scope") ProjectAccessScope scope);
|
||||
|
||||
/**
|
||||
* 更新项目总人数与风险人数
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.ruoyi.ccdi.project.service;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.CcdiProject;
|
||||
import com.ruoyi.ccdi.project.domain.ProjectAccessScope;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankStatement;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiEvidence;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiFileUploadRecord;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiBankStatementMapper;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiEvidenceMapper;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiFileUploadRecordMapper;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
|
||||
import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 项目访问控制。
|
||||
*/
|
||||
@Service
|
||||
public class CcdiProjectAccessService {
|
||||
|
||||
private static final String ROLE_ADMIN = "admin";
|
||||
|
||||
private static final String ROLE_MANAGER = "manager";
|
||||
|
||||
@Resource
|
||||
private CcdiProjectMapper projectMapper;
|
||||
|
||||
@Resource
|
||||
private CcdiBankStatementMapper bankStatementMapper;
|
||||
|
||||
@Resource
|
||||
private CcdiFileUploadRecordMapper fileUploadRecordMapper;
|
||||
|
||||
@Resource
|
||||
private CcdiEvidenceMapper evidenceMapper;
|
||||
|
||||
public ProjectAccessScope buildCurrentScope() {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
String username = SecurityUtils.getUsername();
|
||||
boolean superAdmin = isSuperAdmin(loginUser);
|
||||
boolean projectManager = hasRole(loginUser, ROLE_MANAGER);
|
||||
return new ProjectAccessScope(username, superAdmin || projectManager, superAdmin, projectManager);
|
||||
}
|
||||
|
||||
public boolean canOperate(CcdiProject project) {
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
ProjectAccessScope scope = buildCurrentScope();
|
||||
return scope.isSuperAdmin() || Objects.equals(scope.getUsername(), project.getCreateBy());
|
||||
}
|
||||
|
||||
public void assertCanRead(Long projectId) {
|
||||
CcdiProject project = getRequiredProject(projectId);
|
||||
ProjectAccessScope scope = buildCurrentScope();
|
||||
if (scope.isViewAllProjects() || Objects.equals(scope.getUsername(), project.getCreateBy())) {
|
||||
return;
|
||||
}
|
||||
throw new ServiceException("无权查看该项目");
|
||||
}
|
||||
|
||||
public void assertCanOperate(Long projectId) {
|
||||
CcdiProject project = getRequiredProject(projectId);
|
||||
if (canOperate(project)) {
|
||||
return;
|
||||
}
|
||||
throw new ServiceException("无权操作该项目");
|
||||
}
|
||||
|
||||
public void assertCanReadByBankStatementId(Long bankStatementId) {
|
||||
CcdiBankStatement statement = getRequiredBankStatement(bankStatementId);
|
||||
assertCanRead(statement.getProjectId());
|
||||
}
|
||||
|
||||
public void assertCanReadByFileRecordId(Long fileRecordId) {
|
||||
CcdiFileUploadRecord record = getRequiredFileRecord(fileRecordId);
|
||||
assertCanRead(record.getProjectId());
|
||||
}
|
||||
|
||||
public void assertCanOperateByFileRecordId(Long fileRecordId) {
|
||||
CcdiFileUploadRecord record = getRequiredFileRecord(fileRecordId);
|
||||
assertCanOperate(record.getProjectId());
|
||||
}
|
||||
|
||||
public void assertCanReadByEvidenceId(Long evidenceId) {
|
||||
CcdiEvidence evidence = getRequiredEvidence(evidenceId);
|
||||
assertCanRead(evidence.getProjectId());
|
||||
}
|
||||
|
||||
public void assertSourceProjectsReadable(List<Long> sourceProjectIds) {
|
||||
if (CollectionUtils.isEmpty(sourceProjectIds)) {
|
||||
return;
|
||||
}
|
||||
for (Long sourceProjectId : sourceProjectIds) {
|
||||
assertCanRead(sourceProjectId);
|
||||
}
|
||||
}
|
||||
|
||||
private CcdiProject getRequiredProject(Long projectId) {
|
||||
if (projectId == null) {
|
||||
throw new ServiceException("项目ID不能为空");
|
||||
}
|
||||
CcdiProject project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
throw new ServiceException("项目不存在");
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private CcdiBankStatement getRequiredBankStatement(Long bankStatementId) {
|
||||
if (bankStatementId == null) {
|
||||
throw new ServiceException("流水ID不能为空");
|
||||
}
|
||||
CcdiBankStatement statement = bankStatementMapper.selectById(bankStatementId);
|
||||
if (statement == null) {
|
||||
throw new ServiceException("流水记录不存在");
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
private CcdiFileUploadRecord getRequiredFileRecord(Long fileRecordId) {
|
||||
if (fileRecordId == null) {
|
||||
throw new ServiceException("文件记录ID不能为空");
|
||||
}
|
||||
CcdiFileUploadRecord record = fileUploadRecordMapper.selectById(fileRecordId);
|
||||
if (record == null) {
|
||||
throw new ServiceException("文件记录不存在");
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
private CcdiEvidence getRequiredEvidence(Long evidenceId) {
|
||||
if (evidenceId == null) {
|
||||
throw new ServiceException("证据ID不能为空");
|
||||
}
|
||||
CcdiEvidence evidence = evidenceMapper.selectById(evidenceId);
|
||||
if (evidence == null) {
|
||||
throw new ServiceException("证据不存在");
|
||||
}
|
||||
return evidence;
|
||||
}
|
||||
|
||||
private boolean isSuperAdmin(LoginUser loginUser) {
|
||||
if (loginUser == null) {
|
||||
return false;
|
||||
}
|
||||
if (SecurityUtils.isAdmin(loginUser.getUserId())) {
|
||||
return true;
|
||||
}
|
||||
return hasRole(loginUser, ROLE_ADMIN);
|
||||
}
|
||||
|
||||
private boolean hasRole(LoginUser loginUser, String roleKey) {
|
||||
if (loginUser == null || loginUser.getUser() == null
|
||||
|| CollectionUtils.isEmpty(loginUser.getUser().getRoles())) {
|
||||
return false;
|
||||
}
|
||||
for (SysRole role : loginUser.getUser().getRoles()) {
|
||||
if (roleKey.equals(role.getRoleKey())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.project.constants.CcdiProjectStatusConstants;
|
||||
import com.ruoyi.ccdi.project.domain.CcdiProject;
|
||||
import com.ruoyi.ccdi.project.domain.ProjectAccessScope;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO;
|
||||
@@ -14,6 +15,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiProjectService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
||||
@@ -54,6 +56,9 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
@Resource
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
@Resource
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
|
||||
@@ -82,7 +87,7 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
// 5. 返回VO
|
||||
CcdiProjectVO vo = new CcdiProjectVO();
|
||||
BeanUtils.copyProperties(project, vo);
|
||||
fillLatestTagFailure(project, vo);
|
||||
fillProjectExtraFields(project, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@@ -96,6 +101,7 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
if (existingProject == null) {
|
||||
throw new ServiceException("项目不存在");
|
||||
}
|
||||
projectAccessService.assertCanOperate(dto.getProjectId());
|
||||
|
||||
// 只更新允许修改的字段
|
||||
existingProject.setProjectName(dto.getProjectName());
|
||||
@@ -106,39 +112,46 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
|
||||
CcdiProjectVO vo = new CcdiProjectVO();
|
||||
BeanUtils.copyProperties(existingProject, vo);
|
||||
fillProjectExtraFields(existingProject, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteProject(Long projectId) {
|
||||
projectAccessService.assertCanOperate(projectId);
|
||||
return projectMapper.deleteById(projectId) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiProjectVO getProjectById(Long projectId) {
|
||||
projectAccessService.assertCanRead(projectId);
|
||||
CcdiProject project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
return null;
|
||||
}
|
||||
CcdiProjectVO vo = new CcdiProjectVO();
|
||||
BeanUtils.copyProperties(project, vo);
|
||||
fillLatestTagFailure(project, vo);
|
||||
fillProjectExtraFields(project, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, CcdiProjectQueryDTO queryDTO) {
|
||||
return projectMapper.selectProjectPage(page, queryDTO);
|
||||
ProjectAccessScope scope = projectAccessService.buildCurrentScope();
|
||||
Page<CcdiProjectVO> result = projectMapper.selectProjectPage(page, queryDTO, scope);
|
||||
fillProjectExtraFields(result.getRecords());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CcdiProjectHistoryListItemVO> listHistoryProjects(CcdiProjectQueryDTO queryDTO) {
|
||||
return projectMapper.selectHistoryProjects(queryDTO);
|
||||
return projectMapper.selectHistoryProjects(queryDTO, projectAccessService.buildCurrentScope());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CcdiProjectVO importFromHistory(CcdiProjectImportHistoryDTO dto, String operator) {
|
||||
projectAccessService.assertSourceProjectsReadable(dto.getSourceProjectIds());
|
||||
CcdiProjectSaveDTO saveDTO = new CcdiProjectSaveDTO();
|
||||
saveDTO.setProjectName(dto.getProjectName());
|
||||
saveDTO.setDescription(dto.getDescription());
|
||||
@@ -158,42 +171,34 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
@Override
|
||||
public CcdiProjectStatusCountsVO getStatusCounts() {
|
||||
CcdiProjectStatusCountsVO vo = new CcdiProjectStatusCountsVO();
|
||||
ProjectAccessScope scope = projectAccessService.buildCurrentScope();
|
||||
|
||||
// 统计全部项目
|
||||
Long totalCount = projectMapper.selectCount(null);
|
||||
LambdaQueryWrapper<CcdiProject> baseWrapper = buildScopeWrapper(scope);
|
||||
Long totalCount = projectMapper.selectCount(baseWrapper);
|
||||
vo.setAll(totalCount);
|
||||
|
||||
// 统计进行中项目(状态0)
|
||||
Long status0Count = projectMapper.selectCount(
|
||||
new LambdaQueryWrapper<CcdiProject>()
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.PROCESSING)
|
||||
);
|
||||
Long status0Count = projectMapper.selectCount(buildScopeWrapper(scope)
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.PROCESSING));
|
||||
vo.setStatus0(status0Count);
|
||||
|
||||
// 统计已完成项目(状态1)
|
||||
Long status1Count = projectMapper.selectCount(
|
||||
new LambdaQueryWrapper<CcdiProject>()
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.COMPLETED)
|
||||
);
|
||||
Long status1Count = projectMapper.selectCount(buildScopeWrapper(scope)
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.COMPLETED));
|
||||
vo.setStatus1(status1Count);
|
||||
|
||||
// 统计已归档项目(状态2)
|
||||
Long status2Count = projectMapper.selectCount(
|
||||
new LambdaQueryWrapper<CcdiProject>()
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.ARCHIVED)
|
||||
);
|
||||
Long status2Count = projectMapper.selectCount(buildScopeWrapper(scope)
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.ARCHIVED));
|
||||
vo.setStatus2(status2Count);
|
||||
|
||||
Long status3Count = projectMapper.selectCount(
|
||||
new LambdaQueryWrapper<CcdiProject>()
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAGGING)
|
||||
);
|
||||
Long status3Count = projectMapper.selectCount(buildScopeWrapper(scope)
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAGGING));
|
||||
vo.setStatus3(status3Count);
|
||||
|
||||
Long status4Count = projectMapper.selectCount(
|
||||
new LambdaQueryWrapper<CcdiProject>()
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAG_FAILED)
|
||||
);
|
||||
Long status4Count = projectMapper.selectCount(buildScopeWrapper(scope)
|
||||
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAG_FAILED));
|
||||
vo.setStatus4(status4Count);
|
||||
|
||||
return vo;
|
||||
@@ -202,6 +207,7 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
@Override
|
||||
public void archiveProject(Long projectId, String operator) {
|
||||
CcdiProject project = getRequiredProject(projectId);
|
||||
projectAccessService.assertCanOperate(projectId);
|
||||
if (CcdiProjectStatusConstants.ARCHIVED.equals(project.getStatus())) {
|
||||
throw new ServiceException("项目已归档,无需重复操作");
|
||||
}
|
||||
@@ -293,6 +299,38 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
|
||||
vo.setLatestTagTaskEndTime(latestFailedTask.getEndTime());
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<CcdiProject> buildScopeWrapper(ProjectAccessScope scope) {
|
||||
LambdaQueryWrapper<CcdiProject> wrapper = new LambdaQueryWrapper<>();
|
||||
if (scope != null && !scope.isViewAllProjects()) {
|
||||
wrapper.eq(CcdiProject::getCreateBy, scope.getUsername());
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private void fillProjectExtraFields(List<CcdiProjectVO> records) {
|
||||
if (records == null || records.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ProjectAccessScope scope = projectAccessService.buildCurrentScope();
|
||||
for (CcdiProjectVO vo : records) {
|
||||
fillProjectAccessFields(vo, scope);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillProjectExtraFields(CcdiProject project, CcdiProjectVO vo) {
|
||||
fillLatestTagFailure(project, vo);
|
||||
fillProjectAccessFields(vo, projectAccessService.buildCurrentScope());
|
||||
}
|
||||
|
||||
private void fillProjectAccessFields(CcdiProjectVO vo, ProjectAccessScope scope) {
|
||||
if (vo == null || scope == null) {
|
||||
return;
|
||||
}
|
||||
boolean ownedByCurrentUser = Objects.equals(scope.getUsername(), vo.getCreateBy());
|
||||
vo.setOwnedByCurrentUser(ownedByCurrentUser);
|
||||
vo.setCanOperate(scope.isSuperAdmin() || ownedByCurrentUser);
|
||||
}
|
||||
|
||||
private String resolveOperator(String operator) {
|
||||
return StringUtils.hasText(operator) ? operator : "system";
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
FROM ccdi_project p
|
||||
LEFT JOIN sys_user u ON p.create_by = u.user_name AND u.del_flag = '0'
|
||||
<where>
|
||||
<if test="scope != null and !scope.viewAllProjects">
|
||||
AND p.create_by = #{scope.username}
|
||||
</if>
|
||||
<if test="queryDTO.projectName != null and queryDTO.projectName != ''">
|
||||
AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%')
|
||||
</if>
|
||||
@@ -61,6 +64,9 @@
|
||||
FROM ccdi_project p
|
||||
<where>
|
||||
p.status in ('1', '2')
|
||||
<if test="scope != null and !scope.viewAllProjects">
|
||||
AND p.create_by = #{scope.username}
|
||||
</if>
|
||||
<if test="queryDTO.projectName != null and queryDTO.projectName != ''">
|
||||
AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%')
|
||||
</if>
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
|
||||
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
||||
import com.ruoyi.lsfx.domain.response.GetTokenResponse;
|
||||
@@ -52,6 +53,9 @@ class CcdiProjectServiceImplTest {
|
||||
@Mock
|
||||
private CcdiProjectMapper projectMapper;
|
||||
|
||||
@Mock
|
||||
private CcdiProjectAccessService projectAccessService;
|
||||
|
||||
@Mock
|
||||
private CcdiBankTagTaskMapper bankTagTaskMapper;
|
||||
|
||||
@@ -204,13 +208,13 @@ class CcdiProjectServiceImplTest {
|
||||
archived.setProjectId(2L);
|
||||
archived.setStatus("2");
|
||||
|
||||
when(projectMapper.selectHistoryProjects(queryDTO)).thenReturn(List.of(completed, archived));
|
||||
when(projectMapper.selectHistoryProjects(any(), any())).thenReturn(List.of(completed, archived));
|
||||
|
||||
List<CcdiProjectHistoryListItemVO> result = service.listHistoryProjects(queryDTO);
|
||||
|
||||
assertEquals(2, result.size());
|
||||
assertEquals(List.of(completed, archived), result);
|
||||
verify(projectMapper).selectHistoryProjects(queryDTO);
|
||||
verify(projectMapper).selectHistoryProjects(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# manager 项目权限后端实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
新增 `manager` 角色并建立统一项目访问控制:`admin` 保持最高权限,`manager` 可查看全部项目但只能操作本人创建的项目,普通角色只能查看和操作本人创建的项目。
|
||||
|
||||
## 实施范围
|
||||
|
||||
1. 新增 `ProjectAccessScope` 和 `CcdiProjectAccessService`,统一提供项目读权限、操作权限、流水/文件/证据等资源反查项目后的权限校验。
|
||||
2. 项目列表、历史项目列表、状态统计统一走后端 scope:`admin/manager` 查询全部,普通角色限定 `create_by = 当前用户名`。
|
||||
3. `CcdiProjectVO` 返回 `ownedByCurrentUser`、`canOperate`,供前端展示只读态。
|
||||
4. 项目详情、结果总览、流水明细、专项排查、关系图谱、资金图谱、证据、上传记录、模型参数等接口在服务调用前执行项目读/写权限校验。
|
||||
5. 项目更新、删除、归档、重新分析、上传、拉取本行信息、文件删除、参数保存、证据保存、手工资金流保存均执行 `assertCanOperate`。
|
||||
6. 资金图谱手工资金流保持现有全局资金图逻辑,不新增 `project_id`,不按项目过滤手工边;保存时仅用当前项目 ID 做操作权限校验。
|
||||
7. 新增幂等 SQL `sql/migration/2026-07-01-add-manager-role-project-scope.sql`,按 `role_key='manager'` 新增/更新角色并授予项目菜单权限,不自动绑定用户。
|
||||
|
||||
## 验证
|
||||
|
||||
执行 `mvn -pl ccdi-project -am compile -DskipTests`,重点验证权限服务、Controller 注入、Mapper 参数和 MyBatis XML 条件编译通过。
|
||||
@@ -0,0 +1,18 @@
|
||||
# manager 项目权限前端实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
前端根据后端返回的 `canOperate` 呈现项目只读体验:他人项目可查看结果和明细,不展示或禁用上传、参数配置、重新分析、归档、证据确认、手工资金流保存等写入入口。
|
||||
|
||||
## 实施范围
|
||||
|
||||
1. 项目列表使用 `canOperate` 控制按钮:他人项目仅显示查看入口,重新分析和归档仅在 `canOperate=true` 且状态允许时展示。
|
||||
2. 他人项目从列表进入详情时默认打开 `overview`;详情页路由指向上传或参数配置时自动切换到结果总览。
|
||||
3. 详情页将 `canOperate` 传给上传、参数配置、结果总览、证据确认、项目分析图谱等子组件。
|
||||
4. 上传数据、拉取本行信息、征信导入、文件删除、参数保存、证据确认、手工资金流新增保存均在前端方法入口做只读拦截。
|
||||
5. 关系图谱、资金图谱、资金边流水明细请求携带当前 `projectId` 作为后端读权限校验上下文;资金图谱手工资金流数据仍保持全局图谱逻辑,不按项目过滤。
|
||||
6. 新建项目、历史导入和快捷创建入口继续按 `ccdi:project:add` 菜单权限展示。
|
||||
|
||||
## 验证
|
||||
|
||||
执行 `source ~/.nvm/nvm.sh && cd ruoyi-ui && nvm use && npm run build:prod`,并通过真实浏览器检查列表按钮、详情只读页签、上传/参数/证据/图谱写入入口和查询接口行为。
|
||||
@@ -0,0 +1,22 @@
|
||||
# manager 项目权限实施记录
|
||||
|
||||
## 修改内容
|
||||
|
||||
- 新增后端项目访问控制服务,统一判断 `admin / manager / 创建者` 的项目读权限,以及 `admin / 创建者` 的项目操作权限。
|
||||
- 项目列表、历史项目、状态统计按当前用户角色自动限制范围,并在项目 VO 中返回 `ownedByCurrentUser` 和 `canOperate`。
|
||||
- 项目列表、项目详情、流水明细、上传记录、证据读取等基础读接口不再依赖 `ccdi:project:list/query` 菜单权限,避免普通角色登录后被菜单权限提前拦截。
|
||||
- 为项目详情、结果总览、流水明细、专项排查、关系图谱、资金图谱、上传、参数、证据、重新分析等接口补充项目级读写权限校验。
|
||||
- 新增 `manager` 角色幂等 SQL,按 `role_key='manager'` 维护角色并授予项目相关菜单权限,不绑定具体用户。
|
||||
- 前端项目列表、详情页、上传、参数、证据、项目分析图谱按 `canOperate` 展示只读态,并在写入方法入口拦截。
|
||||
|
||||
## 影响范围
|
||||
|
||||
- `manager` 可查看所有项目,操作他人项目会被后端拒绝;操作本人项目仍受菜单权限控制。
|
||||
- 普通角色可进入项目列表并查看本人创建的项目,直接传入他人项目或资源 ID 会被拒绝;写操作仍受菜单权限和项目归属共同约束。
|
||||
- 资金图谱手工资金流保持全局资金图逻辑,不新增项目归属字段,也不按项目过滤手工边;保存入口只使用当前项目 ID 做操作权限校验。
|
||||
|
||||
## 验证记录
|
||||
|
||||
- 后端计划执行:`mvn -pl ccdi-project -am compile -DskipTests`。
|
||||
- 前端计划执行:`source ~/.nvm/nvm.sh && cd ruoyi-ui && nvm use && npm run build:prod`。
|
||||
- 浏览器计划验证:admin、manager、普通角色的列表范围、详情只读态、按钮显隐和接口拒绝行为。
|
||||
@@ -101,10 +101,10 @@
|
||||
v-if="['0', '3', '4'].includes(scope.row.status)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-right"
|
||||
:icon="canOperate(scope.row) ? 'el-icon-right' : 'el-icon-view'"
|
||||
@click="handleEnter(scope.row)"
|
||||
>
|
||||
进入项目
|
||||
{{ canOperate(scope.row) ? "进入项目" : "查看项目" }}
|
||||
</el-button>
|
||||
|
||||
<template v-if="scope.row.status === '1'">
|
||||
@@ -117,6 +117,7 @@
|
||||
查看结果
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canOperate(scope.row)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@@ -127,6 +128,7 @@
|
||||
重新分析
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canOperate(scope.row)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-folder"
|
||||
@@ -228,6 +230,9 @@ export default {
|
||||
handleArchive(row) {
|
||||
this.$emit("archive", row);
|
||||
},
|
||||
canOperate(row) {
|
||||
return !row || row.canOperate !== false;
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.$emit("pagination", {
|
||||
pageNum: this.pageParams.pageNum,
|
||||
|
||||
@@ -30,13 +30,14 @@
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请填写为什么将该详情确认为证据"
|
||||
:disabled="!canOperate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">
|
||||
<el-button type="primary" :loading="submitting" :disabled="!canOperate" @click="handleSubmit">
|
||||
确认入库
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -63,6 +64,10 @@ export default {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -100,6 +105,10 @@ export default {
|
||||
this.$emit("update:visible", false);
|
||||
},
|
||||
async handleSubmit() {
|
||||
if (!this.canOperate) {
|
||||
this.$message.warning("当前项目仅可查看,不能确认入库证据");
|
||||
return;
|
||||
}
|
||||
if (!this.confirmReason) {
|
||||
this.$message.warning("请填写确认理由/备注");
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="param-config-container" v-loading="loading" element-loading-text="加载中...">
|
||||
<div v-if="isProjectTagging || isProjectArchived" class="readonly-tip">
|
||||
{{ isProjectArchived ? "已归档项目暂不可修改参数。" : "项目正在进行银行流水打标,参数暂不可修改。" }}
|
||||
<div v-if="isWriteLocked" class="readonly-tip">
|
||||
{{ writeLockedMessage }}
|
||||
</div>
|
||||
|
||||
<!-- 模型参数卡片组(垂直堆叠) -->
|
||||
@@ -24,7 +24,7 @@
|
||||
<template #default="{ row }">
|
||||
<el-input
|
||||
v-model="row.paramValue"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
placeholder="请输入阈值"
|
||||
@input="markAsModified(model.modelCode, row)"
|
||||
/>
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
<!-- 统一保存按钮 -->
|
||||
<div class="button-section" v-if="!loading && modelGroups.length > 0">
|
||||
<el-button type="primary" :disabled="isProjectTagging || isProjectArchived || saving" @click="handleSaveAll" :loading="saving">
|
||||
<el-button type="primary" :disabled="isWriteLocked || saving" @click="handleSaveAll" :loading="saving">
|
||||
保存所有修改
|
||||
</el-button>
|
||||
<span v-if="modifiedCount > 0" class="modified-tip">
|
||||
@@ -65,6 +65,10 @@ export default {
|
||||
projectInfo: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -85,6 +89,15 @@ export default {
|
||||
},
|
||||
isProjectArchived() {
|
||||
return String(this.projectInfo.projectStatus) === "2";
|
||||
},
|
||||
isWriteLocked() {
|
||||
return !this.canOperate || this.isProjectTagging || this.isProjectArchived;
|
||||
},
|
||||
writeLockedMessage() {
|
||||
if (!this.canOperate) {
|
||||
return "当前项目仅可查看,暂不可修改参数。";
|
||||
}
|
||||
return this.isProjectArchived ? "已归档项目暂不可修改参数。" : "项目正在进行银行流水打标,参数暂不可修改。";
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -162,6 +175,10 @@ export default {
|
||||
},
|
||||
|
||||
async handleSaveAll() {
|
||||
if (!this.canOperate) {
|
||||
this.$message.warning("当前项目仅可查看,暂不可修改参数");
|
||||
return;
|
||||
}
|
||||
if (this.isProjectArchived) {
|
||||
this.$message.warning("已归档项目暂不可修改参数");
|
||||
return;
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
:source="projectAnalysisSource"
|
||||
:model-summary="projectAnalysisModelSummary"
|
||||
:project-name="projectInfo.projectName"
|
||||
:can-operate="canOperate"
|
||||
@close="handleProjectAnalysisDialogClose"
|
||||
@evidence-confirm="$emit('evidence-confirm', $event)"
|
||||
/>
|
||||
@@ -115,6 +116,10 @@ export default {
|
||||
projectStatus: "0",
|
||||
}),
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
:project-id="projectId"
|
||||
:person="person"
|
||||
:model-summary="modelSummary"
|
||||
:can-operate="canOperate"
|
||||
initial-graph-tab="relation"
|
||||
:graph-tabs="['relation']"
|
||||
/>
|
||||
@@ -123,6 +124,7 @@
|
||||
:project-id="projectId"
|
||||
:person="person"
|
||||
:model-summary="modelSummary"
|
||||
:can-operate="canOperate"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -181,6 +183,10 @@ export default {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
:show-edge-metrics="!isFundOnly"
|
||||
:stacked-fund-detail-pane="isFundOnly"
|
||||
hide-empty-detail-pane
|
||||
:project-id="projectId"
|
||||
:can-operate="canOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -48,6 +50,10 @@ export default {
|
||||
type: Array,
|
||||
default: () => ["fund", "relation"],
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isFundOnly() {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div class="upload-data-container">
|
||||
<!-- 主内容区 -->
|
||||
<div class="main-content">
|
||||
<div v-if="isProjectTagging || isProjectArchived" class="tagging-lock-tip">
|
||||
{{ isProjectArchived ? "项目已归档,暂不可上传或拉取数据。" : "项目正在进行银行流水打标,暂不可上传或拉取数据。" }}
|
||||
<div v-if="isWriteLocked" class="tagging-lock-tip">
|
||||
{{ writeLockedMessage }}
|
||||
</div>
|
||||
|
||||
<!-- 文件上传记录列表 -->
|
||||
@@ -14,7 +14,7 @@
|
||||
<el-button
|
||||
size="small"
|
||||
icon="el-icon-upload2"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
@click="handleOpenBatchUploadDialog"
|
||||
>
|
||||
上传流水
|
||||
@@ -22,7 +22,7 @@
|
||||
<el-button
|
||||
size="small"
|
||||
icon="el-icon-download"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
@click="handleFetchBankInfo"
|
||||
>
|
||||
拉取本行信息
|
||||
@@ -30,7 +30,7 @@
|
||||
<el-button
|
||||
size="small"
|
||||
icon="el-icon-upload2"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
@click="handleGoCreditInfoPage"
|
||||
>
|
||||
征信导入
|
||||
@@ -125,7 +125,7 @@
|
||||
v-model="pullBankInfoForm.idCardText"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
placeholder="仅支持英文逗号分隔"
|
||||
/>
|
||||
<div class="pull-bank-field-tip">
|
||||
@@ -143,7 +143,7 @@
|
||||
:show-file-list="false"
|
||||
:file-list="idCardFileList"
|
||||
accept=".xls,.xlsx"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
:on-change="handleIdCardFileChange"
|
||||
:on-remove="handleIdCardFileRemove"
|
||||
>
|
||||
@@ -175,7 +175,7 @@
|
||||
<el-date-picker
|
||||
class="pull-bank-range-picker"
|
||||
v-model="pullBankInfoForm.dateRange"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
type="daterange"
|
||||
value-format="yyyy-MM-dd"
|
||||
:picker-options="pullBankInfoDatePickerOptions"
|
||||
@@ -189,7 +189,7 @@
|
||||
<el-button @click="pullBankInfoDialogVisible = false">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
:loading="pullBankInfoLoading"
|
||||
@click="handleConfirmPullBankInfo"
|
||||
>
|
||||
@@ -210,7 +210,7 @@
|
||||
drag
|
||||
action="#"
|
||||
multiple
|
||||
:disabled="isProjectTagging || isProjectArchived"
|
||||
:disabled="isWriteLocked"
|
||||
:auto-upload="false"
|
||||
:on-change="handleBatchFileChange"
|
||||
:show-file-list="false"
|
||||
@@ -250,7 +250,7 @@
|
||||
<el-button @click="batchUploadDialogVisible = false">取消</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="isProjectTagging || isProjectArchived || selectedFiles.length === 0"
|
||||
:disabled="isWriteLocked || selectedFiles.length === 0"
|
||||
:loading="uploadLoading"
|
||||
@click="handleBatchUpload"
|
||||
>开始上传</el-button
|
||||
@@ -291,6 +291,10 @@ export default {
|
||||
projectStatus: "0",
|
||||
}),
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -358,6 +362,17 @@ export default {
|
||||
isProjectArchived() {
|
||||
return String(this.projectInfo.projectStatus) === "2";
|
||||
},
|
||||
isWriteLocked() {
|
||||
return !this.canOperate || this.isProjectTagging || this.isProjectArchived;
|
||||
},
|
||||
writeLockedMessage() {
|
||||
if (!this.canOperate) {
|
||||
return "当前项目仅可查看,暂不可上传或拉取数据。";
|
||||
}
|
||||
return this.isProjectArchived
|
||||
? "项目已归档,暂不可上传或拉取数据。"
|
||||
: "项目正在进行银行流水打标,暂不可上传或拉取数据。";
|
||||
},
|
||||
isReportDisabled() {
|
||||
return ["0", "3", "4"].includes(String(this.projectInfo.projectStatus));
|
||||
},
|
||||
@@ -406,13 +421,15 @@ export default {
|
||||
this.$emit("menu-change", { key: "overview", route: "overview" });
|
||||
},
|
||||
handleGoCreditInfoPage() {
|
||||
if (this.isProjectTagging || this.isProjectArchived) {
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
this.$router.push("/maintain/creditInfo");
|
||||
},
|
||||
handleOpenBatchUploadDialog() {
|
||||
if (this.isProjectTagging || this.isProjectArchived) {
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
this.batchUploadDialogVisible = true;
|
||||
@@ -450,7 +467,8 @@ export default {
|
||||
return Array.from(new Set(merged)).join(", ");
|
||||
},
|
||||
async handleIdCardFileChange(file, fileList) {
|
||||
if (this.isProjectTagging || this.isProjectArchived) {
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
const latestFile = (fileList || []).slice(-1);
|
||||
@@ -570,12 +588,8 @@ export default {
|
||||
return this.parseIdCardText(this.pullBankInfoForm.idCardText);
|
||||
},
|
||||
async handleConfirmPullBankInfo() {
|
||||
if (this.isProjectTagging || this.isProjectArchived) {
|
||||
this.$message.warning(
|
||||
this.isProjectArchived
|
||||
? "项目已归档,暂不可上传或拉取数据"
|
||||
: "项目正在进行银行流水打标,暂不可上传或拉取数据"
|
||||
);
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
const idCards = this.buildFinalIdCardList();
|
||||
@@ -634,12 +648,8 @@ export default {
|
||||
},
|
||||
/** 拉取本行信息 */
|
||||
handleFetchBankInfo() {
|
||||
if (this.isProjectTagging || this.isProjectArchived) {
|
||||
this.$message.warning(
|
||||
this.isProjectArchived
|
||||
? "项目已归档,暂不可上传或拉取数据"
|
||||
: "项目正在进行银行流水打标,暂不可上传或拉取数据"
|
||||
);
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
this.resetPullBankInfoForm();
|
||||
@@ -685,6 +695,10 @@ export default {
|
||||
|
||||
/** 批量上传的文件选择变化 */
|
||||
handleBatchFileChange(file, fileList) {
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
if (fileList.length > 100) {
|
||||
this.$message.warning("最多上传100个文件");
|
||||
fileList = fileList.slice(0, 100);
|
||||
@@ -712,17 +726,17 @@ export default {
|
||||
|
||||
/** 删除已选文件 */
|
||||
handleRemoveFile(index) {
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
this.selectedFiles.splice(index, 1);
|
||||
},
|
||||
|
||||
/** 开始批量上传 */
|
||||
async handleBatchUpload() {
|
||||
if (this.isProjectTagging || this.isProjectArchived) {
|
||||
this.$message.warning(
|
||||
this.isProjectArchived
|
||||
? "项目已归档,暂不可上传或拉取数据"
|
||||
: "项目正在进行银行流水打标,暂不可上传或拉取数据"
|
||||
);
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
if (this.selectedFiles.length === 0) {
|
||||
@@ -868,7 +882,11 @@ export default {
|
||||
},
|
||||
|
||||
getRowAction(row) {
|
||||
return getUploadFileAction(row);
|
||||
const action = getUploadFileAction(row);
|
||||
if (!this.canOperate && action && action.key === "delete") {
|
||||
return null;
|
||||
}
|
||||
return action;
|
||||
},
|
||||
|
||||
handleRowAction(row) {
|
||||
@@ -895,6 +913,10 @@ export default {
|
||||
},
|
||||
|
||||
async handleDeleteFile(row) {
|
||||
if (this.isWriteLocked) {
|
||||
this.showWriteLockedMessage();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.$confirm(
|
||||
"删除该文件后将同步删除流水分析平台中的文件,并清除本系统中该文件对应的所有银行流水数据,项目内流水也将重新打标,是否继续?",
|
||||
@@ -923,6 +945,9 @@ export default {
|
||||
this.$message.error("删除失败:" + ((error && error.message) || "未知错误"));
|
||||
}
|
||||
},
|
||||
showWriteLockedMessage() {
|
||||
this.$message.warning(this.writeLockedMessage);
|
||||
},
|
||||
|
||||
hasActivePollingRecords() {
|
||||
return (
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
title="新增主体节点及手工资金流向边"
|
||||
:disabled="!canOperate"
|
||||
@click="handleManualFlowCreate"
|
||||
>
|
||||
新增资金流向
|
||||
@@ -503,6 +504,14 @@ export default {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
projectId: {
|
||||
type: [String, Number],
|
||||
default: null,
|
||||
},
|
||||
canOperate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
autoScroll: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@@ -818,6 +827,10 @@ export default {
|
||||
this.renderChart();
|
||||
},
|
||||
handleManualFlowCreate() {
|
||||
if (!this.canOperate) {
|
||||
this.$message.warning("当前项目仅可查看,不能新增手工资金流向");
|
||||
return;
|
||||
}
|
||||
const centerNode = this.graph.centerNode || this.selectedNode;
|
||||
if (!centerNode || !centerNode.objectKey) {
|
||||
this.$message.warning("请先查询或选择一个起点主体");
|
||||
@@ -843,6 +856,10 @@ export default {
|
||||
});
|
||||
},
|
||||
submitManualFlow() {
|
||||
if (!this.canOperate) {
|
||||
this.$message.warning("当前项目仅可查看,不能新增手工资金流向");
|
||||
return;
|
||||
}
|
||||
if (!this.$refs.manualForm) {
|
||||
return;
|
||||
}
|
||||
@@ -852,7 +869,10 @@ export default {
|
||||
}
|
||||
this.manualDialog.saving = true;
|
||||
try {
|
||||
await saveFundGraphManualEdge(this.manualForm);
|
||||
await saveFundGraphManualEdge({
|
||||
...this.manualForm,
|
||||
projectId: this.projectId,
|
||||
});
|
||||
this.$message.success("手工资金流向已保存");
|
||||
this.manualDialog.visible = false;
|
||||
await this.loadGraph();
|
||||
@@ -884,6 +904,7 @@ export default {
|
||||
try {
|
||||
const response = await getFundGraph({
|
||||
...this.query,
|
||||
projectId: this.projectId,
|
||||
keyword: node.nodeName,
|
||||
objectKey: node.objectKey,
|
||||
});
|
||||
@@ -923,7 +944,7 @@ export default {
|
||||
}
|
||||
this.graphLoading = true;
|
||||
try {
|
||||
const response = await getFundGraph(this.query);
|
||||
const response = await getFundGraph(this.buildFundGraphQuery());
|
||||
this.graph = (response && response.data) || emptyGraph();
|
||||
this.expandedObjectKeys = [];
|
||||
this.clearSelection();
|
||||
@@ -966,7 +987,7 @@ export default {
|
||||
}
|
||||
this.relationGraphLoading = true;
|
||||
try {
|
||||
const response = await getRelationGraph(this.relationQuery);
|
||||
const response = await getRelationGraph(this.buildRelationGraphQuery());
|
||||
this.relationGraph = (response && response.data) || emptyGraph();
|
||||
this.clearRelationSelection();
|
||||
} catch (error) {
|
||||
@@ -998,6 +1019,7 @@ export default {
|
||||
this.suspectedEnterpriseDialog.loading = true;
|
||||
try {
|
||||
const response = await getRelationGraphSuspectedEnterprises({
|
||||
projectId: this.projectId,
|
||||
personName: node.nodeName,
|
||||
certNo: node.idNumber,
|
||||
limit: 10,
|
||||
@@ -1751,6 +1773,7 @@ export default {
|
||||
this.detailLoading = true;
|
||||
try {
|
||||
const response = await getFundGraphEdgeDetail({
|
||||
projectId: this.projectId,
|
||||
fromKey: selectedEdge.fromKey,
|
||||
toKey: selectedEdge.toKey,
|
||||
direction: selectedEdge.direction,
|
||||
@@ -1781,6 +1804,20 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
buildFundGraphQuery(extra = {}) {
|
||||
return {
|
||||
...this.query,
|
||||
...extra,
|
||||
projectId: this.projectId,
|
||||
};
|
||||
},
|
||||
buildRelationGraphQuery(extra = {}) {
|
||||
return {
|
||||
...this.relationQuery,
|
||||
...extra,
|
||||
projectId: this.projectId,
|
||||
};
|
||||
},
|
||||
mergeGraph(currentGraph, nextGraph) {
|
||||
const nodeMap = new Map();
|
||||
const edgeMap = new Map();
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
:is="currentComponent"
|
||||
:project-id="projectId"
|
||||
:project-info="projectInfo"
|
||||
:can-operate="canOperate"
|
||||
@menu-change="handleMenuChange"
|
||||
@refresh-project="handleRefreshProject"
|
||||
@data-uploaded="handleDataUploaded"
|
||||
@@ -94,6 +95,7 @@
|
||||
<evidence-confirm-dialog
|
||||
:visible.sync="evidenceConfirmVisible"
|
||||
:payload="evidencePayload"
|
||||
:can-operate="canOperate"
|
||||
@saved="handleEvidenceSaved"
|
||||
/>
|
||||
<evidence-drawer
|
||||
@@ -162,6 +164,7 @@ export default {
|
||||
projectStatus: "0",
|
||||
latestTagTaskErrorMessage: "",
|
||||
latestTagTaskEndTime: "",
|
||||
canOperate: true,
|
||||
},
|
||||
evidenceConfirmVisible: false,
|
||||
evidenceDrawerVisible: false,
|
||||
@@ -177,6 +180,9 @@ export default {
|
||||
isProjectArchived() {
|
||||
return String(this.projectInfo.projectStatus) === "2";
|
||||
},
|
||||
canOperate() {
|
||||
return this.projectInfo.canOperate !== false;
|
||||
},
|
||||
isProjectTagFailed() {
|
||||
return String(this.projectInfo.projectStatus) === "4";
|
||||
},
|
||||
@@ -200,12 +206,10 @@ export default {
|
||||
this.initActiveTabFromRoute();
|
||||
},
|
||||
"projectInfo.projectStatus"() {
|
||||
this.syncProjectStatusPolling();
|
||||
const accessibleTab = this.resolveAccessibleTab(this.activeTab);
|
||||
if (accessibleTab !== this.activeTab) {
|
||||
this.setActiveTab(accessibleTab);
|
||||
this.syncRouteTab(accessibleTab);
|
||||
}
|
||||
this.syncAccessibleTab();
|
||||
},
|
||||
canOperate() {
|
||||
this.syncAccessibleTab();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
@@ -219,6 +223,14 @@ export default {
|
||||
this.stopProjectStatusPolling();
|
||||
},
|
||||
methods: {
|
||||
syncAccessibleTab() {
|
||||
this.syncProjectStatusPolling();
|
||||
const accessibleTab = this.resolveAccessibleTab(this.activeTab);
|
||||
if (accessibleTab !== this.activeTab) {
|
||||
this.setActiveTab(accessibleTab);
|
||||
this.syncRouteTab(accessibleTab);
|
||||
}
|
||||
},
|
||||
initActiveTabFromRoute() {
|
||||
const tab = (this.$route.query && this.$route.query.tab) || "";
|
||||
const validTabs = ["upload", "config", "overview", "special", "detail"];
|
||||
@@ -230,7 +242,7 @@ export default {
|
||||
}
|
||||
},
|
||||
isArchiveLockedTab(tab) {
|
||||
return this.isProjectArchived && ["upload", "config"].includes(tab);
|
||||
return (this.isProjectArchived || !this.canOperate) && ["upload", "config"].includes(tab);
|
||||
},
|
||||
resolveAccessibleTab(tab) {
|
||||
if (this.isArchiveLockedTab(tab)) {
|
||||
@@ -295,6 +307,7 @@ export default {
|
||||
};
|
||||
this.updatePageTitle();
|
||||
this.syncProjectStatusPolling();
|
||||
this.syncAccessibleTab();
|
||||
return this.projectInfo;
|
||||
} catch (error) {
|
||||
if (!silent) {
|
||||
@@ -436,10 +449,12 @@ export default {
|
||||
/** 菜单选择事件 */
|
||||
handleMenuSelect(index) {
|
||||
if (this.isArchiveLockedTab(index)) {
|
||||
this.$message.warning(this.canOperate ? "已归档项目暂不可进入该页签" : "当前项目仅可查看,不能进入写入页签");
|
||||
return;
|
||||
}
|
||||
console.log("菜单选择:", index);
|
||||
this.setActiveTab(index);
|
||||
this.syncRouteTab(index);
|
||||
},
|
||||
/** UploadData 组件:菜单切换 */
|
||||
handleMenuChange({ key, route }) {
|
||||
@@ -489,6 +504,10 @@ export default {
|
||||
this.initPageData();
|
||||
},
|
||||
handleEvidenceConfirm(payload) {
|
||||
if (!this.canOperate) {
|
||||
this.$message.warning("当前项目仅可查看,不能确认入库证据");
|
||||
return;
|
||||
}
|
||||
this.evidencePayload = {
|
||||
projectId: this.projectId,
|
||||
...(payload || {}),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- 页面标题 -->
|
||||
<div class="page-header">
|
||||
<h2 class="page-title">初核项目管理</h2>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新建项目</el-button>
|
||||
<el-button v-hasPermi="['ccdi:project:add']" type="primary" icon="el-icon-plus" @click="handleAdd">新建项目</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索和操作区 -->
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
<!-- 快捷入口区 -->
|
||||
<quick-entry
|
||||
v-hasPermi="['ccdi:project:add']"
|
||||
@import-history="handleImport"
|
||||
@create-quarterly="handleCreateQuarterly"
|
||||
@create-employee="handleCreateEmployee"
|
||||
@@ -245,7 +246,8 @@ export default {
|
||||
/** 进入项目 */
|
||||
handleEnter(row) {
|
||||
this.$router.push({
|
||||
path: `ccdiProject/detail/${row.projectId}`,
|
||||
path: `/ccdiProject/detail/${row.projectId}`,
|
||||
query: { tab: this.canOperate(row) ? "upload" : "overview" },
|
||||
});
|
||||
// this.$modal.msgSuccess("进入项目: " + row.projectName);
|
||||
},
|
||||
@@ -258,6 +260,10 @@ export default {
|
||||
},
|
||||
/** 重新分析 */
|
||||
async handleReAnalyze(row) {
|
||||
if (!this.canOperate(row)) {
|
||||
this.$modal.msgWarning("当前项目仅可查看,不能重新分析")
|
||||
return
|
||||
}
|
||||
const projectKey = String(row.projectId)
|
||||
if (this.reAnalyzeLoadingMap[projectKey]) {
|
||||
return
|
||||
@@ -286,6 +292,10 @@ export default {
|
||||
},
|
||||
/** 归档项目 */
|
||||
handleArchive(row) {
|
||||
if (!this.canOperate(row)) {
|
||||
this.$modal.msgWarning("当前项目仅可查看,不能归档")
|
||||
return
|
||||
}
|
||||
this.currentArchiveProject = row;
|
||||
this.archiveDialogVisible = true;
|
||||
},
|
||||
@@ -302,6 +312,9 @@ export default {
|
||||
this.$modal.msgError(message)
|
||||
}
|
||||
},
|
||||
canOperate(row) {
|
||||
return !row || row.canOperate !== false
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
65
sql/migration/2026-07-01-add-manager-role-project-scope.sql
Normal file
65
sql/migration/2026-07-01-add-manager-role-project-scope.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
-- 新增项目管理员角色,可重复执行。
|
||||
-- manager 可查看全部项目;项目操作能力由后端项目归属校验和菜单权限共同控制。
|
||||
|
||||
INSERT INTO sys_role (
|
||||
role_name,
|
||||
role_key,
|
||||
role_sort,
|
||||
data_scope,
|
||||
menu_check_strictly,
|
||||
dept_check_strictly,
|
||||
status,
|
||||
del_flag,
|
||||
create_by,
|
||||
create_time,
|
||||
remark
|
||||
)
|
||||
SELECT
|
||||
'项目管理员',
|
||||
'manager',
|
||||
3,
|
||||
'1',
|
||||
1,
|
||||
1,
|
||||
'0',
|
||||
'0',
|
||||
'admin',
|
||||
NOW(),
|
||||
'可查看全部项目,仅可操作本人创建的项目'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys_role
|
||||
WHERE role_key = 'manager'
|
||||
);
|
||||
|
||||
UPDATE sys_role
|
||||
SET role_name = '项目管理员',
|
||||
role_sort = 3,
|
||||
data_scope = '1',
|
||||
menu_check_strictly = 1,
|
||||
dept_check_strictly = 1,
|
||||
status = '0',
|
||||
del_flag = '0',
|
||||
update_by = 'admin',
|
||||
update_time = NOW(),
|
||||
remark = '可查看全部项目,仅可操作本人创建的项目'
|
||||
WHERE role_key = 'manager';
|
||||
|
||||
INSERT IGNORE INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT r.role_id, m.menu_id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m
|
||||
WHERE r.role_key = 'manager'
|
||||
AND (
|
||||
m.perms = 'ccdi:project:list'
|
||||
OR m.perms LIKE 'ccdi:project:%'
|
||||
);
|
||||
|
||||
INSERT IGNORE INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT r.role_id, parent.menu_id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu project_menu
|
||||
ON project_menu.perms = 'ccdi:project:list'
|
||||
JOIN sys_menu parent
|
||||
ON parent.menu_id = project_menu.parent_id
|
||||
WHERE r.role_key = 'manager';
|
||||
Reference in New Issue
Block a user