temp
This commit is contained in:
parent
1eaf3e810e
commit
526370bb41
@ -8,13 +8,14 @@
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<title>天远查 - 婚恋评估、司法涉诉查询、婚姻状态、判决书查询工具</title>
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="天远查依托大数据技术,精准查询司法涉诉风险!AI律师智能分析企业/个人司法风险,支持婚姻状况/婚姻状态/判决书/被执行人/老赖/失信人/限高查询,并提供身份/银行卡/手机号码一键核验!AI律师在线咨询+风险报告。多维防控财产/信用/身份风险!"
|
||||
content="天远查依托大数据技术,精准查询司法涉诉风险!个人司法风险,支持婚姻状况/婚姻状态/判决书/被执行人/老赖/失信人/限高查询,并提供身份/银行卡/手机号码一键核验!多维防控财产/信用/身份风险!"
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="婚恋评估, 司法涉诉查询, 判决书查询, 婚姻状态查询, 老赖, 被执行人, 限高, 失信人, 个人涉诉查询, 企业涉诉查询, 名下车辆核验, 车辆核验, 婚姻状况, 风险报告, 法律风险, 信用风险, 银行卡黑名单, 手机身份证核验, 学历核验, AI律师, 在线查询"
|
||||
content="婚恋评估, 司法涉诉查询, 判决书查询, 婚姻状态查询, 老赖, 被执行人, 限高, 失信人, 个人涉诉查询, 企业涉诉查询, 名下车辆核验, 车辆核验, 婚姻状况, 风险报告, 法律风险, 信用风险, 银行卡黑名单, 手机身份证核验, 学历核验, 在线查询"
|
||||
/>
|
||||
<meta name="author" content="天远查" />
|
||||
<meta
|
||||
|
3
src/auto-imports.d.ts
vendored
3
src/auto-imports.d.ts
vendored
@ -11,6 +11,7 @@ declare global {
|
||||
const VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||
const clearPromotionSession: typeof import('./composables/usePromotion.js')['clearPromotionSession']
|
||||
const closeToast: typeof import('vant/es')['closeToast']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const computedAsync: typeof import('@vueuse/core')['computedAsync']
|
||||
@ -38,7 +39,9 @@ declare global {
|
||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const getPromotionSession: typeof import('./composables/usePromotion.js')['getPromotionSession']
|
||||
const h: typeof import('vue')['h']
|
||||
const handlePromotionLink: typeof import('./composables/usePromotion.js')['handlePromotionLink']
|
||||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const injectLocal: typeof import('@vueuse/core')['injectLocal']
|
||||
|
@ -19,6 +19,8 @@ const useApiFetch = createFetch({
|
||||
// 在请求前添加通用的 Header,例如 Authorization
|
||||
const token = localStorage.getItem("token");
|
||||
const webviewEnv = localStorage.getItem("webview_env");
|
||||
const promoteKey = sessionStorage.getItem("promote_key");
|
||||
|
||||
if (webviewEnv) {
|
||||
platform = webviewEnv;
|
||||
}
|
||||
@ -33,6 +35,13 @@ const useApiFetch = createFetch({
|
||||
Authorization: `${token}`,
|
||||
};
|
||||
}
|
||||
// 如果有推广key,添加到请求头
|
||||
if (promoteKey) {
|
||||
options.headers = {
|
||||
...options.headers,
|
||||
"X-Promote-Key": promoteKey,
|
||||
};
|
||||
}
|
||||
return { options };
|
||||
},
|
||||
async afterFetch({ data, response }) {
|
||||
|
79
src/composables/usePromotion.js
Normal file
79
src/composables/usePromotion.js
Normal file
@ -0,0 +1,79 @@
|
||||
// 记录推广链接访问
|
||||
async function recordPromotionVisit(shortUrl) {
|
||||
try {
|
||||
const { data, error } = await useApiFetch(`/admin/promotion/link/record/${shortUrl}`)
|
||||
.get()
|
||||
.json();
|
||||
|
||||
if (error.value) {
|
||||
throw new Error(error.value);
|
||||
}
|
||||
|
||||
return data.value;
|
||||
} catch (error) {
|
||||
console.error("记录推广访问失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理会话存储
|
||||
function handleSessionStorage(promoteKey) {
|
||||
if (!promoteKey) return;
|
||||
|
||||
try {
|
||||
// 存储推广key
|
||||
sessionStorage.setItem('promote_key', promoteKey);
|
||||
// 存储时间戳,用于判断会话是否过期
|
||||
sessionStorage.setItem('promote_timestamp', Date.now().toString());
|
||||
} catch (error) {
|
||||
console.error("存储会话信息失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 统一的入口函数
|
||||
export function handlePromotionLink(shortUrl) {
|
||||
// 使用 Promise.resolve().then 确保异步执行
|
||||
Promise.resolve().then(async () => {
|
||||
try {
|
||||
const response = await recordPromotionVisit(shortUrl);
|
||||
console.log(response);
|
||||
if (response.code === 200 && response.data.success) {
|
||||
handleSessionStorage(shortUrl);
|
||||
}
|
||||
} catch (error) {
|
||||
// 错误已经在各自的函数中处理,这里只做日志记录
|
||||
console.error("推广链接处理失败:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取会话数据
|
||||
export function getPromotionSession() {
|
||||
try {
|
||||
const promoteKey = sessionStorage.getItem('promote_key');
|
||||
const timestamp = sessionStorage.getItem('promote_timestamp');
|
||||
|
||||
// 检查会话是否过期(30天过期)
|
||||
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
|
||||
if (timestamp && Date.now() - parseInt(timestamp) > THIRTY_DAYS) {
|
||||
clearPromotionSession();
|
||||
return null;
|
||||
}
|
||||
|
||||
return promoteKey;
|
||||
} catch (error) {
|
||||
console.error("获取会话信息失败:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 清除会话数据
|
||||
export function clearPromotionSession() {
|
||||
try {
|
||||
sessionStorage.removeItem('promote_key');
|
||||
sessionStorage.removeItem('promote_timestamp');
|
||||
} catch (error) {
|
||||
console.error("清除会话信息失败:", error);
|
||||
}
|
||||
}
|
@ -43,6 +43,14 @@
|
||||
<div>广西福铭网络科技有限公司版权所有</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <meta
|
||||
name="description"
|
||||
content="天远查依托大数据技术,精准查询司法涉诉风险!AI律师智能分析企业/个人司法风险,支持婚姻状况/婚姻状态/判决书/被执行人/老赖/失信人/限高查询,并提供身份/银行卡/手机号码一键核验!AI律师在线咨询+风险报告。多维防控财产/信用/身份风险!"
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="婚恋评估, 司法涉诉查询, 判决书查询, 婚姻状态查询, 老赖, 被执行人, 限高, 失信人, 个人涉诉查询, 企业涉诉查询, 名下车辆核验, 车辆核验, 婚姻状况, 风险报告, 法律风险, 信用风险, 银行卡黑名单, 手机身份证核验, 学历核验, AI律师, 在线查询"
|
||||
/> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -54,7 +62,7 @@ const route = useRoute();
|
||||
const tabbar = ref("index");
|
||||
const menu = reactive([
|
||||
{ title: "首页", icon: "home-o", name: "index" },
|
||||
{ title: "AI律师", icon: "chat-o", name: "ai" },
|
||||
// { title: "AI律师", icon: "chat-o", name: "ai" },
|
||||
{ title: "我的", icon: "user-o", name: "me" },
|
||||
{ title: "推广代理", icon: "balance-o", name: "promote" },
|
||||
]);
|
||||
|
@ -4,9 +4,22 @@ import GlobalLayout from "@/layouts/GlobalLayout.vue";
|
||||
import HomeLayout from "@/layouts/HomeLayout.vue";
|
||||
import PageLayout from "@/layouts/PageLayout.vue";
|
||||
import index from "@/views/index.vue";
|
||||
import { handlePromotionLink } from "@/composables/usePromotion";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/p/:url",
|
||||
name: "promotionLink",
|
||||
component: () => import("@/views/PromotionLink.vue"),
|
||||
beforeEnter: (to, from, next) => {
|
||||
// 调用处理函数,不等待其完成
|
||||
handlePromotionLink(to.params.url);
|
||||
// 直接跳转到首页
|
||||
next('/');
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
component: GlobalLayout, // 使用 Layout 作为父组件
|
||||
|
@ -58,15 +58,25 @@ const getReferenceDate = computed(() => {
|
||||
|
||||
// 根据相对月份获取实际年月
|
||||
function getActualMonthYear(monthsBack) {
|
||||
const refDate = new Date(getReferenceDate.value);
|
||||
refDate.setMonth(refDate.getMonth() - monthsBack);
|
||||
const month = monthsBack.replace("m", "");
|
||||
if (month === "12") {
|
||||
return "近1年";
|
||||
}
|
||||
return `近${month}月`;
|
||||
// const refDate = new Date(getReferenceDate.value);
|
||||
// refDate.setMonth(refDate.getMonth() - monthsBack);
|
||||
|
||||
const year = refDate.getFullYear();
|
||||
const month = refDate.getMonth() + 1; // JavaScript月份从0开始
|
||||
// const year = refDate.getFullYear();
|
||||
// const month = refDate.getMonth() + 1; // JavaScript月份从0开始
|
||||
|
||||
return `${year}年${month}月`;
|
||||
// return `${year}年${month}月`;
|
||||
}
|
||||
function getActualMonthYearT(monthsBack) {
|
||||
if (monthsBack === "t0") {
|
||||
return "1年内";
|
||||
}
|
||||
return `近${monthsBack.replace("t", "")}月`;
|
||||
}
|
||||
|
||||
// 金额转换函数
|
||||
function getLevelAmount(level) {
|
||||
const levelNum = Number(level) || 1;
|
||||
@ -85,28 +95,17 @@ function getLevelRange(level) {
|
||||
|
||||
// 计算借贷金额数据(按月)
|
||||
const monthlyBorrowData = computed(() => {
|
||||
const months = [
|
||||
"t0",
|
||||
"t1",
|
||||
"t2",
|
||||
"t3",
|
||||
"t4",
|
||||
"t5",
|
||||
"t6",
|
||||
"t7",
|
||||
"t8",
|
||||
"t9",
|
||||
"t10",
|
||||
"t11",
|
||||
];
|
||||
const months = ["m1", "m3", "m6", "m9", "m12"];
|
||||
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
|
||||
return months
|
||||
.map((month, index) => {
|
||||
const borrowKey = `${prefix}_${month}_nbank_lendamt`;
|
||||
const borrowKey = `${prefix}_${month}_nbank_passlendamt`;
|
||||
const borrowAmount = getLevelAmount(data[borrowKey]);
|
||||
console.log(borrowKey, borrowAmount);
|
||||
return {
|
||||
month: getActualMonthYear(index),
|
||||
month: getActualMonthYear(month),
|
||||
amount: borrowAmount,
|
||||
displayAmount: formatAmount(borrowAmount),
|
||||
level: data[borrowKey] || "0",
|
||||
@ -115,23 +114,9 @@ const monthlyBorrowData = computed(() => {
|
||||
})
|
||||
.reverse();
|
||||
});
|
||||
|
||||
// 计算还款金额数据(按月)
|
||||
// 计算应还金额数据(按月)
|
||||
const monthlyRepayData = computed(() => {
|
||||
const months = [
|
||||
"t0",
|
||||
"t1",
|
||||
"t2",
|
||||
"t3",
|
||||
"t4",
|
||||
"t5",
|
||||
"t6",
|
||||
"t7",
|
||||
"t8",
|
||||
"t9",
|
||||
"t10",
|
||||
"t11",
|
||||
];
|
||||
const months = ["m1", "m3", "m6", "m9", "m12"];
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
|
||||
return months
|
||||
@ -139,7 +124,7 @@ const monthlyRepayData = computed(() => {
|
||||
const repayKey = `${prefix}_${month}_nbank_reamt`;
|
||||
const repayAmount = getLevelAmount(data[repayKey]);
|
||||
return {
|
||||
month: getActualMonthYear(index),
|
||||
month: getActualMonthYear(month),
|
||||
amount: repayAmount,
|
||||
displayAmount: formatAmount(repayAmount),
|
||||
level: data[repayKey] || "0",
|
||||
@ -151,20 +136,41 @@ const monthlyRepayData = computed(() => {
|
||||
|
||||
// 计算机构数和借还差值(按月)
|
||||
const monthlyInstitutionData = computed(() => {
|
||||
const months = [
|
||||
"t0",
|
||||
"t1",
|
||||
"t2",
|
||||
"t3",
|
||||
"t4",
|
||||
"t5",
|
||||
"t6",
|
||||
"t7",
|
||||
"t8",
|
||||
"t9",
|
||||
"t10",
|
||||
"t11",
|
||||
];
|
||||
const months = ["m1", "m3", "m6", "m9", "m12"];
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
|
||||
return months
|
||||
.map((month, index) => {
|
||||
const orgKey = `${prefix}_${month}_nbank_passorg`;
|
||||
const numKey = `${prefix}_${month}_nbank_passnum`;
|
||||
const borrowKey = `${prefix}_${month}_nbank_passlendamt`;
|
||||
const repayKey = `${prefix}_${month}_nbank_reamt`;
|
||||
|
||||
const orgCount = Number(data[orgKey] || 0);
|
||||
const loanCount = Number(data[numKey] || 0);
|
||||
const borrowAmount = getLevelAmount(data[borrowKey]);
|
||||
const repayAmount = getLevelAmount(data[repayKey]);
|
||||
|
||||
let ratio = 0;
|
||||
if (borrowAmount > 0) {
|
||||
ratio = ((repayAmount / borrowAmount) * 100).toFixed(2);
|
||||
}
|
||||
|
||||
return {
|
||||
month: getActualMonthYear(month),
|
||||
orgCount,
|
||||
loanCount,
|
||||
borrowAmount: formatAmount(borrowAmount),
|
||||
repayAmount: formatAmount(repayAmount),
|
||||
ratio: `${ratio}%`,
|
||||
};
|
||||
})
|
||||
.reverse();
|
||||
});
|
||||
|
||||
// 计算近期借贷趋势数据(3月、6月、9月、12月)
|
||||
const recentBorrowTrends = computed(() => {
|
||||
const months = ["t0"];
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
|
||||
return months
|
||||
@ -181,14 +187,11 @@ const monthlyInstitutionData = computed(() => {
|
||||
|
||||
let ratio = 0;
|
||||
if (borrowAmount > 0) {
|
||||
ratio = (
|
||||
((borrowAmount - repayAmount) / borrowAmount) *
|
||||
100
|
||||
).toFixed(2);
|
||||
ratio = ((repayAmount / borrowAmount) * 100).toFixed(2);
|
||||
}
|
||||
|
||||
return {
|
||||
month: getActualMonthYear(index),
|
||||
month: getActualMonthYearT(month),
|
||||
orgCount,
|
||||
loanCount,
|
||||
borrowAmount: formatAmount(borrowAmount),
|
||||
@ -199,37 +202,6 @@ const monthlyInstitutionData = computed(() => {
|
||||
.reverse();
|
||||
});
|
||||
|
||||
// 计算近期借贷趋势数据(3月、6月、9月、12月)
|
||||
const recentBorrowTrends = computed(() => {
|
||||
const periods = ["m3", "m6", "m9", "m12"];
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
|
||||
return periods.map((period) => {
|
||||
const amountKey = `${prefix}_${period}_nbank_passlendamt`;
|
||||
const numKey = `${prefix}_${period}_nbank_passnum`;
|
||||
const orgKey = `${prefix}_${period}_nbank_passorg`;
|
||||
|
||||
// 从参考日期计算周期起始日期
|
||||
const monthsBack = Number(period.replace("m", ""));
|
||||
const startDate = new Date(getReferenceDate.value);
|
||||
startDate.setMonth(startDate.getMonth() - monthsBack);
|
||||
const startYear = startDate.getFullYear();
|
||||
const startMonth = startDate.getMonth() + 1;
|
||||
|
||||
// 期间描述
|
||||
const periodDesc = `${startYear}年${startMonth}月至今`;
|
||||
|
||||
return {
|
||||
period: periodDesc,
|
||||
amount: getLevelAmount(data[amountKey]),
|
||||
level: data[amountKey] || "0",
|
||||
levelRange: getLevelRange(data[amountKey]),
|
||||
loanCount: Number(data[numKey] || 0),
|
||||
orgCount: Number(data[orgKey] || 0),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 获取最近一次借贷信息
|
||||
const lastLoanInfo = computed(() => {
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
@ -265,71 +237,59 @@ function formatAmount(amount) {
|
||||
const behaviorSummary = computed(() => {
|
||||
const prefix = `tl_${dataType.value}`;
|
||||
|
||||
// 计算平均借贷金额
|
||||
const totalBorrowAmount = monthlyBorrowData.value.reduce(
|
||||
(sum, item) => sum + item.amount,
|
||||
0
|
||||
);
|
||||
const avgBorrowAmount = totalBorrowAmount / 12;
|
||||
// 获取近一年数据
|
||||
const yearData = recentBorrowTrends.value[0];
|
||||
|
||||
// 计算平均还款金额
|
||||
const totalRepayAmount = monthlyRepayData.value.reduce(
|
||||
(sum, item) => sum + item.amount,
|
||||
0
|
||||
);
|
||||
const avgRepayAmount = totalRepayAmount / 12;
|
||||
// 计算平均月申请次数
|
||||
const avgMonthlyApplications = (yearData.loanCount / 12).toFixed(1);
|
||||
|
||||
// 计算最大借贷和还款金额
|
||||
const maxBorrowAmount = Math.max(
|
||||
...monthlyBorrowData.value.map((item) => item.amount)
|
||||
);
|
||||
const maxRepayAmount = Math.max(
|
||||
...monthlyRepayData.value.map((item) => item.amount)
|
||||
);
|
||||
// 计算平均月审批额度
|
||||
const totalBorrowAmount = Number(yearData.borrowAmount.replace(/,/g, ""));
|
||||
const avgMonthlyAmount = (totalBorrowAmount / 12).toFixed(0);
|
||||
|
||||
// 计算平均借贷机构数
|
||||
const totalOrgCount = monthlyInstitutionData.value.reduce(
|
||||
(sum, item) => sum + item.orgCount,
|
||||
0
|
||||
);
|
||||
const avgOrgCount = (totalOrgCount / 12).toFixed(1);
|
||||
// 计算平均月应还金额
|
||||
const totalRepayAmount = Number(yearData.repayAmount.replace(/,/g, ""));
|
||||
const avgMonthlyRepay = (totalRepayAmount / 12).toFixed(0);
|
||||
|
||||
// 计算借还款比例
|
||||
const repayRatio = avgRepayAmount / avgBorrowAmount;
|
||||
// 计算还款比例
|
||||
const repayRatio =
|
||||
totalBorrowAmount > 0
|
||||
? ((totalRepayAmount / totalBorrowAmount) * 100).toFixed(1)
|
||||
: 0;
|
||||
|
||||
// 计算借贷趋势
|
||||
const borrowTrend = recentBorrowTrends.value.map((item) => item.amount);
|
||||
const isBorrowIncreasing = borrowTrend[3] > borrowTrend[0];
|
||||
|
||||
// 借贷风险评估
|
||||
// 风险评估
|
||||
let riskLevel = "低";
|
||||
let riskDesc = "借贷行为健康,按时还款,借贷金额合理";
|
||||
let riskDesc = "借贷行为健康,借贷金额合理";
|
||||
|
||||
if (repayRatio < 0.5) {
|
||||
// 基于机构数评估
|
||||
if (yearData.orgCount > 5) {
|
||||
riskLevel = "高";
|
||||
riskDesc = "还款比例低,可能存在较大的贷款负担";
|
||||
} else if (repayRatio < 0.8) {
|
||||
riskDesc = "多头借贷风险较高,借贷机构过多";
|
||||
} else if (yearData.orgCount > 3) {
|
||||
riskLevel = "中";
|
||||
riskDesc = "存在一定的贷款负担,还款压力中等";
|
||||
riskDesc = "存在多头借贷风险,借贷机构较多";
|
||||
}
|
||||
|
||||
if (Number(data[`${prefix}_m12_nbank_passorg`]) > 3) {
|
||||
// 基于月均申请次数评估
|
||||
if (avgMonthlyApplications > 3) {
|
||||
riskLevel = riskLevel === "低" ? "中" : "高";
|
||||
riskDesc += ",借贷机构较多,可能存在多头借贷风险";
|
||||
riskDesc += ",月均申请次数较多";
|
||||
}
|
||||
|
||||
// 基于还款比例评估
|
||||
if (repayRatio < 50) {
|
||||
riskLevel = riskLevel === "低" ? "中" : "高";
|
||||
riskDesc += ",还款比例较低";
|
||||
}
|
||||
|
||||
return {
|
||||
avgBorrowAmount: formatAmount(avgBorrowAmount.toFixed(0)),
|
||||
avgRepayAmount: formatAmount(avgRepayAmount.toFixed(0)),
|
||||
maxBorrowAmount: formatAmount(maxBorrowAmount),
|
||||
maxRepayAmount: formatAmount(maxRepayAmount),
|
||||
totalBorrowAmount: formatAmount(totalBorrowAmount),
|
||||
totalRepayAmount: formatAmount(totalRepayAmount),
|
||||
avgOrgCount,
|
||||
repayRatio: (repayRatio * 100).toFixed(1) + "%",
|
||||
trendDesc: isBorrowIncreasing
|
||||
? "借贷金额呈上升趋势"
|
||||
: "借贷金额呈下降趋势",
|
||||
totalApplications: yearData.loanCount,
|
||||
totalOrgs: yearData.orgCount,
|
||||
totalAmount: formatAmount(totalBorrowAmount),
|
||||
avgMonthlyApplications,
|
||||
avgMonthlyAmount: formatAmount(avgMonthlyAmount),
|
||||
avgMonthlyRepay: formatAmount(avgMonthlyRepay),
|
||||
repayRatio: `${repayRatio}%`,
|
||||
riskLevel,
|
||||
riskDesc,
|
||||
};
|
||||
@ -346,7 +306,7 @@ function drawBorrowChart() {
|
||||
const chartData = monthlyBorrowData.value;
|
||||
const option = {
|
||||
title: {
|
||||
text: "月度借贷金额(元)",
|
||||
text: "月度审批额度(元)",
|
||||
left: "center",
|
||||
textStyle: {
|
||||
fontWeight: "bold",
|
||||
@ -378,8 +338,10 @@ function drawBorrowChart() {
|
||||
type: "category",
|
||||
data: chartData.map((item) => item.month),
|
||||
axisLabel: {
|
||||
rotate: 45, // 旋转标签以避免重叠
|
||||
interval: 0,
|
||||
rotate: 45,
|
||||
fontWeight: "bold",
|
||||
margin: 15,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
@ -402,7 +364,7 @@ function drawBorrowChart() {
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "借贷金额",
|
||||
name: "审批额度",
|
||||
type: "bar",
|
||||
data: chartData.map((item) => ({
|
||||
value: item.amount,
|
||||
@ -440,7 +402,7 @@ function drawBorrowChart() {
|
||||
borrowChartInstance.value.setOption(option);
|
||||
}
|
||||
|
||||
// 绘制还款金额图表
|
||||
// 绘制应还金额图表
|
||||
function drawRepayChart() {
|
||||
if (!repayChartRef.value) return;
|
||||
|
||||
@ -451,7 +413,7 @@ function drawRepayChart() {
|
||||
const chartData = monthlyRepayData.value;
|
||||
const option = {
|
||||
title: {
|
||||
text: "月度还款金额(元)",
|
||||
text: "月度应还金额(元)",
|
||||
left: "center",
|
||||
textStyle: {
|
||||
fontWeight: "bold",
|
||||
@ -476,15 +438,17 @@ function drawRepayChart() {
|
||||
grid: {
|
||||
left: "5%",
|
||||
right: "5%",
|
||||
bottom: "0%",
|
||||
bottom: "15%",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: chartData.map((item) => item.month),
|
||||
axisLabel: {
|
||||
rotate: 45, // 旋转标签以避免重叠
|
||||
interval: 0,
|
||||
rotate: 45,
|
||||
fontWeight: "bold",
|
||||
margin: 15,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
@ -507,7 +471,7 @@ function drawRepayChart() {
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "还款金额",
|
||||
name: "应还金额",
|
||||
type: "bar",
|
||||
data: chartData.map((item) => ({
|
||||
value: item.amount,
|
||||
@ -545,7 +509,7 @@ function drawRepayChart() {
|
||||
repayChartInstance.value.setOption(option);
|
||||
}
|
||||
|
||||
// 绘制借贷还款趋势对比图
|
||||
// 绘制借贷应还趋势对比图
|
||||
function drawTrendChart() {
|
||||
if (!trendChartRef.value) return;
|
||||
|
||||
@ -558,7 +522,7 @@ function drawTrendChart() {
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: "借贷与还款金额趋势对比",
|
||||
text: "审批额度与应还金额趋势对比",
|
||||
left: "center",
|
||||
textStyle: {
|
||||
fontWeight: "bold",
|
||||
@ -577,7 +541,7 @@ function drawTrendChart() {
|
||||
shadowColor: "rgba(0, 0, 0, 0.2)",
|
||||
},
|
||||
legend: {
|
||||
data: ["借贷金额", "还款金额"],
|
||||
data: ["审批额度", "应还金额"],
|
||||
top: 30,
|
||||
textStyle: {
|
||||
fontWeight: "bold",
|
||||
@ -586,15 +550,17 @@ function drawTrendChart() {
|
||||
grid: {
|
||||
left: "5%",
|
||||
right: "5%",
|
||||
bottom: "0%",
|
||||
bottom: "15%",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: borrowData.map((item) => item.month),
|
||||
axisLabel: {
|
||||
rotate: 45, // 旋转标签以避免重叠
|
||||
interval: 0,
|
||||
rotate: 45,
|
||||
fontWeight: "bold",
|
||||
margin: 15,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
@ -617,7 +583,7 @@ function drawTrendChart() {
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "借贷金额",
|
||||
name: "审批额度",
|
||||
type: "line",
|
||||
data: borrowData.map((item) => item.amount),
|
||||
smooth: true,
|
||||
@ -641,7 +607,7 @@ function drawTrendChart() {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "还款金额",
|
||||
name: "应还金额",
|
||||
type: "line",
|
||||
data: repayData.map((item) => item.amount),
|
||||
smooth: true,
|
||||
@ -727,7 +693,7 @@ onUnmounted(() => {
|
||||
借贷行为分析报告
|
||||
</h2>
|
||||
<p class="text-sm text-gray-600 ml-6">
|
||||
本报告统计借贷金额与还款情况,帮助评估信贷风险
|
||||
本报告统计审批额度与应还情况,帮助评估信贷风险
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
@ -855,19 +821,19 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<!-- 借贷金额图表 -->
|
||||
<LTitle title="月度借贷金额" type="blue-green" />
|
||||
<LTitle title="近期审批额度" type="blue-green" />
|
||||
<div ref="borrowChartRef" class="chart-container"></div>
|
||||
|
||||
<!-- 还款金额图表 -->
|
||||
<LTitle title="月度还款金额" type="blue-green" />
|
||||
<div ref="repayChartRef" class="chart-container"></div>
|
||||
<!-- 应还金额图表 -->
|
||||
<!--<LTitle title="月度应还金额" type="blue-green" />
|
||||
<div ref="repayChartRef" class="chart-container"></div> -->
|
||||
|
||||
<!-- 借贷还款趋势对比 -->
|
||||
<LTitle title="借贷与还款趋势对比" type="blue-green" />
|
||||
<div ref="trendChartRef" class="chart-container"></div>
|
||||
<!-- 借贷应还趋势对比 -->
|
||||
<!--<LTitle title="审批额度与应还金额趋势对比" type="blue-green" />
|
||||
<div ref="trendChartRef" class="chart-container"></div> -->
|
||||
|
||||
<!-- 借贷机构数和借还差值比例表格 -->
|
||||
<LTitle title="月度借贷机构数与借还比例" type="blue-green" />
|
||||
<LTitle title="近期通过借贷审批情况" type="blue-green" />
|
||||
<div class="overflow-x-auto">
|
||||
<LTable :data="monthlyInstitutionData" type="blue-green">
|
||||
<template #header>
|
||||
@ -881,13 +847,60 @@ onUnmounted(() => {
|
||||
借贷次数
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
借贷金额
|
||||
审批额度
|
||||
</th>
|
||||
<!-- <th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
应还金额
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
还款金额
|
||||
应还比例
|
||||
</th> -->
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<td class="border px-1 py-2 text-xs">
|
||||
{{ row.month }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.orgCount }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.loanCount }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.borrowAmount }}
|
||||
</td>
|
||||
<!-- <td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.repayAmount }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.ratio }}
|
||||
</td> -->
|
||||
</template>
|
||||
</LTable>
|
||||
</div>
|
||||
|
||||
<!-- 近期借贷趋势表格 -->
|
||||
<LTitle title="近1年借贷情况" type="blue-green" />
|
||||
<div class="overflow-x-auto">
|
||||
<LTable :data="recentBorrowTrends" type="blue-green">
|
||||
<template #header>
|
||||
<th class="border px-1 py-2 text-xs min-w-[25%]">
|
||||
时间
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
还款比例
|
||||
借贷机构数
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
借贷次数
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
审批额度
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
应还金额
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
审批与应还比例
|
||||
</th>
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
@ -913,76 +926,35 @@ onUnmounted(() => {
|
||||
</LTable>
|
||||
</div>
|
||||
|
||||
<!-- 近期借贷趋势表格 -->
|
||||
<LTitle title="近期借贷趋势" type="blue-green" />
|
||||
<div class="overflow-x-auto">
|
||||
<LTable :data="recentBorrowTrends" type="blue-green">
|
||||
<template #header>
|
||||
<th class="border px-1 py-2 text-xs min-w-[25%]">
|
||||
时间段
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
借贷金额
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
借贷次数
|
||||
</th>
|
||||
<th class="border px-1 py-2 text-xs min-w-[15%]">
|
||||
借贷机构数
|
||||
</th>
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<td class="border px-1 py-2 text-xs">
|
||||
{{ row.period }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs">
|
||||
{{ row.levelRange }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.loanCount }}
|
||||
</td>
|
||||
<td class="border px-1 py-2 text-xs text-center">
|
||||
{{ row.orgCount }}
|
||||
</td>
|
||||
</template>
|
||||
</LTable>
|
||||
</div>
|
||||
|
||||
<!-- 借贷行为总结 -->
|
||||
<LTitle title="借贷行为总结分析" type="blue-green" />
|
||||
<div class="summary-container bg-blue-50 p-4 rounded-md">
|
||||
<div class="text-xs text-gray-500 mb-2">
|
||||
数据时间范围:
|
||||
{{
|
||||
monthlyBorrowData[monthlyBorrowData.length - 1]
|
||||
?.month || "未知"
|
||||
}}
|
||||
-
|
||||
{{ monthlyBorrowData[0]?.month || "未知" }}
|
||||
数据时间范围: 近1年
|
||||
</div>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
|
||||
<div class="info-card p-3 bg-white rounded shadow-sm">
|
||||
<div class="text-sm text-gray-500">平均月借贷金额</div>
|
||||
<div class="text-sm text-gray-500">总申请次数</div>
|
||||
<div class="text-lg font-semibold">
|
||||
{{ behaviorSummary.avgBorrowAmount }}元
|
||||
{{ behaviorSummary.totalApplications }}次
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card p-3 bg-white rounded shadow-sm">
|
||||
<div class="text-sm text-gray-500">平均月还款金额</div>
|
||||
<div class="text-sm text-gray-500">借贷机构数</div>
|
||||
<div class="text-lg font-semibold">
|
||||
{{ behaviorSummary.avgRepayAmount }}元
|
||||
{{ behaviorSummary.totalOrgs }}家
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card p-3 bg-white rounded shadow-sm">
|
||||
<div class="text-sm text-gray-500">总借贷金额</div>
|
||||
<div class="text-sm text-gray-500">总审批额度</div>
|
||||
<div class="text-lg font-semibold">
|
||||
{{ behaviorSummary.totalBorrowAmount }}元
|
||||
{{ behaviorSummary.totalAmount }}元
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-card p-3 bg-white rounded shadow-sm">
|
||||
<div class="text-sm text-gray-500">平均借贷机构数</div>
|
||||
<div class="text-sm text-gray-500">月均申请次数</div>
|
||||
<div class="text-lg font-semibold">
|
||||
{{ behaviorSummary.avgOrgCount }}
|
||||
{{ behaviorSummary.avgMonthlyApplications }}次
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1003,7 +975,14 @@ onUnmounted(() => {
|
||||
>
|
||||
</div>
|
||||
<div class="text-gray-700">
|
||||
<p>· 借贷趋势: {{ behaviorSummary.trendDesc }}</p>
|
||||
<p>
|
||||
· 月均审批额度:
|
||||
{{ behaviorSummary.avgMonthlyAmount }}元
|
||||
</p>
|
||||
<p>
|
||||
· 月均应还金额:
|
||||
{{ behaviorSummary.avgMonthlyRepay }}元
|
||||
</p>
|
||||
<p>· 还款比例: {{ behaviorSummary.repayRatio }}</p>
|
||||
<p>· {{ behaviorSummary.riskDesc }}</p>
|
||||
</div>
|
||||
|
@ -9,6 +9,11 @@ const featureMap = {
|
||||
name: "婚姻状态",
|
||||
component: defineAsyncComponent(() => import("@/ui/CIDV044.vue")),
|
||||
},
|
||||
G09XM02: {
|
||||
name: "婚姻状态",
|
||||
component: defineAsyncComponent(() => import("@/ui/CIDV044.vue")),
|
||||
remark: '查询结果为"未婚或尚未登记结婚"时,表示婚姻登记处暂无相关的登记记录。婚姻状态信息由婚姻登记处逐级上报,可能存在数据遗漏或更新滞后。当前可查询的婚姻状态包括:未婚或尚未登记结婚、已婚、离异。如您对查询结果有疑问,请联系客服反馈。',
|
||||
},
|
||||
G27BJ05: {
|
||||
name: "借贷申请记录",
|
||||
component: defineAsyncComponent(() =>
|
||||
|
42
src/views/PromotionLink.vue
Normal file
42
src/views/PromotionLink.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 组件内容为空,因为实际处理逻辑在路由守卫中
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.promotion-link-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #3498db;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -9,7 +9,12 @@ const featureMap = {
|
||||
IDV044: {
|
||||
name: "婚姻状态",
|
||||
component: defineAsyncComponent(() => import("@/ui/CIDV044.vue")),
|
||||
remark: '查询结果为"未婚或尚未登记结婚"时,表示婚姻登记处暂无相关的登记记录。婚姻状态信息由婚姻登记处逐级上报,可能存在数据遗漏或更新滞后。当前可查询的婚姻状态包括:未婚或尚未登记结婚、已婚、离异、离异冷静期。如您对查询结果有疑问,请联系客服反馈。',
|
||||
remark: '查询结果为"未婚或尚未登记结婚"时,表示婚姻登记处暂无相关的登记记录。婚姻状态信息由婚姻登记处逐级上报,可能存在数据遗漏或更新滞后。当前可查询的婚姻状态包括:未婚或尚未登记结婚、已婚、离异。如您对查询结果有疑问,请联系客服反馈。',
|
||||
},
|
||||
G09XM02: {
|
||||
name: "婚姻状态",
|
||||
component: defineAsyncComponent(() => import("@/ui/CIDV044.vue")),
|
||||
remark: '查询结果为"未婚或尚未登记结婚"时,表示婚姻登记处暂无相关的登记记录。婚姻状态信息由婚姻登记处逐级上报,可能存在数据遗漏或更新滞后。当前可查询的婚姻状态包括:未婚或尚未登记结婚、已婚、离异。如您对查询结果有疑问,请联系客服反馈。',
|
||||
},
|
||||
G27BJ05: {
|
||||
name: "借贷申请记录",
|
||||
|
@ -1,19 +1,40 @@
|
||||
<template>
|
||||
<div class="bg-gradient-to-b from-[#aeceff] to-white min-h-screen relative">
|
||||
<!-- banner -->
|
||||
<div class="w-full flex justify-center" style="clip-path: ellipse(100% 95% at 50% 0%)">
|
||||
<img src="@/assets/images/hygj_banner.png" alt="核验工具" class="w-full h-auto" />
|
||||
<div
|
||||
class="w-full flex justify-center"
|
||||
style="clip-path: ellipse(100% 95% at 50% 0%)"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/hygj_banner.png"
|
||||
alt="核验工具"
|
||||
class="w-full h-auto"
|
||||
/>
|
||||
</div>
|
||||
<div class="p-6 -my-24 z-1000 absolute">
|
||||
<!-- 分类功能菜单 -->
|
||||
<van-skeleton :row="5" :loading="isFetching">
|
||||
<div v-for="(items, category) in categorizedMenuItems" :key="category" class="card mb-4">
|
||||
<h2 class="text-lg font-bold text-blue-500 mb-3">{{ category }}</h2>
|
||||
<div
|
||||
v-for="(items, category) in categorizedMenuItems"
|
||||
:key="category"
|
||||
class="card mb-4"
|
||||
>
|
||||
<h2 class="text-lg font-bold text-blue-500 mb-3">
|
||||
{{ category }}
|
||||
</h2>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div v-for="(item, index) in items" :key="index" class="flex flex-col items-center"
|
||||
@click="toInquire(item.product)">
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
class="flex flex-col items-center"
|
||||
@click="toInquire(item.product)"
|
||||
>
|
||||
<div class="bg-slate-100 rounded-full p-4">
|
||||
<img :src="item.icon" :alt="item.title" class="w-10 h-10" />
|
||||
<img
|
||||
:src="item.icon"
|
||||
:alt="item.title"
|
||||
class="w-10 h-10"
|
||||
/>
|
||||
</div>
|
||||
<p class="mt-2 text-sm text-center font-semibold">
|
||||
{{ item.title }}
|
||||
@ -24,7 +45,10 @@
|
||||
</van-skeleton>
|
||||
|
||||
<!-- 详情文本 -->
|
||||
<div class="card mt-4" v-if="Object.keys(categorizedMenuItems).length !== 0">
|
||||
<div
|
||||
class="card mt-4"
|
||||
v-if="Object.keys(categorizedMenuItems).length !== 0"
|
||||
>
|
||||
<h2 class="text-lg font-bold text-blue-500 mb-4">
|
||||
核验工具服务
|
||||
</h2>
|
||||
@ -32,9 +56,17 @@
|
||||
本平台提供全方位核验工具服务,助您全面防范风险。功能包括:
|
||||
</p>
|
||||
<van-skeleton :row="3" :loading="isFetching">
|
||||
<div v-for="(items, category) in categorizedMenuItems" :key="category" class="mt-4">
|
||||
<h3 class="font-bold text-md text-gray-700 mb-2">{{ category }}</h3>
|
||||
<ul class="list-disc list-inside space-y-2 text-gray-600">
|
||||
<div
|
||||
v-for="(items, category) in categorizedMenuItems"
|
||||
:key="category"
|
||||
class="mt-4"
|
||||
>
|
||||
<h3 class="font-bold text-md text-gray-700 mb-2">
|
||||
{{ category }}
|
||||
</h3>
|
||||
<ul
|
||||
class="list-disc list-inside space-y-2 text-gray-600"
|
||||
>
|
||||
<li v-for="(item, index) in items" :key="index">
|
||||
<strong>{{ item.title }}:</strong>
|
||||
{{ item.description }}
|
||||
@ -56,16 +88,16 @@ const { fetchRenderData, categorizedMenuItems, isFetching } = useMenuItems();
|
||||
const toInquire = (product) => {
|
||||
router.push("/inquire/" + product);
|
||||
};
|
||||
const webviewEnv = localStorage.getItem('webview_env')
|
||||
const webviewEnv = localStorage.getItem("webview_env");
|
||||
|
||||
onMounted(() => {
|
||||
if (webviewEnv) {
|
||||
router.replace("/ai"); // 或者使用 router.push("/target-page");
|
||||
}
|
||||
// if (webviewEnv) {
|
||||
// router.replace("/ai"); // 或者使用 router.push("/target-page");
|
||||
// }
|
||||
|
||||
fetchRenderData("verify");
|
||||
});
|
||||
const show = ref(false)
|
||||
const show = ref(false);
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -14,10 +14,10 @@ export default defineConfig({
|
||||
port: 5678, // 自定义端口号,可选
|
||||
strictPort: true, // 如果端口被占用则抛出错误而不是使用下一个可用端口
|
||||
proxy: {
|
||||
'/api/v1': {
|
||||
target: 'https://www.tianyuancha.cn', // 本地接口地址
|
||||
changeOrigin: true,
|
||||
},
|
||||
// '/api/v1': {
|
||||
// target: 'https://www.tianyuancha.cn', // 本地接口地址
|
||||
// changeOrigin: true,
|
||||
// },
|
||||
|
||||
"/api/v1/chat": {
|
||||
target: "https://www.tianyuancha.cn", // 本地接口地址
|
||||
@ -25,10 +25,10 @@ export default defineConfig({
|
||||
// rewrite: (path) => path.replace(/^\/api\/v1\/chat/, '/chat')
|
||||
},
|
||||
|
||||
// "/api/v1": {
|
||||
// target: "https://6m4685017o.goho.co", // 本地接口地址
|
||||
// changeOrigin: true,
|
||||
// },
|
||||
"/api/v1": {
|
||||
target: "https://6m4685017o.goho.co", // 本地接口地址
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
Loading…
Reference in New Issue
Block a user