调整专项核查详情展示并补充家庭资产负债测试数据

This commit is contained in:
wkc
2026-03-24 21:34:38 +08:00
parent eaea112831
commit adb6b00ed0
19 changed files with 816 additions and 34 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
assets/专项核查.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

@@ -0,0 +1,13 @@
# 在专项核查页面开发员工家庭资产负债专项核查功能
- 范围为项目内的员工
- 家庭总年收入与家庭总负债之和,对比家庭总资产之和
- 家庭总年收入为员工本人年收入 + 员工配偶年收入(如有)
- 家庭总资产之和为员工与配偶关联的资产总和
- 家庭总负债为来源于员工和配偶的征信中的贷款与负债总和
- 总年收入+ 总负债 < 总资产 * 1.5 时,为正常
- 总资产 * 3 > 总年收入+ 总负债 > 总资产 * 1.5 时,提示存在风险
- 总年收入+ 总负债 > 总资产 * 3 时,提示高风险
- 在专项核查页面添加一个卡片,标题为员工家庭资产负债专项核查
- 卡片内展示项目内员工核查列表,展示每个员工家庭的总收入 总资产,总负债和风险情况。点开详情展示所有数据细项。
- 展示风格与结果总览其他组件的展示效果统一
- 使用frontend-design设计前端展示效果

View File

@@ -0,0 +1,84 @@
# 专项核查家庭资产负债测试数据实施计划
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
>
> 按仓库 `AGENTS.md` 约定,本次在当前会话直接执行,不启用 subagent。
**Goal:**`project_id = 51` 的“员工家庭资产负债专项核查”补充一组可重复执行的测试数据,覆盖正常、风险、高风险和缺失信息等典型情况。
**Architecture:** 复用现有测试项目 `51`,直接向 `ccdi_base_staff``ccdi_staff_fmy_relation``ccdi_asset_info``ccdi_debts_info``ccdi_bank_statement_tag_result` 补充专项核查专用样本,不新增新的项目、流水文件或前端入口。测试数据脚本采用“先删后插”的幂等方式,确保重复执行不会堆积脏数据,并通过与专项核查 SQL 同口径的查询完成验证。
**Tech Stack:** MySQL 8、仓库脚本 `bin/mysql_utf8_exec.sh`、专项核查 Mapper SQL、Markdown 实施与验证文档
---
### Task 1: 设计覆盖场景与金额口径
**Files:**
- Modify: `docs/plans/misc/2026-03-24-special-check-family-asset-liability-test-data-implementation.md`
- Create: `sql/migration/2026-03-24-add-special-check-family-asset-liability-test-data.sql`
- [x] **Step 1: 明确测试项目与入围方式**
复用 `project_id = 51`,通过 `ccdi_bank_statement_tag_result.object_type = 'STAFF_ID_CARD'` + `object_key = 员工身份证号` 的对象命中方式将新增员工纳入专项核查范围。
- [x] **Step 2: 设计 6 类样本**
1. 正常边界:`收入 + 负债 = 资产 * 1.5`
2. 风险边界:`收入 + 负债 = 资产 * 3`
3. 高风险:`收入 + 负债 > 资产 * 3`
4. 缺少本人负债:本人无负债记录,但家庭仍有配偶负债
5. 缺少本人资产:本人无资产记录,但家庭仍有配偶资产
6. 单身完整:无配偶,但本人资产与负债完整
- [x] **Step 3: 固化金额口径**
所有资产均使用 `current_value`,所有负债均使用 `principal_balance`,缺失判断严格沿用专项核查现有逻辑:
- 本人资产记录数为 `0` 时输出 `MISSING_INFO`
- 本人负债记录数为 `0` 时输出 `MISSING_INFO`
### Task 2: 编写幂等测试数据脚本
**Files:**
- Create: `sql/migration/2026-03-24-add-special-check-family-asset-liability-test-data.sql`
- [x] **Step 1: 先清理专用样本数据**
删除本次样本对应的员工、配偶关系、资产、负债和项目命中记录,确保脚本可重复执行。
- [x] **Step 2: 插入专项核查员工与配偶关系**
新增 6 名专项核查专用员工,其中 5 名带配偶关系,并补充本人/配偶年收入。
- [x] **Step 3: 插入资产与负债明细**
按场景写入本人与配偶资产、负债,确保边界值和缺失值可直接命中现有风险判断。
- [x] **Step 4: 插入项目命中记录**
`ccdi_bank_statement_tag_result` 写入对象命中数据,使样本员工进入 `project_id = 51` 的专项核查范围。
### Task 3: 执行脚本并验证结果
**Files:**
- Modify: `docs/reports/implementation/2026-03-24-special-check-family-asset-liability-test-data-record.md`
- Create: `docs/tests/records/2026-03-24-special-check-family-asset-liability-test-data-verification.md`
- [x] **Step 1: 执行脚本**
Run: `bin/mysql_utf8_exec.sh sql/migration/2026-03-24-add-special-check-family-asset-liability-test-data.sql`
Expected: 无报错返回,事务成功提交。
- [x] **Step 2: 查询列表结果**
按专项核查同口径 SQL 查询 `project_id = 51` 下名称为 `专项核查%` 的员工,验证金额汇总和风险等级是否符合预期。
- [x] **Step 3: 查询缺失信息详情**
验证“缺少本人负债样本”“缺少本人资产样本”的详情缺失标记是否分别返回 `missingSelfDebtInfo = 1``missingSelfAssetInfo = 1`
- [x] **Step 4: 补实施与验证记录**
将脚本路径、覆盖场景、执行结果与验证摘要沉淀到实施记录和验证文档中。

View File

@@ -0,0 +1,25 @@
# 专项核查详情卡片顺序调整实施记录
## 基本信息
- 日期2026-03-24
- 范围:专项核查查看详情区域卡片顺序
- 类型:前端展示调整
## 修改内容
1. 调整 `ruoyi-ui/src/views/ccdiProject/components/detail/FamilyAssetLiabilityDetail.vue` 中详情卡片顺序。
2. 卡片顺序由“收入明细、资产明细、负债明细”调整为“收入明细、负债明细、资产明细”。
3. 未修改卡片中的字段内容、日期格式化逻辑和响应式样式,仅调整展示顺序。
## 测试与验证
- 执行:`node tests/unit/special-check-detail-layout.test.js`
- 执行:`node tests/unit/special-check-detail-date-display.test.js`
- 执行:`node tests/unit/special-check-family-table.test.js`
- 执行:`node tests/unit/special-check-detail-expand.test.js`
- 结果:通过
## 影响说明
- 仅影响专项核查详情区域三张卡片的展示顺序,不影响接口返回、字段取值和展开交互。

View File

@@ -0,0 +1,25 @@
# 专项核查详情日期时间展示优化实施记录
## 基本信息
- 日期2026-03-24
- 范围:专项核查列表中“查看详情”展开区域
- 类型:前端展示优化
## 修改内容
1. 调整 `ruoyi-ui/src/views/ccdiProject/components/detail/FamilyAssetLiabilityDetail.vue` 中资产明细、负债明细的日期列展示方式。
2. 新增 `formatDetailDateTime` 方法,统一格式化详情中的 `valuationDate``queryDate`
3. 当日期值包含非零时间时,展示 `yyyy-MM-dd HH:mm:ss`;当时间为 `00:00:00` 时,仅展示 `yyyy-MM-dd`,避免出现无意义的零点时间。
4. 空值或不可解析值统一展示为 `-`
## 测试与验证
- 执行:`node tests/unit/special-check-detail-date-display.test.js`
- 执行:`node tests/unit/special-check-detail-layout.test.js`
- 执行:`node tests/unit/special-check-detail-expand.test.js`
- 结果:通过
## 影响说明
- 仅影响专项核查详情展开区的日期显示,不涉及接口、后端逻辑和数据结构调整。

View File

@@ -0,0 +1,94 @@
# 2026-03-24 专项核查页员工家庭资产负债专项核查测试数据实施记录
## 本次新增文件
- SQL 脚本
- `sql/migration/2026-03-24-add-special-check-family-asset-liability-test-data.sql`
- 计划文档
- `docs/plans/misc/2026-03-24-special-check-family-asset-liability-test-data-implementation.md`
## 数据落点
- `ccdi_base_staff`
- 新增 6 名专项核查专用员工
- `ccdi_staff_fmy_relation`
- 新增 5 条配偶关系,补充配偶收入
- `ccdi_asset_info`
- 新增资产明细,覆盖本人资产、配偶资产、单身资产
- `ccdi_debts_info`
- 新增负债明细,覆盖本人负债、配偶负债、单身负债
- `ccdi_bank_statement_tag_result`
-`project_id = 51` 新增对象命中记录,使样本员工进入专项核查范围
## 覆盖场景
### 1. 正常边界
- 员工:`专项核查正常边界样本`
- 目标:验证 `comparisonAmount = totalAsset * 1.5` 时命中 `NORMAL / 正常`
- 设计值:
- 家庭总收入:`300000.00`
- 家庭总资产:`1000000.00`
- 家庭总负债:`1200000.00`
### 2. 风险边界
- 员工:`专项核查风险边界样本`
- 目标:验证 `comparisonAmount = totalAsset * 3` 时命中 `RISK / 存在风险`
- 设计值:
- 家庭总收入:`300000.00`
- 家庭总资产:`500000.00`
- 家庭总负债:`1200000.00`
### 3. 高风险
- 员工:`专项核查高风险样本`
- 目标:验证 `comparisonAmount > totalAsset * 3` 时命中 `HIGH / 高风险`
- 设计值:
- 家庭总收入:`240000.00`
- 家庭总资产:`500000.00`
- 家庭总负债:`1400100.00`
### 4. 缺少本人负债
- 员工:`专项核查缺少负债样本`
- 目标:验证本人无负债记录时优先输出 `MISSING_INFO / 缺少信息`
- 设计值:
- 家庭总收入:`300000.00`
- 家庭总资产:`800000.00`
- 家庭总负债:`200000.00`
### 5. 缺少本人资产
- 员工:`专项核查缺少资产样本`
- 目标:验证本人无资产记录时优先输出 `MISSING_INFO / 缺少信息`
- 设计值:
- 家庭总收入:`350000.00`
- 家庭总资产:`600000.00`
- 家庭总负债:`400000.00`
### 6. 单身完整
- 员工:`专项核查单身完整样本`
- 目标:验证无配偶情况下仍可正常汇总本人资产与负债
- 设计值:
- 家庭总收入:`180000.00`
- 家庭总资产:`400000.00`
- 家庭总负债:`300000.00`
## 脚本策略
- 使用固定 `staff_id` 与身份证号作为专用测试样本主键
- 先删除后插入,确保脚本支持重复执行
- 不创建新的项目或路由,不改动现有专项核查逻辑
- 复用已有项目 `51`,避免引入额外项目初始化成本
## 执行与验证
- 执行脚本:
- `bin/mysql_utf8_exec.sh sql/migration/2026-03-24-add-special-check-family-asset-liability-test-data.sql`
- 验证记录:
- `docs/tests/records/2026-03-24-special-check-family-asset-liability-test-data-verification.md`
- 验证结论:
- 6 名专用样本均已进入 `project_id = 51` 的专项核查范围
- 正常边界、风险边界、高风险、缺少本人负债、缺少本人资产、单身完整 6 类场景均已命中预期结果

View File

@@ -0,0 +1,23 @@
# 专项排查图谱占位卡片前端实施记录
## 改动日期
2026-03-24
## 改动范围
- `ruoyi-ui/src/views/ccdiProject/components/detail/SpecialCheck.vue`
- `docs/tests/scripts/check-special-check-graph-placeholder.js`
## 实施内容
1. 在专项排查页面的“专项核查”区域下方新增一张静态占位卡片。
2. 卡片用于预留后续图谱外链入口,当前展示标题、说明文案、占位状态和禁用按钮。
3. 保持现有页面结构不变,不新增接口、不调整路由、不影响已有家庭资产负债专项核查卡片。
4. 新增轻量校验脚本,用于检查占位卡片关键结构与文案是否存在。
5. 根据页面占位展示需要,将图谱占位卡片的最小高度调整为 `500px`,增强视觉占位效果。
## 结果说明
- 专项排查页面现在包含“员工家庭资产负债专项核查”和“图谱外链展示”两张卡片。
- 图谱卡片当前仅作为占位入口,后续接入真实外链时可直接在现有卡片基础上扩展。

View File

@@ -0,0 +1,24 @@
# 专项核查汇总展示顺序调整实施记录
## 基本信息
- 日期2026-03-24
- 范围:专项核查列表汇总列展示顺序
- 类型:前端展示调整
## 修改内容
1. 调整 `ruoyi-ui/src/views/ccdiProject/components/detail/FamilyAssetLiabilitySection.vue` 中专项核查列表汇总列顺序。
2. 汇总字段展示顺序由“家庭总年收入、家庭总资产、家庭总负债”调整为“家庭总年收入、家庭总负债、家庭总资产”。
3. 未修改接口返回字段、排序逻辑和详情展开逻辑,仅调整前端表格列位置。
## 测试与验证
- 执行:`node tests/unit/special-check-family-table.test.js`
- 执行:`node tests/unit/special-check-detail-expand.test.js`
- 执行:`node tests/unit/special-check-detail-date-display.test.js`
- 结果:通过
## 影响说明
- 仅影响专项核查列表汇总列的前端展示顺序,不影响数据内容和后端接口。

View File

@@ -0,0 +1,66 @@
# 2026-03-24 专项核查页员工家庭资产负债专项核查测试数据验证记录
## 执行命令
```bash
bin/mysql_utf8_exec.sh sql/migration/2026-03-24-add-special-check-family-asset-liability-test-data.sql
```
## 执行结果
- 执行时间2026-03-24 20:58:39 +0800
- 执行结果:`PASS`
- 说明:脚本执行无报错,事务成功提交
## 列表口径验证
### 验证 SQL
```sql
SELECT
bs.name AS staff_name,
COALESCE(bs.annual_income, 0) + COALESCE(spouse.spouse_income, 0) AS total_income,
COALESCE(asset.total_asset, 0) AS total_asset,
COALESCE(debt.total_debt, 0) AS total_debt,
COALESCE(bs.annual_income, 0) + COALESCE(spouse.spouse_income, 0) + COALESCE(debt.total_debt, 0) AS comparison_amount,
CASE
WHEN COALESCE(asset.self_asset_count, 0) = 0 OR COALESCE(debt.self_debt_count, 0) = 0 THEN 'MISSING_INFO'
WHEN COALESCE(bs.annual_income, 0) + COALESCE(spouse.spouse_income, 0) + COALESCE(debt.total_debt, 0) <= COALESCE(asset.total_asset, 0) * 1.5 THEN 'NORMAL'
WHEN COALESCE(bs.annual_income, 0) + COALESCE(spouse.spouse_income, 0) + COALESCE(debt.total_debt, 0) <= COALESCE(asset.total_asset, 0) * 3 THEN 'RISK'
ELSE 'HIGH'
END AS risk_level_code
FROM ccdi_base_staff bs
...
WHERE bs.name LIKE '专项核查%'
ORDER BY bs.staff_id;
```
### 验证结果
| 员工 | 家庭总收入 | 家庭总资产 | 家庭总负债 | 对比金额 | 风险结果 |
|------|------------|------------|------------|----------|----------|
| 专项核查正常边界样本 | 300000.00 | 1000000.00 | 1200000.00 | 1500000.00 | NORMAL |
| 专项核查风险边界样本 | 300000.00 | 500000.00 | 1200000.00 | 1500000.00 | RISK |
| 专项核查高风险样本 | 240000.00 | 500000.00 | 1400100.00 | 1640100.00 | HIGH |
| 专项核查缺少负债样本 | 300000.00 | 800000.00 | 200000.00 | 500000.00 | MISSING_INFO |
| 专项核查缺少资产样本 | 350000.00 | 600000.00 | 400000.00 | 750000.00 | MISSING_INFO |
| 专项核查单身完整样本 | 180000.00 | 400000.00 | 300000.00 | 480000.00 | NORMAL |
## 缺失标记验证
### 验证结果
| 员工 | missing_self_asset_info | missing_self_debt_info | self_total_asset | self_total_debt |
|------|-------------------------|------------------------|------------------|-----------------|
| 专项核查缺少负债样本 | 0 | 1 | 450000.00 | 0.00 |
| 专项核查缺少资产样本 | 1 | 0 | 0.00 | 250000.00 |
## 项目入围验证
- `project_id = 51` 下新增专项核查样本命中数:`6`
- 说明6 名专用员工均已进入专项核查范围
## 结论
- 新增测试数据已覆盖正常边界、风险边界、高风险、缺少本人负债、缺少本人资产、单身完整 6 类情况
- 当前专项核查风险判断口径与缺失标记口径均能被这组样本稳定命中

View File

@@ -0,0 +1,38 @@
# 专项排查图谱占位卡片前端验证记录
## 验证日期
2026-03-24
## 验证内容
### 1. 轻量校验脚本红绿验证
- 首次执行命令:
```bash
node docs/tests/scripts/check-special-check-graph-placeholder.js
```
- 初始结果:失败
- 失败原因:`SpecialCheck.vue` 中缺少图谱占位卡片的关键结构与文案
- 修改后再次执行命令:
```bash
node docs/tests/scripts/check-special-check-graph-placeholder.js
```
- 结果:通过
- 追加校验:脚本已覆盖 `min-height: 500px` 的高度断言
### 2. 前端构建验证
- 执行命令:
```bash
cd ruoyi-ui && npm run build:prod
```
- 结果:通过
- 备注构建输出存在既有的资源体积告警asset size limit / entrypoint size limit未出现与本次改动相关的编译错误

View File

@@ -0,0 +1,31 @@
const fs = require("fs");
const path = require("path");
const componentPath = path.resolve(
__dirname,
"../../../ruoyi-ui/src/views/ccdiProject/components/detail/SpecialCheck.vue"
);
const componentContent = fs.readFileSync(componentPath, "utf8");
const requiredSnippets = [
'class="graph-placeholder-card"',
"图谱外链展示",
"用于后续接入外链图谱页面",
"待接入",
"min-height: 500px",
];
const missingSnippets = requiredSnippets.filter(
(snippet) => !componentContent.includes(snippet)
);
if (missingSnippets.length) {
console.error("专项核查图谱占位卡片校验失败,缺少以下内容:");
missingSnippets.forEach((snippet) => {
console.error(`- ${snippet}`);
});
process.exit(1);
}
console.log("专项核查图谱占位卡片校验通过");

View File

@@ -24,32 +24,6 @@
</div>
</section>
<section class="detail-block">
<div class="block-header">
<div>
<div class="block-title">资产明细</div>
<div class="block-subtitle">展示本人及配偶资产小计与明细列表</div>
</div>
</div>
<div v-if="!assetDetail.missingSelfAssetInfo" class="detail-summary">
<span>本人资产小计{{ formatAmount(assetDetail.selfTotalAsset) }}</span>
<span>配偶资产小计{{ formatAmount(assetDetail.spouseTotalAsset) }}</span>
</div>
<el-table v-if="assetItems.length" :data="assetItems" size="mini" class="detail-table">
<el-table-column prop="assetName" label="资产名称" min-width="140" />
<el-table-column prop="assetMainType" label="资产大类" min-width="100" />
<el-table-column prop="assetSubType" label="资产小类" min-width="120" />
<el-table-column prop="holderName" label="持有人" min-width="100" />
<el-table-column label="当前估值" min-width="120">
<template slot-scope="scope">
<span>{{ formatAmount(scope.row.currentValue) }}</span>
</template>
</el-table-column>
<el-table-column prop="valuationDate" label="估值日期" min-width="120" />
</el-table>
<el-empty v-else :image-size="64" description="暂无资产明细" />
</section>
<section class="detail-block">
<div class="block-header">
<div>
@@ -72,15 +46,51 @@
<span>{{ formatAmount(scope.row.principalBalance) }}</span>
</template>
</el-table-column>
<el-table-column prop="queryDate" label="查询日期" min-width="120" />
<el-table-column label="查询日期" min-width="160">
<template slot-scope="scope">
<span>{{ formatDetailDateTime(scope.row.queryDate) }}</span>
</template>
</el-table-column>
</el-table>
<el-empty v-else :image-size="64" description="暂无负债明细" />
</section>
<section class="detail-block">
<div class="block-header">
<div>
<div class="block-title">资产明细</div>
<div class="block-subtitle">展示本人及配偶资产小计与明细列表</div>
</div>
</div>
<div v-if="!assetDetail.missingSelfAssetInfo" class="detail-summary">
<span>本人资产小计{{ formatAmount(assetDetail.selfTotalAsset) }}</span>
<span>配偶资产小计{{ formatAmount(assetDetail.spouseTotalAsset) }}</span>
</div>
<el-table v-if="assetItems.length" :data="assetItems" size="mini" class="detail-table">
<el-table-column prop="assetName" label="资产名称" min-width="140" />
<el-table-column prop="assetMainType" label="资产大类" min-width="100" />
<el-table-column prop="assetSubType" label="资产小类" min-width="120" />
<el-table-column prop="holderName" label="持有人" min-width="100" />
<el-table-column label="当前估值" min-width="120">
<template slot-scope="scope">
<span>{{ formatAmount(scope.row.currentValue) }}</span>
</template>
</el-table-column>
<el-table-column label="估值日期" min-width="160">
<template slot-scope="scope">
<span>{{ formatDetailDateTime(scope.row.valuationDate) }}</span>
</template>
</el-table-column>
</el-table>
<el-empty v-else :image-size="64" description="暂无资产明细" />
</section>
</div>
</div>
</template>
<script>
import { parseTime } from "@/utils/ruoyi";
export default {
name: "FamilyAssetLiabilityDetail",
props: {
@@ -140,6 +150,17 @@ export default {
maximumFractionDigits: 2,
})} 元`;
},
formatDetailDateTime(value) {
if (!value) {
return "-";
}
const formatted = parseTime(value, "{y}-{m}-{d} {h}:{i}:{s}");
if (!formatted) {
return "-";
}
const hasTime = !formatted.endsWith(" 00:00:00");
return parseTime(value, hasTime ? "{y}-{m}-{d} {h}:{i}:{s}" : "{y}-{m}-{d}") || "-";
},
},
};
</script>

View File

@@ -36,16 +36,16 @@
<span>{{ formatAmount(scope.row.totalIncome) }}</span>
</template>
</el-table-column>
<el-table-column label="家庭总资产" min-width="140">
<template slot-scope="scope">
<span>{{ formatAmount(scope.row.totalAsset) }}</span>
</template>
</el-table-column>
<el-table-column label="家庭总负债" min-width="140">
<template slot-scope="scope">
<span>{{ formatAmount(scope.row.totalDebt) }}</span>
</template>
</el-table-column>
<el-table-column label="家庭总资产" min-width="140">
<template slot-scope="scope">
<span>{{ formatAmount(scope.row.totalAsset) }}</span>
</template>
</el-table-column>
<el-table-column label="风险情况" min-width="120">
<template slot-scope="scope">
<el-tag size="mini" effect="plain" :type="resolveRiskTagType(scope.row.riskLevelCode)">

View File

@@ -20,6 +20,23 @@
:title="sectionTitle"
:subtitle="sectionSubtitle"
/>
<section class="graph-placeholder-card">
<div class="graph-placeholder-header">
<div>
<div class="graph-placeholder-title">图谱外链展示</div>
<div class="graph-placeholder-subtitle">用于后续接入外链图谱页面</div>
</div>
<el-tag size="mini" type="info" effect="plain">占位中</el-tag>
</div>
<div class="graph-placeholder-body">
<div class="graph-placeholder-text">
当前卡片用于预留专项核查图谱入口后续接入外链地址后可在此直接跳转展示
</div>
<el-button type="primary" size="small" disabled>待接入</el-button>
</div>
</section>
</div>
</div>
</template>
@@ -129,4 +146,48 @@ export default {
.special-check-page {
min-height: 400px;
}
.graph-placeholder-card {
margin-top: 16px;
min-height: 500px;
padding: 20px;
background: #fff;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
}
.graph-placeholder-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.graph-placeholder-title {
font-size: 16px;
font-weight: 600;
color: #1f2937;
}
.graph-placeholder-subtitle {
margin-top: 4px;
font-size: 12px;
color: #94a3b8;
}
.graph-placeholder-body {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-top: 18px;
padding: 16px 18px;
border: 1px dashed #dbeafe;
background: #f8fbff;
}
.graph-placeholder-text {
font-size: 14px;
line-height: 22px;
color: #475569;
}
</style>

View File

@@ -0,0 +1,25 @@
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const componentPath = path.resolve(
__dirname,
"../../src/views/ccdiProject/components/detail/FamilyAssetLiabilityDetail.vue"
);
const source = fs.readFileSync(componentPath, "utf8");
[
"formatDetailDateTime(value)",
'return parseTime(value, hasTime ? "{y}-{m}-{d} {h}:{i}:{s}" : "{y}-{m}-{d}") || "-";',
"{{ formatDetailDateTime(scope.row.valuationDate) }}",
"{{ formatDetailDateTime(scope.row.queryDate) }}",
].forEach((token) => {
assert(source.includes(token), `专项核查详情日期展示缺少关键实现: ${token}`);
});
assert(
source.includes("const hasTime = !formatted.endsWith(\" 00:00:00\");"),
"专项核查详情应隐藏无意义的零点时间"
);
console.log("special-check-detail-date-display test passed");

View File

@@ -9,8 +9,8 @@ const source = fs.readFileSync(
[
"收入明细",
"资产明细",
"负债明细",
"资产明细",
"本人收入",
"配偶收入",
"本人资产小计",
@@ -26,6 +26,15 @@ assert(source.includes("missingSelfDebtInfo"), "负债卡片应支持缺少信
assert(source.includes('v-if="!assetDetail.missingSelfAssetInfo"'), "资产小计应可隐藏");
assert(source.includes('v-if="!debtDetail.missingSelfDebtInfo"'), "负债小计应可隐藏");
const incomeIndex = source.indexOf("收入明细");
const debtIndex = source.indexOf("负债明细");
const assetIndex = source.indexOf("资产明细");
assert(incomeIndex > -1, "缺少收入明细卡片");
assert(debtIndex > -1, "缺少负债明细卡片");
assert(assetIndex > -1, "缺少资产明细卡片");
assert(incomeIndex < debtIndex && debtIndex < assetIndex, "详情卡片顺序应为收入、负债、资产");
assert(
source.includes("grid-template-columns: repeat(3, minmax(0, 1fr));"),
"三个详情卡片应横向均分"

View File

@@ -12,8 +12,8 @@ const source = fs.readFileSync(
"身份证号",
"所属部门",
"家庭总年收入",
"家庭总资产",
"家庭总负债",
"家庭总资产",
"风险情况",
"操作",
"查看详情",
@@ -23,3 +23,15 @@ const source = fs.readFileSync(
assert(source.includes("loading"), "列表区块应接收加载状态");
assert(source.includes("rows"), "列表区块应消费列表数据");
const incomeIndex = source.indexOf('label="家庭总年收入"');
const debtIndex = source.indexOf('label="家庭总负债"');
const assetIndex = source.indexOf('label="家庭总资产"');
assert(incomeIndex > -1, "缺少家庭总年收入列");
assert(debtIndex > -1, "缺少家庭总负债列");
assert(assetIndex > -1, "缺少家庭总资产列");
assert(
incomeIndex < debtIndex && debtIndex < assetIndex,
"汇总列顺序应为家庭总年收入、家庭总负债、家庭总资产"
);

View File

@@ -0,0 +1,231 @@
START TRANSACTION;
-- 1. 清理本次专项核查专用样本
DELETE FROM ccdi_bank_statement_tag_result
WHERE project_id = 51
AND object_type = 'STAFF_ID_CARD'
AND object_key IN (
'330101199003010101',
'330101199003010102',
'330101199003010103',
'330101199003010104',
'330101199003010105',
'330101199003010106'
);
DELETE FROM ccdi_debts_info
WHERE person_id IN (
'330101199003010101',
'330101199003010102',
'330101199003010103',
'330101199003010104',
'330101199003010105',
'330101199003010106',
'330101199104010101',
'330101199104010102',
'330101199104010103',
'330101199104010104',
'330101199104010105'
);
DELETE FROM ccdi_asset_info
WHERE family_id IN (
'330101199003010101',
'330101199003010102',
'330101199003010103',
'330101199003010104',
'330101199003010105',
'330101199003010106'
)
OR person_id IN (
'330101199003010101',
'330101199003010102',
'330101199003010103',
'330101199003010104',
'330101199003010105',
'330101199003010106',
'330101199104010101',
'330101199104010102',
'330101199104010103',
'330101199104010104',
'330101199104010105'
);
DELETE FROM ccdi_staff_fmy_relation
WHERE person_id IN (
'330101199003010101',
'330101199003010102',
'330101199003010103',
'330101199003010104',
'330101199003010105'
)
AND relation_cert_no IN (
'330101199104010101',
'330101199104010102',
'330101199104010103',
'330101199104010104',
'330101199104010105'
);
DELETE FROM ccdi_base_staff
WHERE staff_id IN (1900001, 1900002, 1900003, 1900004, 1900005, 1900006)
OR id_card IN (
'330101199003010101',
'330101199003010102',
'330101199003010103',
'330101199003010104',
'330101199003010105',
'330101199003010106'
);
-- 2. 新增专项核查员工
INSERT INTO ccdi_base_staff (
staff_id,
name,
dept_id,
id_card,
phone,
annual_income,
hire_date,
status,
create_by,
create_time,
update_by,
update_time
) VALUES
(1900001, '专项核查正常边界样本', 100, '330101199003010101', '13900000001', 200000.00, '2020-01-10', '0', 'admin', NOW(), 'admin', NOW()),
(1900002, '专项核查风险边界样本', 100, '330101199003010102', '13900000002', 180000.00, '2020-01-10', '0', 'admin', NOW(), 'admin', NOW()),
(1900003, '专项核查高风险样本', 100, '330101199003010103', '13900000003', 150000.00, '2020-01-10', '0', 'admin', NOW(), 'admin', NOW()),
(1900004, '专项核查缺少负债样本', 100, '330101199003010104', '13900000004', 160000.00, '2020-01-10', '0', 'admin', NOW(), 'admin', NOW()),
(1900005, '专项核查缺少资产样本', 100, '330101199003010105', '13900000005', 220000.00, '2020-01-10', '0', 'admin', NOW(), 'admin', NOW()),
(1900006, '专项核查单身完整样本', 100, '330101199003010106', '13900000006', 180000.00, '2020-01-10', '0', 'admin', NOW(), 'admin', NOW());
-- 3. 新增配偶关系
INSERT INTO ccdi_staff_fmy_relation (
person_id,
relation_type,
relation_name,
gender,
birth_date,
relation_cert_type,
relation_cert_no,
mobile_phone1,
contact_address,
relation_desc,
status,
effective_date,
remark,
data_source,
is_emp_family,
is_cust_family,
created_by,
updated_by,
create_time,
update_time,
annual_income
) VALUES
('330101199003010101', '配偶', '边界配偶甲', 'F', '1991-04-01', '身份证', '330101199104010101', '13800000001', '专项核查测试地址1', '专项核查正常边界配偶', 1, NOW(), '专项核查测试数据', 'MANUAL', 1, 0, 'admin', 'admin', NOW(), NOW(), 100000.00),
('330101199003010102', '配偶', '边界配偶乙', 'F', '1991-04-01', '身份证', '330101199104010102', '13800000002', '专项核查测试地址2', '专项核查风险边界配偶', 1, NOW(), '专项核查测试数据', 'MANUAL', 1, 0, 'admin', 'admin', NOW(), NOW(), 120000.00),
('330101199003010103', '配偶', '高风险配偶', 'F', '1991-04-01', '身份证', '330101199104010103', '13800000003', '专项核查测试地址3', '专项核查高风险配偶', 1, NOW(), '专项核查测试数据', 'MANUAL', 1, 0, 'admin', 'admin', NOW(), NOW(), 90000.00),
('330101199003010104', '配偶', '负债缺失配偶', 'F', '1991-04-01', '身份证', '330101199104010104', '13800000004', '专项核查测试地址4', '专项核查缺少本人负债配偶', 1, NOW(), '专项核查测试数据', 'MANUAL', 1, 0, 'admin', 'admin', NOW(), NOW(), 140000.00),
('330101199003010105', '配偶', '资产缺失配偶', 'F', '1991-04-01', '身份证', '330101199104010105', '13800000005', '专项核查测试地址5', '专项核查缺少本人资产配偶', 1, NOW(), '专项核查测试数据', 'MANUAL', 1, 0, 'admin', 'admin', NOW(), NOW(), 130000.00);
-- 4. 新增资产明细
INSERT INTO ccdi_asset_info (
family_id,
person_id,
asset_main_type,
asset_sub_type,
asset_name,
ownership_ratio,
purchase_eval_date,
original_value,
current_value,
valuation_date,
asset_status,
remarks,
create_by,
update_by
) VALUES
('330101199003010101', '330101199003010101', '房产', '住宅', '专项核查正常边界样本-本人住宅', 100.00, '2024-01-01', 400000.00, 400000.00, '2026-03-20', '正常', '专项核查测试数据-正常边界', 'admin', 'admin'),
('330101199003010101', '330101199003010101', '金融资产', '理财', '专项核查正常边界样本-本人理财', 100.00, '2024-06-01', 200000.00, 200000.00, '2026-03-18', '正常', '专项核查测试数据-正常边界', 'admin', 'admin'),
('330101199003010101', '330101199104010101', '车辆', '家用汽车', '专项核查正常边界样本-配偶车辆', 100.00, '2024-02-01', 250000.00, 250000.00, '2026-03-17', '正常', '专项核查测试数据-正常边界', 'admin', 'admin'),
('330101199003010101', '330101199104010101', '金融资产', '基金', '专项核查正常边界样本-配偶基金', 100.00, '2024-07-01', 150000.00, 150000.00, '2026-03-16', '正常', '专项核查测试数据-正常边界', 'admin', 'admin'),
('330101199003010102', '330101199003010102', '房产', '公寓', '专项核查风险边界样本-本人公寓', 100.00, '2024-01-01', 200000.00, 200000.00, '2026-03-20', '正常', '专项核查测试数据-风险边界', 'admin', 'admin'),
('330101199003010102', '330101199104010102', '车辆', '新能源车', '专项核查风险边界样本-配偶车辆', 100.00, '2024-04-01', 300000.00, 300000.00, '2026-03-19', '正常', '专项核查测试数据-风险边界', 'admin', 'admin'),
('330101199003010103', '330101199003010103', '房产', '住宅', '专项核查高风险样本-本人住宅', 100.00, '2024-01-01', 200000.00, 200000.00, '2026-03-20', '正常', '专项核查测试数据-高风险', 'admin', 'admin'),
('330101199003010103', '330101199104010103', '金融资产', '股票', '专项核查高风险样本-配偶股票', 100.00, '2024-05-01', 300000.00, 300000.00, '2026-03-18', '正常', '专项核查测试数据-高风险', 'admin', 'admin'),
('330101199003010104', '330101199003010104', '房产', '住宅', '专项核查缺少负债样本-本人住宅', 100.00, '2024-01-01', 450000.00, 450000.00, '2026-03-20', '正常', '专项核查测试数据-缺少本人负债', 'admin', 'admin'),
('330101199003010104', '330101199104010104', '金融资产', '理财', '专项核查缺少负债样本-配偶理财', 100.00, '2024-06-01', 350000.00, 350000.00, '2026-03-18', '正常', '专项核查测试数据-缺少本人负债', 'admin', 'admin'),
('330101199003010105', '330101199104010105', '房产', '住宅', '专项核查缺少资产样本-配偶住宅', 100.00, '2024-01-01', 600000.00, 600000.00, '2026-03-20', '正常', '专项核查测试数据-缺少本人资产', 'admin', 'admin'),
('330101199003010106', '330101199003010106', '房产', '住宅', '专项核查单身完整样本-本人住宅', 100.00, '2024-01-01', 250000.00, 250000.00, '2026-03-20', '正常', '专项核查测试数据-单身完整', 'admin', 'admin'),
('330101199003010106', '330101199003010106', '金融资产', '存款', '专项核查单身完整样本-本人存款', 100.00, '2024-05-01', 150000.00, 150000.00, '2026-03-18', '正常', '专项核查测试数据-单身完整', 'admin', 'admin');
-- 5. 新增负债明细
INSERT INTO ccdi_debts_info (
person_id,
person_name,
query_date,
debt_main_type,
debt_sub_type,
creditor_type,
debt_name,
principal_balance,
debt_total_amount,
debt_status,
create_by,
update_by
) VALUES
('330101199003010101', '专项核查正常边界样本', '2026-03-24', '贷款', '房贷', '银行', '专项核查正常边界样本-本人房贷', 700000.00, 730000.00, '正常', 'admin', 'admin'),
('330101199104010101', '边界配偶甲', '2026-03-24', '贷款', '消费贷', '银行', '专项核查正常边界样本-配偶消费贷', 500000.00, 520000.00, '正常', 'admin', 'admin'),
('330101199003010102', '专项核查风险边界样本', '2026-03-24', '贷款', '经营贷', '银行', '专项核查风险边界样本-本人经营贷', 600000.00, 620000.00, '正常', 'admin', 'admin'),
('330101199003010102', '专项核查风险边界样本', '2026-03-23', '信用卡', '分期', '银行', '专项核查风险边界样本-本人信用卡分期', 100000.00, 102000.00, '正常', 'admin', 'admin'),
('330101199104010102', '边界配偶乙', '2026-03-24', '贷款', '房贷', '银行', '专项核查风险边界样本-配偶房贷', 500000.00, 530000.00, '正常', 'admin', 'admin'),
('330101199003010103', '专项核查高风险样本', '2026-03-24', '贷款', '房贷', '银行', '专项核查高风险样本-本人房贷', 900000.00, 930000.00, '正常', 'admin', 'admin'),
('330101199104010103', '高风险配偶', '2026-03-24', '贷款', '网贷', '消费金融', '专项核查高风险样本-配偶网贷', 500100.00, 510000.00, '正常', 'admin', 'admin'),
('330101199104010104', '负债缺失配偶', '2026-03-24', '贷款', '消费贷', '银行', '专项核查缺少负债样本-配偶消费贷', 200000.00, 205000.00, '正常', 'admin', 'admin'),
('330101199003010105', '专项核查缺少资产样本', '2026-03-24', '贷款', '信用贷', '银行', '专项核查缺少资产样本-本人信用贷', 250000.00, 255000.00, '正常', 'admin', 'admin'),
('330101199104010105', '资产缺失配偶', '2026-03-24', '贷款', '消费贷', '银行', '专项核查缺少资产样本-配偶消费贷', 150000.00, 152000.00, '正常', 'admin', 'admin'),
('330101199003010106', '专项核查单身完整样本', '2026-03-24', '贷款', '信用贷', '银行', '专项核查单身完整样本-本人信用贷', 180000.00, 182000.00, '正常', 'admin', 'admin'),
('330101199003010106', '专项核查单身完整样本', '2026-03-23', '信用卡', '分期', '银行', '专项核查单身完整样本-本人信用卡分期', 120000.00, 121500.00, '正常', 'admin', 'admin');
-- 6. 新增项目命中对象,使样本进入专项核查范围
INSERT INTO ccdi_bank_statement_tag_result (
project_id,
model_code,
model_name,
rule_code,
rule_name,
indicator_code,
result_type,
risk_level,
bank_statement_id,
object_type,
object_key,
group_id,
log_id,
reason_detail,
business_caliber_snapshot,
hit_value_snapshot,
create_by,
update_by,
remark
) VALUES
(51, 'ABNORMAL_TRANSACTION', '异常交易', 'LOW_INCOME_RELATIVE_LARGE_TRANSACTION', '低收入亲属大额交易', NULL, 'OBJECT', 'GENERAL', NULL, 'STAFF_ID_CARD', '330101199003010101', NULL, NULL, '专项核查测试数据-正常边界样本入围', '专项核查测试数据', '专项核查正常边界样本', 'admin', 'admin', '专项核查测试数据'),
(51, 'ABNORMAL_TRANSACTION', '异常交易', 'LOW_INCOME_RELATIVE_LARGE_TRANSACTION', '低收入亲属大额交易', NULL, 'OBJECT', 'GENERAL', NULL, 'STAFF_ID_CARD', '330101199003010102', NULL, NULL, '专项核查测试数据-风险边界样本入围', '专项核查测试数据', '专项核查风险边界样本', 'admin', 'admin', '专项核查测试数据'),
(51, 'ABNORMAL_TRANSACTION', '异常交易', 'LOW_INCOME_RELATIVE_LARGE_TRANSACTION', '低收入亲属大额交易', NULL, 'OBJECT', 'GENERAL', NULL, 'STAFF_ID_CARD', '330101199003010103', NULL, NULL, '专项核查测试数据-高风险样本入围', '专项核查测试数据', '专项核查高风险样本', 'admin', 'admin', '专项核查测试数据'),
(51, 'ABNORMAL_TRANSACTION', '异常交易', 'LOW_INCOME_RELATIVE_LARGE_TRANSACTION', '低收入亲属大额交易', NULL, 'OBJECT', 'GENERAL', NULL, 'STAFF_ID_CARD', '330101199003010104', NULL, NULL, '专项核查测试数据-缺少负债样本入围', '专项核查测试数据', '专项核查缺少负债样本', 'admin', 'admin', '专项核查测试数据'),
(51, 'ABNORMAL_TRANSACTION', '异常交易', 'LOW_INCOME_RELATIVE_LARGE_TRANSACTION', '低收入亲属大额交易', NULL, 'OBJECT', 'GENERAL', NULL, 'STAFF_ID_CARD', '330101199003010105', NULL, NULL, '专项核查测试数据-缺少资产样本入围', '专项核查测试数据', '专项核查缺少资产样本', 'admin', 'admin', '专项核查测试数据'),
(51, 'ABNORMAL_TRANSACTION', '异常交易', 'LOW_INCOME_RELATIVE_LARGE_TRANSACTION', '低收入亲属大额交易', NULL, 'OBJECT', 'GENERAL', NULL, 'STAFF_ID_CARD', '330101199003010106', NULL, NULL, '专项核查测试数据-单身完整样本入围', '专项核查测试数据', '专项核查单身完整样本', 'admin', 'admin', '专项核查测试数据');
COMMIT;