diff --git a/.env b/.env index 7e2ad0f..031ec6a 100644 --- a/.env +++ b/.env @@ -1,4 +1,6 @@ +# VITE_API_URL=https://www.quannengcha.com/ VITE_API_URL= + VITE_API_PREFIX=/api/v1 VITE_COMPANY_NAME=海南海宇大数据有限公司 @@ -18,4 +20,10 @@ VITE_CHAT_AES_IV=345GDFED433223DF VITE_SHARE_TITLE=全能查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用 VITE_SHARE_DESC=提供个人信用评估、入职背调、信贷风控、企业风险监测等服务 VITE_SHARE_IMG=https://www.quannengcha.com/logo.png -VITE_TOKEN_VERSION=1.0 \ No newline at end of file +VITE_TOKEN_VERSION=1.0 + +# 阿里云滑块验证码配置 +VITE_ALIYUN_CAPTCHA_SCENE_ID=wynt39to +# 是否启用加密模式(true/false),需要在阿里云控制台开启加密模式 +# 注意:根据代码逻辑,设置为 true 表示禁用加密,设置为 false 表示启用加密 +VITE_ALIYUN_CAPTCHA_ENCRYPTED=true diff --git a/index.html b/index.html index e410714..5babd69 100644 --- a/index.html +++ b/index.html @@ -28,15 +28,15 @@ - 全能查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用 + 全能查官网_个人婚姻状态报告_综合风险排查工具箱 @@ -45,28 +45,28 @@ - + - + @@ -83,11 +83,11 @@ "@context": "https://schema.org", "@type": "WebSite", "name": "全能查", - "url": "https://www.zhinengcha.cn/", + "url": "https://www.quannengcha.com/", "description": "专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用", "potentialAction": { "@type": "SearchAction", - "target": "https://www.zhinengcha.cn/search?q={search_term_string}", + "target": "https://www.quannengcha.com/search?q={search_term_string}", "query-input": "required name=search_term_string" } } @@ -98,7 +98,7 @@ "@context": "https://schema.org", "@type": "Organization", "name": "全能查", - "url": "https://www.zhinengcha.cn/", + "url": "https://www.quannengcha.com/", "description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用" } @@ -109,10 +109,19 @@ delete window.wx; + + + + - + - + + + +
+

全能查合作政策指南_合作伙伴权益与结算说明_官方文档

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/agent.html b/public/seo-templates/agent.html new file mode 100644 index 0000000..03df2e9 --- /dev/null +++ b/public/seo-templates/agent.html @@ -0,0 +1,80 @@ + + + + + + + + 全能查代理 - 免费开通代理权限 | 大数据风险报告代理 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

全能查代理 - 免费开通代理权限 | 大数据风险报告代理

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/example.html b/public/seo-templates/example.html new file mode 100644 index 0000000..937eb1d --- /dev/null +++ b/public/seo-templates/example.html @@ -0,0 +1,80 @@ + + + + + + + + 示例报告 - 全能查报告展示 | 大数据风险报告样例 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

示例报告 - 全能查报告展示 | 大数据风险报告样例

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/help-guide.html b/public/seo-templates/help-guide.html new file mode 100644 index 0000000..b9ba181 --- /dev/null +++ b/public/seo-templates/help-guide.html @@ -0,0 +1,80 @@ + + + + + + + + 使用指南 - 全能查操作教程 | 功能说明 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

使用指南 - 全能查操作教程 | 功能说明

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/help.html b/public/seo-templates/help.html new file mode 100644 index 0000000..d4955b3 --- /dev/null +++ b/public/seo-templates/help.html @@ -0,0 +1,80 @@ + + + + + + + + 帮助中心 - 全能查使用指南 | 常见问题解答 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

帮助中心 - 全能查使用指南 | 常见问题解答

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/index.html b/public/seo-templates/index.html new file mode 100644 index 0000000..0619b93 --- /dev/null +++ b/public/seo-templates/index.html @@ -0,0 +1,80 @@ + + + + + + + + 全能查官网_个人婚姻状态报告_综合风险排查工具箱 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

全能查官网_个人婚姻状态报告_综合风险排查工具箱

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-backgroundcheck.html b/public/seo-templates/inquire-backgroundcheck.html new file mode 100644 index 0000000..3e2da15 --- /dev/null +++ b/public/seo-templates/inquire-backgroundcheck.html @@ -0,0 +1,80 @@ + + + + + + + + 职场背景核验报告_候选人职业风险与竞业核验_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

职场背景核验报告_候选人职业风险与竞业核验_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-companyinfo.html b/public/seo-templates/inquire-companyinfo.html new file mode 100644 index 0000000..1ca8fce --- /dev/null +++ b/public/seo-templates/inquire-companyinfo.html @@ -0,0 +1,80 @@ + + + + + + + + 企业工商信用画像_经营异常与商业风险透视_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

企业工商信用画像_经营异常与商业风险透视_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-consumerFinanceReport.html b/public/seo-templates/inquire-consumerFinanceReport.html new file mode 100644 index 0000000..b180b9c --- /dev/null +++ b/public/seo-templates/inquire-consumerFinanceReport.html @@ -0,0 +1,80 @@ + + + + + + + + 个人履约能力评估_经济风险与收支压力参考_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

个人履约能力评估_经济风险与收支压力参考_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-homeservice.html b/public/seo-templates/inquire-homeservice.html new file mode 100644 index 0000000..603f30f --- /dev/null +++ b/public/seo-templates/inquire-homeservice.html @@ -0,0 +1,80 @@ + + + + + + + + 家政人员背景核实_保姆月嫂司法安全评估_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

家政人员背景核实_保姆月嫂司法安全评估_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-marriage.html b/public/seo-templates/inquire-marriage.html new file mode 100644 index 0000000..f0122f0 --- /dev/null +++ b/public/seo-templates/inquire-marriage.html @@ -0,0 +1,80 @@ + + + + + + + + 婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-preloanbackgroundcheck.html b/public/seo-templates/inquire-preloanbackgroundcheck.html new file mode 100644 index 0000000..2aed849 --- /dev/null +++ b/public/seo-templates/inquire-preloanbackgroundcheck.html @@ -0,0 +1,80 @@ + + + + + + + + 综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-riskassessment.html b/public/seo-templates/inquire-riskassessment.html new file mode 100644 index 0000000..1c93cc5 --- /dev/null +++ b/public/seo-templates/inquire-riskassessment.html @@ -0,0 +1,80 @@ + + + + + + + + 个人综合风险分析_履约能力画像_多维数据检测_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

个人综合风险分析_履约能力画像_多维数据检测_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/promote.html b/public/seo-templates/promote.html new file mode 100644 index 0000000..3bd627e --- /dev/null +++ b/public/seo-templates/promote.html @@ -0,0 +1,80 @@ + + + + + + + + 全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/service.html b/public/seo-templates/service.html new file mode 100644 index 0000000..fd9f4bd --- /dev/null +++ b/public/seo-templates/service.html @@ -0,0 +1,80 @@ + + + + + + + + 客服中心 - 全能查在线客服 | 技术支持 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

客服中心 - 全能查在线客服 | 技术支持

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/site.webmanifest b/public/site.webmanifest index a426b20..25f295a 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -1,5 +1,5 @@ { - "name": "全能查|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用", + "name": "全能查官网_个人婚姻状态报告_综合风险排查工具箱", "short_name": "全能查", "description": "专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用", "start_url": "/", diff --git a/public/sitemap.xml b/public/sitemap.xml index 261c820..6cee3fa 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,67 +1,67 @@ - https://www.zhinengcha.cn/ + https://www.quannengcha.com/ 2025-08-01 daily 1.0 - https://www.zhinengcha.cn/agent + https://www.quannengcha.com/agent 2025-08-01 weekly 0.8 - https://www.zhinengcha.cn/help + https://www.quannengcha.com/help 2025-08-01 monthly 0.7 - https://www.zhinengcha.cn/help/guide + https://www.quannengcha.com/help/guide 2025-08-01 monthly 0.6 - https://www.zhinengcha.cn/example + https://www.quannengcha.com/example 2025-08-01 monthly 0.6 - https://www.zhinengcha.cn/service + https://www.quannengcha.com/service 2025-08-01 monthly 0.5 - https://www.zhinengcha.cn/privacyPolicy + https://www.quannengcha.com/privacyPolicy 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/userAgreement + https://www.quannengcha.com/userAgreement 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/agentManageAgreement + https://www.quannengcha.com/agentManageAgreement 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/agentSerivceAgreement + https://www.quannengcha.com/agentSerivceAgreement 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/authorization + https://www.quannengcha.com/authorization 2025-08-01 yearly 0.3 diff --git a/server/crawler-detector.js b/server/crawler-detector.js new file mode 100644 index 0000000..b49fec1 --- /dev/null +++ b/server/crawler-detector.js @@ -0,0 +1,170 @@ +/** + * 爬虫检测模块 + * 用于识别搜索引擎爬虫和社交媒体爬虫 + */ + +class CrawlerDetector { + constructor() { + // 常见搜索引擎爬虫User-Agent列表 + this.crawlerPatterns = [ + // 百度爬虫 + 'baiduspider', + 'baiduspider-mobile', + 'baiduspider-image', + 'baiduspider-video', + 'baiduspider-news', + 'baiduboxapp', + + // Google爬虫 + 'googlebot', + 'googlebot-image', + 'googlebot-news', + 'googlebot-mobile', + 'googlebot-video', + 'google-web-snippet', + + // 360搜索 + '360spider', + 'soha-agent', + 'haosouspider', + + // 搜狗搜索 + 'sogou spider', + 'sogou news spider', + 'sogou orion spider', + 'sogou-blog', + + // 必应 + 'bingbot', + 'msnbot', + + // 雅虎 + 'slurp', + + // 搜搜 + 'sosospider', + 'sosoimagespider', + + // 有道 + 'youdaobot', + 'yodaobot', + + // 头条搜索 + 'bytedance-spider', + 'toutiaospider', + + // 社交媒体爬虫 + 'facebookexternalhit', + 'facebookcatalog', + 'twitterbot', + 'linkedinbot', + 'whatsapp', + 'telegrambot', + 'viber', + 'line', + + // 其他常见爬虫 + 'applebot', + 'semrushbot', + 'ahrefsbot', + 'mj12bot', + 'dotbot', + 'crawler', + 'spider', + 'bot' + ] + + // 需要检测的头部字段 + this.crawlerHeaders = ['x-bot', 'x-crawler', 'x-forwarded-for'] + } + + /** + * 检测请求是否来自爬虫 + * @param {Object} req - HTTP请求对象 + * @returns {Boolean} 是否为爬虫 + */ + isCrawler(req) { + const userAgent = req.headers['user-agent']?.toLowerCase() || '' + const headers = req.headers + + // 1. 通过User-Agent检测 + if (this.checkUserAgent(userAgent)) { + console.log(`[CrawlerDetector] 检测到爬虫 UA: ${userAgent}`) + return true + } + + // 2. 通过特定头部检测 + if (this.checkHeaders(headers)) { + console.log(`[CrawlerDetector] 检测到爬虫 Headers`) + return true + } + + // 3. 通过IP地址检测(可选) + // if (this.checkIP(req.connection.remoteAddress)) { + // return true + // } + + return false + } + + /** + * 检查User-Agent + * @param {String} userAgent + * @returns {Boolean} + */ + checkUserAgent(userAgent) { + if (!userAgent) return false + + return this.crawlerPatterns.some(pattern => { + return userAgent.includes(pattern.toLowerCase()) + }) + } + + /** + * 检查请求头 + * @param {Object} headers + * @returns {Boolean} + */ + checkHeaders(headers) { + for (const header of this.crawlerHeaders) { + const headerValue = headers[header]?.toLowerCase() + if (headerValue && (headerValue.includes('bot') || headerValue.includes('crawler'))) { + return true + } + } + return false + } + + /** + * 检查IP地址是否为已知爬虫IP + * @param {String} ip + * @returns {Boolean} + */ + checkIP(ip) { + // 这里可以添加已知爬虫IP段的检测 + // 需要定期更新爬虫IP列表 + return false + } + + /** + * 获取爬虫类型 + * @param {String} userAgent + * @returns {String} 爬虫类型 + */ + getCrawlerType(userAgent) { + const ua = userAgent.toLowerCase() + + if (ua.includes('baiduspider')) return 'baidu' + if (ua.includes('googlebot')) return 'google' + if (ua.includes('bingbot') || ua.includes('msnbot')) return 'bing' + if (ua.includes('360spider')) return '360' + if (ua.includes('sogou spider')) return 'sogou' + if (ua.includes('facebookexternalhit')) return 'facebook' + if (ua.includes('twitterbot')) return 'twitter' + if (ua.includes('linkedinbot')) return 'linkedin' + + return 'unknown' + } +} + +module.exports = CrawlerDetector diff --git a/server/generate-seo-templates.cjs b/server/generate-seo-templates.cjs new file mode 100644 index 0000000..a856bcc --- /dev/null +++ b/server/generate-seo-templates.cjs @@ -0,0 +1,245 @@ +/** + * SEO模板生成器 + * 根据 useSEO.js 的页面配置自动生成静态 HTML 模板,供爬虫访问时返回 + * 配置与 src/composables/useSEO.js 保持一致 + * + * 多站点:通过环境变量 SEO_BASE_URL 指定 canonical/og:url 域名后生成 + * 例:SEO_BASE_URL=https://www.quannengcha.com node generate-seo-templates.cjs + */ + +const fs = require('fs') +const path = require('path') + +const BASE_URL = process.env.SEO_BASE_URL || 'https://www.quannengcha.com' + +// 页面 SEO 配置(与 src/composables/useSEO.js 的 routeConfigs 保持一致) +const pageSEOConfigs = { + 'index.html': { + title: '全能查官网_个人婚姻状态报告_综合风险排查工具箱', + description: '全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。', + keywords: '全能查,婚姻状态核实,风险排查工具,个人风险预警,第三方背调,商业信用评估', + url: BASE_URL + }, + 'agent-system-guide.html': { + title: '全能查合作政策指南_合作伙伴权益与结算说明_官方文档', + description: '全能查官方合作体系说明文档。详细解读合作伙伴的等级权益、服务费结算标准及晋升机制。致力于构建公平、透明的商业合作生态,助力合作伙伴快速上手业务。', + keywords: '合作伙伴政策,服务费结算,渠道等级说明,业务操作指南,代理系统后台', + url: `${BASE_URL}/agent/system-guide` + }, + 'inquire-riskassessment.html': { + title: '个人综合风险分析_履约能力画像_多维数据检测_全能查', + description: '全能查个人风险报告为您提供全方位的信用健康度参考。基于公开数据深度解析综合风险指数、司法关联风险、历史履约趋势及潜在的负面标签。数据客观中立,帮助用户建立良好的个人履约记录管理意识。', + keywords: '个人风险检测,履约能力分析,综合风险指数,信用健康度,个人数据画像', + url: `${BASE_URL}/inquire/riskassessment` + }, + 'inquire-companyinfo.html': { + title: '企业工商信用画像_经营异常与商业风险透视_全能查', + description: '全能查企业版深度透视商业真相。聚合工商、司法及税务公开数据,核验企业经营异常名录、行政处罚、法律诉讼及股权穿透信息。全方位评估合作伙伴的商业健康度,规避合同违约风险。', + keywords: '企业信用评估,工商背景核验,商业风险评估,公司经营异常,合作方背景核实', + url: `${BASE_URL}/inquire/companyinfo` + }, + 'inquire-preloanbackgroundcheck.html': { + title: '综合履约评分检测_多平台履约记录分析_个人财务履约报告_全能查', + description: '全能查提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。', + keywords: '综合评分检测,多重履约压力分析,履约能力评估,综合评分优化,个人数据画像', + url: `${BASE_URL}/inquire/preloanbackgroundcheck` + }, + 'inquire-marriage.html': { + title: '婚前综合背景了解_情感安全风险评估_家庭履约分析_全能查', + description: '全能查婚恋风险报告基于合法公开数据,辅助评估对象的婚前背景。核心核验司法涉诉记录、失信被执行历史、多重履约能力及不良社会标签。拒绝情感盲区,用数据守护您的家庭与财产安全。', + keywords: '婚前背景报告,恋爱对象风险,情感安全评估,司法记录核验,家庭风险防范', + url: `${BASE_URL}/inquire/marriage` + }, + 'inquire-backgroundcheck.html': { + title: '职场背景核验报告_候选人职业风险与竞业核验_全能查', + description: '全能查为企业提供专业的入职背调服务。一键筛查候选人的学历背景、涉及的商业利益冲突、劳动仲裁记录及社会不良风险。数据实时合规,降低企业用工试错成本,提升招聘决策效率。', + keywords: '员工入职背调,职业背景核实,竞业限制评估,职场信用报告,候选人风险筛查', + url: `${BASE_URL}/inquire/backgroundcheck` + }, + 'inquire-homeservice.html': { + title: '家政人员背景核实_保姆月嫂司法安全评估_全能查', + description: '全能查针对家庭用工场景,提供客观的家政人员背景核验服务。重点核验身份信息、司法涉诉记录及失信历史。辅助雇主识别高危人员,让居家养老育儿更安心。', + keywords: '保姆背景核验,家政风险筛查,月嫂司法记录,雇佣安全评估,家政人员核验', + url: `${BASE_URL}/inquire/homeservice` + }, + 'inquire-consumerFinanceReport.html': { + title: '个人履约能力评估_经济风险与收支压力参考_全能查', + description: '全能查履约报告基于大数据算法,提供个人经济稳定性的客观分析。多维度检测综合履约分、经济关联风险及潜在的资金压力指数。本服务仅提供大数据层面的风险参考,助您优化财务管理。', + keywords: '履约能力评估,经济风险指数,综合评分波动,资金压力分析,财务健康度', + url: `${BASE_URL}/inquire/consumerFinanceReport` + }, + 'agent.html': { + title: '全能查代理 - 免费开通代理权限 | 大数据风险报告代理', + description: '全能查代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。', + keywords: '全能查代理, 免费代理, 大数据风险报告代理, 代理权限, 代理收益', + url: `${BASE_URL}/agent` + }, + 'help.html': { + title: '帮助中心 - 全能查使用指南 | 常见问题解答', + description: '全能查帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。', + keywords: '全能查帮助, 使用指南, 常见问题, 操作教程, 客服支持', + url: `${BASE_URL}/help` + }, + 'help-guide.html': { + title: '使用指南 - 全能查操作教程 | 功能说明', + description: '全能查详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。', + keywords: '使用指南, 操作教程, 功能说明, 快速上手, 全能查教程', + url: `${BASE_URL}/help/guide` + }, + 'example.html': { + title: '示例报告 - 全能查报告展示 | 大数据风险报告样例', + description: '全能查示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。', + keywords: '示例报告, 报告展示, 报告样例, 大数据风险报告, 婚姻查询报告', + url: `${BASE_URL}/example` + }, + 'service.html': { + title: '客服中心 - 全能查在线客服 | 技术支持', + description: '全能查客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。', + keywords: '客服中心, 在线客服, 技术支持, 问题反馈, 全能查客服', + url: `${BASE_URL}/service` + }, + 'promote.html': { + title: '全能查合伙人计划_风控平台系统招商_渠道合作平台_全能查', + description: '全能查开放全国渠道合作,提供零门槛的风险评估系统接入服务。一键开通独立后台,支持婚恋、职场、家政及商业风控等多场景报告推广。正规项目,结算透明,赋能流量方实现合规商业价值。', + keywords: '风控系统代理,风险评估平台招商,平台渠道合作,企业服务创业,全能查合伙人', + url: `${BASE_URL}/promote` + } +} + +/** + * 规范化文案:统一为中文标点,避免乱码 + */ +function normalizeText(str) { + if (typeof str !== 'string') return str + return str + .replace(/\uFFFD/g, '') + .replace(/。/g, '。') + .replace(/、/g, '、') +} + +/** + * 转义 HTML 属性值 + */ +function escapeAttr(str) { + if (typeof str !== 'string') return '' + return str + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>') +} + +/** + * 生成单页 HTML 模板 + */ +function generateHTMLTemplate(config) { + const title = normalizeText(config.title) + const description = normalizeText(config.description) + const keywords = normalizeText(config.keywords) + const structuredData = { + '@context': 'https://schema.org', + '@type': 'WebPage', + name: title, + description: description, + url: config.url, + mainEntity: { + '@type': 'Organization', + name: '全能查', + url: 'https://www.quannengcha.com/', + description: '专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用' + } + } + + return ` + + + + + + + ${escapeAttr(title)} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

${escapeAttr(title)}

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

${escapeAttr(description)}

+
+

关于全能查

+

全能查是您的掌上风控工具箱。平台基于合规数据,提供个人婚姻状态分析、职场背调及黑名单筛查服务。无需繁琐流程,客观中立,一键生成包含婚姻涉诉历史与家庭风险的综合报告,助您快速识别潜在隐患。

+
+
+

核心服务

+
    +
  • 个人综合风险分析与履约能力画像
  • +
  • 企业工商信用画像与商业风险透视
  • +
  • 婚前综合背景了解与情感安全风险评估
  • +
  • 职场背景核验与入职背调
  • +
  • 家政人员背景核实与安全评估
  • +
  • 个人履约能力评估与经济风险分析
  • +
+
+
+ +` +} + +function main() { + const outputDir = path.join(__dirname, '../public/seo-templates') + + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }) + console.log(`✓ 创建模板目录: ${outputDir}`) + } + + let successCount = 0 + Object.entries(pageSEOConfigs).forEach(([filename, config]) => { + const htmlContent = generateHTMLTemplate(config) + const filePath = path.join(outputDir, filename) + fs.writeFileSync(filePath, htmlContent, 'utf-8') + console.log(`✓ 生成模板: ${filename}`) + successCount++ + }) + + console.log(`\n✓ 成功生成 ${successCount} 个 SEO 模板文件`) + console.log(`📁 模板目录: ${outputDir}`) + console.log(`💡 配置与 useSEO.js 一致,当前域名: ${BASE_URL}`) +} + +main() diff --git a/server/middleware.js b/server/middleware.js new file mode 100644 index 0000000..ce115ed --- /dev/null +++ b/server/middleware.js @@ -0,0 +1,179 @@ +/** + * SEO中间件 + * 用于在Node.js服务器中检测爬虫并返回静态HTML + */ + +const fs = require('fs') +const path = require('path') +const CrawlerDetector = require('./crawler-detector') + +class SEOMiddleware { + constructor(options = {}) { + this.detector = new CrawlerDetector() + this.templateDir = options.templateDir || path.join(__dirname, '../public/seo-templates') + this.defaultTemplate = options.defaultTemplate || 'index.html' + this.fallbackToSPA = options.fallbackToSPA !== false + this.debug = options.debug || false + + // 路由到模板的映射(与 useSEO.js 及 generate-seo-templates.cjs 保持一致;子路径放前面以优先精确匹配) + this.routeTemplateMap = { + '/': 'index.html', + '/agent/system-guide': 'agent-system-guide.html', + '/inquire/riskassessment': 'inquire-riskassessment.html', + '/inquire/companyinfo': 'inquire-companyinfo.html', + '/inquire/preloanbackgroundcheck': 'inquire-preloanbackgroundcheck.html', + '/inquire/marriage': 'inquire-marriage.html', + '/inquire/backgroundcheck': 'inquire-backgroundcheck.html', + '/inquire/homeservice': 'inquire-homeservice.html', + '/inquire/consumerFinanceReport': 'inquire-consumerFinanceReport.html', + '/agent': 'agent.html', + '/help/guide': 'help-guide.html', + '/help': 'help.html', + '/example': 'example.html', + '/service': 'service.html', + '/promote': 'promote.html' + } + + // 初始化模板缓存 + this.templateCache = new Map() + this.cacheTemplates() + } + + /** + * 缓存所有模板文件 + */ + cacheTemplates() { + try { + if (!fs.existsSync(this.templateDir)) { + console.warn(`[SEOMiddleware] 模板目录不存在: ${this.templateDir}`) + return + } + + const files = fs.readdirSync(this.templateDir) + files.forEach(file => { + const filePath = path.join(this.templateDir, file) + if (fs.statSync(filePath).isFile()) { + this.templateCache.set(file, fs.readFileSync(filePath, 'utf-8')) + if (this.debug) { + console.log(`[SEOMiddleware] 已缓存模板: ${file}`) + } + } + }) + + console.log(`[SEOMiddleware] 已缓存 ${this.templateCache.size} 个模板文件`) + } catch (error) { + console.error('[SEOMiddleware] 缓存模板失败:', error) + } + } + + /** + * 获取对应的模板文件名 + * @param {String} path - 请求路径 + * @returns {String} 模板文件名 + */ + getTemplatePath(requestPath) { + // 完全匹配 + if (this.routeTemplateMap[requestPath]) { + return this.routeTemplateMap[requestPath] + } + + // 模糊匹配(处理动态路由) + const matchedKey = Object.keys(this.routeTemplateMap).find(route => { + return requestPath.startsWith(route) + }) + + return matchedKey ? this.routeTemplateMap[matchedKey] : this.defaultTemplate + } + + /** + * 获取模板内容 + * @param {String} templateName - 模板文件名 + * @returns {String|null} 模板内容 + */ + getTemplate(templateName) { + // 首先尝试缓存 + let content = this.templateCache.get(templateName) + + // 如果缓存中没有,尝试从磁盘读取 + if (!content) { + try { + const filePath = path.join(this.templateDir, templateName) + if (fs.existsSync(filePath)) { + content = fs.readFileSync(filePath, 'utf-8') + this.templateCache.set(templateName, content) + } + } catch (error) { + console.error(`[SEOMiddleware] 读取模板失败: ${templateName}`, error) + } + } + + return content || null + } + + /** + * Express中间件 + */ + express() { + return (req, res, next) => { + // 检测是否为爬虫 + if (this.detector.isCrawler(req)) { + const templateName = this.getTemplatePath(req.path) + const template = this.getTemplate(templateName) + + if (template) { + // 设置响应头 + res.setHeader('Content-Type', 'text/html; charset=utf-8') + res.setHeader('X-SEOMiddleware', 'prerendered') + + // 返回静态HTML + if (this.debug) { + console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${req.path}`) + } + + return res.send(template) + } + } + + // 不是爬虫或模板不存在,继续处理SPA + next() + } + } + + /** + * Koa中间件 + */ + koa() { + return async (ctx, next) => { + // 检测是否为爬虫 + if (this.detector.isCrawler(ctx.req)) { + const templateName = this.getTemplatePath(ctx.path) + const template = this.getTemplate(templateName) + + if (template) { + ctx.type = 'text/html; charset=utf-8' + ctx.set('X-SEOMiddleware', 'prerendered') + + if (this.debug) { + console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${ctx.path}`) + } + + ctx.body = template + return + } + } + + await next() + } + } + + /** + * 重新加载模板缓存 + */ + reloadCache() { + this.templateCache.clear() + this.cacheTemplates() + console.log('[SEOMiddleware] 模板缓存已重新加载') + } +} + +module.exports = SEOMiddleware diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..dbb7c3e --- /dev/null +++ b/server/package.json @@ -0,0 +1,27 @@ +{ + "name": "tydata-seo-server", + "version": "1.0.0", + "description": "SPA SEO 优化 - 爬虫检测与静态 HTML 回退,与 useSEO.js 同步", + "main": "server-example-express.js", + "scripts": { + "start": "node server-example-express.js", + "dev": "node server-example-express.js", + "generate": "node generate-seo-templates.cjs", + "test": "node test-seo.js", + "test:crawler": "node test-crawler-detection.js" + }, + "keywords": [ + "seo", + "crawler", + "spa", + "prerender" + ], + "license": "MIT", + "dependencies": { + "express": "^4.18.2", + "compression": "^1.7.4" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/server/server-example-express.js b/server/server-example-express.js new file mode 100644 index 0000000..811d63e --- /dev/null +++ b/server/server-example-express.js @@ -0,0 +1,36 @@ +/** + * Express服务器示例 + * 展示如何集成SEO中间件 + */ + +const express = require('express') +const path = require('path') +const SEOMiddleware = require('./middleware') + +const app = express() +const port = process.env.PORT || 3000 + +// 初始化SEO中间件 +const seoMiddleware = new SEOMiddleware({ + templateDir: path.join(__dirname, '../public/seo-templates'), + debug: process.env.NODE_ENV === 'development' +}) + +// 应用SEO中间件(必须在静态文件服务之前) +app.use(seoMiddleware.express()) + +// 静态文件服务 +app.use(express.static(path.join(__dirname, '../dist'))) + +// SPA路由处理 +app.get('*', (req, res) => { + res.sendFile(path.join(__dirname, '../dist/index.html')) +}) + +// 启动服务器 +app.listen(port, () => { + console.log(`🚀 服务器运行在 http://localhost:${port}`) + console.log(`🔍 SEO中间件已启用`) +}) + +module.exports = app diff --git a/server/test-crawler-detection.js b/server/test-crawler-detection.js new file mode 100644 index 0000000..d494d78 --- /dev/null +++ b/server/test-crawler-detection.js @@ -0,0 +1,112 @@ +/** + * 爬虫检测测试脚本 + * 用于验证爬虫检测功能是否正常工作 + */ + +const CrawlerDetector = require('./crawler-detector') + +const detector = new CrawlerDetector() + +// 测试用例 +const testCases = [ + // 爬虫User-Agent + { userAgent: 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)', expected: true, description: '百度爬虫' }, + { userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', expected: true, description: 'Google爬虫' }, + { userAgent: 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)', expected: true, description: '必应爬虫' }, + { userAgent: 'Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)', expected: true, description: '搜狗爬虫' }, + { userAgent: '360Spider', expected: true, description: '360爬虫' }, + { userAgent: 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)', expected: true, description: 'Facebook爬虫' }, + { userAgent: 'Twitterbot/1.0', expected: true, description: 'Twitter爬虫' }, + { userAgent: 'LinkedInBot/1.0 (compatible; Mozilla/5.0; +https://www.linkedin.com/help/linkedin/answer/8665)', expected: true, description: 'LinkedIn爬虫' }, + + // 正常浏览器User-Agent + { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', expected: false, description: 'Chrome浏览器' }, + { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0', expected: false, description: 'Firefox浏览器' }, + { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15', expected: false, description: 'Safari浏览器' }, + { userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', expected: false, description: 'iPhone Safari' }, + { userAgent: 'Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36', expected: false, description: 'Android Chrome' }, + { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0', expected: false, description: 'Edge浏览器' }, + + // 边界情况 + { userAgent: '', expected: false, description: '空User-Agent' }, + { userAgent: 'Mozilla/5.0 (compatible; MyBot/1.0)', expected: true, description: '包含bot关键词' }, + { userAgent: 'Mozilla/5.0 (compatible; Spider/1.0)', expected: true, description: '包含spider关键词' }, + { userAgent: 'Mozilla/5.0 (compatible; Crawler/1.0)', expected: true, description: '包含crawler关键词' } +] + +console.log('='.repeat(70)) +console.log('爬虫检测测试') +console.log('='.repeat(70)) +console.log() + +let passed = 0 +let failed = 0 + +testCases.forEach((testCase, index) => { + const req = { + headers: { + 'user-agent': testCase.userAgent + } + } + + const result = detector.isCrawler(req) + const success = result === testCase.expected + const status = success ? '✓ 通过' : '✗ 失败' + const crawlerType = result ? detector.getCrawlerType(testCase.userAgent) : 'N/A' + + if (success) { + passed++ + console.log(`${status} 测试 ${index + 1}: ${testCase.description}`) + } else { + failed++ + console.error(`${status} 测试 ${index + 1}: ${testCase.description}`) + console.error(` User-Agent: ${testCase.userAgent.substring(0, 80)}...`) + console.error(` 预期: ${testCase.expected}, 实际: ${result}`) + } + + if (result) { + console.log(` 识别为: ${crawlerType} 爬虫`) + } +}) + +console.log() +console.log('='.repeat(70)) +console.log(`测试结果: ${passed} 通过, ${failed} 失败, 共 ${testCases.length} 个测试`) +console.log('='.repeat(70)) +console.log() + +// 测试爬虫类型识别 +console.log('爬虫类型识别测试:') +console.log('-'.repeat(70)) + +const crawlerTypes = [ + { userAgent: 'Baiduspider', expected: 'baidu', description: '百度爬虫' }, + { userAgent: 'Googlebot', expected: 'google', description: 'Google爬虫' }, + { userAgent: 'bingbot', expected: 'bing', description: '必应爬虫' }, + { userAgent: '360spider', expected: '360', description: '360爬虫' }, + { userAgent: 'sogou spider', expected: 'sogou', description: '搜狗爬虫' }, + { userAgent: 'facebookexternalhit', expected: 'facebook', description: 'Facebook爬虫' }, + { userAgent: 'Twitterbot', expected: 'twitter', description: 'Twitter爬虫' }, + { userAgent: 'linkedinbot', expected: 'linkedin', description: 'LinkedIn爬虫' } +] + +let typePassed = 0 +crawlerTypes.forEach(test => { + const result = detector.getCrawlerType(test.userAgent) + const success = result === test.expected + + if (success) { + typePassed++ + console.log(`✓ ${test.description}: ${result}`) + } else { + console.error(`✗ ${test.description}: 预期 ${test.expected}, 实际 ${result}`) + } +}) + +console.log() +console.log('='.repeat(70)) +console.log(`爬虫类型识别: ${typePassed}/${crawlerTypes.length} 正确`) +console.log('='.repeat(70)) + +// 退出码 +process.exit(failed === 0 ? 0 : 1) diff --git a/server/test-seo.js b/server/test-seo.js new file mode 100644 index 0000000..209c1d7 --- /dev/null +++ b/server/test-seo.js @@ -0,0 +1,178 @@ +/** + * SEO 端到端检测脚本 + * 模拟爬虫与普通用户请求,验证是否返回正确的页面 + * + * 使用前请先启动服务器: npm run start + * 然后运行: npm run test 或 node test-seo.js + */ + +const http = require('http') +const https = require('https') + +const BASE_URL = process.env.SEO_TEST_URL || 'http://localhost:3000' + +// 要检测的路由及期望的 SEO 标题关键词(与 useSEO.js 一致,天远数据) +const ROUTES = [ + { path: '/', titleKeyword: '天远数据' }, + { path: '/agent', titleKeyword: '天远数据代理' }, + { path: '/help', titleKeyword: '天远数据帮助中心' }, + { path: '/inquire/personalData', titleKeyword: '个人综合风险报告' }, + { path: '/agent/promote', titleKeyword: '推广码' }, + { path: '/historyQuery', titleKeyword: '我的报告' } +] + +function request(url, userAgent) { + return new Promise((resolve, reject) => { + const lib = url.startsWith('https') ? https : http + const req = lib.get(url, { + headers: { 'User-Agent': userAgent }, + timeout: 10000 + }, res => { + const chunks = [] + res.on('data', chunk => chunks.push(chunk)) + res.on('end', () => { + resolve({ + statusCode: res.statusCode, + headers: res.headers, + body: Buffer.concat(chunks).toString('utf-8') + }) + }) + }) + req.on('error', reject) + req.on('timeout', () => { + req.destroy() + reject(new Error('请求超时')) + }) + }) +} + +function extractTitle(html) { + const match = html.match(/]*>([^<]+)<\/title>/i) + return match ? match[1].trim() : null +} + +function hasMetaDescription(html) { + return / { 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; diff --git a/src/components/BaseReport.vue b/src/components/BaseReport.vue index 92563ec..b7214c9 100644 --- a/src/components/BaseReport.vue +++ b/src/components/BaseReport.vue @@ -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, diff --git a/src/components/BindPhoneDialog.vue b/src/components/BindPhoneDialog.vue index 8ad7cfe..88a31d4 100644 --- a/src/components/BindPhoneDialog.vue +++ b/src/components/BindPhoneDialog.vue @@ -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() { diff --git a/src/components/BindPhoneOnlyDialog.vue b/src/components/BindPhoneOnlyDialog.vue index 23cc1dd..1b2b7f7 100644 --- a/src/components/BindPhoneOnlyDialog.vue +++ b/src/components/BindPhoneOnlyDialog.vue @@ -1,12 +1,14 @@ + + + + \ No newline at end of file diff --git a/src/views/Inquire.vue b/src/views/Inquire.vue index 8b354b1..e80c775 100644 --- a/src/views/Inquire.vue +++ b/src/views/Inquire.vue @@ -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 = ` +
+

亲爱的用户,您好!

+ +

婚恋报告正在优化升级中,需要查询请前往天远查。

+ + +
+ + + +
+ + +
+ `; + + 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() { \ No newline at end of file diff --git a/src/views/InvitationAgentApply.vue b/src/views/InvitationAgentApply.vue index 1deabb0..ffcf2e4 100644 --- a/src/views/InvitationAgentApply.vue +++ b/src/views/InvitationAgentApply.vue @@ -33,6 +33,8 @@ diff --git a/src/views/Login.vue b/src/views/Login.vue index 613f136..25890c2 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -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() { diff --git a/src/views/NotFound.vue b/src/views/NotFound.vue index 7a95b30..dce9f04 100644 --- a/src/views/NotFound.vue +++ b/src/views/NotFound.vue @@ -32,7 +32,7 @@ onMounted(() => { title: '404 - 页面未找到 | 全能查', description: '抱歉,您访问的页面不存在。全能查专业大数据风险管控平台,提供大数据风险报告查询、婚姻状况查询、个人信用评估等服务。', keywords: '404, 页面未找到, 全能查, 大数据风险管控', - url: 'https://www.zhinengcha.cn/404' + url: 'https://www.quannengcha.com/404' }) }) diff --git a/src/views/Register.vue b/src/views/Register.vue index ae160d7..20b1819 100644 --- a/src/views/Register.vue +++ b/src/views/Register.vue @@ -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() { diff --git a/src/views/Withdraw.vue b/src/views/Withdraw.vue index 83a7a8f..23fad58 100644 --- a/src/views/Withdraw.vue +++ b/src/views/Withdraw.vue @@ -22,41 +22,96 @@
-
- -

支付宝提现

-
- - -
- - - - - 可填写支付宝账户绑定的手机号 -
- -
- - - - - 请填写支付宝账户认证的真实姓名 -
+ + + +
+
+ + 支付宝提现 +
+ +
+ + + + + 可填写支付宝账户绑定的手机号 +
+ +
+ + + + + 请填写支付宝账户认证的真实姓名 +
+
+
+ +
+
+ + 银行卡提现 +
+ +
+ + + + + 请填写与实名一致的开户银行卡号 +
+ +
+ + + + +
+ +
+ + + + + 需与银行卡开户姓名一致 +
+
+
+
@@ -91,11 +146,19 @@
提现须知
-
    + +
    • · 每日限提现1次,最低50元
    • · 提现收取6%税收
    • · 到账时间:24小时内
    + +
      +
    • · 每日限提现1次,最低50元
    • +
    • · 提现收取6%税收
    • +
    • · 到账时间:1-3个工作日(需人工审核)
    • +
    • · 银行卡提现:请确保开户行、户名与实名一致,到账前会有审核
    • +
@@ -201,11 +264,16 @@