From ccc9fffe89f19eaa9fb927bb8ab119de033d0c91 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Wed, 17 Dec 2025 19:48:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9AJRZQ3C9R=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E8=A1=8C=E4=B8=BA=E6=8C=87=E6=95=B0=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BaseReport.vue | 10 +- .../JRZQ3C9R/components/BasicInfoSection.vue | 200 +++++++++++ .../components/InsufficientRatioSection.vue | 107 ++++++ .../components/LoanAndOverdueSection.vue | 322 ++++++++++++++++++ .../components/QueryOverviewSection.vue | 252 ++++++++++++++ .../JRZQ3C9R/components/QueryTrendSection.vue | 136 ++++++++ .../components/RepayFailTrendSection.vue | 104 ++++++ .../components/RepayOrgAndLevelSection.vue | 232 +++++++++++++ .../components/RepaySuccessTrendSection.vue | 104 ++++++ .../JRZQ3C9R/components/RepayTrendSection.vue | 124 +++++++ src/ui/JRZQ3C9R/components/ScoreSection.vue | 71 ++++ src/ui/JRZQ3C9R/index.vue | 105 ++++++ src/ui/JRZQ3C9R/utils/dataParser.js | 160 +++++++++ 13 files changed, 1926 insertions(+), 1 deletion(-) create mode 100644 src/ui/JRZQ3C9R/components/BasicInfoSection.vue create mode 100644 src/ui/JRZQ3C9R/components/InsufficientRatioSection.vue create mode 100644 src/ui/JRZQ3C9R/components/LoanAndOverdueSection.vue create mode 100644 src/ui/JRZQ3C9R/components/QueryOverviewSection.vue create mode 100644 src/ui/JRZQ3C9R/components/QueryTrendSection.vue create mode 100644 src/ui/JRZQ3C9R/components/RepayFailTrendSection.vue create mode 100644 src/ui/JRZQ3C9R/components/RepayOrgAndLevelSection.vue create mode 100644 src/ui/JRZQ3C9R/components/RepaySuccessTrendSection.vue create mode 100644 src/ui/JRZQ3C9R/components/RepayTrendSection.vue create mode 100644 src/ui/JRZQ3C9R/components/ScoreSection.vue create mode 100644 src/ui/JRZQ3C9R/index.vue create mode 100644 src/ui/JRZQ3C9R/utils/dataParser.js diff --git a/src/components/BaseReport.vue b/src/components/BaseReport.vue index c6203e6..0d0b653 100644 --- a/src/components/BaseReport.vue +++ b/src/components/BaseReport.vue @@ -565,6 +565,14 @@ const featureMap = { component: defineAsyncComponent(() => import("@/ui/YYSY8B1C/index.vue")), remark: '手机在网时长查询用于检测用户手机号码的在网使用时长。在网时长越长,通常表示用户身份越稳定,信用风险越低。需要注意的是,如果手机号码存在携号转网的情况,那么在网时长会从转网的时候重新计算,转网前的在网时长不计入当前在网时长。建议结合手机携号转网查询结果进行综合评估。' }, + + // 支付行为指数 + JRZQ3C9R: { + name: "支付行为指数", + component: defineAsyncComponent(() => import("@/ui/JRZQ3C9R/index.vue")), + remark: '支付行为指数基于近两年的查验记录、还款成功与失败表现以及余额不足情况,对用户支付与还款习惯进行量化评分,用于评估其支付稳定性与违约风险。' + }, + }; const maskValue = computed(() => { @@ -664,7 +672,7 @@ const featureRiskLevels = { 'QYGL3F8E': 5, // 人企关系加强版 'QCXG7A2B': 5, // 名下车辆 'JRZQ09J8': 5, // 收入评估 - + 'JRZQ3C9R': 5, // 支付行为指数 // 🔵 低风险类 - 权重 3 'IVYZ5733': 3, // 婚姻状态 'IVYZ9A2B': 3, // 学历信息 diff --git a/src/ui/JRZQ3C9R/components/BasicInfoSection.vue b/src/ui/JRZQ3C9R/components/BasicInfoSection.vue new file mode 100644 index 0000000..ba46d40 --- /dev/null +++ b/src/ui/JRZQ3C9R/components/BasicInfoSection.vue @@ -0,0 +1,200 @@ + + + + + diff --git a/src/ui/JRZQ3C9R/components/InsufficientRatioSection.vue b/src/ui/JRZQ3C9R/components/InsufficientRatioSection.vue new file mode 100644 index 0000000..61493ca --- /dev/null +++ b/src/ui/JRZQ3C9R/components/InsufficientRatioSection.vue @@ -0,0 +1,107 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/components/LoanAndOverdueSection.vue b/src/ui/JRZQ3C9R/components/LoanAndOverdueSection.vue new file mode 100644 index 0000000..228128b --- /dev/null +++ b/src/ui/JRZQ3C9R/components/LoanAndOverdueSection.vue @@ -0,0 +1,322 @@ + + + + + diff --git a/src/ui/JRZQ3C9R/components/QueryOverviewSection.vue b/src/ui/JRZQ3C9R/components/QueryOverviewSection.vue new file mode 100644 index 0000000..431b818 --- /dev/null +++ b/src/ui/JRZQ3C9R/components/QueryOverviewSection.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/src/ui/JRZQ3C9R/components/QueryTrendSection.vue b/src/ui/JRZQ3C9R/components/QueryTrendSection.vue new file mode 100644 index 0000000..a7a5221 --- /dev/null +++ b/src/ui/JRZQ3C9R/components/QueryTrendSection.vue @@ -0,0 +1,136 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/components/RepayFailTrendSection.vue b/src/ui/JRZQ3C9R/components/RepayFailTrendSection.vue new file mode 100644 index 0000000..d357e78 --- /dev/null +++ b/src/ui/JRZQ3C9R/components/RepayFailTrendSection.vue @@ -0,0 +1,104 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/components/RepayOrgAndLevelSection.vue b/src/ui/JRZQ3C9R/components/RepayOrgAndLevelSection.vue new file mode 100644 index 0000000..4422ec5 --- /dev/null +++ b/src/ui/JRZQ3C9R/components/RepayOrgAndLevelSection.vue @@ -0,0 +1,232 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/components/RepaySuccessTrendSection.vue b/src/ui/JRZQ3C9R/components/RepaySuccessTrendSection.vue new file mode 100644 index 0000000..b5a4d2b --- /dev/null +++ b/src/ui/JRZQ3C9R/components/RepaySuccessTrendSection.vue @@ -0,0 +1,104 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/components/RepayTrendSection.vue b/src/ui/JRZQ3C9R/components/RepayTrendSection.vue new file mode 100644 index 0000000..14ff8fa --- /dev/null +++ b/src/ui/JRZQ3C9R/components/RepayTrendSection.vue @@ -0,0 +1,124 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/components/ScoreSection.vue b/src/ui/JRZQ3C9R/components/ScoreSection.vue new file mode 100644 index 0000000..971de32 --- /dev/null +++ b/src/ui/JRZQ3C9R/components/ScoreSection.vue @@ -0,0 +1,71 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/index.vue b/src/ui/JRZQ3C9R/index.vue new file mode 100644 index 0000000..5ed41c7 --- /dev/null +++ b/src/ui/JRZQ3C9R/index.vue @@ -0,0 +1,105 @@ + + + + + + + diff --git a/src/ui/JRZQ3C9R/utils/dataParser.js b/src/ui/JRZQ3C9R/utils/dataParser.js new file mode 100644 index 0000000..63c5dc9 --- /dev/null +++ b/src/ui/JRZQ3C9R/utils/dataParser.js @@ -0,0 +1,160 @@ +/** + * 支付行为指数(JRZQ3C9R)数据解析工具 + */ + +/** + * 将 -1 / 空 / null 统一视为 0,其他数值转为 Number + */ +export function normalizeValue(value) { + if (value === undefined || value === null || value === "" || value === -1) { + return 0; + } + const num = Number(value); + return Number.isNaN(num) ? 0 : num; +} + +/** + * 从原始 data 中提取真正的指标对象 + * 兼容多种包裹结构: + * - { code, data: {...} } + * - { data: { code, data: {...} } } + */ +export function extractPpcmData(raw) { + if (!raw) return {}; + + // example.json 结构:data.data.data + if (raw.data && raw.data.data) { + return raw.data.data || {}; + } + + // 已经是 { code, data } 这一层 + if (raw.data && !raw.code) { + return raw.data || {}; + } + + return raw || {}; +} + +/** + * 获取支付行为评分(原始 300-900 分) + */ +export function getBehavScore(ppcm) { + const score = normalizeValue(ppcm.ppcm_behav_score); + return score; +} + +/** + * 将 300-900 分映射到 0-100 分(用于统一风险评分体系) + */ +export function mapScoreTo100(score) { + if (!score || score <= 0) { + return 100; + } + // 限制在 [300,900] + const clamped = Math.min(900, Math.max(300, score)); + // 300 -> 0, 900 -> 100 + const mapped = ((clamped - 300) / 600) * 100; + return Math.round(mapped); +} + +/** + * 支付行为评分等级标签 + */ +export function getBehavLevel(score) { + if (!score || score <= 0) return "暂无评分"; + if (score >= 800) return "优秀"; + if (score >= 750) return "良好"; + if (score >= 700) return "中等"; + if (score >= 650) return "一般"; + return "偏低"; +} + +/** + * 通用时间段 + */ +export const PERIODS = [ + { key: "d7", label: "近7天" }, + { key: "m1", label: "近1个月" }, + { key: "m3", label: "近3个月" }, + { key: "m6", label: "近6个月" }, + { key: "m12", label: "近1年" }, + { key: "m24", label: "近2年" }, +]; + +/** + * 获取查验次数统计(按时间段) + * ppcm_{period}_bank_qynum / _nbank_fin_qynum / _nbank_other_qynum / _qynum + */ +export function getQueryCountsByPeriod(ppcm) { + const result = {}; + + PERIODS.forEach((p) => { + const prefix = `ppcm_${p.key}`; + result[p.key] = { + bank: normalizeValue(ppcm[`${prefix}_bank_qynum`]), + nbankFin: normalizeValue(ppcm[`${prefix}_nbank_fin_qynum`]), + nbankOther: normalizeValue(ppcm[`${prefix}_nbank_other_qynum`]), + total: normalizeValue(ppcm[`${prefix}_qynum`]), + }; + }); + + return result; +} + +/** + * 获取还款成功 / 失败次数统计(按时间段) + * success:ppcm_{period}_succ_repnum + * fail:ppcm_{period}_fail_repnum + */ +export function getRepayCountsByPeriod(ppcm) { + const result = {}; + + PERIODS.forEach((p) => { + const prefix = `ppcm_${p.key}`; + result[p.key] = { + success: normalizeValue(ppcm[`${prefix}_succ_repnum`]), + fail: normalizeValue(ppcm[`${prefix}_fail_repnum`]), + }; + }); + + return result; +} + +/** + * 获取余额不足失败占比(按时间段) + * ppcm_{period}_fail_neh_repnum_ratio + */ +export function getInsufficientRatioByPeriod(ppcm) { + const result = {}; + + PERIODS.forEach((p) => { + const prefix = `ppcm_${p.key}`; + result[p.key] = normalizeValue(ppcm[`${prefix}_fail_neh_repnum_ratio`]); + }); + + return result; +} + +/** + * 解析最近一次查验距今天数区间编码 + * ppcm_latest_qytoday: 1-10 档位 + */ +export function getLatestQueryBucket(ppcm) { + const code = normalizeValue(ppcm.ppcm_latest_qytoday); + if (!code) return "暂无查验记录"; + + const mapping = { + 1: "0-7天", + 2: "7-15天", + 3: "15-30天", + 4: "30-60天", + 5: "60-90天", + 6: "90-120天", + 7: "120-150天", + 8: "150-180天", + 9: "180-360天", + 10: "360天以上", + }; + + return mapping[code] || "未知区间"; +}