新增项目管理员角色权限控制

This commit is contained in:
wkc
2026-07-01 16:12:03 +08:00
parent 6c70149e0c
commit 64ddc362e3
33 changed files with 727 additions and 92 deletions

View File

@@ -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.CcdiBankStatementDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO; import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementFilterOptionsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiBankStatementListVO; 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.ccdi.project.service.ICcdiBankStatementService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
@@ -39,13 +40,16 @@ public class CcdiBankStatementController extends BaseController {
@Resource @Resource
private ICcdiBankStatementService bankStatementService; private ICcdiBankStatementService bankStatementService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 分页查询流水明细 * 分页查询流水明细
*/ */
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "分页查询流水明细") @Operation(summary = "分页查询流水明细")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public TableDataInfo list(CcdiBankStatementQueryDTO queryDTO) { public TableDataInfo list(CcdiBankStatementQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
PageDomain pageDomain = TableSupport.buildPageRequest(); PageDomain pageDomain = TableSupport.buildPageRequest();
Page<CcdiBankStatementListVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()); Page<CcdiBankStatementListVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
Page<CcdiBankStatementListVO> result = bankStatementService.selectStatementPage(page, queryDTO); Page<CcdiBankStatementListVO> result = bankStatementService.selectStatementPage(page, queryDTO);
@@ -57,8 +61,8 @@ public class CcdiBankStatementController extends BaseController {
*/ */
@GetMapping("/options") @GetMapping("/options")
@Operation(summary = "查询项目级筛选项") @Operation(summary = "查询项目级筛选项")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getOptions(Long projectId) { public AjaxResult getOptions(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiBankStatementFilterOptionsVO options = bankStatementService.getFilterOptions(projectId); CcdiBankStatementFilterOptionsVO options = bankStatementService.getFilterOptions(projectId);
return AjaxResult.success(options); return AjaxResult.success(options);
} }
@@ -68,8 +72,8 @@ public class CcdiBankStatementController extends BaseController {
*/ */
@GetMapping("/detail/{bankStatementId}") @GetMapping("/detail/{bankStatementId}")
@Operation(summary = "查询流水详情") @Operation(summary = "查询流水详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getDetail(@PathVariable Long bankStatementId) { public AjaxResult getDetail(@PathVariable Long bankStatementId) {
projectAccessService.assertCanReadByBankStatementId(bankStatementId);
CcdiBankStatementDetailVO detail = bankStatementService.getStatementDetail(bankStatementId); CcdiBankStatementDetailVO detail = bankStatementService.getStatementDetail(bankStatementId);
return AjaxResult.success(detail); return AjaxResult.success(detail);
} }
@@ -81,6 +85,7 @@ public class CcdiBankStatementController extends BaseController {
@Operation(summary = "导出流水明细") @Operation(summary = "导出流水明细")
@PreAuthorize("@ss.hasPermi('ccdi:project:export')") @PreAuthorize("@ss.hasPermi('ccdi:project:export')")
public void export(HttpServletResponse response, CcdiBankStatementQueryDTO queryDTO) { public void export(HttpServletResponse response, CcdiBankStatementQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiBankStatementExcel> list = bankStatementService.selectStatementListForExport(queryDTO); List<CcdiBankStatementExcel> list = bankStatementService.selectStatementListForExport(queryDTO);
ExcelUtil<CcdiBankStatementExcel> util = new ExcelUtil<>(CcdiBankStatementExcel.class); ExcelUtil<CcdiBankStatementExcel> util = new ExcelUtil<>(CcdiBankStatementExcel.class);
util.exportExcel(response, list, "流水明细"); util.exportExcel(response, list, "流水明细");

View File

@@ -1,6 +1,7 @@
package com.ruoyi.ccdi.project.controller; package com.ruoyi.ccdi.project.controller;
import com.ruoyi.ccdi.project.domain.dto.CcdiBankTagRebuildDTO; 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.ccdi.project.service.ICcdiBankTagService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; 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 io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -27,12 +29,17 @@ public class CcdiBankTagController extends BaseController {
@Resource @Resource
private ICcdiBankTagService bankTagService; private ICcdiBankTagService bankTagService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 手动提交流水标签重算任务 * 手动提交流水标签重算任务
*/ */
@Operation(summary = "手动重算项目流水标签") @Operation(summary = "手动重算项目流水标签")
@PostMapping("/rebuild") @PostMapping("/rebuild")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult rebuild(@Validated @RequestBody CcdiBankTagRebuildDTO dto) { public AjaxResult rebuild(@Validated @RequestBody CcdiBankTagRebuildDTO dto) {
projectAccessService.assertCanOperate(dto.getProjectId());
String operator = SecurityUtils.getUsername(); String operator = SecurityUtils.getUsername();
log.info("【流水标签】收到手动重算请求: projectId={}, modelCode={}, operator={}", log.info("【流水标签】收到手动重算请求: projectId={}, modelCode={}, operator={}",
dto.getProjectId(), dto.getModelCode(), operator); dto.getProjectId(), dto.getModelCode(), operator);

View File

@@ -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.CcdiEvidenceQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiEvidenceSaveDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiEvidenceSaveDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiEvidenceVO; 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.ccdi.project.service.ICcdiEvidenceService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
@@ -34,13 +35,17 @@ public class CcdiEvidenceController extends BaseController {
@Resource @Resource
private ICcdiEvidenceService evidenceService; private ICcdiEvidenceService evidenceService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 保存证据 * 保存证据
*/ */
@PostMapping @PostMapping
@Operation(summary = "保存证据") @Operation(summary = "保存证据")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult saveEvidence(@Validated @RequestBody CcdiEvidenceSaveDTO dto) { public AjaxResult saveEvidence(@Validated @RequestBody CcdiEvidenceSaveDTO dto) {
projectAccessService.assertCanOperate(dto.getProjectId());
CcdiEvidenceVO vo = evidenceService.saveEvidence(dto, SecurityUtils.getUsername()); CcdiEvidenceVO vo = evidenceService.saveEvidence(dto, SecurityUtils.getUsername());
return AjaxResult.success("证据入库成功", vo); return AjaxResult.success("证据入库成功", vo);
} }
@@ -50,8 +55,8 @@ public class CcdiEvidenceController extends BaseController {
*/ */
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "查询项目证据列表") @Operation(summary = "查询项目证据列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult listEvidence(CcdiEvidenceQueryDTO queryDTO) { public AjaxResult listEvidence(CcdiEvidenceQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiEvidenceVO> list = evidenceService.listEvidence(queryDTO); List<CcdiEvidenceVO> list = evidenceService.listEvidence(queryDTO);
return AjaxResult.success(list); return AjaxResult.success(list);
} }
@@ -61,8 +66,8 @@ public class CcdiEvidenceController extends BaseController {
*/ */
@GetMapping("/{evidenceId}") @GetMapping("/{evidenceId}")
@Operation(summary = "查询证据详情") @Operation(summary = "查询证据详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getEvidence(@PathVariable Long evidenceId) { public AjaxResult getEvidence(@PathVariable Long evidenceId) {
projectAccessService.assertCanReadByEvidenceId(evidenceId);
CcdiEvidenceVO vo = evidenceService.getEvidence(evidenceId); CcdiEvidenceVO vo = evidenceService.getEvidence(evidenceId);
return AjaxResult.success(vo); return AjaxResult.success(vo);
} }

View File

@@ -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.entity.CcdiFileUploadRecord;
import com.ruoyi.ccdi.project.domain.vo.CcdiFileUploadStatisticsVO; import com.ruoyi.ccdi.project.domain.vo.CcdiFileUploadStatisticsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiIdCardParseVO; 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.ccdi.project.service.ICcdiFileUploadService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; 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 io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -40,17 +42,22 @@ public class CcdiFileUploadController extends BaseController {
@Resource @Resource
private ICcdiFileUploadService fileUploadService; private ICcdiFileUploadService fileUploadService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 批量上传文件(异步) * 批量上传文件(异步)
*/ */
@PostMapping("/batch") @PostMapping("/batch")
@Operation(summary = "批量上传文件", description = "异步批量上传流水文件") @Operation(summary = "批量上传文件", description = "异步批量上传流水文件")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult batchUpload(@RequestParam Long projectId, public AjaxResult batchUpload(@RequestParam Long projectId,
@RequestParam MultipartFile[] files) { @RequestParam MultipartFile[] files) {
// 参数校验 // 参数校验
if (projectId == null) { if (projectId == null) {
return AjaxResult.error("项目ID不能为空"); return AjaxResult.error("项目ID不能为空");
} }
projectAccessService.assertCanOperate(projectId);
if (files == null || files.length == 0) { if (files == null || files.length == 0) {
return AjaxResult.error("请选择要上传的文件"); return AjaxResult.error("请选择要上传的文件");
} }
@@ -95,6 +102,7 @@ public class CcdiFileUploadController extends BaseController {
*/ */
@PostMapping("/parse-id-card-file") @PostMapping("/parse-id-card-file")
@Operation(summary = "解析身份证文件", description = "解析首个sheet第一列的身份证号") @Operation(summary = "解析身份证文件", description = "解析首个sheet第一列的身份证号")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult parseIdCardFile(@RequestParam MultipartFile file) { public AjaxResult parseIdCardFile(@RequestParam MultipartFile file) {
if (file == null || file.isEmpty()) { if (file == null || file.isEmpty()) {
return AjaxResult.error("身份证文件不能为空"); return AjaxResult.error("身份证文件不能为空");
@@ -108,10 +116,12 @@ public class CcdiFileUploadController extends BaseController {
*/ */
@PostMapping("/pull-bank-info") @PostMapping("/pull-bank-info")
@Operation(summary = "拉取本行信息", description = "按身份证号批量提交拉取本行信息任务") @Operation(summary = "拉取本行信息", description = "按身份证号批量提交拉取本行信息任务")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult pullBankInfo(@RequestBody CcdiPullBankInfoSubmitDTO dto) { public AjaxResult pullBankInfo(@RequestBody CcdiPullBankInfoSubmitDTO dto) {
if (dto == null || dto.getProjectId() == null) { if (dto == null || dto.getProjectId() == null) {
return AjaxResult.error("项目ID不能为空"); return AjaxResult.error("项目ID不能为空");
} }
projectAccessService.assertCanOperate(dto.getProjectId());
if (CollectionUtils.isEmpty(dto.getIdCards())) { if (CollectionUtils.isEmpty(dto.getIdCards())) {
return AjaxResult.error("身份证号不能为空"); return AjaxResult.error("身份证号不能为空");
} }
@@ -138,6 +148,7 @@ public class CcdiFileUploadController extends BaseController {
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "查询上传记录列表", description = "分页查询文件上传记录") @Operation(summary = "查询上传记录列表", description = "分页查询文件上传记录")
public TableDataInfo list(CcdiFileUploadQueryDTO queryDTO) { public TableDataInfo list(CcdiFileUploadQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
PageDomain pageDomain = TableSupport.buildPageRequest(); PageDomain pageDomain = TableSupport.buildPageRequest();
Page<CcdiFileUploadRecord> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()); Page<CcdiFileUploadRecord> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
Page<CcdiFileUploadRecord> result = fileUploadService.selectPage(page, queryDTO); Page<CcdiFileUploadRecord> result = fileUploadService.selectPage(page, queryDTO);
@@ -150,6 +161,7 @@ public class CcdiFileUploadController extends BaseController {
@GetMapping("/statistics/{projectId}") @GetMapping("/statistics/{projectId}")
@Operation(summary = "查询上传统计", description = "统计各状态的文件数量") @Operation(summary = "查询上传统计", description = "统计各状态的文件数量")
public AjaxResult getStatistics(@PathVariable Long projectId) { public AjaxResult getStatistics(@PathVariable Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiFileUploadStatisticsVO statistics = fileUploadService.countByStatus(projectId); CcdiFileUploadStatisticsVO statistics = fileUploadService.countByStatus(projectId);
return AjaxResult.success(statistics); return AjaxResult.success(statistics);
} }
@@ -160,6 +172,7 @@ public class CcdiFileUploadController extends BaseController {
@GetMapping("/detail/{id}") @GetMapping("/detail/{id}")
@Operation(summary = "查询记录详情", description = "根据ID查询文件上传记录详情") @Operation(summary = "查询记录详情", description = "根据ID查询文件上传记录详情")
public AjaxResult getDetail(@PathVariable Long id) { public AjaxResult getDetail(@PathVariable Long id) {
projectAccessService.assertCanReadByFileRecordId(id);
CcdiFileUploadRecord record = fileUploadService.getById(id); CcdiFileUploadRecord record = fileUploadService.getById(id);
return AjaxResult.success(record); return AjaxResult.success(record);
} }
@@ -169,7 +182,9 @@ public class CcdiFileUploadController extends BaseController {
*/ */
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
@Operation(summary = "删除上传文件", description = "按上传记录ID删除文件并清理流水") @Operation(summary = "删除上传文件", description = "按上传记录ID删除文件并清理流水")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult deleteFile(@PathVariable Long id) { public AjaxResult deleteFile(@PathVariable Long id) {
projectAccessService.assertCanOperateByFileRecordId(id);
Long userId = SecurityUtils.getUserId(); Long userId = SecurityUtils.getUserId();
String message = fileUploadService.deleteFileUploadRecord(id, userId); String message = fileUploadService.deleteFileUploadRecord(id, userId);
return AjaxResult.success(message); return AjaxResult.success(message);

View File

@@ -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.CcdiFundGraphNodeVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO; import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphVO; 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.ccdi.project.service.ICcdiFundGraphService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
@@ -38,10 +39,14 @@ public class CcdiFundGraphController extends BaseController {
@Resource @Resource
private ICcdiFundGraphService fundGraphService; private ICcdiFundGraphService fundGraphService;
@Resource
private CcdiProjectAccessService projectAccessService;
@GetMapping("/search") @GetMapping("/search")
@Operation(summary = "查询资金流图谱主体") @Operation(summary = "查询资金流图谱主体")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult searchSubjects(CcdiFundGraphQueryDTO queryDTO) { public AjaxResult searchSubjects(CcdiFundGraphQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiFundGraphNodeVO> subjects = fundGraphService.searchSubjects(queryDTO); List<CcdiFundGraphNodeVO> subjects = fundGraphService.searchSubjects(queryDTO);
return AjaxResult.success(subjects); return AjaxResult.success(subjects);
} }
@@ -50,6 +55,7 @@ public class CcdiFundGraphController extends BaseController {
@Operation(summary = "查询一层资金流图谱") @Operation(summary = "查询一层资金流图谱")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getGraph(CcdiFundGraphQueryDTO queryDTO) { public AjaxResult getGraph(CcdiFundGraphQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiFundGraphVO graph = fundGraphService.getFundGraph(queryDTO); CcdiFundGraphVO graph = fundGraphService.getFundGraph(queryDTO);
return AjaxResult.success(graph); return AjaxResult.success(graph);
} }
@@ -58,6 +64,7 @@ public class CcdiFundGraphController extends BaseController {
@Operation(summary = "查询资金边流水明细") @Operation(summary = "查询资金边流水明细")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public TableDataInfo getEdgeDetail(CcdiFundGraphEdgeDetailQueryDTO queryDTO) { public TableDataInfo getEdgeDetail(CcdiFundGraphEdgeDetailQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
PageDomain pageDomain = TableSupport.buildPageRequest(); PageDomain pageDomain = TableSupport.buildPageRequest();
Page<CcdiFundGraphStatementVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()); Page<CcdiFundGraphStatementVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
Page<CcdiFundGraphStatementVO> result = fundGraphService.getEdgeDetails(page, queryDTO); Page<CcdiFundGraphStatementVO> result = fundGraphService.getEdgeDetails(page, queryDTO);
@@ -66,9 +73,10 @@ public class CcdiFundGraphController extends BaseController {
@PostMapping("/manual-edge") @PostMapping("/manual-edge")
@Operation(summary = "新增手工资金流向") @Operation(summary = "新增手工资金流向")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult saveManualEdge(@RequestBody CcdiFundGraphManualEdgeSaveDTO saveDTO) { public AjaxResult saveManualEdge(@RequestBody CcdiFundGraphManualEdgeSaveDTO saveDTO) {
try { try {
projectAccessService.assertCanOperate(saveDTO == null ? null : saveDTO.getProjectId());
CcdiFundGraphEdgeVO edge = fundGraphService.saveManualEdge(saveDTO, SecurityUtils.getUsername()); CcdiFundGraphEdgeVO edge = fundGraphService.saveManualEdge(saveDTO, SecurityUtils.getUsername());
return AjaxResult.success(edge); return AjaxResult.success(edge);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {

View File

@@ -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.ModelListVO;
import com.ruoyi.ccdi.project.domain.vo.ModelParamVO; import com.ruoyi.ccdi.project.domain.vo.ModelParamVO;
import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO; import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO;
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
import com.ruoyi.ccdi.project.service.ICcdiModelParamService; import com.ruoyi.ccdi.project.service.ICcdiModelParamService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -31,12 +33,17 @@ public class CcdiModelParamController extends BaseController {
@Resource @Resource
private ICcdiModelParamService modelParamService; private ICcdiModelParamService modelParamService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 查询模型列表 * 查询模型列表
*/ */
@Operation(summary = "查询模型列表") @Operation(summary = "查询模型列表")
@GetMapping("/modelList") @GetMapping("/modelList")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult listModels(@RequestParam(required = false) Long projectId) { public AjaxResult listModels(@RequestParam(required = false) Long projectId) {
assertCanReadProjectParam(projectId);
List<ModelListVO> list = modelParamService.selectModelList(projectId); List<ModelListVO> list = modelParamService.selectModelList(projectId);
return success(list); return success(list);
} }
@@ -46,7 +53,9 @@ public class CcdiModelParamController extends BaseController {
*/ */
@Operation(summary = "查询模型参数列表") @Operation(summary = "查询模型参数列表")
@GetMapping("/list") @GetMapping("/list")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult list(@Validated ModelParamQueryDTO queryDTO) { public AjaxResult list(@Validated ModelParamQueryDTO queryDTO) {
assertCanReadProjectParam(queryDTO.getProjectId());
List<ModelParamVO> list = modelParamService.selectParamList(queryDTO); List<ModelParamVO> list = modelParamService.selectParamList(queryDTO);
return success(list); return success(list);
} }
@@ -57,7 +66,9 @@ public class CcdiModelParamController extends BaseController {
@Operation(summary = "保存模型参数") @Operation(summary = "保存模型参数")
@Log(title = "模型参数配置", businessType = BusinessType.UPDATE) @Log(title = "模型参数配置", businessType = BusinessType.UPDATE)
@PostMapping("/save") @PostMapping("/save")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult save(@Validated @RequestBody ModelParamSaveDTO saveDTO) { public AjaxResult save(@Validated @RequestBody ModelParamSaveDTO saveDTO) {
assertCanOperateProjectParam(saveDTO.getProjectId());
modelParamService.saveParams(saveDTO); modelParamService.saveParams(saveDTO);
return success("保存成功"); return success("保存成功");
} }
@@ -67,7 +78,9 @@ public class CcdiModelParamController extends BaseController {
*/ */
@Operation(summary = "查询所有模型及其参数") @Operation(summary = "查询所有模型及其参数")
@GetMapping("/listAll") @GetMapping("/listAll")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult listAll(@Validated ModelParamAllQueryDTO queryDTO) { public AjaxResult listAll(@Validated ModelParamAllQueryDTO queryDTO) {
assertCanReadProjectParam(queryDTO.getProjectId());
ModelParamAllVO result = modelParamService.selectAllParams(queryDTO.getProjectId()); ModelParamAllVO result = modelParamService.selectAllParams(queryDTO.getProjectId());
return success(result); return success(result);
} }
@@ -78,8 +91,24 @@ public class CcdiModelParamController extends BaseController {
@Operation(summary = "批量保存所有模型参数") @Operation(summary = "批量保存所有模型参数")
@Log(title = "模型参数配置", businessType = BusinessType.UPDATE) @Log(title = "模型参数配置", businessType = BusinessType.UPDATE)
@PostMapping("/saveAll") @PostMapping("/saveAll")
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
public AjaxResult saveAll(@Validated @RequestBody ModelParamSaveAllDTO saveAllDTO) { public AjaxResult saveAll(@Validated @RequestBody ModelParamSaveAllDTO saveAllDTO) {
assertCanOperateProjectParam(saveAllDTO.getProjectId());
modelParamService.saveAllParams(saveAllDTO); modelParamService.saveAllParams(saveAllDTO);
return success("保存成功"); 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);
}
} }

View File

@@ -85,7 +85,6 @@ public class CcdiProjectController extends BaseController {
*/ */
@GetMapping("/{projectId}") @GetMapping("/{projectId}")
@Operation(summary = "查询项目详情") @Operation(summary = "查询项目详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getProject(@PathVariable Long projectId) { public AjaxResult getProject(@PathVariable Long projectId) {
CcdiProjectVO vo = projectService.getProjectById(projectId); CcdiProjectVO vo = projectService.getProjectById(projectId);
return AjaxResult.success(vo); return AjaxResult.success(vo);
@@ -96,7 +95,6 @@ public class CcdiProjectController extends BaseController {
*/ */
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "查询项目列表") @Operation(summary = "查询项目列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
public TableDataInfo listProject(CcdiProjectQueryDTO queryDTO) { public TableDataInfo listProject(CcdiProjectQueryDTO queryDTO) {
PageDomain pageDomain = TableSupport.buildPageRequest(); PageDomain pageDomain = TableSupport.buildPageRequest();
Page<CcdiProjectVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()); Page<CcdiProjectVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
@@ -109,7 +107,6 @@ public class CcdiProjectController extends BaseController {
*/ */
@GetMapping("/history") @GetMapping("/history")
@Operation(summary = "查询历史项目列表") @Operation(summary = "查询历史项目列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
public AjaxResult listHistoryProjects(CcdiProjectQueryDTO queryDTO) { public AjaxResult listHistoryProjects(CcdiProjectQueryDTO queryDTO) {
List<CcdiProjectHistoryListItemVO> result = projectService.listHistoryProjects(queryDTO); List<CcdiProjectHistoryListItemVO> result = projectService.listHistoryProjects(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
@@ -131,7 +128,6 @@ public class CcdiProjectController extends BaseController {
*/ */
@GetMapping("/statusCounts") @GetMapping("/statusCounts")
@Operation(summary = "查询项目状态统计") @Operation(summary = "查询项目状态统计")
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
public AjaxResult getStatusCounts() { public AjaxResult getStatusCounts() {
CcdiProjectStatusCountsVO counts = projectService.getStatusCounts(); CcdiProjectStatusCountsVO counts = projectService.getStatusCounts();
return AjaxResult.success(counts); return AjaxResult.success(counts);

View File

@@ -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.CcdiProjectRiskPeopleOverviewVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionPageVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionPageVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectTopRiskPeopleVO; 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.ccdi.project.service.ICcdiProjectOverviewService;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
@@ -51,6 +52,9 @@ public class CcdiProjectOverviewController extends BaseController {
@Resource @Resource
private ICcdiProjectOverviewService overviewService; private ICcdiProjectOverviewService overviewService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 查询风险仪表盘 * 查询风险仪表盘
*/ */
@@ -58,6 +62,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询风险仪表盘") @Operation(summary = "查询风险仪表盘")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getDashboard(Long projectId) { public AjaxResult getDashboard(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiProjectOverviewDashboardVO dashboard = overviewService.getDashboard(projectId); CcdiProjectOverviewDashboardVO dashboard = overviewService.getDashboard(projectId);
return AjaxResult.success(dashboard); return AjaxResult.success(dashboard);
} }
@@ -69,6 +74,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询风险人员总览") @Operation(summary = "查询风险人员总览")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getRiskPeople(CcdiProjectRiskPeopleQueryDTO queryDTO) { public AjaxResult getRiskPeople(CcdiProjectRiskPeopleQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectRiskPeopleOverviewVO overview = overviewService.getRiskPeopleOverview(queryDTO); CcdiProjectRiskPeopleOverviewVO overview = overviewService.getRiskPeopleOverview(queryDTO);
return AjaxResult.success(overview); return AjaxResult.success(overview);
} }
@@ -80,6 +86,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询外部人员预警") @Operation(summary = "查询外部人员预警")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExternalPersons(CcdiProjectExternalPersonQueryDTO queryDTO) { public AjaxResult getExternalPersons(CcdiProjectExternalPersonQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExternalPersonWarningVO warnings = overviewService.getExternalPersonWarnings(queryDTO); CcdiProjectExternalPersonWarningVO warnings = overviewService.getExternalPersonWarnings(queryDTO);
return AjaxResult.success(warnings); return AjaxResult.success(warnings);
} }
@@ -91,6 +98,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询外部人员风险汇总") @Operation(summary = "查询外部人员风险汇总")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExternalRiskSummary(Long projectId) { public AjaxResult getExternalRiskSummary(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiProjectExternalRiskSummaryVO summary = overviewService.getExternalRiskSummary(projectId); CcdiProjectExternalRiskSummaryVO summary = overviewService.getExternalRiskSummary(projectId);
return AjaxResult.success(summary); return AjaxResult.success(summary);
} }
@@ -102,6 +110,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询中高风险人员TOP10") @Operation(summary = "查询中高风险人员TOP10")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getTopRiskPeople(Long projectId) { public AjaxResult getTopRiskPeople(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiProjectTopRiskPeopleVO topRiskPeople = overviewService.getTopRiskPeople(projectId); CcdiProjectTopRiskPeopleVO topRiskPeople = overviewService.getTopRiskPeople(projectId);
return AjaxResult.success(topRiskPeople); return AjaxResult.success(topRiskPeople);
} }
@@ -113,6 +122,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询风险模型卡片") @Operation(summary = "查询风险模型卡片")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getRiskModelCards(Long projectId) { public AjaxResult getRiskModelCards(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiProjectRiskModelCardsVO cards = overviewService.getRiskModelCards(projectId); CcdiProjectRiskModelCardsVO cards = overviewService.getRiskModelCards(projectId);
return AjaxResult.success(cards); return AjaxResult.success(cards);
} }
@@ -124,6 +134,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询风险模型命中人员") @Operation(summary = "查询风险模型命中人员")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getRiskModelPeople(CcdiProjectRiskModelPeopleQueryDTO queryDTO) { public AjaxResult getRiskModelPeople(CcdiProjectRiskModelPeopleQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectRiskModelPeopleVO people = overviewService.getRiskModelPeople(queryDTO); CcdiProjectRiskModelPeopleVO people = overviewService.getRiskModelPeople(queryDTO);
return AjaxResult.success(people); return AjaxResult.success(people);
} }
@@ -135,6 +146,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询外部人员风险模型卡片") @Operation(summary = "查询外部人员风险模型卡片")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExternalRiskModelCards(Long projectId) { public AjaxResult getExternalRiskModelCards(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiProjectRiskModelCardsVO cards = overviewService.getExternalRiskModelCards(projectId); CcdiProjectRiskModelCardsVO cards = overviewService.getExternalRiskModelCards(projectId);
return AjaxResult.success(cards); return AjaxResult.success(cards);
} }
@@ -146,6 +158,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询外部人员风险模型命中人员") @Operation(summary = "查询外部人员风险模型命中人员")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExternalRiskModelPeople(CcdiProjectExternalRiskModelPeopleQueryDTO queryDTO) { public AjaxResult getExternalRiskModelPeople(CcdiProjectExternalRiskModelPeopleQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectRiskModelPeopleVO people = overviewService.getExternalRiskModelPeople(queryDTO); CcdiProjectRiskModelPeopleVO people = overviewService.getExternalRiskModelPeople(queryDTO);
return AjaxResult.success(people); return AjaxResult.success(people);
} }
@@ -157,6 +170,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询项目分析详情") @Operation(summary = "查询项目分析详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO) { public AjaxResult getPersonAnalysisDetail(CcdiProjectPersonAnalysisDetailQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectPersonAnalysisDetailVO detail = overviewService.getPersonAnalysisDetail(queryDTO); CcdiProjectPersonAnalysisDetailVO detail = overviewService.getPersonAnalysisDetail(queryDTO);
return AjaxResult.success(detail); return AjaxResult.success(detail);
} }
@@ -168,6 +182,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询涉疑交易明细") @Operation(summary = "查询涉疑交易明细")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getSuspiciousTransactions(CcdiProjectSuspiciousTransactionQueryDTO queryDTO) { public AjaxResult getSuspiciousTransactions(CcdiProjectSuspiciousTransactionQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectSuspiciousTransactionPageVO pageVO = overviewService.getSuspiciousTransactions(queryDTO); CcdiProjectSuspiciousTransactionPageVO pageVO = overviewService.getSuspiciousTransactions(queryDTO);
return AjaxResult.success(pageVO); return AjaxResult.success(pageVO);
} }
@@ -179,6 +194,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询项目员工负面征信") @Operation(summary = "查询项目员工负面征信")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getEmployeeCreditNegative(CcdiProjectEmployeeCreditNegativeQueryDTO queryDTO) { public AjaxResult getEmployeeCreditNegative(CcdiProjectEmployeeCreditNegativeQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectEmployeeCreditNegativePageVO pageVO = overviewService.getEmployeeCreditNegative(queryDTO); CcdiProjectEmployeeCreditNegativePageVO pageVO = overviewService.getEmployeeCreditNegative(queryDTO);
return AjaxResult.success(pageVO); return AjaxResult.success(pageVO);
} }
@@ -190,6 +206,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "查询异常账户人员信息") @Operation(summary = "查询异常账户人员信息")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getAbnormalAccountPeople(CcdiProjectAbnormalAccountQueryDTO queryDTO) { public AjaxResult getAbnormalAccountPeople(CcdiProjectAbnormalAccountQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectAbnormalAccountPageVO pageVO = overviewService.getAbnormalAccountPeople(queryDTO); CcdiProjectAbnormalAccountPageVO pageVO = overviewService.getAbnormalAccountPeople(queryDTO);
return AjaxResult.success(pageVO); return AjaxResult.success(pageVO);
} }
@@ -204,6 +221,7 @@ public class CcdiProjectOverviewController extends BaseController {
HttpServletResponse response, HttpServletResponse response,
CcdiProjectSuspiciousTransactionQueryDTO queryDTO CcdiProjectSuspiciousTransactionQueryDTO queryDTO
) { ) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiProjectSuspiciousTransactionExcel> rows = overviewService.exportSuspiciousTransactions(queryDTO); List<CcdiProjectSuspiciousTransactionExcel> rows = overviewService.exportSuspiciousTransactions(queryDTO);
ExcelUtil<CcdiProjectSuspiciousTransactionExcel> util = ExcelUtil<CcdiProjectSuspiciousTransactionExcel> util =
new ExcelUtil<>(CcdiProjectSuspiciousTransactionExcel.class); new ExcelUtil<>(CcdiProjectSuspiciousTransactionExcel.class);
@@ -217,6 +235,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "导出风险人员总览") @Operation(summary = "导出风险人员总览")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public void exportRiskPeople(HttpServletResponse response, Long projectId) { public void exportRiskPeople(HttpServletResponse response, Long projectId) {
projectAccessService.assertCanRead(projectId);
List<CcdiProjectRiskPeopleOverviewExcel> rows = overviewService.exportRiskPeopleOverview(projectId); List<CcdiProjectRiskPeopleOverviewExcel> rows = overviewService.exportRiskPeopleOverview(projectId);
ExcelUtil<CcdiProjectRiskPeopleOverviewExcel> util = ExcelUtil<CcdiProjectRiskPeopleOverviewExcel> util =
new ExcelUtil<>(CcdiProjectRiskPeopleOverviewExcel.class); new ExcelUtil<>(CcdiProjectRiskPeopleOverviewExcel.class);
@@ -230,6 +249,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "导出外部人员预警") @Operation(summary = "导出外部人员预警")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public void exportExternalPersons(HttpServletResponse response, Long projectId) { public void exportExternalPersons(HttpServletResponse response, Long projectId) {
projectAccessService.assertCanRead(projectId);
List<CcdiProjectExternalPersonWarningExcel> rows = overviewService.exportExternalPersonWarnings(projectId); List<CcdiProjectExternalPersonWarningExcel> rows = overviewService.exportExternalPersonWarnings(projectId);
ExcelUtil<CcdiProjectExternalPersonWarningExcel> util = ExcelUtil<CcdiProjectExternalPersonWarningExcel> util =
new ExcelUtil<>(CcdiProjectExternalPersonWarningExcel.class); new ExcelUtil<>(CcdiProjectExternalPersonWarningExcel.class);
@@ -243,6 +263,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "导出风险模型命中人员") @Operation(summary = "导出风险模型命中人员")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public void exportRiskModelPeople(HttpServletResponse response, CcdiProjectRiskModelPeopleQueryDTO queryDTO) { public void exportRiskModelPeople(HttpServletResponse response, CcdiProjectRiskModelPeopleQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiProjectRiskModelPeopleExcel> rows = overviewService.exportRiskModelPeople(queryDTO); List<CcdiProjectRiskModelPeopleExcel> rows = overviewService.exportRiskModelPeople(queryDTO);
ExcelUtil<CcdiProjectRiskModelPeopleExcel> util = ExcelUtil<CcdiProjectRiskModelPeopleExcel> util =
new ExcelUtil<>(CcdiProjectRiskModelPeopleExcel.class); new ExcelUtil<>(CcdiProjectRiskModelPeopleExcel.class);
@@ -259,6 +280,7 @@ public class CcdiProjectOverviewController extends BaseController {
HttpServletResponse response, HttpServletResponse response,
CcdiProjectExternalRiskModelPeopleQueryDTO queryDTO CcdiProjectExternalRiskModelPeopleQueryDTO queryDTO
) { ) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiProjectRiskModelPeopleExcel> rows = overviewService.exportExternalRiskModelPeople(queryDTO); List<CcdiProjectRiskModelPeopleExcel> rows = overviewService.exportExternalRiskModelPeople(queryDTO);
ExcelUtil<CcdiProjectRiskModelPeopleExcel> util = ExcelUtil<CcdiProjectRiskModelPeopleExcel> util =
new ExcelUtil<>(CcdiProjectRiskModelPeopleExcel.class); new ExcelUtil<>(CcdiProjectRiskModelPeopleExcel.class);
@@ -272,6 +294,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "导出风险明细") @Operation(summary = "导出风险明细")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public void exportRiskDetails(HttpServletResponse response, Long projectId) { public void exportRiskDetails(HttpServletResponse response, Long projectId) {
projectAccessService.assertCanRead(projectId);
overviewService.exportRiskDetails(response, projectId); overviewService.exportRiskDetails(response, projectId);
} }
@@ -282,6 +305,7 @@ public class CcdiProjectOverviewController extends BaseController {
@Operation(summary = "导出结果总览报告") @Operation(summary = "导出结果总览报告")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public void exportOverviewReport(HttpServletResponse response, Long projectId) { public void exportOverviewReport(HttpServletResponse response, Long projectId) {
projectAccessService.assertCanRead(projectId);
overviewService.exportOverviewReport(response, projectId); overviewService.exportOverviewReport(response, projectId);
} }
} }

View File

@@ -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.CcdiProjectExtendedTransferListVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityDetailVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityDetailVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectFamilyAssetLiabilityListVO; 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.ccdi.project.service.ICcdiProjectSpecialCheckService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
@@ -39,6 +40,9 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Resource @Resource
private ICcdiProjectSpecialCheckService specialCheckService; private ICcdiProjectSpecialCheckService specialCheckService;
@Resource
private CcdiProjectAccessService projectAccessService;
/** /**
* 查询员工家庭资产负债列表 * 查询员工家庭资产负债列表
*/ */
@@ -46,6 +50,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询员工家庭资产负债列表") @Operation(summary = "查询员工家庭资产负债列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getFamilyAssetLiabilityList(@Validated CcdiProjectFamilyAssetLiabilityListQueryDTO queryDTO) { public AjaxResult getFamilyAssetLiabilityList(@Validated CcdiProjectFamilyAssetLiabilityListQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectFamilyAssetLiabilityListVO result = specialCheckService.getFamilyAssetLiabilityList(queryDTO); CcdiProjectFamilyAssetLiabilityListVO result = specialCheckService.getFamilyAssetLiabilityList(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -57,6 +62,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询员工家庭资产负债详情") @Operation(summary = "查询员工家庭资产负债详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getFamilyAssetLiabilityDetail(@Validated CcdiProjectFamilyAssetLiabilityDetailQueryDTO queryDTO) { public AjaxResult getFamilyAssetLiabilityDetail(@Validated CcdiProjectFamilyAssetLiabilityDetailQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectFamilyAssetLiabilityDetailVO result = specialCheckService.getFamilyAssetLiabilityDetail(queryDTO); CcdiProjectFamilyAssetLiabilityDetailVO result = specialCheckService.getFamilyAssetLiabilityDetail(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -68,6 +74,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询采购拓展列表") @Operation(summary = "查询采购拓展列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExtendedPurchaseList(@Validated CcdiProjectExtendedPurchaseQueryDTO queryDTO) { public AjaxResult getExtendedPurchaseList(@Validated CcdiProjectExtendedPurchaseQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExtendedPurchaseListVO result = specialCheckService.getExtendedPurchaseList(queryDTO); CcdiProjectExtendedPurchaseListVO result = specialCheckService.getExtendedPurchaseList(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -79,6 +86,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询采购拓展详情") @Operation(summary = "查询采购拓展详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExtendedPurchaseDetail(@Validated CcdiProjectExtendedPurchaseDetailQueryDTO queryDTO) { public AjaxResult getExtendedPurchaseDetail(@Validated CcdiProjectExtendedPurchaseDetailQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExtendedPurchaseDetailVO result = specialCheckService.getExtendedPurchaseDetail(queryDTO); CcdiProjectExtendedPurchaseDetailVO result = specialCheckService.getExtendedPurchaseDetail(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -90,6 +98,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询招聘拓展列表") @Operation(summary = "查询招聘拓展列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExtendedRecruitmentList(@Validated CcdiProjectExtendedRecruitmentQueryDTO queryDTO) { public AjaxResult getExtendedRecruitmentList(@Validated CcdiProjectExtendedRecruitmentQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExtendedRecruitmentListVO result = specialCheckService.getExtendedRecruitmentList(queryDTO); CcdiProjectExtendedRecruitmentListVO result = specialCheckService.getExtendedRecruitmentList(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -101,6 +110,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询招聘拓展详情") @Operation(summary = "查询招聘拓展详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExtendedRecruitmentDetail(@Validated CcdiProjectExtendedRecruitmentDetailQueryDTO queryDTO) { public AjaxResult getExtendedRecruitmentDetail(@Validated CcdiProjectExtendedRecruitmentDetailQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExtendedRecruitmentDetailVO result = specialCheckService.getExtendedRecruitmentDetail(queryDTO); CcdiProjectExtendedRecruitmentDetailVO result = specialCheckService.getExtendedRecruitmentDetail(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -112,6 +122,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询调动拓展列表") @Operation(summary = "查询调动拓展列表")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExtendedTransferList(@Validated CcdiProjectExtendedTransferQueryDTO queryDTO) { public AjaxResult getExtendedTransferList(@Validated CcdiProjectExtendedTransferQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExtendedTransferListVO result = specialCheckService.getExtendedTransferList(queryDTO); CcdiProjectExtendedTransferListVO result = specialCheckService.getExtendedTransferList(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }
@@ -123,6 +134,7 @@ public class CcdiProjectSpecialCheckController extends BaseController {
@Operation(summary = "查询调动拓展详情") @Operation(summary = "查询调动拓展详情")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getExtendedTransferDetail(@Validated CcdiProjectExtendedTransferDetailQueryDTO queryDTO) { public AjaxResult getExtendedTransferDetail(@Validated CcdiProjectExtendedTransferDetailQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiProjectExtendedTransferDetailVO result = specialCheckService.getExtendedTransferDetail(queryDTO); CcdiProjectExtendedTransferDetailVO result = specialCheckService.getExtendedTransferDetail(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }

View File

@@ -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.CcdiRelationGraphNodeVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseVO; import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphVO; 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.ccdi.project.service.ICcdiRelationGraphService;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
@@ -29,10 +30,14 @@ public class CcdiRelationGraphController extends BaseController {
@Resource @Resource
private ICcdiRelationGraphService relationGraphService; private ICcdiRelationGraphService relationGraphService;
@Resource
private CcdiProjectAccessService projectAccessService;
@GetMapping("/search") @GetMapping("/search")
@Operation(summary = "查询关系图谱主体") @Operation(summary = "查询关系图谱主体")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult searchSubjects(CcdiRelationGraphQueryDTO queryDTO) { public AjaxResult searchSubjects(CcdiRelationGraphQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
List<CcdiRelationGraphNodeVO> subjects = relationGraphService.searchSubjects(queryDTO); List<CcdiRelationGraphNodeVO> subjects = relationGraphService.searchSubjects(queryDTO);
return AjaxResult.success(subjects); return AjaxResult.success(subjects);
} }
@@ -41,6 +46,7 @@ public class CcdiRelationGraphController extends BaseController {
@Operation(summary = "查询一层关系图谱") @Operation(summary = "查询一层关系图谱")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getGraph(CcdiRelationGraphQueryDTO queryDTO) { public AjaxResult getGraph(CcdiRelationGraphQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiRelationGraphVO graph = relationGraphService.getRelationGraph(queryDTO); CcdiRelationGraphVO graph = relationGraphService.getRelationGraph(queryDTO);
return AjaxResult.success(graph); return AjaxResult.success(graph);
} }
@@ -49,6 +55,7 @@ public class CcdiRelationGraphController extends BaseController {
@Operation(summary = "查询关系图谱疑似同名企业") @Operation(summary = "查询关系图谱疑似同名企业")
@PreAuthorize("@ss.hasPermi('ccdi:project:query')") @PreAuthorize("@ss.hasPermi('ccdi:project:query')")
public AjaxResult getSuspectedEnterprises(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO) { public AjaxResult getSuspectedEnterprises(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO) {
projectAccessService.assertCanRead(queryDTO.getProjectId());
CcdiRelationGraphSuspectedEnterpriseVO result = relationGraphService.getSuspectedEnterprises(queryDTO); CcdiRelationGraphSuspectedEnterpriseVO result = relationGraphService.getSuspectedEnterprises(queryDTO);
return AjaxResult.success(result); return AjaxResult.success(result);
} }

View File

@@ -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;
}

View File

@@ -10,6 +10,9 @@ import java.math.BigDecimal;
@Data @Data
public class CcdiFundGraphManualEdgeSaveDTO { public class CcdiFundGraphManualEdgeSaveDTO {
/** 当前项目ID仅用于写权限校验不参与手工资金流归属过滤 */
private Long projectId;
/** 起点主体object_key为空时默认使用当前查询中心 */ /** 起点主体object_key为空时默认使用当前查询中心 */
private String fromObjectKey; private String fromObjectKey;

View File

@@ -8,6 +8,9 @@ import lombok.Data;
@Data @Data
public class CcdiRelationGraphSuspectedEnterpriseQueryDTO { public class CcdiRelationGraphSuspectedEnterpriseQueryDTO {
/** 项目ID */
private Long projectId;
/** 姓名 */ /** 姓名 */
private String personName; private String personName;

View File

@@ -61,4 +61,10 @@ public class CcdiProjectVO {
/** 创建者姓名(真实姓名) */ /** 创建者姓名(真实姓名) */
private String createByName; private String createByName;
/** 是否当前用户创建 */
private Boolean ownedByCurrentUser;
/** 当前用户是否可操作 */
private Boolean canOperate;
} }

View File

@@ -3,6 +3,7 @@ package com.ruoyi.ccdi.project.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.domain.CcdiProject; 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.dto.CcdiProjectQueryDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
@@ -25,7 +26,9 @@ public interface CcdiProjectMapper extends BaseMapper<CcdiProject> {
* @param queryDTO 查询条件 * @param queryDTO 查询条件
* @return 分页结果 * @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 查询条件 * @param queryDTO 查询条件
* @return 历史项目列表 * @return 历史项目列表
*/ */
List<CcdiProjectHistoryListItemVO> selectHistoryProjects(@Param("queryDTO") CcdiProjectQueryDTO queryDTO); List<CcdiProjectHistoryListItemVO> selectHistoryProjects(@Param("queryDTO") CcdiProjectQueryDTO queryDTO,
@Param("scope") ProjectAccessScope scope);
/** /**
* 更新项目总人数与风险人数 * 更新项目总人数与风险人数

View File

@@ -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;
}
}

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.constants.CcdiProjectStatusConstants; import com.ruoyi.ccdi.project.constants.CcdiProjectStatusConstants;
import com.ruoyi.ccdi.project.domain.CcdiProject; 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.CcdiProjectImportHistoryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO; 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.domain.vo.CcdiProjectVO;
import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper; import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper; import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
import com.ruoyi.ccdi.project.service.ICcdiProjectService; import com.ruoyi.ccdi.project.service.ICcdiProjectService;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.lsfx.client.LsfxAnalysisClient; import com.ruoyi.lsfx.client.LsfxAnalysisClient;
@@ -54,6 +56,9 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
@Resource @Resource
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
@Resource
private CcdiProjectAccessService projectAccessService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) { public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
@@ -82,7 +87,7 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
// 5. 返回VO // 5. 返回VO
CcdiProjectVO vo = new CcdiProjectVO(); CcdiProjectVO vo = new CcdiProjectVO();
BeanUtils.copyProperties(project, vo); BeanUtils.copyProperties(project, vo);
fillLatestTagFailure(project, vo); fillProjectExtraFields(project, vo);
return vo; return vo;
} }
@@ -96,6 +101,7 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
if (existingProject == null) { if (existingProject == null) {
throw new ServiceException("项目不存在"); throw new ServiceException("项目不存在");
} }
projectAccessService.assertCanOperate(dto.getProjectId());
// 只更新允许修改的字段 // 只更新允许修改的字段
existingProject.setProjectName(dto.getProjectName()); existingProject.setProjectName(dto.getProjectName());
@@ -106,39 +112,46 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
CcdiProjectVO vo = new CcdiProjectVO(); CcdiProjectVO vo = new CcdiProjectVO();
BeanUtils.copyProperties(existingProject, vo); BeanUtils.copyProperties(existingProject, vo);
fillProjectExtraFields(existingProject, vo);
return vo; return vo;
} }
@Override @Override
public boolean deleteProject(Long projectId) { public boolean deleteProject(Long projectId) {
projectAccessService.assertCanOperate(projectId);
return projectMapper.deleteById(projectId) > 0; return projectMapper.deleteById(projectId) > 0;
} }
@Override @Override
public CcdiProjectVO getProjectById(Long projectId) { public CcdiProjectVO getProjectById(Long projectId) {
projectAccessService.assertCanRead(projectId);
CcdiProject project = projectMapper.selectById(projectId); CcdiProject project = projectMapper.selectById(projectId);
if (project == null) { if (project == null) {
return null; return null;
} }
CcdiProjectVO vo = new CcdiProjectVO(); CcdiProjectVO vo = new CcdiProjectVO();
BeanUtils.copyProperties(project, vo); BeanUtils.copyProperties(project, vo);
fillLatestTagFailure(project, vo); fillProjectExtraFields(project, vo);
return vo; return vo;
} }
@Override @Override
public Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, CcdiProjectQueryDTO queryDTO) { 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 @Override
public List<CcdiProjectHistoryListItemVO> listHistoryProjects(CcdiProjectQueryDTO queryDTO) { public List<CcdiProjectHistoryListItemVO> listHistoryProjects(CcdiProjectQueryDTO queryDTO) {
return projectMapper.selectHistoryProjects(queryDTO); return projectMapper.selectHistoryProjects(queryDTO, projectAccessService.buildCurrentScope());
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public CcdiProjectVO importFromHistory(CcdiProjectImportHistoryDTO dto, String operator) { public CcdiProjectVO importFromHistory(CcdiProjectImportHistoryDTO dto, String operator) {
projectAccessService.assertSourceProjectsReadable(dto.getSourceProjectIds());
CcdiProjectSaveDTO saveDTO = new CcdiProjectSaveDTO(); CcdiProjectSaveDTO saveDTO = new CcdiProjectSaveDTO();
saveDTO.setProjectName(dto.getProjectName()); saveDTO.setProjectName(dto.getProjectName());
saveDTO.setDescription(dto.getDescription()); saveDTO.setDescription(dto.getDescription());
@@ -158,42 +171,34 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
@Override @Override
public CcdiProjectStatusCountsVO getStatusCounts() { public CcdiProjectStatusCountsVO getStatusCounts() {
CcdiProjectStatusCountsVO vo = new CcdiProjectStatusCountsVO(); 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); vo.setAll(totalCount);
// 统计进行中项目状态0 // 统计进行中项目状态0
Long status0Count = projectMapper.selectCount( Long status0Count = projectMapper.selectCount(buildScopeWrapper(scope)
new LambdaQueryWrapper<CcdiProject>() .eq(CcdiProject::getStatus, CcdiProjectStatusConstants.PROCESSING));
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.PROCESSING)
);
vo.setStatus0(status0Count); vo.setStatus0(status0Count);
// 统计已完成项目状态1 // 统计已完成项目状态1
Long status1Count = projectMapper.selectCount( Long status1Count = projectMapper.selectCount(buildScopeWrapper(scope)
new LambdaQueryWrapper<CcdiProject>() .eq(CcdiProject::getStatus, CcdiProjectStatusConstants.COMPLETED));
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.COMPLETED)
);
vo.setStatus1(status1Count); vo.setStatus1(status1Count);
// 统计已归档项目状态2 // 统计已归档项目状态2
Long status2Count = projectMapper.selectCount( Long status2Count = projectMapper.selectCount(buildScopeWrapper(scope)
new LambdaQueryWrapper<CcdiProject>() .eq(CcdiProject::getStatus, CcdiProjectStatusConstants.ARCHIVED));
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.ARCHIVED)
);
vo.setStatus2(status2Count); vo.setStatus2(status2Count);
Long status3Count = projectMapper.selectCount( Long status3Count = projectMapper.selectCount(buildScopeWrapper(scope)
new LambdaQueryWrapper<CcdiProject>() .eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAGGING));
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAGGING)
);
vo.setStatus3(status3Count); vo.setStatus3(status3Count);
Long status4Count = projectMapper.selectCount( Long status4Count = projectMapper.selectCount(buildScopeWrapper(scope)
new LambdaQueryWrapper<CcdiProject>() .eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAG_FAILED));
.eq(CcdiProject::getStatus, CcdiProjectStatusConstants.TAG_FAILED)
);
vo.setStatus4(status4Count); vo.setStatus4(status4Count);
return vo; return vo;
@@ -202,6 +207,7 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
@Override @Override
public void archiveProject(Long projectId, String operator) { public void archiveProject(Long projectId, String operator) {
CcdiProject project = getRequiredProject(projectId); CcdiProject project = getRequiredProject(projectId);
projectAccessService.assertCanOperate(projectId);
if (CcdiProjectStatusConstants.ARCHIVED.equals(project.getStatus())) { if (CcdiProjectStatusConstants.ARCHIVED.equals(project.getStatus())) {
throw new ServiceException("项目已归档,无需重复操作"); throw new ServiceException("项目已归档,无需重复操作");
} }
@@ -293,6 +299,38 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
vo.setLatestTagTaskEndTime(latestFailedTask.getEndTime()); 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) { private String resolveOperator(String operator) {
return StringUtils.hasText(operator) ? operator : "system"; return StringUtils.hasText(operator) ? operator : "system";
} }

View File

@@ -40,6 +40,9 @@
FROM ccdi_project p FROM ccdi_project p
LEFT JOIN sys_user u ON p.create_by = u.user_name AND u.del_flag = '0' LEFT JOIN sys_user u ON p.create_by = u.user_name AND u.del_flag = '0'
<where> <where>
<if test="scope != null and !scope.viewAllProjects">
AND p.create_by = #{scope.username}
</if>
<if test="queryDTO.projectName != null and queryDTO.projectName != ''"> <if test="queryDTO.projectName != null and queryDTO.projectName != ''">
AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%') AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%')
</if> </if>
@@ -61,6 +64,9 @@
FROM ccdi_project p FROM ccdi_project p
<where> <where>
p.status in ('1', '2') 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 != ''"> <if test="queryDTO.projectName != null and queryDTO.projectName != ''">
AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%') AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%')
</if> </if>

View File

@@ -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.domain.vo.CcdiProjectVO;
import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper; import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper; import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.service.CcdiProjectAccessService;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.lsfx.client.LsfxAnalysisClient; import com.ruoyi.lsfx.client.LsfxAnalysisClient;
import com.ruoyi.lsfx.domain.response.GetTokenResponse; import com.ruoyi.lsfx.domain.response.GetTokenResponse;
@@ -52,6 +53,9 @@ class CcdiProjectServiceImplTest {
@Mock @Mock
private CcdiProjectMapper projectMapper; private CcdiProjectMapper projectMapper;
@Mock
private CcdiProjectAccessService projectAccessService;
@Mock @Mock
private CcdiBankTagTaskMapper bankTagTaskMapper; private CcdiBankTagTaskMapper bankTagTaskMapper;
@@ -204,13 +208,13 @@ class CcdiProjectServiceImplTest {
archived.setProjectId(2L); archived.setProjectId(2L);
archived.setStatus("2"); 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); List<CcdiProjectHistoryListItemVO> result = service.listHistoryProjects(queryDTO);
assertEquals(2, result.size()); assertEquals(2, result.size());
assertEquals(List.of(completed, archived), result); assertEquals(List.of(completed, archived), result);
verify(projectMapper).selectHistoryProjects(queryDTO); verify(projectMapper).selectHistoryProjects(any(), any());
} }
@Test @Test

View File

@@ -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 条件编译通过。

View File

@@ -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`,并通过真实浏览器检查列表按钮、详情只读页签、上传/参数/证据/图谱写入入口和查询接口行为。

View File

@@ -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、普通角色的列表范围、详情只读态、按钮显隐和接口拒绝行为。

View File

@@ -101,10 +101,10 @@
v-if="['0', '3', '4'].includes(scope.row.status)" v-if="['0', '3', '4'].includes(scope.row.status)"
size="mini" size="mini"
type="text" type="text"
icon="el-icon-right" :icon="canOperate(scope.row) ? 'el-icon-right' : 'el-icon-view'"
@click="handleEnter(scope.row)" @click="handleEnter(scope.row)"
> >
进入项目 {{ canOperate(scope.row) ? "进入项目" : "查看项目" }}
</el-button> </el-button>
<template v-if="scope.row.status === '1'"> <template v-if="scope.row.status === '1'">
@@ -117,6 +117,7 @@
查看结果 查看结果
</el-button> </el-button>
<el-button <el-button
v-if="canOperate(scope.row)"
size="mini" size="mini"
type="text" type="text"
icon="el-icon-refresh" icon="el-icon-refresh"
@@ -127,6 +128,7 @@
重新分析 重新分析
</el-button> </el-button>
<el-button <el-button
v-if="canOperate(scope.row)"
size="mini" size="mini"
type="text" type="text"
icon="el-icon-folder" icon="el-icon-folder"
@@ -228,6 +230,9 @@ export default {
handleArchive(row) { handleArchive(row) {
this.$emit("archive", row); this.$emit("archive", row);
}, },
canOperate(row) {
return !row || row.canOperate !== false;
},
handleSizeChange(val) { handleSizeChange(val) {
this.$emit("pagination", { this.$emit("pagination", {
pageNum: this.pageParams.pageNum, pageNum: this.pageParams.pageNum,

View File

@@ -30,13 +30,14 @@
maxlength="500" maxlength="500"
show-word-limit show-word-limit
placeholder="请填写为什么将该详情确认为证据" placeholder="请填写为什么将该详情确认为证据"
:disabled="!canOperate"
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer"> <div slot="footer">
<el-button @click="handleClose">取消</el-button> <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> </el-button>
</div> </div>
@@ -63,6 +64,10 @@ export default {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
canOperate: {
type: Boolean,
default: true,
},
}, },
data() { data() {
return { return {
@@ -100,6 +105,10 @@ export default {
this.$emit("update:visible", false); this.$emit("update:visible", false);
}, },
async handleSubmit() { async handleSubmit() {
if (!this.canOperate) {
this.$message.warning("当前项目仅可查看,不能确认入库证据");
return;
}
if (!this.confirmReason) { if (!this.confirmReason) {
this.$message.warning("请填写确认理由/备注"); this.$message.warning("请填写确认理由/备注");
return; return;

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="param-config-container" v-loading="loading" element-loading-text="加载中..."> <div class="param-config-container" v-loading="loading" element-loading-text="加载中...">
<div v-if="isProjectTagging || isProjectArchived" class="readonly-tip"> <div v-if="isWriteLocked" class="readonly-tip">
{{ isProjectArchived ? "已归档项目暂不可修改参数" : "项目正在进行银行流水打标参数暂不可修改" }} {{ writeLockedMessage }}
</div> </div>
<!-- 模型参数卡片组垂直堆叠 --> <!-- 模型参数卡片组垂直堆叠 -->
@@ -24,7 +24,7 @@
<template #default="{ row }"> <template #default="{ row }">
<el-input <el-input
v-model="row.paramValue" v-model="row.paramValue"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
placeholder="请输入阈值" placeholder="请输入阈值"
@input="markAsModified(model.modelCode, row)" @input="markAsModified(model.modelCode, row)"
/> />
@@ -42,7 +42,7 @@
<!-- 统一保存按钮 --> <!-- 统一保存按钮 -->
<div class="button-section" v-if="!loading && modelGroups.length > 0"> <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> </el-button>
<span v-if="modifiedCount > 0" class="modified-tip"> <span v-if="modifiedCount > 0" class="modified-tip">
@@ -65,6 +65,10 @@ export default {
projectInfo: { projectInfo: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
canOperate: {
type: Boolean,
default: true
} }
}, },
data() { data() {
@@ -85,6 +89,15 @@ export default {
}, },
isProjectArchived() { isProjectArchived() {
return String(this.projectInfo.projectStatus) === "2"; return String(this.projectInfo.projectStatus) === "2";
},
isWriteLocked() {
return !this.canOperate || this.isProjectTagging || this.isProjectArchived;
},
writeLockedMessage() {
if (!this.canOperate) {
return "当前项目仅可查看,暂不可修改参数。";
}
return this.isProjectArchived ? "已归档项目暂不可修改参数。" : "项目正在进行银行流水打标,参数暂不可修改。";
} }
}, },
watch: { watch: {
@@ -162,6 +175,10 @@ export default {
}, },
async handleSaveAll() { async handleSaveAll() {
if (!this.canOperate) {
this.$message.warning("当前项目仅可查看,暂不可修改参数");
return;
}
if (this.isProjectArchived) { if (this.isProjectArchived) {
this.$message.warning("已归档项目暂不可修改参数"); this.$message.warning("已归档项目暂不可修改参数");
return; return;

View File

@@ -58,6 +58,7 @@
:source="projectAnalysisSource" :source="projectAnalysisSource"
:model-summary="projectAnalysisModelSummary" :model-summary="projectAnalysisModelSummary"
:project-name="projectInfo.projectName" :project-name="projectInfo.projectName"
:can-operate="canOperate"
@close="handleProjectAnalysisDialogClose" @close="handleProjectAnalysisDialogClose"
@evidence-confirm="$emit('evidence-confirm', $event)" @evidence-confirm="$emit('evidence-confirm', $event)"
/> />
@@ -115,6 +116,10 @@ export default {
projectStatus: "0", projectStatus: "0",
}), }),
}, },
canOperate: {
type: Boolean,
default: true,
},
}, },
data() { data() {
return { return {

View File

@@ -112,6 +112,7 @@
:project-id="projectId" :project-id="projectId"
:person="person" :person="person"
:model-summary="modelSummary" :model-summary="modelSummary"
:can-operate="canOperate"
initial-graph-tab="relation" initial-graph-tab="relation"
:graph-tabs="['relation']" :graph-tabs="['relation']"
/> />
@@ -123,6 +124,7 @@
:project-id="projectId" :project-id="projectId"
:person="person" :person="person"
:model-summary="modelSummary" :model-summary="modelSummary"
:can-operate="canOperate"
/> />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@@ -181,6 +183,10 @@ export default {
type: String, type: String,
default: "", default: "",
}, },
canOperate: {
type: Boolean,
default: true,
},
}, },
data() { data() {
return { return {

View File

@@ -14,6 +14,8 @@
:show-edge-metrics="!isFundOnly" :show-edge-metrics="!isFundOnly"
:stacked-fund-detail-pane="isFundOnly" :stacked-fund-detail-pane="isFundOnly"
hide-empty-detail-pane hide-empty-detail-pane
:project-id="projectId"
:can-operate="canOperate"
/> />
</div> </div>
</template> </template>
@@ -48,6 +50,10 @@ export default {
type: Array, type: Array,
default: () => ["fund", "relation"], default: () => ["fund", "relation"],
}, },
canOperate: {
type: Boolean,
default: true,
},
}, },
computed: { computed: {
isFundOnly() { isFundOnly() {

View File

@@ -2,8 +2,8 @@
<div class="upload-data-container"> <div class="upload-data-container">
<!-- 主内容区 --> <!-- 主内容区 -->
<div class="main-content"> <div class="main-content">
<div v-if="isProjectTagging || isProjectArchived" class="tagging-lock-tip"> <div v-if="isWriteLocked" class="tagging-lock-tip">
{{ isProjectArchived ? "项目已归档暂不可上传或拉取数据" : "项目正在进行银行流水打标暂不可上传或拉取数据" }} {{ writeLockedMessage }}
</div> </div>
<!-- 文件上传记录列表 --> <!-- 文件上传记录列表 -->
@@ -14,7 +14,7 @@
<el-button <el-button
size="small" size="small"
icon="el-icon-upload2" icon="el-icon-upload2"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
@click="handleOpenBatchUploadDialog" @click="handleOpenBatchUploadDialog"
> >
上传流水 上传流水
@@ -22,7 +22,7 @@
<el-button <el-button
size="small" size="small"
icon="el-icon-download" icon="el-icon-download"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
@click="handleFetchBankInfo" @click="handleFetchBankInfo"
> >
拉取本行信息 拉取本行信息
@@ -30,7 +30,7 @@
<el-button <el-button
size="small" size="small"
icon="el-icon-upload2" icon="el-icon-upload2"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
@click="handleGoCreditInfoPage" @click="handleGoCreditInfoPage"
> >
征信导入 征信导入
@@ -125,7 +125,7 @@
v-model="pullBankInfoForm.idCardText" v-model="pullBankInfoForm.idCardText"
type="textarea" type="textarea"
:rows="5" :rows="5"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
placeholder="仅支持英文逗号分隔" placeholder="仅支持英文逗号分隔"
/> />
<div class="pull-bank-field-tip"> <div class="pull-bank-field-tip">
@@ -143,7 +143,7 @@
:show-file-list="false" :show-file-list="false"
:file-list="idCardFileList" :file-list="idCardFileList"
accept=".xls,.xlsx" accept=".xls,.xlsx"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
:on-change="handleIdCardFileChange" :on-change="handleIdCardFileChange"
:on-remove="handleIdCardFileRemove" :on-remove="handleIdCardFileRemove"
> >
@@ -175,7 +175,7 @@
<el-date-picker <el-date-picker
class="pull-bank-range-picker" class="pull-bank-range-picker"
v-model="pullBankInfoForm.dateRange" v-model="pullBankInfoForm.dateRange"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
type="daterange" type="daterange"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
:picker-options="pullBankInfoDatePickerOptions" :picker-options="pullBankInfoDatePickerOptions"
@@ -189,7 +189,7 @@
<el-button @click="pullBankInfoDialogVisible = false">取消</el-button> <el-button @click="pullBankInfoDialogVisible = false">取消</el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
:loading="pullBankInfoLoading" :loading="pullBankInfoLoading"
@click="handleConfirmPullBankInfo" @click="handleConfirmPullBankInfo"
> >
@@ -210,7 +210,7 @@
drag drag
action="#" action="#"
multiple multiple
:disabled="isProjectTagging || isProjectArchived" :disabled="isWriteLocked"
:auto-upload="false" :auto-upload="false"
:on-change="handleBatchFileChange" :on-change="handleBatchFileChange"
:show-file-list="false" :show-file-list="false"
@@ -250,7 +250,7 @@
<el-button @click="batchUploadDialogVisible = false">取消</el-button> <el-button @click="batchUploadDialogVisible = false">取消</el-button>
<el-button <el-button
type="primary" type="primary"
:disabled="isProjectTagging || isProjectArchived || selectedFiles.length === 0" :disabled="isWriteLocked || selectedFiles.length === 0"
:loading="uploadLoading" :loading="uploadLoading"
@click="handleBatchUpload" @click="handleBatchUpload"
>开始上传</el-button >开始上传</el-button
@@ -291,6 +291,10 @@ export default {
projectStatus: "0", projectStatus: "0",
}), }),
}, },
canOperate: {
type: Boolean,
default: true,
},
}, },
data() { data() {
return { return {
@@ -358,6 +362,17 @@ export default {
isProjectArchived() { isProjectArchived() {
return String(this.projectInfo.projectStatus) === "2"; return String(this.projectInfo.projectStatus) === "2";
}, },
isWriteLocked() {
return !this.canOperate || this.isProjectTagging || this.isProjectArchived;
},
writeLockedMessage() {
if (!this.canOperate) {
return "当前项目仅可查看,暂不可上传或拉取数据。";
}
return this.isProjectArchived
? "项目已归档,暂不可上传或拉取数据。"
: "项目正在进行银行流水打标,暂不可上传或拉取数据。";
},
isReportDisabled() { isReportDisabled() {
return ["0", "3", "4"].includes(String(this.projectInfo.projectStatus)); return ["0", "3", "4"].includes(String(this.projectInfo.projectStatus));
}, },
@@ -406,13 +421,15 @@ export default {
this.$emit("menu-change", { key: "overview", route: "overview" }); this.$emit("menu-change", { key: "overview", route: "overview" });
}, },
handleGoCreditInfoPage() { handleGoCreditInfoPage() {
if (this.isProjectTagging || this.isProjectArchived) { if (this.isWriteLocked) {
this.showWriteLockedMessage();
return; return;
} }
this.$router.push("/maintain/creditInfo"); this.$router.push("/maintain/creditInfo");
}, },
handleOpenBatchUploadDialog() { handleOpenBatchUploadDialog() {
if (this.isProjectTagging || this.isProjectArchived) { if (this.isWriteLocked) {
this.showWriteLockedMessage();
return; return;
} }
this.batchUploadDialogVisible = true; this.batchUploadDialogVisible = true;
@@ -450,7 +467,8 @@ export default {
return Array.from(new Set(merged)).join(", "); return Array.from(new Set(merged)).join(", ");
}, },
async handleIdCardFileChange(file, fileList) { async handleIdCardFileChange(file, fileList) {
if (this.isProjectTagging || this.isProjectArchived) { if (this.isWriteLocked) {
this.showWriteLockedMessage();
return; return;
} }
const latestFile = (fileList || []).slice(-1); const latestFile = (fileList || []).slice(-1);
@@ -570,12 +588,8 @@ export default {
return this.parseIdCardText(this.pullBankInfoForm.idCardText); return this.parseIdCardText(this.pullBankInfoForm.idCardText);
}, },
async handleConfirmPullBankInfo() { async handleConfirmPullBankInfo() {
if (this.isProjectTagging || this.isProjectArchived) { if (this.isWriteLocked) {
this.$message.warning( this.showWriteLockedMessage();
this.isProjectArchived
? "项目已归档,暂不可上传或拉取数据"
: "项目正在进行银行流水打标,暂不可上传或拉取数据"
);
return; return;
} }
const idCards = this.buildFinalIdCardList(); const idCards = this.buildFinalIdCardList();
@@ -634,12 +648,8 @@ export default {
}, },
/** 拉取本行信息 */ /** 拉取本行信息 */
handleFetchBankInfo() { handleFetchBankInfo() {
if (this.isProjectTagging || this.isProjectArchived) { if (this.isWriteLocked) {
this.$message.warning( this.showWriteLockedMessage();
this.isProjectArchived
? "项目已归档,暂不可上传或拉取数据"
: "项目正在进行银行流水打标,暂不可上传或拉取数据"
);
return; return;
} }
this.resetPullBankInfoForm(); this.resetPullBankInfoForm();
@@ -685,6 +695,10 @@ export default {
/** 批量上传的文件选择变化 */ /** 批量上传的文件选择变化 */
handleBatchFileChange(file, fileList) { handleBatchFileChange(file, fileList) {
if (this.isWriteLocked) {
this.showWriteLockedMessage();
return;
}
if (fileList.length > 100) { if (fileList.length > 100) {
this.$message.warning("最多上传100个文件"); this.$message.warning("最多上传100个文件");
fileList = fileList.slice(0, 100); fileList = fileList.slice(0, 100);
@@ -712,17 +726,17 @@ export default {
/** 删除已选文件 */ /** 删除已选文件 */
handleRemoveFile(index) { handleRemoveFile(index) {
if (this.isWriteLocked) {
this.showWriteLockedMessage();
return;
}
this.selectedFiles.splice(index, 1); this.selectedFiles.splice(index, 1);
}, },
/** 开始批量上传 */ /** 开始批量上传 */
async handleBatchUpload() { async handleBatchUpload() {
if (this.isProjectTagging || this.isProjectArchived) { if (this.isWriteLocked) {
this.$message.warning( this.showWriteLockedMessage();
this.isProjectArchived
? "项目已归档,暂不可上传或拉取数据"
: "项目正在进行银行流水打标,暂不可上传或拉取数据"
);
return; return;
} }
if (this.selectedFiles.length === 0) { if (this.selectedFiles.length === 0) {
@@ -868,7 +882,11 @@ export default {
}, },
getRowAction(row) { getRowAction(row) {
return getUploadFileAction(row); const action = getUploadFileAction(row);
if (!this.canOperate && action && action.key === "delete") {
return null;
}
return action;
}, },
handleRowAction(row) { handleRowAction(row) {
@@ -895,6 +913,10 @@ export default {
}, },
async handleDeleteFile(row) { async handleDeleteFile(row) {
if (this.isWriteLocked) {
this.showWriteLockedMessage();
return;
}
try { try {
await this.$confirm( await this.$confirm(
"删除该文件后将同步删除流水分析平台中的文件,并清除本系统中该文件对应的所有银行流水数据,项目内流水也将重新打标,是否继续?", "删除该文件后将同步删除流水分析平台中的文件,并清除本系统中该文件对应的所有银行流水数据,项目内流水也将重新打标,是否继续?",
@@ -923,6 +945,9 @@ export default {
this.$message.error("删除失败:" + ((error && error.message) || "未知错误")); this.$message.error("删除失败:" + ((error && error.message) || "未知错误"));
} }
}, },
showWriteLockedMessage() {
this.$message.warning(this.writeLockedMessage);
},
hasActivePollingRecords() { hasActivePollingRecords() {
return ( return (

View File

@@ -80,6 +80,7 @@
plain plain
icon="el-icon-plus" icon="el-icon-plus"
title="新增主体节点及手工资金流向边" title="新增主体节点及手工资金流向边"
:disabled="!canOperate"
@click="handleManualFlowCreate" @click="handleManualFlowCreate"
> >
新增资金流向 新增资金流向
@@ -503,6 +504,14 @@ export default {
type: String, type: String,
default: "", default: "",
}, },
projectId: {
type: [String, Number],
default: null,
},
canOperate: {
type: Boolean,
default: true,
},
autoScroll: { autoScroll: {
type: Boolean, type: Boolean,
default: true, default: true,
@@ -818,6 +827,10 @@ export default {
this.renderChart(); this.renderChart();
}, },
handleManualFlowCreate() { handleManualFlowCreate() {
if (!this.canOperate) {
this.$message.warning("当前项目仅可查看,不能新增手工资金流向");
return;
}
const centerNode = this.graph.centerNode || this.selectedNode; const centerNode = this.graph.centerNode || this.selectedNode;
if (!centerNode || !centerNode.objectKey) { if (!centerNode || !centerNode.objectKey) {
this.$message.warning("请先查询或选择一个起点主体"); this.$message.warning("请先查询或选择一个起点主体");
@@ -843,6 +856,10 @@ export default {
}); });
}, },
submitManualFlow() { submitManualFlow() {
if (!this.canOperate) {
this.$message.warning("当前项目仅可查看,不能新增手工资金流向");
return;
}
if (!this.$refs.manualForm) { if (!this.$refs.manualForm) {
return; return;
} }
@@ -852,7 +869,10 @@ export default {
} }
this.manualDialog.saving = true; this.manualDialog.saving = true;
try { try {
await saveFundGraphManualEdge(this.manualForm); await saveFundGraphManualEdge({
...this.manualForm,
projectId: this.projectId,
});
this.$message.success("手工资金流向已保存"); this.$message.success("手工资金流向已保存");
this.manualDialog.visible = false; this.manualDialog.visible = false;
await this.loadGraph(); await this.loadGraph();
@@ -884,6 +904,7 @@ export default {
try { try {
const response = await getFundGraph({ const response = await getFundGraph({
...this.query, ...this.query,
projectId: this.projectId,
keyword: node.nodeName, keyword: node.nodeName,
objectKey: node.objectKey, objectKey: node.objectKey,
}); });
@@ -923,7 +944,7 @@ export default {
} }
this.graphLoading = true; this.graphLoading = true;
try { try {
const response = await getFundGraph(this.query); const response = await getFundGraph(this.buildFundGraphQuery());
this.graph = (response && response.data) || emptyGraph(); this.graph = (response && response.data) || emptyGraph();
this.expandedObjectKeys = []; this.expandedObjectKeys = [];
this.clearSelection(); this.clearSelection();
@@ -966,7 +987,7 @@ export default {
} }
this.relationGraphLoading = true; this.relationGraphLoading = true;
try { try {
const response = await getRelationGraph(this.relationQuery); const response = await getRelationGraph(this.buildRelationGraphQuery());
this.relationGraph = (response && response.data) || emptyGraph(); this.relationGraph = (response && response.data) || emptyGraph();
this.clearRelationSelection(); this.clearRelationSelection();
} catch (error) { } catch (error) {
@@ -998,6 +1019,7 @@ export default {
this.suspectedEnterpriseDialog.loading = true; this.suspectedEnterpriseDialog.loading = true;
try { try {
const response = await getRelationGraphSuspectedEnterprises({ const response = await getRelationGraphSuspectedEnterprises({
projectId: this.projectId,
personName: node.nodeName, personName: node.nodeName,
certNo: node.idNumber, certNo: node.idNumber,
limit: 10, limit: 10,
@@ -1751,6 +1773,7 @@ export default {
this.detailLoading = true; this.detailLoading = true;
try { try {
const response = await getFundGraphEdgeDetail({ const response = await getFundGraphEdgeDetail({
projectId: this.projectId,
fromKey: selectedEdge.fromKey, fromKey: selectedEdge.fromKey,
toKey: selectedEdge.toKey, toKey: selectedEdge.toKey,
direction: selectedEdge.direction, 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) { mergeGraph(currentGraph, nextGraph) {
const nodeMap = new Map(); const nodeMap = new Map();
const edgeMap = new Map(); const edgeMap = new Map();

View File

@@ -80,6 +80,7 @@
:is="currentComponent" :is="currentComponent"
:project-id="projectId" :project-id="projectId"
:project-info="projectInfo" :project-info="projectInfo"
:can-operate="canOperate"
@menu-change="handleMenuChange" @menu-change="handleMenuChange"
@refresh-project="handleRefreshProject" @refresh-project="handleRefreshProject"
@data-uploaded="handleDataUploaded" @data-uploaded="handleDataUploaded"
@@ -94,6 +95,7 @@
<evidence-confirm-dialog <evidence-confirm-dialog
:visible.sync="evidenceConfirmVisible" :visible.sync="evidenceConfirmVisible"
:payload="evidencePayload" :payload="evidencePayload"
:can-operate="canOperate"
@saved="handleEvidenceSaved" @saved="handleEvidenceSaved"
/> />
<evidence-drawer <evidence-drawer
@@ -162,6 +164,7 @@ export default {
projectStatus: "0", projectStatus: "0",
latestTagTaskErrorMessage: "", latestTagTaskErrorMessage: "",
latestTagTaskEndTime: "", latestTagTaskEndTime: "",
canOperate: true,
}, },
evidenceConfirmVisible: false, evidenceConfirmVisible: false,
evidenceDrawerVisible: false, evidenceDrawerVisible: false,
@@ -177,6 +180,9 @@ export default {
isProjectArchived() { isProjectArchived() {
return String(this.projectInfo.projectStatus) === "2"; return String(this.projectInfo.projectStatus) === "2";
}, },
canOperate() {
return this.projectInfo.canOperate !== false;
},
isProjectTagFailed() { isProjectTagFailed() {
return String(this.projectInfo.projectStatus) === "4"; return String(this.projectInfo.projectStatus) === "4";
}, },
@@ -200,12 +206,10 @@ export default {
this.initActiveTabFromRoute(); this.initActiveTabFromRoute();
}, },
"projectInfo.projectStatus"() { "projectInfo.projectStatus"() {
this.syncProjectStatusPolling(); this.syncAccessibleTab();
const accessibleTab = this.resolveAccessibleTab(this.activeTab); },
if (accessibleTab !== this.activeTab) { canOperate() {
this.setActiveTab(accessibleTab); this.syncAccessibleTab();
this.syncRouteTab(accessibleTab);
}
}, },
}, },
created() { created() {
@@ -219,6 +223,14 @@ export default {
this.stopProjectStatusPolling(); this.stopProjectStatusPolling();
}, },
methods: { methods: {
syncAccessibleTab() {
this.syncProjectStatusPolling();
const accessibleTab = this.resolveAccessibleTab(this.activeTab);
if (accessibleTab !== this.activeTab) {
this.setActiveTab(accessibleTab);
this.syncRouteTab(accessibleTab);
}
},
initActiveTabFromRoute() { initActiveTabFromRoute() {
const tab = (this.$route.query && this.$route.query.tab) || ""; const tab = (this.$route.query && this.$route.query.tab) || "";
const validTabs = ["upload", "config", "overview", "special", "detail"]; const validTabs = ["upload", "config", "overview", "special", "detail"];
@@ -230,7 +242,7 @@ export default {
} }
}, },
isArchiveLockedTab(tab) { isArchiveLockedTab(tab) {
return this.isProjectArchived && ["upload", "config"].includes(tab); return (this.isProjectArchived || !this.canOperate) && ["upload", "config"].includes(tab);
}, },
resolveAccessibleTab(tab) { resolveAccessibleTab(tab) {
if (this.isArchiveLockedTab(tab)) { if (this.isArchiveLockedTab(tab)) {
@@ -295,6 +307,7 @@ export default {
}; };
this.updatePageTitle(); this.updatePageTitle();
this.syncProjectStatusPolling(); this.syncProjectStatusPolling();
this.syncAccessibleTab();
return this.projectInfo; return this.projectInfo;
} catch (error) { } catch (error) {
if (!silent) { if (!silent) {
@@ -436,10 +449,12 @@ export default {
/** 菜单选择事件 */ /** 菜单选择事件 */
handleMenuSelect(index) { handleMenuSelect(index) {
if (this.isArchiveLockedTab(index)) { if (this.isArchiveLockedTab(index)) {
this.$message.warning(this.canOperate ? "已归档项目暂不可进入该页签" : "当前项目仅可查看,不能进入写入页签");
return; return;
} }
console.log("菜单选择:", index); console.log("菜单选择:", index);
this.setActiveTab(index); this.setActiveTab(index);
this.syncRouteTab(index);
}, },
/** UploadData 组件:菜单切换 */ /** UploadData 组件:菜单切换 */
handleMenuChange({ key, route }) { handleMenuChange({ key, route }) {
@@ -489,6 +504,10 @@ export default {
this.initPageData(); this.initPageData();
}, },
handleEvidenceConfirm(payload) { handleEvidenceConfirm(payload) {
if (!this.canOperate) {
this.$message.warning("当前项目仅可查看,不能确认入库证据");
return;
}
this.evidencePayload = { this.evidencePayload = {
projectId: this.projectId, projectId: this.projectId,
...(payload || {}), ...(payload || {}),

View File

@@ -3,7 +3,7 @@
<!-- 页面标题 --> <!-- 页面标题 -->
<div class="page-header"> <div class="page-header">
<h2 class="page-title">初核项目管理</h2> <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> </div>
<!-- 搜索和操作区 --> <!-- 搜索和操作区 -->
@@ -29,6 +29,7 @@
<!-- 快捷入口区 --> <!-- 快捷入口区 -->
<quick-entry <quick-entry
v-hasPermi="['ccdi:project:add']"
@import-history="handleImport" @import-history="handleImport"
@create-quarterly="handleCreateQuarterly" @create-quarterly="handleCreateQuarterly"
@create-employee="handleCreateEmployee" @create-employee="handleCreateEmployee"
@@ -245,7 +246,8 @@ export default {
/** 进入项目 */ /** 进入项目 */
handleEnter(row) { handleEnter(row) {
this.$router.push({ 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); // this.$modal.msgSuccess("进入项目: " + row.projectName);
}, },
@@ -258,6 +260,10 @@ export default {
}, },
/** 重新分析 */ /** 重新分析 */
async handleReAnalyze(row) { async handleReAnalyze(row) {
if (!this.canOperate(row)) {
this.$modal.msgWarning("当前项目仅可查看,不能重新分析")
return
}
const projectKey = String(row.projectId) const projectKey = String(row.projectId)
if (this.reAnalyzeLoadingMap[projectKey]) { if (this.reAnalyzeLoadingMap[projectKey]) {
return return
@@ -286,6 +292,10 @@ export default {
}, },
/** 归档项目 */ /** 归档项目 */
handleArchive(row) { handleArchive(row) {
if (!this.canOperate(row)) {
this.$modal.msgWarning("当前项目仅可查看,不能归档")
return
}
this.currentArchiveProject = row; this.currentArchiveProject = row;
this.archiveDialogVisible = true; this.archiveDialogVisible = true;
}, },
@@ -302,6 +312,9 @@ export default {
this.$modal.msgError(message) this.$modal.msgError(message)
} }
}, },
canOperate(row) {
return !row || row.canOperate !== false
},
}, },
}; };
</script> </script>

View 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';