SNAPSHOT W7 已部署稳定态 — 凯迪ERP+OA一体化平台 (MET 73.3%)
恢复点(restore point)。别人改崩后可 git reset --hard 回到此提交。 == 此快照内容 == - 后端 oa-backend: 734 控制器 / 711 实体 (Spring Boot 3.2.5 + SQLite, 端口8091) - 前端 modern-ui/app: Vue3+Vite, 约700页 (构建产物已在 oa-backend/src/main/resources/static) - 数据库 oa-backend/data/oa.db: 含全部演示数据 (强制入库, 6.6MB) - 交接文档 go.md + go-code-reference/endpoints/entities/database.md - 多代理建设脚本 .claude/wf-*.js == 状态 == - 对 凯迪科技ERP_20260507.xlsx 合规 MET ~73.3% (PARTIAL 75: 34可建+6种子/bug+35外部硬天花板) - 安全: 5轮红队+5轮复检, default-deny分级鉴权, 连续零可利用 - W3~W7 累计补完436缺口; W8末轮(40缺口)为半成品(源码树可编译但未集成) - 运行: cd oa-backend; java -jar build/libs/oa-backend-0.1.0.jar --server.port=8091; admin/123456 == 排除(gitignore, 可再生) == node_modules / oa-backend/build / .jdks / *.log / Backup-ERP-* / 弃用的OFBiz核心(只保留modern-ui) 完整文件夹备份见同目录 Backup-ERP-20260615-191517/ (含上述全部, 仅缺 node_modules) 时间戳: 20260615-191517 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,439 @@
|
||||
package com.kaidi.oa.web;
|
||||
|
||||
import com.kaidi.oa.common.ApiException;
|
||||
import com.kaidi.oa.common.ApiResp;
|
||||
import com.kaidi.oa.common.Money;
|
||||
import com.kaidi.oa.domain.ComplianceAlertRule;
|
||||
import com.kaidi.oa.domain.HrNonCompete;
|
||||
import com.kaidi.oa.domain.IpAsset;
|
||||
import com.kaidi.oa.domain.LegalCreditInvest;
|
||||
import com.kaidi.oa.domain.LitigationCase;
|
||||
import com.kaidi.oa.repository.ComplianceAlertRuleRepository;
|
||||
import com.kaidi.oa.repository.HrNonCompeteRepository;
|
||||
import com.kaidi.oa.repository.IpAssetRepository;
|
||||
import com.kaidi.oa.repository.LegalCreditInvestRepository;
|
||||
import com.kaidi.oa.repository.LitigationCaseRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 法务风险部·与其他部门接口(需求 §9)。
|
||||
*
|
||||
* <p>补完三条跨部门联动缺口(Gap low 9):
|
||||
* <ol>
|
||||
* <li><b>销售合同客户信用风险预警</b>:销售部签约前调用
|
||||
* {@code GET /api/oa/legal-cross-dept/sales-customer-check?customerName=} 自动聚合:
|
||||
* - 法务专项调查结论(LegalCreditInvest)
|
||||
* - 在案诉讼信息(LitigationCase.opponent 模糊匹配)
|
||||
* - 命中的合规预警规则(ComplianceAlertRule + 预警模拟)
|
||||
* 返回综合风险评级(低/中/高/紧急)及处理建议,无需法务手动查阅三张表。</li>
|
||||
*
|
||||
* <li><b>HR 劳动纠纷案件自动建档</b>:HR 部门对离职员工或劳动纠纷发起快速建档,
|
||||
* 调用 {@code POST /api/oa/legal-cross-dept/hr-labor-dispute-register} 一键在
|
||||
* LitigationCase 中创建劳动仲裁案件记录,并同步将当事人竞业限制状态推进到「离职-补偿中」
|
||||
* (若 employeeId 关联的 HrNonCompete 存在且状态为「在职-未触发」)。</li>
|
||||
*
|
||||
* <li><b>知识产权与法务状态同步看板</b>:
|
||||
* {@code GET /api/oa/legal-cross-dept/ip-status-sync} 聚合 IpAsset 台账当前状态
|
||||
* 映射到法务关注维度:即将失效专利、未缴年费、授权维持专利数;
|
||||
* 供法务无需进入知识产权部系统即可掌握全局 IP 保护状态。</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>所有读口包含敏感数据(涉诉/信用/专利),已纳入 SENSITIVE_READ_PREFIXES(见 sharedFileSnippets)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/oa/legal-cross-dept")
|
||||
public class LegalCrossDeptController {
|
||||
|
||||
private final LitigationCaseRepository caseRepo;
|
||||
private final LegalCreditInvestRepository investRepo;
|
||||
private final ComplianceAlertRuleRepository ruleRepo;
|
||||
private final HrNonCompeteRepository nonCompeteRepo;
|
||||
private final IpAssetRepository ipAssetRepo;
|
||||
|
||||
public LegalCrossDeptController(LitigationCaseRepository caseRepo,
|
||||
LegalCreditInvestRepository investRepo,
|
||||
ComplianceAlertRuleRepository ruleRepo,
|
||||
HrNonCompeteRepository nonCompeteRepo,
|
||||
IpAssetRepository ipAssetRepo) {
|
||||
this.caseRepo = caseRepo;
|
||||
this.investRepo = investRepo;
|
||||
this.ruleRepo = ruleRepo;
|
||||
this.nonCompeteRepo = nonCompeteRepo;
|
||||
this.ipAssetRepo = ipAssetRepo;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 1. 销售合同客户信用风险预警(销售部→法务部自动联动,Gap §9-1)
|
||||
// ========================================================================
|
||||
|
||||
public record CustomerRiskItem(String category, String level, String content) {}
|
||||
|
||||
public record CustomerRiskResult(
|
||||
String customerName,
|
||||
String overallRiskLevel,
|
||||
String suggestion,
|
||||
boolean blacklisted,
|
||||
boolean hasActiveLitigation,
|
||||
int litigationCount,
|
||||
BigDecimal litigationTotalAmount,
|
||||
String latestInvestConclusion,
|
||||
List<CustomerRiskItem> riskItems
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 销售签约前客户涉诉/信用风险一键预检。
|
||||
* 聚合三个数据源:法务调查结论 + 在案诉讼 + 合规预警规则,自动给出综合风险等级。
|
||||
* 销售部门新签合同前、法务自动推送触发时均可调用,无需手工查询。
|
||||
*/
|
||||
@GetMapping("/sales-customer-check")
|
||||
public ApiResp<CustomerRiskResult> salesCustomerCheck(
|
||||
@RequestParam String customerName) {
|
||||
if (customerName == null || customerName.isBlank()) {
|
||||
throw new ApiException(400, "customerName 不能为空");
|
||||
}
|
||||
String name = customerName.trim();
|
||||
|
||||
// 法务调查结论(按客户名模糊)
|
||||
List<LegalCreditInvest> invests = investRepo.findByCustomerNameContaining(name);
|
||||
String latestConclusion = null;
|
||||
boolean blacklisted = false;
|
||||
for (LegalCreditInvest inv : invests) {
|
||||
if (inv.isBlacklisted()) {
|
||||
blacklisted = true;
|
||||
}
|
||||
if ("已结案".equals(inv.getStatus()) && inv.getConclusion() != null) {
|
||||
latestConclusion = inv.getConclusion();
|
||||
}
|
||||
}
|
||||
|
||||
// 在案诉讼(按对方当事人名称模糊匹配)
|
||||
List<LitigationCase> cases = caseRepo.findByOpponentContaining(name);
|
||||
boolean hasActive = cases.stream().anyMatch(c -> !"已结案".equals(c.getStatus()));
|
||||
BigDecimal totalAmt = BigDecimal.ZERO;
|
||||
for (LitigationCase c : cases) {
|
||||
totalAmt = Money.add(totalAmt, c.getAmount() == null ? BigDecimal.ZERO : c.getAmount());
|
||||
}
|
||||
|
||||
// 命中合规预警规则(触发场景=销售)
|
||||
List<ComplianceAlertRule> salesRules = ruleRepo.findByEnabled(Boolean.TRUE).stream()
|
||||
.filter(r -> "销售".equals(r.getTriggerScene()) || "通用".equals(r.getTriggerScene()))
|
||||
.toList();
|
||||
|
||||
// 构建风险条目
|
||||
List<CustomerRiskItem> items = new ArrayList<>();
|
||||
String overallLevel = "低";
|
||||
|
||||
if (blacklisted) {
|
||||
items.add(new CustomerRiskItem("失信", "紧急", "客户已列入失信被执行人名单,禁止合作"));
|
||||
overallLevel = "紧急";
|
||||
}
|
||||
if (hasActive) {
|
||||
long activeCnt = cases.stream().filter(c -> !"已结案".equals(c.getStatus())).count();
|
||||
items.add(new CustomerRiskItem("诉讼", "高",
|
||||
"客户存在 " + activeCnt + " 起未结案诉讼,标的金额合计 " + totalAmt.toPlainString() + " 元"));
|
||||
if (!"紧急".equals(overallLevel)) {
|
||||
overallLevel = "高";
|
||||
}
|
||||
} else if (!cases.isEmpty()) {
|
||||
items.add(new CustomerRiskItem("诉讼历史", "中",
|
||||
"客户有 " + cases.size() + " 起历史诉讼记录(均已结案),注意合同条款设计"));
|
||||
if ("低".equals(overallLevel)) {
|
||||
overallLevel = "中";
|
||||
}
|
||||
}
|
||||
if ("驳回".equals(latestConclusion)) {
|
||||
items.add(new CustomerRiskItem("法务调查", "高", "法务专项调查结论为「驳回」,建议暂停合作"));
|
||||
if (!"紧急".equals(overallLevel)) {
|
||||
overallLevel = "高";
|
||||
}
|
||||
} else if ("需进一步调查".equals(latestConclusion)) {
|
||||
items.add(new CustomerRiskItem("法务调查", "中", "法务专项调查尚需进一步核查,建议延缓签约"));
|
||||
if ("低".equals(overallLevel)) {
|
||||
overallLevel = "中";
|
||||
}
|
||||
} else if ("通过".equals(latestConclusion)) {
|
||||
items.add(new CustomerRiskItem("法务调查", "低", "法务专项调查结论通过,信用状况良好"));
|
||||
}
|
||||
|
||||
for (ComplianceAlertRule r : salesRules) {
|
||||
items.add(new CustomerRiskItem("合规规则", r.getAlertLevel(),
|
||||
"触发合规预警规则:" + r.getRuleName() + "(" + r.getCondition() + ")"));
|
||||
if ("紧急".equals(r.getAlertLevel())) {
|
||||
overallLevel = "紧急";
|
||||
} else if ("高".equals(r.getAlertLevel()) && !"紧急".equals(overallLevel)) {
|
||||
overallLevel = "高";
|
||||
}
|
||||
}
|
||||
|
||||
String suggestion;
|
||||
switch (overallLevel) {
|
||||
case "紧急" -> suggestion = "禁止签约。客户存在失信/重大法律风险,须经法务总监和总经理特批后方可进行任何商务往来。";
|
||||
case "高" -> suggestion = "暂缓签约。需法务部门完成专项调查并出具法律意见书,合同须添加特殊担保/保函条款。";
|
||||
case "中" -> suggestion = "谨慎签约。建议在合同中加强违约责任条款,设置分批付款里程碑,并持续跟踪诉讼进展。";
|
||||
default -> suggestion = "可以签约。客户信用状况良好,按标准流程审批即可。";
|
||||
}
|
||||
|
||||
return ApiResp.ok(new CustomerRiskResult(
|
||||
name, overallLevel, suggestion,
|
||||
blacklisted, hasActive, cases.size(), totalAmt,
|
||||
latestConclusion == null ? "无记录" : latestConclusion,
|
||||
items
|
||||
));
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 2. HR 劳动纠纷案件快速建档(HR→法务自动联动,Gap §9-2)
|
||||
// ========================================================================
|
||||
|
||||
public record LaborDisputeRegisterReq(
|
||||
String employeeId,
|
||||
String employeeName,
|
||||
String dept,
|
||||
String disputeType,
|
||||
String description,
|
||||
Double claimAmount,
|
||||
String tribunal,
|
||||
String filingDate,
|
||||
String lawyer
|
||||
) {}
|
||||
|
||||
public record LaborDisputeRegisterResult(
|
||||
Long litigationCaseId,
|
||||
String caseNo,
|
||||
boolean nonCompeteTriggered,
|
||||
String nonCompeteStatus,
|
||||
String message
|
||||
) {}
|
||||
|
||||
/**
|
||||
* HR 劳动纠纷快速建档。
|
||||
* 在 LitigationCase 中创建劳动仲裁案件,并自动检查:
|
||||
* 若 employeeId 关联的 HrNonCompete 存在且状态为「在职-未触发」,
|
||||
* 则自动将其推进到「离职-补偿中」状态(离职触发钩子),补完 Gap §9-2 手动建档问题。
|
||||
*/
|
||||
@PostMapping("/hr-labor-dispute-register")
|
||||
@Transactional
|
||||
public ApiResp<LaborDisputeRegisterResult> hrLaborDisputeRegister(
|
||||
@RequestBody LaborDisputeRegisterReq req) {
|
||||
if (req.employeeName() == null || req.employeeName().isBlank()) {
|
||||
throw new ApiException(400, "employeeName 不能为空");
|
||||
}
|
||||
|
||||
// 创建诉讼案件
|
||||
LitigationCase kase = new LitigationCase();
|
||||
kase.setCaseNo("LAB-" + System.currentTimeMillis() % 100000);
|
||||
String disputeType = req.disputeType() == null || req.disputeType().isBlank()
|
||||
? "劳动合同纠纷" : req.disputeType();
|
||||
kase.setCaseName(req.employeeName() + disputeType + "案");
|
||||
kase.setCause(disputeType);
|
||||
kase.setOpponent(req.employeeName()
|
||||
+ (req.dept() != null && !req.dept().isBlank() ? "(" + req.dept() + ")" : ""));
|
||||
kase.setOurRole("被申请人");
|
||||
kase.setTribunal(req.tribunal() == null || req.tribunal().isBlank()
|
||||
? "广州市天河区劳动人事争议仲裁委员会" : req.tribunal());
|
||||
kase.setAmount(Money.of(req.claimAmount()));
|
||||
kase.setStage("诉前调解");
|
||||
kase.setLawyer(req.lawyer() == null || req.lawyer().isBlank() ? "待指派" : req.lawyer());
|
||||
kase.setFilingDate(req.filingDate() == null || req.filingDate().isBlank()
|
||||
? java.time.LocalDate.now().toString() : req.filingDate());
|
||||
kase.setResult("审理中");
|
||||
kase.setStatus("进行中");
|
||||
kase.setRemark("由 HR 系统劳动纠纷模块自动创建。当事人:" + req.employeeName()
|
||||
+ (req.description() != null ? ";" + req.description() : ""));
|
||||
kase.setCreatedAt(Instant.now());
|
||||
LitigationCase saved = caseRepo.save(kase);
|
||||
|
||||
// 自动触发竞业限制(联动钩子)
|
||||
boolean ncTriggered = false;
|
||||
String ncStatus = "无竞业限制记录";
|
||||
if (req.employeeId() != null && !req.employeeId().isBlank()) {
|
||||
List<HrNonCompete> ncs = nonCompeteRepo.findByEmployeeId(req.employeeId());
|
||||
for (HrNonCompete nc : ncs) {
|
||||
if ("在职-未触发".equals(nc.getStatus())) {
|
||||
nc.setStatus("离职-补偿中");
|
||||
String today = java.time.LocalDate.now().toString();
|
||||
if (nc.getStartDate() == null || nc.getStartDate().isBlank()) {
|
||||
nc.setStartDate(today);
|
||||
if (nc.getRestrictionPeriod() != null && nc.getRestrictionPeriod() > 0) {
|
||||
java.time.LocalDate end = java.time.LocalDate.now()
|
||||
.plusMonths(nc.getRestrictionPeriod());
|
||||
nc.setEndDate(end.toString());
|
||||
}
|
||||
}
|
||||
nonCompeteRepo.save(nc);
|
||||
ncTriggered = true;
|
||||
ncStatus = "已自动推进为「离职-补偿中」";
|
||||
break;
|
||||
}
|
||||
ncStatus = nc.getStatus();
|
||||
}
|
||||
}
|
||||
|
||||
String msg = "劳动仲裁案件已创建(案号 " + saved.getCaseNo() + ")"
|
||||
+ (ncTriggered ? ",竞业限制已自动触发" : "");
|
||||
return ApiResp.ok(new LaborDisputeRegisterResult(
|
||||
saved.getId(), saved.getCaseNo(), ncTriggered, ncStatus, msg));
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 3. 知识产权法务状态同步看板(IP部→法务部,Gap §9-3)
|
||||
// ========================================================================
|
||||
|
||||
public record IpStatusItem(
|
||||
Long id, String proposalNo, String name, String ipType,
|
||||
String stage, String legalStatus, String grantDate,
|
||||
double totalCost, String agency
|
||||
) {}
|
||||
|
||||
public record IpStatusSyncResult(
|
||||
int totalAssets,
|
||||
int authorizedMaintaining,
|
||||
int pendingFee,
|
||||
int expiringSoon,
|
||||
int invalidTerminated,
|
||||
int inApplication,
|
||||
List<IpStatusItem> atRiskAssets,
|
||||
Map<String, Integer> byType,
|
||||
Map<String, Integer> byLegalStatus
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 知识产权法务状态同步看板。
|
||||
* 从 IpAsset 台账聚合法务关注的核心维度,让法务部门无需进入知识产权部系统即可:
|
||||
* - 掌握全量 IP 资产保护状态分布;
|
||||
* - 快速识别已授权维持/即将失效/年费逾期的高风险资产;
|
||||
* - 与法务诉讼台账(专利侵权案)进行对照分析。
|
||||
* 补完 Gap §9-3:跨部门自动同步机制(只读聚合,无双写风险)。
|
||||
*/
|
||||
@GetMapping("/ip-status-sync")
|
||||
public ApiResp<IpStatusSyncResult> ipStatusSync() {
|
||||
List<IpAsset> all = ipAssetRepo.findAll();
|
||||
int total = all.size();
|
||||
int authorized = 0, pendingFee = 0, expiringSoon = 0, invalid = 0, inApp = 0;
|
||||
Map<String, Integer> byType = new LinkedHashMap<>();
|
||||
Map<String, Integer> byLegal = new LinkedHashMap<>();
|
||||
List<IpStatusItem> atRisk = new ArrayList<>();
|
||||
|
||||
String today = java.time.LocalDate.now().toString();
|
||||
String in90 = java.time.LocalDate.now().plusDays(90).toString();
|
||||
|
||||
for (IpAsset a : all) {
|
||||
String ls = a.getLegalStatus() == null ? "未知" : a.getLegalStatus();
|
||||
String stage = a.getStage() == null ? "未知" : a.getStage();
|
||||
String ipType = a.getIpType() == null ? "其他" : a.getIpType();
|
||||
|
||||
byType.merge(ipType, 1, Integer::sum);
|
||||
byLegal.merge(ls, 1, Integer::sum);
|
||||
|
||||
switch (ls) {
|
||||
case "授权维持" -> authorized++;
|
||||
case "申请中", "公开", "实审" -> inApp++;
|
||||
case "失效终止", "无效宣告" -> invalid++;
|
||||
}
|
||||
|
||||
// 到期预警:授权维持且授权日+20年在90天内(发明专利20年保护期近)
|
||||
boolean atRiskFlag = false;
|
||||
if ("授权维持".equals(ls) && a.getGrantDate() != null && !a.getGrantDate().isBlank()) {
|
||||
try {
|
||||
java.time.LocalDate gd = java.time.LocalDate.parse(a.getGrantDate().substring(0, 10));
|
||||
java.time.LocalDate expiry = gd.plusYears(20);
|
||||
String expiryStr = expiry.toString();
|
||||
if (expiryStr.compareTo(today) >= 0 && expiryStr.compareTo(in90) <= 0) {
|
||||
expiringSoon++;
|
||||
atRiskFlag = true;
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
if ("无效宣告".equals(ls) || "失效终止".equals(ls)) {
|
||||
atRiskFlag = true;
|
||||
}
|
||||
if (atRiskFlag) {
|
||||
atRisk.add(new IpStatusItem(
|
||||
a.getId(), a.getProposalNo(), a.getName(), a.getIpType(),
|
||||
stage, ls, a.getGrantDate(),
|
||||
a.getTotalCost() == null ? 0.0 : a.getTotalCost().doubleValue(),
|
||||
a.getAgency()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return ApiResp.ok(new IpStatusSyncResult(
|
||||
total, authorized, pendingFee, expiringSoon, invalid, inApp,
|
||||
atRisk, byType, byLegal
|
||||
));
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 4. 综合跨部门联动统计看板(Dashboard 聚合接口)
|
||||
// ========================================================================
|
||||
|
||||
public record LegalCrossDeptDashboard(
|
||||
// 诉讼看板
|
||||
long litigationTotal,
|
||||
long litigationActive,
|
||||
double litigationTotalAmount,
|
||||
// 竞业限制看板
|
||||
long nonCompeteTotal,
|
||||
long nonCompeteActive,
|
||||
long nonCompeteViolated,
|
||||
// 合规规则看板
|
||||
long alertRuleTotal,
|
||||
long alertRuleEnabled,
|
||||
// 信用调查看板
|
||||
long investTotal,
|
||||
long investDriven,
|
||||
// 知识产权看板
|
||||
long ipTotal,
|
||||
long ipAuthorized
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 跨部门联动统计看板:法务部门首页仪表盘所需的综合数字,
|
||||
* 一次调用返回诉讼/竞业/合规规则/信用调查/知识产权五个维度数字。
|
||||
*/
|
||||
@GetMapping("/dashboard")
|
||||
public ApiResp<LegalCrossDeptDashboard> dashboard() {
|
||||
List<LitigationCase> cases = caseRepo.findAll();
|
||||
long litActive = cases.stream().filter(c -> !"已结案".equals(c.getStatus())).count();
|
||||
BigDecimal litAmt = BigDecimal.ZERO;
|
||||
for (LitigationCase c : cases) {
|
||||
litAmt = Money.add(litAmt, c.getAmount() == null ? BigDecimal.ZERO : c.getAmount());
|
||||
}
|
||||
|
||||
List<HrNonCompete> ncs = nonCompeteRepo.findAll();
|
||||
long ncActive = ncs.stream().filter(nc ->
|
||||
"离职-补偿中".equals(nc.getStatus()) || "在职-未触发".equals(nc.getStatus())).count();
|
||||
long ncViolated = ncs.stream().filter(nc -> "已违约".equals(nc.getStatus())).count();
|
||||
|
||||
List<ComplianceAlertRule> rules = ruleRepo.findAll();
|
||||
long ruleEnabled = rules.stream().filter(r -> Boolean.TRUE.equals(r.getEnabled())).count();
|
||||
|
||||
List<LegalCreditInvest> invests = investRepo.findAll();
|
||||
long investDriven = invests.stream().filter(inv -> "驳回".equals(inv.getConclusion())).count();
|
||||
|
||||
List<IpAsset> ipAssets = ipAssetRepo.findAll();
|
||||
long ipAuthorized = ipAssets.stream()
|
||||
.filter(a -> "授权维持".equals(a.getLegalStatus())).count();
|
||||
|
||||
return ApiResp.ok(new LegalCrossDeptDashboard(
|
||||
cases.size(), litActive, litAmt.doubleValue(),
|
||||
ncs.size(), ncActive, ncViolated,
|
||||
rules.size(), ruleEnabled,
|
||||
invests.size(), investDriven,
|
||||
ipAssets.size(), ipAuthorized
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user