完善外部人员预警与项目分析上线内容

This commit is contained in:
wjj
2026-06-30 10:23:55 +08:00
parent 4e90e22ee2
commit 5e4bfca05b
77 changed files with 5788 additions and 333 deletions

View File

@@ -0,0 +1,912 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>结果总览 - 外部人员预警原型</title>
<style>
:root {
--bg: #f5f7fa;
--panel: #ffffff;
--line: #dcdfe6;
--line-soft: #ebeef5;
--text: #303133;
--sub: #606266;
--muted: #909399;
--primary: #2f6fed;
--primary-soft: #eaf1ff;
--danger: #d93026;
--danger-soft: #fdecea;
--warning: #b56a00;
--warning-soft: #fff4df;
--success: #1f7a45;
--success-soft: #e8f5ee;
--orange: #c75c00;
--orange-soft: #fff0e3;
--shadow: 0 8px 22px rgba(31, 45, 61, 0.08);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
color: var(--text);
background: var(--bg);
font-family: "Microsoft YaHei", "PingFang SC", Arial, sans-serif;
font-size: 14px;
letter-spacing: 0;
}
button,
input,
select {
font: inherit;
}
.page {
min-height: 100vh;
padding: 18px 24px 28px;
}
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 14px;
}
.breadcrumbs {
color: var(--muted);
font-size: 13px;
margin-bottom: 6px;
}
h1 {
margin: 0;
font-size: 22px;
line-height: 1.3;
font-weight: 650;
letter-spacing: 0;
}
.project-meta {
display: flex;
flex-wrap: wrap;
gap: 10px 16px;
margin-top: 8px;
color: var(--sub);
font-size: 13px;
}
.toolbar {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
justify-content: flex-end;
}
.btn {
height: 34px;
border: 1px solid var(--line);
border-radius: 4px;
padding: 0 12px;
background: var(--panel);
color: var(--text);
cursor: pointer;
}
.btn.primary {
border-color: var(--primary);
background: var(--primary);
color: #fff;
}
.btn.ghost {
color: var(--primary);
border-color: #b8cdfd;
background: #fff;
}
.overview {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 12px;
margin-bottom: 14px;
}
.metric {
min-height: 86px;
padding: 14px;
background: var(--panel);
border: 1px solid var(--line-soft);
border-radius: 6px;
box-shadow: var(--shadow);
}
.metric-title {
color: var(--sub);
font-size: 13px;
margin-bottom: 10px;
white-space: nowrap;
}
.metric-value {
font-size: 26px;
line-height: 1;
font-weight: 700;
margin-bottom: 8px;
}
.metric-note {
color: var(--muted);
font-size: 12px;
white-space: nowrap;
}
.metric.danger .metric-value {
color: var(--danger);
}
.metric.warning .metric-value {
color: var(--warning);
}
.metric.primary .metric-value {
color: var(--primary);
}
.grid {
display: grid;
grid-template-columns: minmax(0, 1fr) 360px;
gap: 14px;
align-items: start;
}
.section {
background: var(--panel);
border: 1px solid var(--line-soft);
border-radius: 6px;
box-shadow: var(--shadow);
margin-bottom: 14px;
overflow: hidden;
}
.section-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px 16px;
border-bottom: 1px solid var(--line-soft);
}
.section-title {
font-size: 16px;
font-weight: 650;
}
.section-body {
padding: 14px 16px 16px;
}
.segmented {
display: inline-grid;
grid-template-columns: repeat(2, minmax(112px, 1fr));
height: 34px;
border: 1px solid var(--line);
border-radius: 4px;
overflow: hidden;
background: #f8f9fb;
}
.segmented button {
border: 0;
border-right: 1px solid var(--line);
background: transparent;
color: var(--sub);
cursor: pointer;
padding: 0 12px;
}
.segmented button:last-child {
border-right: 0;
}
.segmented button.active {
background: var(--primary);
color: #fff;
}
.filters {
display: flex;
gap: 10px;
flex-wrap: wrap;
align-items: center;
margin-bottom: 12px;
}
.field {
height: 34px;
min-width: 148px;
border: 1px solid var(--line);
border-radius: 4px;
padding: 0 10px;
background: #fff;
color: var(--text);
}
.field.search {
min-width: 220px;
flex: 1;
}
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
th {
height: 40px;
background: #f5f7fa;
color: var(--sub);
font-weight: 600;
border-bottom: 1px solid var(--line);
text-align: left;
padding: 0 10px;
white-space: nowrap;
}
td {
height: 48px;
border-bottom: 1px solid var(--line-soft);
padding: 8px 10px;
vertical-align: middle;
color: var(--text);
word-break: break-word;
}
tr.selected {
background: #f4f8ff;
}
tr:hover {
background: #f8fbff;
}
.col-name {
width: 15%;
}
.col-type {
width: 12%;
}
.col-cert {
width: 20%;
}
.col-level {
width: 10%;
}
.col-count {
width: 10%;
}
.col-risk {
width: 24%;
}
.col-action {
width: 9%;
text-align: right;
}
.link {
border: 0;
background: transparent;
color: var(--primary);
cursor: pointer;
padding: 0;
}
.tag {
display: inline-flex;
align-items: center;
min-height: 24px;
padding: 0 8px;
border-radius: 3px;
font-size: 12px;
line-height: 1.2;
white-space: nowrap;
border: 1px solid transparent;
}
.tag + .tag {
margin-left: 6px;
}
.tag.danger {
color: var(--danger);
background: var(--danger-soft);
border-color: #f5c7c3;
}
.tag.warning {
color: var(--warning);
background: var(--warning-soft);
border-color: #ffd994;
}
.tag.primary {
color: var(--primary);
background: var(--primary-soft);
border-color: #c7d8ff;
}
.tag.success {
color: var(--success);
background: var(--success-soft);
border-color: #b7e0c9;
}
.tag.orange {
color: var(--orange);
background: var(--orange-soft);
border-color: #ffd0a8;
}
.tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.tags .tag {
margin: 0;
}
.models {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
}
.model-item {
min-height: 92px;
border: 1px solid var(--line-soft);
border-radius: 6px;
padding: 12px;
background: #fbfcff;
}
.model-name {
color: var(--sub);
font-size: 13px;
margin-bottom: 10px;
}
.model-count {
font-size: 24px;
line-height: 1;
font-weight: 700;
margin-bottom: 8px;
}
.model-foot {
color: var(--muted);
font-size: 12px;
}
.side-panel {
position: sticky;
top: 14px;
}
.identity {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 14px;
}
.kv {
min-height: 58px;
border: 1px solid var(--line-soft);
border-radius: 5px;
padding: 9px 10px;
background: #fbfcff;
}
.kv-label {
color: var(--muted);
font-size: 12px;
margin-bottom: 6px;
white-space: nowrap;
}
.kv-value {
color: var(--text);
font-size: 14px;
font-weight: 600;
word-break: break-word;
}
.detail-title {
font-weight: 650;
margin: 18px 0 10px;
}
.mini-table th {
height: 34px;
font-size: 12px;
padding: 0 8px;
}
.mini-table td {
height: 42px;
font-size: 12px;
padding: 7px 8px;
}
.risk-text {
color: var(--sub);
line-height: 1.55;
}
.empty-graph {
height: 126px;
border: 1px dashed #c9cdd4;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
color: var(--muted);
background: #fafbfc;
}
.detail-table .col-date {
width: 13%;
}
.detail-table .col-subject {
width: 12%;
}
.detail-table .col-party {
width: 16%;
}
.detail-table .col-labels {
width: 27%;
}
.detail-table .col-amount {
width: 12%;
text-align: right;
}
.amount {
text-align: right;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.footer-note {
color: var(--muted);
font-size: 12px;
padding: 0 2px;
}
@media (max-width: 1280px) {
.overview {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid {
grid-template-columns: 1fr;
}
.side-panel {
position: static;
}
}
@media (max-width: 760px) {
.page {
padding: 14px;
}
.topbar,
.section-head {
align-items: flex-start;
flex-direction: column;
}
.toolbar {
width: 100%;
justify-content: flex-start;
}
.overview,
.models,
.identity {
grid-template-columns: 1fr;
}
.field,
.field.search,
.segmented {
width: 100%;
}
table {
min-width: 880px;
}
.table-wrap {
overflow-x: auto;
}
}
</style>
</head>
<body>
<main class="page">
<header class="topbar">
<div>
<div class="breadcrumbs">初核项目 / 流水分析 / 结果总览</div>
<h1>结果总览</h1>
<div class="project-meta">
<span>项目编号HZ20260624001</span>
<span>导入流水18,426 笔</span>
<span>分析批次2026-06-24 09:38</span>
</div>
</div>
<div class="toolbar">
<button class="btn">导出结果</button>
<button class="btn ghost">专项排查</button>
<button class="btn primary">重新分析</button>
</div>
</header>
<section class="overview" aria-label="结果总览统计">
<div class="metric">
<div class="metric-title">分析主体数</div>
<div class="metric-value">126</div>
<div class="metric-note">员工、亲属及外部人员</div>
</div>
<div class="metric danger">
<div class="metric-title">高风险主体</div>
<div class="metric-value">8</div>
<div class="metric-note">较上批次 +2</div>
</div>
<div class="metric warning">
<div class="metric-title">中风险主体</div>
<div class="metric-value">21</div>
<div class="metric-note">待人工复核</div>
</div>
<div class="metric primary">
<div class="metric-title">外部人员预警</div>
<div class="metric-value">12</div>
<div class="metric-note">中介 5 人,其他 7 人</div>
</div>
<div class="metric">
<div class="metric-title">命中模型</div>
<div class="metric-value">17</div>
<div class="metric-note">含外部人员模型 4 个</div>
</div>
<div class="metric">
<div class="metric-title">涉疑交易金额</div>
<div class="metric-value">286.4万</div>
<div class="metric-note">按交易标签汇总</div>
</div>
</section>
<section class="grid">
<div>
<section class="section">
<div class="section-head">
<div class="section-title">风险主体</div>
<div class="segmented" role="tablist" aria-label="风险主体类型">
<button class="active" type="button" data-subject-tab="external">外部人员预警</button>
<button type="button" data-subject-tab="staff">员工风险</button>
</div>
</div>
<div class="section-body">
<div class="filters">
<input class="field search" type="text" value="" placeholder="搜索姓名、证件号、账户" />
<select class="field">
<option>全部主体类型</option>
<option>中介</option>
<option>外部人员</option>
</select>
<select class="field">
<option>全部风险等级</option>
<option>高风险</option>
<option>中风险</option>
<option>低风险</option>
</select>
<button class="btn primary">查询</button>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="col-name">风险主体</th>
<th class="col-type">主体类型</th>
<th class="col-cert">证件号</th>
<th class="col-level">风险等级</th>
<th class="col-count">命中模型数</th>
<th class="col-risk">核心风险点</th>
<th class="col-action">操作</th>
</tr>
</thead>
<tbody id="subjectRows">
<tr class="selected" data-name="王某" data-type="中介" data-cert="330************1234" data-level="高风险" data-models="4" data-risk="与员工亲属资金往来、大额转账、特殊金额交易" data-tags="外部人员大额交易,外部人员异常交易,外部人员可疑关系,特殊金额交易">
<td>王某</td>
<td><span class="tag primary">中介</span></td>
<td>330************1234</td>
<td><span class="tag danger">高风险</span></td>
<td>4</td>
<td>与员工亲属资金往来、大额转账、特殊金额交易</td>
<td class="col-action"><button class="link" type="button">详情</button></td>
</tr>
<tr data-name="李某" data-type="外部人员" data-cert="341************6612" data-level="中风险" data-models="2" data-risk="疑似赌博敏感交易、同日多笔转账" data-tags="外部人员异常交易,可疑赌博">
<td>李某</td>
<td><span class="tag orange">外部人员</span></td>
<td>341************6612</td>
<td><span class="tag warning">中风险</span></td>
<td>2</td>
<td>疑似赌博敏感交易、同日多笔转账</td>
<td class="col-action"><button class="link" type="button">详情</button></td>
</tr>
<tr data-name="赵某" data-type="外部人员" data-cert="320************4789" data-level="中风险" data-models="2" data-risk="与员工多次互转、夜间集中交易" data-tags="外部人员异常交易,外部人员可疑关系">
<td>赵某</td>
<td><span class="tag orange">外部人员</span></td>
<td>320************4789</td>
<td><span class="tag warning">中风险</span></td>
<td>2</td>
<td>与员工多次互转、夜间集中交易</td>
<td class="col-action"><button class="link" type="button">详情</button></td>
</tr>
<tr data-name="陈某" data-type="中介" data-cert="362************9021" data-level="低风险" data-models="1" data-risk="单笔交易金额超过外部人员阈值" data-tags="外部人员大额交易">
<td>陈某</td>
<td><span class="tag primary">中介</span></td>
<td>362************9021</td>
<td><span class="tag success">低风险</span></td>
<td>1</td>
<td>单笔交易金额超过外部人员阈值</td>
<td class="col-action"><button class="link" type="button">详情</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section class="section">
<div class="section-head">
<div class="section-title">风险模型</div>
<button class="btn">模型配置</button>
</div>
<div class="section-body">
<div class="models">
<div class="model-item">
<div class="model-name">外部人员大额交易</div>
<div class="model-count">9</div>
<div class="model-foot">单笔或累计金额超过阈值</div>
</div>
<div class="model-item">
<div class="model-name">外部人员异常交易</div>
<div class="model-count">6</div>
<div class="model-foot">频次、时间、金额形态异常</div>
</div>
<div class="model-item">
<div class="model-name">外部人员可疑赌博</div>
<div class="model-count">3</div>
<div class="model-foot">命中赌博敏感交易特征</div>
</div>
<div class="model-item">
<div class="model-name">外部人员可疑关系</div>
<div class="model-count">2</div>
<div class="model-foot">涉及员工或员工亲属资金往来</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="section-head">
<div class="section-title">涉疑交易明细</div>
<button class="btn">查看全部</button>
</div>
<div class="section-body">
<div class="table-wrap">
<table class="detail-table">
<thead>
<tr>
<th class="col-date">交易时间</th>
<th class="col-subject">风险主体</th>
<th>主体类型</th>
<th class="col-party">交易对手</th>
<th>对手类型</th>
<th class="col-labels">异常标签</th>
<th class="col-amount">金额</th>
</tr>
</thead>
<tbody>
<tr>
<td>2026-05-18 10:42</td>
<td>王某</td>
<td><span class="tag primary">中介</span></td>
<td>刘某某</td>
<td><span class="tag warning">员工亲属</span></td>
<td>
<div class="tags">
<span class="tag danger">外部人员可疑关系</span>
<span class="tag warning">特殊金额交易</span>
</div>
</td>
<td class="amount">180,000.00</td>
</tr>
<tr>
<td>2026-05-22 21:16</td>
<td>李某</td>
<td><span class="tag orange">外部人员</span></td>
<td>周某</td>
<td><span class="tag orange">外部人员</span></td>
<td>
<div class="tags">
<span class="tag warning">可疑赌博</span>
<span class="tag primary">夜间集中交易</span>
</div>
</td>
<td class="amount">52,000.00</td>
</tr>
<tr>
<td>2026-06-03 09:27</td>
<td>赵某</td>
<td><span class="tag orange">外部人员</span></td>
<td>张三</td>
<td><span class="tag primary">员工</span></td>
<td>
<div class="tags">
<span class="tag danger">外部人员可疑关系</span>
<span class="tag primary">多次互转</span>
</div>
</td>
<td class="amount">36,800.00</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
<aside class="side-panel">
<section class="section">
<div class="section-head">
<div class="section-title">外部人员风险详情</div>
<span class="tag danger" id="detailLevel">高风险</span>
</div>
<div class="section-body">
<div class="identity">
<div class="kv">
<div class="kv-label">风险主体</div>
<div class="kv-value" id="detailName">王某</div>
</div>
<div class="kv">
<div class="kv-label">主体类型</div>
<div class="kv-value" id="detailType">中介</div>
</div>
<div class="kv">
<div class="kv-label">证件号</div>
<div class="kv-value" id="detailCert">330************1234</div>
</div>
<div class="kv">
<div class="kv-label">命中模型数</div>
<div class="kv-value" id="detailModels">4</div>
</div>
</div>
<div class="detail-title">命中标签</div>
<div class="tags" id="detailTags">
<span class="tag danger">外部人员大额交易</span>
<span class="tag warning">外部人员异常交易</span>
<span class="tag primary">外部人员可疑关系</span>
<span class="tag orange">特殊金额交易</span>
</div>
<div class="detail-title">核心风险点</div>
<div class="risk-text" id="detailRisk">与员工亲属资金往来、大额转账、特殊金额交易</div>
<div class="detail-title">关联交易</div>
<table class="mini-table">
<thead>
<tr>
<th>对手方</th>
<th>对手类型</th>
<th>金额</th>
</tr>
</thead>
<tbody>
<tr>
<td>刘某某</td>
<td>员工亲属</td>
<td class="amount">180,000.00</td>
</tr>
<tr>
<td>张三</td>
<td>员工</td>
<td class="amount">36,800.00</td>
</tr>
</tbody>
</table>
<div class="detail-title">关系图谱</div>
<div class="empty-graph">外部人员图谱暂未接入</div>
</div>
</section>
<div class="footer-note">外部人员口径:本方证件号未命中员工及员工亲属,命中中介库本人证件号时标记为中介。</div>
</aside>
</section>
</main>
<script>
const rows = Array.from(document.querySelectorAll("#subjectRows tr"));
const detailName = document.getElementById("detailName");
const detailType = document.getElementById("detailType");
const detailCert = document.getElementById("detailCert");
const detailModels = document.getElementById("detailModels");
const detailRisk = document.getElementById("detailRisk");
const detailLevel = document.getElementById("detailLevel");
const detailTags = document.getElementById("detailTags");
function tagClass(text) {
if (text.includes("大额") || text.includes("可疑关系")) return "danger";
if (text.includes("异常") || text.includes("赌博")) return "warning";
if (text.includes("特殊")) return "orange";
return "primary";
}
function selectRow(row) {
rows.forEach((item) => item.classList.remove("selected"));
row.classList.add("selected");
detailName.textContent = row.dataset.name;
detailType.textContent = row.dataset.type;
detailCert.textContent = row.dataset.cert;
detailModels.textContent = row.dataset.models;
detailRisk.textContent = row.dataset.risk;
detailLevel.textContent = row.dataset.level;
detailLevel.className = "tag " + (row.dataset.level === "高风险" ? "danger" : row.dataset.level === "中风险" ? "warning" : "success");
detailTags.innerHTML = "";
row.dataset.tags.split(",").forEach((text) => {
const tag = document.createElement("span");
tag.className = "tag " + tagClass(text);
tag.textContent = text;
detailTags.appendChild(tag);
});
}
rows.forEach((row) => {
row.addEventListener("click", () => selectRow(row));
});
document.querySelectorAll("[data-subject-tab]").forEach((button) => {
button.addEventListener("click", () => {
document.querySelectorAll("[data-subject-tab]").forEach((item) => item.classList.remove("active"));
button.classList.add("active");
});
});
</script>
</body>
</html>