This commit is contained in:
2026-02-28 17:30:07 +08:00
47 changed files with 3414 additions and 692 deletions

View File

@@ -117,6 +117,7 @@ declare global {
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
const useAgent: typeof import('./composables/useAgent.js')['useAgent']
const useAgentStore: typeof import('./stores/agentStore.js')['useAgentStore']
const useAliyunCaptcha: typeof import('./composables/useAliyunCaptcha.js')['default']
const useAnimate: typeof import('@vueuse/core')['useAnimate']
const useApiFetch: typeof import('./composables/useApiFetch.js')['default']
const useAppStore: typeof import('./stores/appStore.js')['useAppStore']

View File

@@ -127,6 +127,7 @@ const router = useRouter();
const show = defineModel("show");
import { useCascaderAreaData } from "@vant/area-data";
import { showToast } from "vant"; // 引入 showToast 方法
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
const emit = defineEmits(); // 确保 emit 可以正确使用
const props = defineProps({
isSelf: {
@@ -139,6 +140,7 @@ const props = defineProps({
},
});
const { isSelf, userName } = toRefs(props);
const { runWithCaptcha } = useAliyunCaptcha();
const form = ref({
referrer: "",
region: "",
@@ -173,20 +175,22 @@ const getSmsCode = async () => {
loadingSms.value = true;
const { data, error } = await useApiFetch("auth/sendSms")
.post({ mobile: form.value.mobile, actionType: "agentApply" })
.json();
loadingSms.value = false;
if (data.value && !error.value) {
if (data.value.code === 200) {
showToast({ message: "获取成功" });
startCountdown(); // 启动倒计时
} else {
showToast(data.value.msg);
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch("auth/sendSms")
.post({ mobile: form.value.mobile, actionType: "agentApply", captchaVerifyParam })
.json(),
(res) => {
loadingSms.value = false;
if (res.code === 200) {
showToast({ message: "获取成功" });
startCountdown(); // 启动倒计时
} else {
showToast(res.msg || "获取验证码失败");
}
}
}
);
};
let timer = null;

View File

@@ -269,6 +269,12 @@ const featureMap = {
name: "违约失信",
component: defineAsyncComponent(() => import("@/ui/CFLXG3D56.vue")),
},
// IVYZ0S0D:{
// name: "劳动仲裁信息查询(个人版)",
// component: defineAsyncComponent(() => import("@/ui/CIVYZ0S0D.vue")),
// remark: '劳动仲裁信息查询(个人版)用于查询个人在劳动仲裁方面的信息,包括劳动仲裁案件数量、劳动仲裁案件类型、劳动仲裁案件结果等。',
// },
FLXG0V4B: {
name: "司法涉诉",
@@ -381,10 +387,10 @@ const featureMap = {
name: "逾期风险综述",
component: defineAsyncComponent(() => import("@/ui/CDWBG8B4D/components/OverdueRiskSection.vue")),
},
// DWBG8B4D_CourtInfo: {
// name: "法院曝光台信息",
// component: defineAsyncComponent(() => import("@/ui/CDWBG8B4D/components/MultCourtInfoSection.vue")),
// },
DWBG8B4D_CourtInfo: {
name: "法院曝光台信息",
component: defineAsyncComponent(() => import("@/ui/CDWBG8B4D/components/MultCourtInfoSection.vue")),
},
DWBG8B4D_LoanEvaluation: {
name: "借贷评估",
component: defineAsyncComponent(() => import("@/ui/CDWBG8B4D/components/LoanEvaluationSection.vue")),
@@ -470,10 +476,10 @@ const featureMap = {
name: "关联风险监督",
component: defineAsyncComponent(() => import("@/ui/DWBG6A2C/components/RiskSupervisionSection.vue")),
},
// DWBG6A2C_CourtRiskInfo: {
// name: "法院风险信息",
// component: defineAsyncComponent(() => import("@/ui/DWBG6A2C/components/CourtRiskInfoSection.vue")),
// },
DWBG6A2C_CourtRiskInfo: {
name: "法院风险信息",
component: defineAsyncComponent(() => import("@/ui/DWBG6A2C/components/CourtRiskInfoSection.vue")),
},
// 贷款风险报告
JRZQ5E9F: {
name: "贷款风险评估",
@@ -678,6 +684,8 @@ const featureRiskLevels = {
'QCXG7A2B': 10, // 名下车辆
'JRZQ09J8': 10, // 收入评估
'JRZQ3C9R': 10, // 支付行为指数
// 'IVYZ0S0D': 10, // 个人仲裁信息
// 🔵 低风险类 - 权重 3-5
'IVYZ5733': 4, // 婚姻状态
@@ -685,6 +693,7 @@ const featureRiskLevels = {
'IVYZ3P9M': 4, // 学历信息查询(实时版)
'IVYZ0S0D': 20, // 劳动仲裁信息
// 📊 复合报告类 - 按子模块动态计算
'DWBG8B4D': 0, // 谛听多维报告(由子模块计算)
'DWBG6A2C': 0, // 司南报告(由子模块计算)
@@ -699,6 +708,7 @@ const featureRiskLevels = {
'DWBG8B4D_LeasingRisk': 18,
'DWBG8B4D_RiskSupervision': 25,
'DWBG8B4D_RiskWarningTab': 30,
'DWBG8B4D_CourtInfo': 31,
// 司南报告子模块
'DWBG6A2C_StandLiveInfo': 10,
@@ -713,6 +723,7 @@ const featureRiskLevels = {
'DWBG6A2C_CreditDetail': 15,
'DWBG6A2C_RentalBehavior': 15,
'DWBG6A2C_RiskSupervision': 25,
'DWBG6A2C_CourtRiskInfo': 29,
// 贷款风险评估子模块
'CJRZQ5E9F_RiskOverview': 25,

View File

@@ -7,6 +7,7 @@ import { useUserStore } from "@/stores/userStore";
import { showToast } from "vant";
import useApiFetch from "@/composables/useApiFetch";
import { registerByInviteCode } from "@/api/agent";
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
const emit = defineEmits(['register-success'])
const router = useRouter();
@@ -14,6 +15,7 @@ const route = useRoute();
const dialogStore = useDialogStore();
const agentStore = useAgentStore();
const userStore = useUserStore();
const { runWithCaptcha } = useAliyunCaptcha();
const appName = import.meta.env.VITE_APP_NAME || '全能查';
const phoneNumber = ref("");
const verificationCode = ref("");
@@ -80,26 +82,31 @@ async function sendVerificationCode() {
showToast({ message: "请先输入邀请码" });
return;
}
const actionType = hasAccount.value ? "bindMobile" : "agentApply";
const { data, error } = await useApiFetch("auth/sendSms")
.post({ mobile: phoneNumber.value, actionType })
.json();
if (data.value && !error.value) {
if (data.value.code === 200) {
showToast({ message: "获取成功" });
startCountdown();
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('registerVerificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(data.value.msg);
const actionType = hasAccount.value ? "bindMobile" : "agentApply";
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch("auth/sendSms")
.post({ mobile: phoneNumber.value, actionType, captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showToast({ message: "获取成功" });
startCountdown();
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('registerVerificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(res.msg || "获取验证码失败");
}
}
}
);
}
function startCountdown() {

View File

@@ -1,12 +1,14 @@
<script setup>
import { ref, computed, nextTick } from "vue";
import { useDialogStore } from "@/stores/dialogStore";
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
const emit = defineEmits(['bind-success'])
const router = useRouter();
const dialogStore = useDialogStore();
const agentStore = useAgentStore();
const userStore = useUserStore();
const { runWithCaptcha } = useAliyunCaptcha();
const appName = import.meta.env.VITE_APP_NAME || '全能查';
const phoneNumber = ref("");
const verificationCode = ref("");
@@ -37,25 +39,29 @@ async function sendVerificationCode() {
showToast({ message: "请输入有效的手机号" });
return;
}
const { data, error } = await useApiFetch("auth/sendSms")
.post({ mobile: phoneNumber.value, actionType: "bindMobile" })
.json();
if (data.value && !error.value) {
if (data.value.code === 200) {
showToast({ message: "获取成功" });
startCountdown();
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('bindPhoneVerificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(data.value.msg);
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch("auth/sendSms")
.post({ mobile: phoneNumber.value, actionType: "bindMobile", captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showToast({ message: "获取成功" });
startCountdown();
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('bindPhoneVerificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(res.msg || "获取验证码失败");
}
}
}
);
}
function startCountdown() {

View File

@@ -132,7 +132,7 @@ import { useRoute, useRouter } from "vue-router";
import { useUserStore } from "@/stores/userStore";
import { useDialogStore } from "@/stores/dialogStore";
import { useEnv } from "@/composables/useEnv";
import { showConfirmDialog } from "vant";
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
import Payment from "@/components/Payment.vue";
import BindPhoneOnlyDialog from "@/components/BindPhoneOnlyDialog.vue";
@@ -200,6 +200,7 @@ const dialogStore = useDialogStore();
const userStore = useUserStore();
const { isWeChat } = useEnv();
const appStore = useAppStore();
const { runWithCaptcha } = useAliyunCaptcha();
// 响应式数据
const showPayment = ref(false);
@@ -320,26 +321,11 @@ function handleBindSuccess() {
}
}
// 处理输入框点击事件
// 处理输入框点击事件(浏览/填写表单无需登录,仅付款时需要登录)
const handleInputClick = async () => {
if (!isLoggedIn.value) {
if (!isWeChat.value && props.type !== 'promotion') {
try {
await showConfirmDialog({
title: '提示',
message: '您需要登录后才能进行查询,是否前往登录?',
confirmButtonText: '前往登录',
cancelButtonText: '取消',
});
router.push('/login');
} catch {
// 用户点击取消,什么都不做
}
}
} else {
if (isWeChat.value && !userStore.mobile && props.type !== 'promotion') {
dialogStore.openBindPhone();
}
// 已登录且在微信环境下未绑定手机号时,提示绑定
if (isLoggedIn.value && isWeChat.value && !userStore.mobile && props.type !== 'promotion') {
dialogStore.openBindPhone();
}
};
@@ -440,22 +426,27 @@ async function sendVerificationCode() {
return;
}
const { data, error } = await useApiFetch("/auth/sendSms")
.post({ mobile: formData.mobile, actionType: "query" })
.json();
if (!error.value && data.value.code === 200) {
showToast({ message: "验证码发送成功", type: "success" });
startCountdown();
nextTick(() => {
const verificationCodeInput = document.getElementById('verificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch("/auth/sendSms")
.post({ mobile: formData.mobile, actionType: "query", captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showToast({ message: "验证码发送成功", type: "success" });
startCountdown();
nextTick(() => {
const verificationCodeInput = document.getElementById('verificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast({ message: res.msg || "验证码发送失败,请重试" });
}
});
} else {
showToast({ message: "验证码发送失败,请重试" });
}
}
);
}
let timer = null;

View File

@@ -6,11 +6,14 @@ import { useAgentStore } from "@/stores/agentStore";
import { useUserStore } from "@/stores/userStore";
import { showToast } from "vant";
import { realNameAuth } from "@/api/agent";
import useApiFetch from "@/composables/useApiFetch";
import { useAliyunCaptcha } from "@/composables/useAliyunCaptcha";
const router = useRouter();
const dialogStore = useDialogStore();
const agentStore = useAgentStore();
const userStore = useUserStore();
const { runWithCaptcha } = useAliyunCaptcha();
// 表单数据
const realName = ref("");
const idCard = ref("");
@@ -59,18 +62,22 @@ async function sendVerificationCode() {
showToast({ message: "请输入有效的手机号" });
return;
}
const { data, error } = await useApiFetch("auth/sendSms")
.post({ mobile: phoneNumber.value, actionType: "realName" })
.json();
if (data.value && !error.value) {
if (data.value.code === 200) {
showToast({ message: "获取成功" });
startCountdown();
} else {
showToast(data.value.msg);
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch("auth/sendSms")
.post({ mobile: phoneNumber.value, actionType: "realName", captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showToast({ message: "获取成功" });
startCountdown();
} else {
showToast(res.msg || "获取验证码失败");
}
}
}
);
}
function startCountdown() {

View File

@@ -0,0 +1,172 @@
import { showToast, showLoadingToast, closeToast } from "vant";
import useApiFetch from "@/composables/useApiFetch";
// 阿里云验证码场景 ID
const ALIYUN_CAPTCHA_SCENE_ID = "wynt39to";
// 是否启用加密模式(通过环境变量控制,非加密模式时前端不调用后端获取 EncryptedSceneId
const ENABLE_ENCRYPTED =
import.meta.env.VITE_ALIYUN_CAPTCHA_ENCRYPTED === "false";
let captchaInitialised = false;
/** 首次初始化后SDK 会异步调用 getInstance用此 Promise 在实例就绪后再 show */
let captchaReadyPromise = null;
let captchaReadyResolve = null;
async function ensureCaptchaInit() {
if (captchaInitialised || typeof window === "undefined") return;
if (typeof window.initAliyunCaptcha !== "function") return;
captchaInitialised = true;
window.captcha = null;
window.__lastBizResponse = null;
window.__onCaptchaBizSuccess = null;
captchaReadyPromise = new Promise((resolve) => {
captchaReadyResolve = resolve;
});
// 非加密模式:仅传 SceneId不调用后端接口
if (!ENABLE_ENCRYPTED) {
window.initAliyunCaptcha({
SceneId: ALIYUN_CAPTCHA_SCENE_ID,
mode: "popup",
element: "#captcha-element",
getInstance(instance) {
window.captcha = instance;
if (typeof captchaReadyResolve === "function") {
captchaReadyResolve();
captchaReadyResolve = null;
}
},
captchaVerifyCallback(param) {
return typeof window.__captchaVerifyCallback === "function"
? window.__captchaVerifyCallback(param)
: Promise.resolve({
captchaResult: false,
bizResult: false,
});
},
onBizResultCallback(bizResult) {
if (typeof window.__onBizResultCallback === "function") {
window.__onBizResultCallback(bizResult);
}
window.__lastBizResponse = null;
window.__onCaptchaBizSuccess = null;
},
slideStyle: { width: 360, height: 40 },
language: "cn",
});
return;
}
// 加密模式:先从后端获取 EncryptedSceneId再初始化
const { data, error } = await useApiFetch("/captcha/encryptedSceneId")
.post()
.json();
const resp = data?.value;
const encryptedSceneId = resp?.data?.encryptedSceneId;
if (error?.value || !encryptedSceneId) {
showToast({ message: "获取验证码参数失败,请稍后重试" });
captchaInitialised = false;
captchaReadyPromise = null;
captchaReadyResolve = null;
return;
}
window.initAliyunCaptcha({
SceneId: ALIYUN_CAPTCHA_SCENE_ID,
EncryptedSceneId: encryptedSceneId,
mode: "popup",
element: "#captcha-element",
getInstance(instance) {
window.captcha = instance;
if (typeof captchaReadyResolve === "function") {
captchaReadyResolve();
captchaReadyResolve = null;
}
},
captchaVerifyCallback(param) {
return typeof window.__captchaVerifyCallback === "function"
? window.__captchaVerifyCallback(param)
: Promise.resolve({ captchaResult: false, bizResult: false });
},
onBizResultCallback(bizResult) {
if (typeof window.__onBizResultCallback === "function") {
window.__onBizResultCallback(bizResult);
}
window.__lastBizResponse = null;
window.__onCaptchaBizSuccess = null;
},
slideStyle: { width: 360, height: 40 },
language: "cn",
});
}
/**
* 阿里云滑块验证码通用封装。
* 依赖 index.html 中已加载的 AliyunCaptcha.js初始化在首次调起时执行。
*
* @param { (captchaVerifyParam: string) => Promise<{ data: Ref, error: Ref }> } bizVerify - 业务请求函数,接收滑块参数,返回 useApiFetch 的 { data, error }
* @param { (res: any) => void } [onSuccess] - 业务成功回调code===200 时调用,传入接口返回的 data.value
*/
export function useAliyunCaptcha() {
/**
* 先弹出滑块,通过后执行 bizVerify(captchaVerifyParam),再根据结果调用 onSuccess。
*/
async function runWithCaptcha(bizVerify, onSuccess) {
if (typeof window === "undefined") {
showToast({ message: "验证码仅支持浏览器环境" });
return;
}
const loading = showLoadingToast({
message: "安全验证加载中...",
forbidClick: true,
duration: 0,
loadingType: "spinner",
});
try {
window.__captchaVerifyCallback = async (captchaVerifyParam) => {
window.__lastBizResponse = null;
const { data, error } = await bizVerify(captchaVerifyParam);
const result = data?.value ?? data;
if (error?.value || !result) {
return { captchaResult: false, bizResult: false };
}
window.__lastBizResponse = result;
const captchaOk = result.captchaVerifyResult !== false;
const bizOk = result.code === 200;
return { captchaResult: captchaOk, bizResult: bizOk };
};
window.__onBizResultCallback = (bizResult) => {
if (
bizResult === true &&
window.__lastBizResponse &&
typeof window.__onCaptchaBizSuccess === "function"
) {
window.__onCaptchaBizSuccess(window.__lastBizResponse);
}
};
await ensureCaptchaInit();
// 首次初始化时 SDK 会异步调用 getInstance需等待实例就绪后再 show
if (captchaReadyPromise) {
await captchaReadyPromise;
captchaReadyPromise = null;
}
if (!window.captcha) {
showToast({ message: "验证码未加载,请刷新页面重试" });
return;
}
window.__onCaptchaBizSuccess = onSuccess;
window.captcha.show();
} finally {
closeToast();
}
}
return { runWithCaptcha };
}
export default useAliyunCaptcha;

View File

@@ -6,12 +6,12 @@ export function useSEO() {
// 默认SEO信息
const defaultSEO = {
title: "全能查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用",
title: "全能查官网_个人婚姻状态报告_综合风险排查工具箱",
description:
"全能查,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。",
"全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。",
keywords:
"大数据风险报告查询、大数据风险评估、大数据分析报告、个人大数据风险查询、小微企业风险、贷前风险背调、代理管理平台、免费开通代理、风险管控平台、信用风险分析、企业风险报告、贷前信用审核、失信人名单查询、被执行人信息、信用黑名单查询",
url: "https://www.zhinengcha.cn",
"全能查,婚姻状态核实,风险排查工具,个人风险预警,第三方背调,商业信用评估",
url: "https://www.quannengcha.com",
};
// 页面SEO配置
@@ -137,7 +137,7 @@ export function useSEO() {
mainEntity: {
"@type": "Organization",
name: "全能查",
url: "https://www.zhinengcha.cn/",
url: "https://www.quannengcha.com/",
description:
"专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用",
},
@@ -153,11 +153,59 @@ export function useSEO() {
const updateSEOByRoute = () => {
const routeConfigs = {
"/": {
title: "全能查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用",
title: "全能查官网_个人婚姻状态报告_综合风险排查工具箱",
description:
"全能查,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。",
"全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。",
keywords:
"大数据风险报告查询、大数据风险评估、大数据分析报告、个人大数据风险查询、小微企业风险、贷前风险背调、代理管理平台、免费开通代理、风险管控平台、信用风险分析、企业风险报告、贷前信用审核、失信人名单查询、被执行人信息、信用黑名单查询",
"全能查,婚姻状态核实,风险排查工具,个人风险预警,第三方背调,商业信用评估",
},
"/agent/system-guide": {
title: "全能查合作政策指南_合作伙伴权益与结算说明_官方文档",
description:
"全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。",
keywords: "合作伙伴政策,服务费结算,渠道等级说明,业务操作指南,代理系统后台",
},
// 个人查询
'/inquire/riskassessment': {
title: '个人综合风险分析_履约能力画像_多维数据检测_全能查',
description: '全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。',
keywords: '个人风险检测,履约能力分析,综合风险指数,信用健康度,个人数据画像'
},
// 企业查询
'/inquire/companyinfo': {
title: '企业工商信用画像_经营异常与商业风险透视_全能查',
description: '全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。',
keywords: '企业信用评估,工商背景核验,商业风险评估,公司经营异常,合作方背景核实'
},
// 贷前风险
'/inquire/preloanbackgroundcheck': {
title: '综合履约评分检测_多平台履约记录分析_个人财务履约报告_天远助手',
description: '天远助手提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。',
keywords: '综合评分检测,多重履约压力分析,履约能力评估,综合评分优化,个人数据画像'
},
// 婚恋风险
'/inquire/marriage': {
title: '婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查',
description: '全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。',
keywords: '婚前背景报告,恋爱对象风险,情感安全评估,司法记录核验,家庭风险防范'
},
// 入职背调
'/inquire/backgroundcheck': {
title: '职场背景核验报告_候选人职业风险与竞业核验_全能查',
description: '全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。',
keywords: '员工入职背调,职业背景核实,竞业限制评估,职场信用报告,候选人风险筛查'
},
// 家政风险
'/inquire/homeservice': {
title: '家政人员背景核实_保姆月嫂司法安全评估_全能查',
description: '全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。',
keywords: '保姆背景核验,家政风险筛查,月嫂司法记录,雇佣安全评估,家政人员核验'
},
'/inquire/consumerFinanceReport': {
title: '个人履约能力评估_经济风险与收支压力参考_全能查',
description: '全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。',
keywords: '履约能力评估,经济风险指数,综合评分波动,资金压力分析,财务健康度'
},
"/agent": {
title: "全能查代理 - 免费开通代理权限 | 大数据风险报告代理",
@@ -191,6 +239,11 @@ export function useSEO() {
"全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。",
keywords: "客服中心, 在线客服, 技术支持, 问题反馈, 全能查客服",
},
"/promote": {
title: "全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查",
description:"全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。",
keywords:"风控系统代理,风险评估平台招商,平台渠道合作,企业服务创业,全能查合伙人",
},
};
const currentPath = route?.path || "/";
@@ -198,7 +251,7 @@ export function useSEO() {
updateSEO({
...config,
url: `https://www.zhinengcha.cn${currentPath}`,
url: `https://www.quannengcha.com${currentPath}`,
});
};

View File

@@ -509,7 +509,7 @@ router.afterEach((to) => {
const seoConfig = {
title: `${to.meta.title} - 全能查`,
description: `全能查${to.meta.title}页面,提供专业的大数据风险管控服务。`,
url: `https://www.zhinengcha.cn${to.path}`,
url: `https://www.quannengcha.com${to.path}`,
};
updateSEO(seoConfig);
}

481
src/ui/CIVYZ0S0D.vue Normal file
View File

@@ -0,0 +1,481 @@
<script setup lang="ts">
import { computed } from 'vue';
// 接收父组件传入的 props
const props = defineProps({
data: Object,
params: Object,
});
// 定义组件名称,用于在控制台输出调试信息
const componentName = 'IVYZ0S0D';
// 将 props.data 赋值给 reportData 变量
let reportData: any = props.data || {};
// 如果 reportData 不为空,则将其赋值给变量
if (reportData) {
console.log(`${componentName} 组件接收到的数据:`, reportData);
} else {
console.log(`${componentName} 组件未接收到数据`);
}
// 获取状态描述文本
const getStatusText = (value: number) => {
if (value === 1) return '未命中';
if (value === 2) return '命中';
return '未知';
};
// 获取通知函状态描述文本
const getNoticeLetterStatusText = (value: number) => {
if (value === 1) return '未命中';
if (value === 2) return '命中';
return '未知';
};
// 获取通知函期间描述文本
const getNoticeLetterPeriodText = (period: number) => {
const periodMap: Record<number, string> = {
0: '没有被发送通知函',
1: '近2年内',
2: '2-4年',
3: '5年以上'
};
return periodMap[period] || '未知期间';
};
// 获取背景颜色
const getBackgroundColor = (value: number) => {
if (value === 1) return '#e8f5e8'; // 浅绿色
if (value === 2) return '#ffe8e8'; // 浅红色
return '#f5f5f5'; // 默认灰色
};
// 获取边框颜色
const getBorderColor = (value: number) => {
if (value === 1) return '#4caf50'; // 绿色边框
if (value === 2) return '#f44336'; // 红色边框
return '#ccc'; // 默认灰色边框
};
// 判断是否应该隐藏该条目(如果是带时间范围的"未命中"
const shouldHideItem = (itemText: string) => {
// 检查是否包含时间范围关键词并且结果是"未命中"
const timeRangeKeywords = ['近2年', '近3年', '近4年', '近5年', '2-4年', '5年以上'];
const isTimeRangeItem = timeRangeKeywords.some(keyword => itemText.includes(keyword));
const isNoRisk = itemText.includes('未命中');
// 如果是时间范围项目且结果是"未命中",则隐藏
return isTimeRangeItem && isNoRisk;
};
// 获取风险类型数组 - 所有模块都显示
const riskTypes = computed(() => {
const risks: {title: string, value: number, details: string | string[], bgColor: string, borderColor: string}[] = [];
// 总体风险
if (reportData.risk_flag !== undefined) {
risks.push({
title: '总体风险',
value: reportData.risk_flag,
details: getStatusText(reportData.risk_flag),
bgColor: getBackgroundColor(reportData.risk_flag),
borderColor: getBorderColor(reportData.risk_flag)
});
}
// 失信风险
if (reportData.dishonesty && reportData.dishonesty.dishonesty !== undefined) {
risks.push({
title: '失信风险',
value: reportData.dishonesty.dishonesty,
details: getStatusText(reportData.dishonesty.dishonesty),
bgColor: getBackgroundColor(reportData.dishonesty.dishonesty),
borderColor: getBorderColor(reportData.dishonesty.dishonesty)
});
}
// 高消费限制风险
if (reportData.high_consumption && reportData.high_consumption.high_consumption !== undefined) {
risks.push({
title: '高消费限制风险',
value: reportData.high_consumption.high_consumption,
details: getStatusText(reportData.high_consumption.high_consumption),
bgColor: getBackgroundColor(reportData.high_consumption.high_consumption),
borderColor: getBorderColor(reportData.high_consumption.high_consumption)
});
}
// 劳动争议风险
if (reportData.labor_disputes) {
let details: string[] = [];
if (reportData.labor_disputes.labor_disputes !== undefined) {
details.push(`当前: ${getStatusText(reportData.labor_disputes.labor_disputes)}`);
}
if (reportData.labor_disputes.labor_disputes_3y !== undefined) {
const detail = `近3年: ${getStatusText(reportData.labor_disputes.labor_disputes_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.labor_disputes.labor_disputes_5y !== undefined) {
const detail = `近5年: ${getStatusText(reportData.labor_disputes.labor_disputes_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.labor_disputes.labor_contract !== undefined) {
details.push(`劳动合同: ${getStatusText(reportData.labor_disputes.labor_contract)}`);
}
if (reportData.labor_disputes.labor_relation !== undefined) {
details.push(`劳动关系: ${getStatusText(reportData.labor_disputes.labor_relation)}`);
}
if (reportData.labor_disputes.labor_relation_3y !== undefined) {
const detail = `近3年劳动关系: ${getStatusText(reportData.labor_disputes.labor_relation_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.labor_disputes.labor_relation_5y !== undefined) {
const detail = `近5年劳动关系: ${getStatusText(reportData.labor_disputes.labor_relation_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (details.length > 0) {
risks.push({
title: '劳动争议风险',
value: Math.max(...Object.values(reportData.labor_disputes).filter(v => typeof v === 'number')),
details: details,
bgColor: getBackgroundColor(Math.max(...Object.values(reportData.labor_disputes).filter(v => typeof v === 'number'))),
borderColor: getBorderColor(Math.max(...Object.values(reportData.labor_disputes).filter(v => typeof v === 'number')))
});
}
}
// 社会保险纠纷风险
if (reportData.social_insurance) {
let details: string[] = [];
if (reportData.social_insurance.social_insurance !== undefined) {
details.push(`社保纠纷: ${getStatusText(reportData.social_insurance.social_insurance)}`);
}
if (reportData.social_insurance.pension !== undefined) {
details.push(`养老纠纷: ${getStatusText(reportData.social_insurance.pension)}`);
}
if (reportData.social_insurance.pension_3y !== undefined) {
const detail = `近3年养老: ${getStatusText(reportData.social_insurance.pension_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.pension_5y !== undefined) {
const detail = `近5年养老: ${getStatusText(reportData.social_insurance.pension_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.injury_insurance !== undefined) {
details.push(`工伤纠纷: ${getStatusText(reportData.social_insurance.injury_insurance)}`);
}
if (reportData.social_insurance.injury_insurance_3y !== undefined) {
const detail = `近3年工伤: ${getStatusText(reportData.social_insurance.injury_insurance_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.injury_insurance_5y !== undefined) {
const detail = `近5年工伤: ${getStatusText(reportData.social_insurance.injury_insurance_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.unemployment_insurance !== undefined) {
details.push(`失业纠纷: ${getStatusText(reportData.social_insurance.unemployment_insurance)}`);
}
if (reportData.social_insurance.unemployment_insurance_3y !== undefined) {
const detail = `近3年失业: ${getStatusText(reportData.social_insurance.unemployment_insurance_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.unemployment_insurance_5y !== undefined) {
const detail = `近5年失业: ${getStatusText(reportData.social_insurance.unemployment_insurance_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.medical_insurance !== undefined) {
details.push(`医疗纠纷: ${getStatusText(reportData.social_insurance.medical_insurance)}`);
}
if (reportData.social_insurance.medical_insurance_3y !== undefined) {
const detail = `近3年医疗: ${getStatusText(reportData.social_insurance.medical_insurance_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.medical_insurance_5y !== undefined) {
const detail = `近5年医疗: ${getStatusText(reportData.social_insurance.medical_insurance_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.maternity_insurance !== undefined) {
details.push(`生育纠纷: ${getStatusText(reportData.social_insurance.maternity_insurance)}`);
}
if (reportData.social_insurance.maternity_insurance_3y !== undefined) {
const detail = `近3年生育: ${getStatusText(reportData.social_insurance.maternity_insurance_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.social_insurance.maternity_insurance_5y !== undefined) {
const detail = `近5年生育: ${getStatusText(reportData.social_insurance.maternity_insurance_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (details.length > 0) {
risks.push({
title: '社会保险纠纷风险',
value: Math.max(...Object.values(reportData.social_insurance).filter(v => typeof v === 'number')),
details: details,
bgColor: getBackgroundColor(Math.max(...Object.values(reportData.social_insurance).filter(v => typeof v === 'number'))),
borderColor: getBorderColor(Math.max(...Object.values(reportData.social_insurance).filter(v => typeof v === 'number')))
});
}
}
// 福利待遇纠纷
if (reportData.welfare_disputes && reportData.welfare_disputes.welfare !== undefined) {
risks.push({
title: '福利待遇纠纷',
value: reportData.welfare_disputes.welfare,
details: getStatusText(reportData.welfare_disputes.welfare),
bgColor: getBackgroundColor(reportData.welfare_disputes.welfare),
borderColor: getBorderColor(reportData.welfare_disputes.welfare)
});
}
// 人事争议类纠纷
if (reportData.personnel_disputes) {
let details: string[] = [];
if (reportData.personnel_disputes.personnel_dispute !== undefined) {
details.push(`人事争议: ${getStatusText(reportData.personnel_disputes.personnel_dispute)}`);
}
if (reportData.personnel_disputes.resignation_dispute !== undefined) {
details.push(`辞职争议: ${getStatusText(reportData.personnel_disputes.resignation_dispute)}`);
}
if (reportData.personnel_disputes.resignation_dispute_3y !== undefined) {
const detail = `近3年辞职: ${getStatusText(reportData.personnel_disputes.resignation_dispute_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.personnel_disputes.resignation_dispute_5y !== undefined) {
const detail = `近5年辞职: ${getStatusText(reportData.personnel_disputes.resignation_dispute_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.personnel_disputes.dismissal_dispute !== undefined) {
details.push(`辞退争议: ${getStatusText(reportData.personnel_disputes.dismissal_dispute)}`);
}
if (reportData.personnel_disputes.dismissal_dispute_3y !== undefined) {
const detail = `近3年辞退: ${getStatusText(reportData.personnel_disputes.dismissal_dispute_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.personnel_disputes.dismissal_dispute_5y !== undefined) {
const detail = `近5年辞退: ${getStatusText(reportData.personnel_disputes.dismissal_dispute_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (details.length > 0) {
risks.push({
title: '人事争议类纠纷',
value: Math.max(...Object.values(reportData.personnel_disputes).filter(v => typeof v === 'number')),
details: details,
bgColor: getBackgroundColor(Math.max(...Object.values(reportData.personnel_disputes).filter(v => typeof v === 'number'))),
borderColor: getBorderColor(Math.max(...Object.values(reportData.personnel_disputes).filter(v => typeof v === 'number')))
});
}
}
// 仲裁相关案件
if (reportData.arbitration) {
let details: string[] = [];
if (reportData.arbitration.arbitration_confirmation !== undefined) {
details.push(`仲裁确认: ${getStatusText(reportData.arbitration.arbitration_confirmation)}`);
}
if (reportData.arbitration.arbitration_confirmation_3y !== undefined) {
const detail = `近3年仲裁确认: ${getStatusText(reportData.arbitration.arbitration_confirmation_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.arbitration.arbitration_confirmation_5y !== undefined) {
const detail = `近5年仲裁确认: ${getStatusText(reportData.arbitration.arbitration_confirmation_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.arbitration.arbitration_revocation !== undefined) {
details.push(`仲裁撤销: ${getStatusText(reportData.arbitration.arbitration_revocation)}`);
}
if (reportData.arbitration.arbitration_revocation_3y !== undefined) {
const detail = `近3年仲裁撤销: ${getStatusText(reportData.arbitration.arbitration_revocation_3y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (reportData.arbitration.arbitration_revocation_5y !== undefined) {
const detail = `近5年仲裁撤销: ${getStatusText(reportData.arbitration.arbitration_revocation_5y)}`;
if (!shouldHideItem(detail)) {
details.push(detail);
}
}
if (details.length > 0) {
risks.push({
title: '仲裁相关案件',
value: Math.max(...Object.values(reportData.arbitration).filter(v => typeof v === 'number')),
details: details,
bgColor: getBackgroundColor(Math.max(...Object.values(reportData.arbitration).filter(v => typeof v === 'number'))),
borderColor: getBorderColor(Math.max(...Object.values(reportData.arbitration).filter(v => typeof v === 'number')))
});
}
}
// 通知函触达
if (reportData.notice_letter && reportData.notice_letter.notice_letter !== undefined) {
let statusText = getNoticeLetterStatusText(reportData.notice_letter.notice_letter);
let periodText = '';
if (reportData.notice_letter.notice_letter_period !== undefined) {
periodText = `期间: ${getNoticeLetterPeriodText(reportData.notice_letter.notice_letter_period)}`;
}
const detailParts = [`状态: ${statusText}`];
if (periodText) {
detailParts.push(periodText);
}
risks.push({
title: '通知函触达',
value: reportData.notice_letter.notice_letter,
details: detailParts,
bgColor: getBackgroundColor(reportData.notice_letter.notice_letter),
borderColor: getBorderColor(reportData.notice_letter.notice_letter)
});
}
return risks;
});
// 检查是否至少有一个数据类别有内容
const hasAnyData = computed(() => {
return riskTypes.value.length > 0;
});
</script>
<template>
<div class="ivyz0s0d-container">
<!-- 风险卡片网格 -->
<div v-if="hasAnyData" class="risk-cards-grid">
<div
v-for="(risk, index) in riskTypes"
:key="index"
class="risk-card"
:style="{ backgroundColor: risk.bgColor, borderLeft: `4px solid ${risk.borderColor}` }"
>
<div class="risk-card__content">
<h4 class="risk-card__title">{{ risk.title }}</h4>
<div class="risk-card__status">
<!-- details 是字符串时显示单行 -->
<p v-if="typeof risk.details === 'string'" class="risk-detail-item">{{ risk.details }}</p>
<!-- details 是数组时每项占一行 -->
<p
v-else
v-for="(detail, idx) in risk.details"
:key="idx"
class="risk-detail-item"
>{{ detail }}</p>
</div>
</div>
</div>
</div>
<!-- 无数据提示 -->
<div v-if="!hasAnyData" class="no-data">
<p>暂无相关风险数据</p>
</div>
</div>
</template>
<style scoped>
.ivyz0s0d-container {
padding: 20px;
font-family: Arial, sans-serif;
}
.risk-cards-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.risk-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.risk-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.risk-card__content {
display: flex;
flex-direction: column;
}
.risk-card__title {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: bold;
color: #333;
}
.risk-card__status {
margin: 0;
font-size: 14px;
color: #666;
}
.risk-detail-item {
margin: 0 0 4px 0;
line-height: 1.4;
}
.risk-detail-item:last-child {
margin-bottom: 0;
}
.no-data {
text-align: center;
color: #999;
font-style: italic;
padding: 20px;
}
</style>

View File

@@ -18,45 +18,127 @@ const feature = ref(route.params.feature);
// 获取产品信息
const featureData = ref({});
// 检查是否可以查询:已登录且已绑定手机号
// 检查是否可以查询:不需要登录,直接允许查询
const canQuery = computed(() => {
return isLoggedIn.value && mobile.value && mobile.value.trim() !== '';
return true; // 允许未登录用户查询
});
// 检查登录状态和手机号绑定
// 初始化:检查支付回调并加载产品信息
onMounted(async () => {
// 检查支付回调
isFinishPayment();
// 检查是否已登录
// 如果有 token尝试加载用户信息但不强制
const token = localStorage.getItem("token");
if (!token) {
showToast({ message: "请先登录才能使用查询功能" });
router.replace("/login");
return;
if (token) {
try {
await userStore.fetchUserInfo();
} catch (error) {
console.warn("获取用户信息失败(可选):", error);
// 不影响查询功能,继续执行
}
}
// 获取用户信息(包括手机号)
try {
await userStore.fetchUserInfo();
} catch (error) {
console.error("获取用户信息失败:", error);
showToast({ message: "获取用户信息失败,请重新登录" });
router.replace("/login");
return;
// 添加婚姻查询的特殊处理
if (feature.value === 'marriage') {
showMarriageUpgradeNotice();
}
// 检查是否已绑定手机号
if (!mobile.value || mobile.value.trim() === '') {
showToast({ message: "请先绑定手机号才能使用查询功能" });
router.replace("/me");
return;
}
// 已登录且已绑定手机号,可以查询
// 直接加载产品信息,不需要登录
await getProduct();
});
function showMarriageUpgradeNotice() {
// 创建自定义弹窗
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
modal.style.display = 'flex';
modal.style.justifyContent = 'center';
modal.style.alignItems = 'center';
modal.style.zIndex = '9999';
modal.innerHTML = `
<div style="
background: white;
border-radius: 12px;
padding: 24px;
margin: 20px;
max-width: 400px;
width: 90%;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
position: relative;
overflow-y: auto;
max-height: 90vh;
">
<h3 style="
color: #333;
text-align: center;
margin-top: 0;
margin-bottom: 16px;
font-size: 18px;
">亲爱的用户,您好!</h3>
<p style="
color: #666;
line-height: 1.6;
margin: 8px 0;
text-align: center;
font-size: 14px;
">婚恋报告正在优化升级中,需要查询请前往天远查。</p>
<div style="display: flex; gap: 12px; margin-bottom: 16px;">
<button id="jumpNowBtn" style="
flex: 1;
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
color: white;
border: none;
padding: 12px 0;
border-radius: 25px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
">是</button>
<button id="remindLaterBtn" style="
flex: 1;
background: #f8f9fa;
color: #666;
border: 1px solid #ddd;
padding: 12px 0;
border-radius: 25px;
cursor: pointer;
font-size: 14px;
">否</button>
</div>
</div>
`;
document.body.appendChild(modal);
// 绑定按钮事件
const jumpNowBtn = modal.querySelector('#jumpNowBtn');
const remindLaterBtn = modal.querySelector('#remindLaterBtn');
jumpNowBtn.addEventListener('click', () => {
// 跳转到新版首页
window.open('https://www.tianyuancha.cn/', '_blank');
document.body.removeChild(modal);
});
remindLaterBtn.addEventListener('click', () => {
// 跳转到指定网站
window.location.href = 'https://www.quannengcha.com/';
});
}
function isFinishPayment() {
const query = new URLSearchParams(window.location.search);
let orderNo = query.get("out_trade_no");
@@ -88,20 +170,6 @@ async function getProduct() {
</script>
<template>
<!-- 未登录或未绑定手机号提示 -->
<div v-if="!canQuery" class="min-h-screen flex items-center justify-center p-6">
<div class="text-center">
<div class="text-lg font-bold mb-4">无法使用查询功能</div>
<div class="text-gray-600 mb-6">
<span v-if="!isLoggedIn">请先登录</span>
<span v-else>请先绑定手机号</span>
</div>
<button @click="router.push(isLoggedIn ? '/me' : '/login')"
class="px-6 py-3 bg-primary text-white rounded-lg">
{{ isLoggedIn ? '去绑定手机号' : '去登录' }}
</button>
</div>
</div>
<!-- 已登录且已绑定手机号可以使用查询功能 -->
<InquireForm v-else :type="'normal'" :feature="feature" :feature-data="featureData" />
<!-- 直接显示查询表单不需要登录 -->
<InquireForm :type="'normal'" :feature="feature" :feature-data="featureData" />
</template>

View File

@@ -33,6 +33,8 @@
<script setup>
import { aesDecrypt } from "@/utils/crypto";
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
const { runWithCaptcha } = useAliyunCaptcha()
const showApplyPopup = ref(false);
const route = useRoute();
const router = useRouter();
@@ -48,6 +50,7 @@ const agentApply = () => {
showApplyPopup.value = true;
};
// 跳转到首页
const goToHome = () => {
router.replace("/promote");
@@ -77,50 +80,41 @@ onBeforeMount(async () => {
await store.fetchAgentStatus();
}
});
import { applyForAgent, registerByInviteCode } from "@/api/agent";
import useApiFetch from '@/composables/useApiFetch'
const submitApplication = async (formData) => {
const { region, mobile, wechat_id, code, referrer } = formData;
// 根据是否已登录选择不同的API
const isLoggedIn = !!localStorage.getItem("token");
const apiCall = isLoggedIn ? applyForAgent : registerByInviteCode;
let postData = {
region,
mobile,
wechat_id,
code,
referrer,
};
const apiUrl = isLoggedIn ? 'agent/apply' : 'agent/register/invite';
const { data, error } = await apiCall(postData);
if (data.value && !error.value) {
if (data.value.code === 200) {
showApplyPopup.value = false;
showToast({ message: "注册成功,您已成为代理!" });
// 更新token和状态
if (data.value.data.accessToken) {
localStorage.setItem("token", data.value.data.accessToken);
localStorage.setItem(
"refreshAfter",
data.value.data.refreshAfter
);
localStorage.setItem(
"accessExpire",
data.value.data.accessExpire
);
// 重新获取代理状态
await store.fetchAgentStatus();
await userStore.fetchUserInfo();
// 跳转到代理主页
router.replace("/agent");
// 使用滑块验证码保护申请接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch(apiUrl)
.post({ region, mobile, wechat_id, code, referrer, captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showApplyPopup.value = false;
showToast({ message: "注册成功,您已成为代理!" });
// 更新token和状态
if (res.data.accessToken) {
localStorage.setItem("token", res.data.accessToken);
localStorage.setItem("refreshAfter", res.data.refreshAfter);
localStorage.setItem("accessExpire", res.data.accessExpire);
// 重新获取代理状态
store.fetchAgentStatus();
userStore.fetchUserInfo();
// 跳转到代理主页
router.replace("/agent");
}
} else {
showToast({ message: res.msg || "申请失败" });
}
} else {
console.log("申请失败", data.value);
}
}
);
};
</script>

View File

@@ -6,11 +6,13 @@ import { useUserStore } from '@/stores/userStore'
import { useRouter, useRoute } from 'vue-router'
import { mobileCodeLogin } from '@/api/user'
import useApiFetch from '@/composables/useApiFetch'
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
const router = useRouter()
const route = useRoute()
const agentStore = useAgentStore()
const userStore = useUserStore()
const { runWithCaptcha } = useAliyunCaptcha()
const phoneNumber = ref('')
const verificationCode = ref('')
@@ -35,25 +37,29 @@ async function sendVerificationCode() {
return
}
const { data, error } = await useApiFetch('auth/sendSms')
.post({ mobile: phoneNumber.value, actionType: 'login' })
.json()
if (data.value && !error.value) {
if (data.value.code === 200) {
showToast({ message: "获取成功" });
startCountdown()
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('verificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(data.value.msg)
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch('auth/sendSms')
.post({ mobile: phoneNumber.value, actionType: 'login', captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showToast({ message: "获取成功" });
startCountdown()
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('verificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(res.msg || "获取验证码失败")
}
}
}
);
}
function startCountdown() {

View File

@@ -32,7 +32,7 @@ onMounted(() => {
title: '404 - 页面未找到 | 全能查',
description: '抱歉,您访问的页面不存在。全能查专业大数据风险管控平台,提供大数据风险报告查询、婚姻状况查询、个人信用评估等服务。',
keywords: '404, 页面未找到, 全能查, 大数据风险管控',
url: 'https://www.zhinengcha.cn/404'
url: 'https://www.quannengcha.com/404'
})
})
</script>

View File

@@ -6,11 +6,13 @@ import { useAgentStore } from '@/stores/agentStore'
import { useUserStore } from '@/stores/userStore'
import { useRoute, useRouter } from 'vue-router'
import useApiFetch from '@/composables/useApiFetch'
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
const router = useRouter()
const route = useRoute()
const agentStore = useAgentStore()
const userStore = useUserStore()
const { runWithCaptcha } = useAliyunCaptcha()
const appName = import.meta.env.VITE_APP_NAME || '全能查';
const phoneNumber = ref('')
@@ -84,25 +86,28 @@ async function sendVerificationCode() {
return
}
const { data, error } = await useApiFetch('auth/sendSms')
.post({ mobile: phoneNumber.value, actionType: 'agentApply' })
.json()
if (data.value && !error.value) {
if (data.value.code === 200) {
showToast({ message: "获取成功" });
startCountdown()
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('verificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(data.value.msg)
// 使用滑块验证码保护发送短信接口
runWithCaptcha(
(captchaVerifyParam) =>
useApiFetch('auth/sendSms')
.post({ mobile: phoneNumber.value, actionType: 'agentApply', captchaVerifyParam })
.json(),
(res) => {
if (res.code === 200) {
showToast({ message: "获取成功" });
startCountdown()
// 聚焦到验证码输入框
nextTick(() => {
const verificationCodeInput = document.getElementById('verificationCode');
if (verificationCodeInput) {
verificationCodeInput.focus();
}
});
} else {
showToast(res.msg || "获取验证码失败")
}
}
}
);
}
function startCountdown() {

View File

@@ -22,41 +22,96 @@
<div>
<!-- 提现卡片 -->
<div class="rounded-xl shadow-lg p-6 mb-4" style="background: linear-gradient(135deg, var(--van-theme-primary-light), rgba(255,255,255,0.8));">
<div class="flex items-center mb-6">
<van-icon name="alipay" class="text-xl mr-2" style="color: #1677FF;" />
<h1 class="text-xl font-bold" style="color: var(--van-text-color);">支付宝提现</h1>
</div>
<!-- 支付宝账号 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">支付宝账号</label>
<van-field v-model="alipayAccount" placeholder="请输入支付宝账号"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm"
:rules="[{ required: true, message: ' ' }]">
<template #left-icon>
<van-icon name="phone-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
<small class="text-xs mt-1 block" style="color: var(--van-text-color-2);">可填写支付宝账户绑定的手机号</small>
</div>
<!-- 支付宝实名姓名 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">实名姓名</label>
<van-field v-model="realName" placeholder="请输入支付宝认证姓名"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm" :rules="[
{
required: true,
message: ' ',
validator: (val) =>
/^[\u4e00-\u9fa5]{2,4}$/.test(val),
},
]">
<template #left-icon>
<van-icon name="contact-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
<small class="text-xs mt-1 block" style="color: var(--van-text-color-2);">请填写支付宝账户认证的真实姓名</small>
</div>
<!-- 提现方式切换 -->
<van-tabs v-model:active="withdrawalType" shrink class="mb-4" title-active-color="var(--van-theme-primary)" @change="onWithdrawalTypeChange">
<van-tab title="支付宝" :name="1">
<div class="pt-2">
<div class="flex items-center mb-4">
<van-icon name="alipay" class="text-xl mr-2" style="color: #1677FF;" />
<span class="text-base font-medium" style="color: var(--van-text-color);">支付宝提现</span>
</div>
<!-- 支付宝账号 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">支付宝账号</label>
<van-field v-model="alipayAccount" placeholder="请输入支付宝账号"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm"
:rules="[{ required: true, message: ' ' }]">
<template #left-icon>
<van-icon name="phone-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
<small class="text-xs mt-1 block" style="color: var(--van-text-color-2);">可填写支付宝账户绑定的手机号</small>
</div>
<!-- 支付宝实名姓名 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">实名姓名</label>
<van-field v-model="realName" placeholder="请输入支付宝认证姓名"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm" :rules="[
{
required: true,
message: ' ',
validator: (val) =>
/^[\u4e00-\u9fa5]{2,4}$/.test(val),
},
]">
<template #left-icon>
<van-icon name="contact-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
<small class="text-xs mt-1 block" style="color: var(--van-text-color-2);">请填写支付宝账户认证的真实姓名</small>
</div>
</div>
</van-tab>
<van-tab title="银行卡" :name="2">
<div class="pt-2">
<div class="flex items-center mb-4">
<van-icon name="balance-list-o" class="text-xl mr-2" style="color: var(--van-theme-primary);" />
<span class="text-base font-medium" style="color: var(--van-text-color);">银行卡提现</span>
</div>
<!-- 银行卡号 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">银行卡号</label>
<van-field v-model="bankCardNo" placeholder="请输入银行卡号" type="number"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm"
:rules="[{ required: true, message: ' ' }]">
<template #left-icon>
<van-icon name="balance-list-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
<small class="text-xs mt-1 block" style="color: var(--van-text-color-2);">请填写与实名一致的开户银行卡号</small>
</div>
<!-- 开户行名称 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">开户行名称</label>
<van-field v-model="bankName" placeholder="请输入开户行名称中国工商银行XX支行"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm"
:rules="[{ required: true, message: ' ' }]">
<template #left-icon>
<van-icon name="shop-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
</div>
<!-- 收款人姓名 -->
<div class="mb-6">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">收款人姓名</label>
<van-field v-model="bankPayeeName" placeholder="请输入银行卡户主姓名"
class="flex items-center rounded-lg bg-white/90 backdrop-blur-sm shadow-sm" :rules="[
{
required: true,
message: ' ',
validator: (val) =>
/^[\u4e00-\u9fa5]{2,4}$/.test(val),
},
]">
<template #left-icon>
<van-icon name="contact-o" style="color: var(--van-text-color-2);" />
</template>
</van-field>
<small class="text-xs mt-1 block" style="color: var(--van-text-color-2);">需与银行卡开户姓名一致</small>
</div>
</div>
</van-tab>
</van-tabs>
<!-- 提现金额 -->
<div class="mb-4">
<label class="text-sm mb-2 block" style="color: var(--van-text-color);">提现金额</label>
@@ -91,11 +146,19 @@
<div class="flex items-center text-sm mb-2" style="color: var(--van-theme-primary);">
<van-icon name="warning" class="mr-1" />提现须知
</div>
<ul class="text-xs space-y-1" style="color: var(--van-text-color);">
<!-- 支付宝提现说明 -->
<ul v-if="withdrawalType === 1" class="text-xs space-y-1" style="color: var(--van-text-color);">
<li>· 每日限提现1次最低50元</li>
<li>· 提现收取6%税收</li>
<li>· 到账时间24小时内</li>
</ul>
<!-- 银行卡提现说明 -->
<ul v-else class="text-xs space-y-1" style="color: var(--van-text-color);">
<li>· 每日限提现1次最低50元</li>
<li>· 提现收取6%税收</li>
<li>· 到账时间1-3个工作日需人工审核</li>
<li>· 银行卡提现请确保开户行户名与实名一致到账前会有审核</li>
</ul>
</div>
<!-- 税收说明 -->
@@ -201,11 +264,16 @@
</h2>
<template v-if="status === 2">
<p class="text-sm" style="color: var(--van-text-color-2);">
已向
<span style="color: var(--van-theme-primary);">{{
alipayAccount
}}</span>
转账
<template v-if="withdrawalType === 1">
已向
<span style="color: var(--van-theme-primary);">{{ alipayAccount }}</span>
转账
</template>
<template v-else>
已向
<span style="color: var(--van-theme-primary);">尾号{{ displayBankCardTail }}</span>
银行卡转账
</template>
</p>
<p class="text-2xl font-bold mt-2" style="color: #10b981;">
¥{{ amount }}
@@ -227,8 +295,9 @@
<!-- 辅助文案 -->
<div class="text-xs space-y-1.5" style="color: var(--van-text-color-2);">
<template v-if="status === 2">
<p>预计24小时内到账</p>
<p>可在支付宝账单中查看详情</p>
<p>预计1-3个工作日到账需人工审核</p>
<p v-if="withdrawalType === 1">可在支付宝账单中查看详情</p>
<p v-else>请留意银行卡到账通知</p>
</template>
<template v-if="status === 1">
<p>您的申请已进入处理队列</p>
@@ -289,6 +358,12 @@ const estimatedActualAmount = computed(() => {
return Number(amount.value) - estimatedTaxAmount.value;
});
// 银行卡号尾号(成功弹窗展示用)
const displayBankCardTail = computed(() => {
const no = (bankCardNo.value || "").replace(/\s/g, "");
return no.length >= 4 ? no.slice(-4) : no || "****";
});
// 样式配置
const statusIcon = {
1: "clock",
@@ -325,11 +400,29 @@ const statusMessages = {
3: "提现失败",
};
// 表单数据
// 提现方式1=支付宝2=银行卡
const withdrawalType = ref(1);
// 表单数据 - 支付宝
const alipayAccount = ref("");
const amount = ref(0);
const availableAmount = ref(null);
const realName = ref("");
// 表单数据 - 银行卡
const bankCardNo = ref("");
const bankName = ref("");
const bankPayeeName = ref("");
// 切换提现方式时清空另一侧部分字段(金额保留)
const onWithdrawalTypeChange = () => {
if (withdrawalType.value === 1) {
bankCardNo.value = "";
bankName.value = "";
bankPayeeName.value = "";
} else {
alipayAccount.value = "";
realName.value = "";
}
};
const getData = async () => {
const { data, error } = await getRevenueInfo();
@@ -350,35 +443,58 @@ const validateAmount = (val) => {
};
const validateForm = () => {
if (!realName.value.trim()) {
showToast("请输入账户实名姓名");
return false;
}
if (!/^[\u4e00-\u9fa5]{2,4}$/.test(realName.value)) {
showToast("请输入2-4位中文姓名");
return false;
}
if (!alipayAccount.value.trim()) {
showToast("请输入支付宝账号");
return false;
}
const amountNum = Number(amount.value);
if (!amount.value || isNaN(amountNum)) {
showToast("请输入有效金额");
return false;
}
if (amountNum < 50) {
showToast("提现金额不能低于50元");
return false;
}
if (amountNum > availableAmount.value) {
showToast("超过可提现金额");
return false;
}
if (withdrawalType.value === 1) {
// 支付宝
if (!realName.value.trim()) {
showToast("请输入账户实名姓名");
return false;
}
if (!/^[\u4e00-\u9fa5]{2,4}$/.test(realName.value)) {
showToast("请输入2-4位中文姓名");
return false;
}
if (!alipayAccount.value.trim()) {
showToast("请输入支付宝账号");
return false;
}
} else {
// 银行卡
if (!bankCardNo.value.trim()) {
showToast("请输入银行卡号");
return false;
}
if (!/^\d{16,19}$/.test(bankCardNo.value.replace(/\s/g, ""))) {
showToast("请输入正确的银行卡号");
return false;
}
if (!bankName.value.trim()) {
showToast("请输入开户行名称");
return false;
}
if (!bankPayeeName.value.trim()) {
showToast("请输入收款人姓名");
return false;
}
if (!/^[\u4e00-\u9fa5]{2,4}$/.test(bankPayeeName.value)) {
showToast("请输入2-4位中文姓名");
return false;
}
}
return true;
};
@@ -409,11 +525,19 @@ const confirmWithdraw = async () => {
isSubmitting.value = true;
try {
const { applyWithdrawal } = await import('@/api/agent');
const { data, error } = await applyWithdrawal({
payee_account: alipayAccount.value,
const payload = {
withdrawal_type: withdrawalType.value,
amount: Number(amount.value),
payee_name: realName.value,
});
payee_name: withdrawalType.value === 1 ? realName.value : bankPayeeName.value,
};
if (withdrawalType.value === 1) {
payload.payee_account = alipayAccount.value;
} else {
payload.payee_account = bankCardNo.value.replace(/\s/g, "");
payload.bank_card_no = bankCardNo.value.replace(/\s/g, "");
payload.bank_name = bankName.value.trim();
}
const { data, error } = await applyWithdrawal(payload);
if (data.value?.code === 200 && !error.value) {
status.value = 1; // 新系统申请后状态为1待审核
showTaxConfirmPopup.value = false;
@@ -450,6 +574,9 @@ const resetForm = () => {
alipayAccount.value = "";
amount.value = "";
realName.value = "";
bankCardNo.value = "";
bankName.value = "";
bankPayeeName.value = "";
};
</script>