diff --git a/backend/src/services/risk.service.ts b/backend/src/services/risk.service.ts index 2d7d56f..57d1219 100644 --- a/backend/src/services/risk.service.ts +++ b/backend/src/services/risk.service.ts @@ -1553,6 +1553,7 @@ export async function getAnnualValueReport(orgId: string, year: number) { policiesPublished, monthlyRisks, employeeRiskDetails, + pendingRisks, ] = await Promise.all([ prisma.riskItem.count({ where: { @@ -1631,6 +1632,20 @@ export async function getAnnualValueReport(orgId: string, year: number) { }, orderBy: { estimatedLoss: 'desc' }, }), + // 未解决的风险列表(PENDING状态),按预估损失降序,最多100条 + prisma.riskItem.findMany({ + where: { + orgId, status: 'PENDING', + estimatedLoss: { gt: 0 }, + }, + include: { + employee: { + select: { id: true, name: true, department: true, idCardHash: true }, + }, + }, + orderBy: { estimatedLoss: 'desc' }, + take: 100, + }), ]) // 按身份证号去重(同一人可能有多条 Employee 记录),无身份证号时回退到 employeeId @@ -1763,16 +1778,42 @@ export async function getAnnualValueReport(orgId: string, year: number) { policiesPublished, } - const summary = roi >= 1000 - ? `${year} 年系统创造价值约 ${fmtMoney(totalValue)},ROI 达 ${roi}%,规避潜在损失 ${fmtMoney(lossAvoided)},节约 HR 工时 ${timeSaved} 小时` - : roi >= 300 - ? `${year} 年系统创造价值约 ${fmtMoney(totalValue)},ROI ${roi}%,处理风险 ${risksResolved} 项,AI 辅助 ${aiConversations + aiReviews} 次` - : `${year} 年系统已运行,处理风险 ${risksResolved} 项,AI 辅助 ${aiConversations + aiReviews} 次,建议加强使用深度` + const summary = `${year} 年规避潜在损失 ${fmtMoney(lossAvoided)},节约 HR 工时 ${timeSaved} 小时,仍有 ${pendingRisks.length} 项风险待处理` + + // 未解决风险按员工去重+风险类别去重 + const pendingBreakdown: Record = {} + for (const r of pendingRisks) { + const personKey = r.employee?.idCardHash || r.employee?.name || r.employeeId || '_unknown' + if (!pendingBreakdown[personKey]) { + pendingBreakdown[personKey] = { + name: r.employee?.name || '未知员工', + department: r.employee?.department || '-', + riskCount: 0, + totalLoss: 0, + details: [], + } + } + pendingBreakdown[personKey].riskCount++ + pendingBreakdown[personKey].totalLoss += r.estimatedLoss || 0 + pendingBreakdown[personKey].details.push({ + title: r.title, + estimatedLoss: r.estimatedLoss || 0, + legalBasis: getLegalBasis(r.title), + }) + } + const pendingRiskDetails = Object.values(pendingBreakdown) + .map(p => ({ ...p, details: p.details.sort((a, b) => b.estimatedLoss - a.estimatedLoss) })) + .sort((a, b) => b.totalLoss - a.totalLoss) return { year, totalValue, - roi, metrics, timeline, costSaved, @@ -1780,6 +1821,7 @@ export async function getAnnualValueReport(orgId: string, year: number) { lossAvoided, adjustedLossAvoided, employeeDetails, + pendingRiskDetails, summary, } } @@ -1795,7 +1837,6 @@ export async function saveAnnualValueReport(orgId: string, userId: string, year: orgId, year: result.year, totalValue: result.totalValue, - roi: result.roi, metrics: result.metrics as any, timeline: result.timeline as any, costSaved: result.costSaved, diff --git a/frontend/src/pages/tools/AnnualValueReport.tsx b/frontend/src/pages/tools/AnnualValueReport.tsx index faea2ec..2f08190 100644 --- a/frontend/src/pages/tools/AnnualValueReport.tsx +++ b/frontend/src/pages/tools/AnnualValueReport.tsx @@ -117,7 +117,7 @@ export default function AnnualValueReport() { - {/* ROI 横幅 */} + {/* 年度总价值概览 */}
@@ -125,13 +125,13 @@ export default function AnnualValueReport() {
-
投资回报率 (ROI)
-
{report.roi}%
+
年度总价值
+
{fmtMoney(report.totalValue)}
-
年度总价值
-
{fmtMoney(report.totalValue)}
+
规避损失
+
{fmtMoney(report.adjustedLossAvoided || 0)}

{report.summary}

@@ -168,7 +168,7 @@ export default function AnnualValueReport() {
{r.year} 年 - ROI {r.roi}% + 总价值 {fmtMoney(r.totalValue)} {r.summary}
{new Date(r.createdAt).toLocaleDateString('zh-CN')} @@ -270,6 +270,61 @@ export default function AnnualValueReport() { )} + {/* 未解决风险列表 */} + {report.pendingRiskDetails && report.pendingRiskDetails.length > 0 && ( + +

+ + 待处理风险 ({report.pendingRiskDetails.length} 人) +

+
+ + + + + + + + + + + + {report.pendingRiskDetails.map((emp: any, idx: number) => ( + + + + + + + + ))} + + + + + + + + +
员工部门风险数潜在损失风险明细
{emp.name}{emp.department}{emp.riskCount}¥{emp.totalLoss.toLocaleString()} +
+ {emp.details.map((d: any, i: number) => ( +
+ {d.title} + · + {d.legalBasis} + · + ¥{d.estimatedLoss.toLocaleString()} +
+ ))} +
+
合计 + ¥{report.pendingRiskDetails.reduce((s: number, e: any) => s + e.totalLoss, 0).toLocaleString()} +
+
+
+ )} + {/* 价值计算说明 */}

价值计算说明

@@ -290,10 +345,6 @@ export default function AnnualValueReport() { 总价值:规避损失 + 节约成本
-
- - ROI:总价值 ÷ 系统年费(¥12,000)× 100%,上限 9999% -
法定上限:双倍工资≤11个月(第82条)、经济补偿N≤12个月月薪≤社平3倍(第47条)、违法解除2N≤24个月(第87条)