2025-10-22 23:06:43 +08:00

283 lines
9.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { onLaunch, onShow, onError } from '@dcloudio/uni-app';
import { ShoproInit } from './sheep';
import sheep from '@/sheep';
// 防止重复登录的标志
let isLoggingIn = false;
onLaunch(() => {
// 隐藏原生导航栏 使用自定义底部导航
uni.hideTabBar({
fail: () => {},
});
// 初始化移动端调试控制台仅H5环境
// #ifdef H5
initVConsole();
// #endif
// 加载Shopro底层依赖
ShoproInit();
// 检测建行生活登录参数
checkCCBLogin();
// 启动 JSBridge 监控每10秒打印一次
// #ifdef H5
startJSBridgeMonitor();
// #endif
});
/**
* 初始化 vConsole 移动端调试控制台
* 在H5环境下提供类似Chrome DevTools的功能
*/
const initVConsole = () => {
// 动态导入vConsole避免打包到非H5平台
import('vconsole')
.then((module) => {
const VConsole = module.default;
const vConsole = new VConsole({
defaultPlugins: ['system', 'network', 'element', 'storage'],
maxLogNumber: 1000,
disableLogScrolling: false,
});
// 保存实例供后续使用
window.vConsole = vConsole;
})
.catch((err) => {
console.error('[App] vConsole加载失败:', err);
});
};
onError((err) => {
console.log('AppOnError:', err);
});
onShow(() => {
// #ifdef APP-PLUS
// 获取urlSchemes参数
const args = plus.runtime.arguments;
if (args) {
}
// 获取剪贴板
uni.getClipboardData({
success: (res) => {},
});
// #endif
});
/**
* JSBridge 注入情况监控
* 每10秒打印一次所有建行相关 JSBridge 对象的状态打印15次后自动停止
*/
const startJSBridgeMonitor = () => {
let count = 0;
const maxCount = 15;
// 立即执行一次
printJSBridgeStatus(++count, maxCount);
// 每10秒执行一次
const timer = setInterval(() => {
printJSBridgeStatus(++count, maxCount);
// 达到15次后清除定时器
if (count >= maxCount) {
clearInterval(timer);
console.log('[JSBridge] 监控已停止已打印15次');
}
}, 10000);
};
/**
* 打印 JSBridge 注入状态(精简版)
*/
const printJSBridgeStatus = (count, maxCount) => {
const timestamp = new Date().toLocaleTimeString('zh-CN', { hour12: false });
const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
const isAndroid = /Android/i.test(navigator.userAgent);
// 检测各个 Bridge 对象
const hasMbspay =
typeof window.mbspay !== 'undefined' && typeof window.mbspay.directpay === 'function';
const hasCCBBridge = typeof window.CCBBridge !== 'undefined';
const hasWebViewBridge = typeof window.WebViewJavascriptBridge !== 'undefined';
const hasAnyBridge = hasMbspay || hasCCBBridge || hasWebViewBridge;
// 支付能力
const canPay = isIOS || (isAndroid && hasMbspay);
// 一行输出所有状态(包含计数)
console.log(
`[JSBridge ${timestamp}] (${count}/${maxCount}) ` +
`设备:${isIOS ? 'iOS' : isAndroid ? 'Android' : 'PC'} | ` +
`mbspay:${hasMbspay ? '✅' : '❌'} | ` +
`CCBBridge:${hasCCBBridge ? '✅' : '❌'} | ` +
`WebViewBridge:${hasWebViewBridge ? '✅' : '❌'} | ` +
`支付能力:${canPay ? '✅' : '❌'} | ` +
`Bridge状态:${hasAnyBridge ? '✅就绪' : '❌未就绪'}`,
);
};
/**
* 检测URL中的建行登录参数并自动登录
* 建行跳转URL格式url?platform=ccblife&channel=mbs&ccbParamSJ=xxx&CITYID=330100&USERCITYID=440100
*
* 逻辑:
* 1. 解析URL参数获取ccbParamSJ
* 2. 与本地存储的lastCcbParamSJ比较
* 3. 如果一致则无需重新登录
* 4. 如果不一致则需要切换用户(退出当前用户后重新登录)
*/
const checkCCBLogin = () => {
// #ifdef H5
try {
let ccbParamSJ = null;
let platform = null;
let cityid = null;
// 优先从search中提取参数建行标准格式url?ccbParamSJ=xxx&CITYID=xxx
if (window.location.search) {
const urlParams = new URLSearchParams(window.location.search);
ccbParamSJ = urlParams.get('ccbParamSJ');
platform = urlParams.get('platform') || 'ccblife';
cityid = urlParams.get('CITYID') || urlParams.get('cityid');
}
// 备用从hash中提取参数UniApp内部跳转可能使用
if (!ccbParamSJ && window.location.hash.includes('?')) {
const hashParts = window.location.hash.split('?');
if (hashParts.length > 1) {
const hashParams = new URLSearchParams(hashParts[1]);
ccbParamSJ = hashParams.get('ccbParamSJ');
platform = hashParams.get('platform') || 'ccblife';
cityid = hashParams.get('CITYID') || hashParams.get('cityid');
}
}
// 获取上次保存的ccbParamSJ
const lastCcbParamSJ = uni.getStorageSync('lastCcbParamSJ') || null;
// 判断参数是否变化
const isParamChanged = ccbParamSJ && lastCcbParamSJ !== ccbParamSJ;
const isFirstTime = ccbParamSJ && !lastCcbParamSJ;
// 如果有建行参数固定建行生活环境只要有ccbParamSJ就执行登录
if (ccbParamSJ) {
// 如果参数未变化,无需重新登录
if (!isParamChanged && !isFirstTime) {
console.log('[CCB] 参数未变化,跳过登录');
const cleanUrl = window.location.origin + '/pages/index/index';
window.history.replaceState({}, '', cleanUrl);
return;
}
console.log(`[CCB] ${isParamChanged ? '切换用户' : '首次登录'}`);
// 防止重复调用
if (isLoggingIn) {
console.log('[CCB] 登录进行中,跳过');
return;
}
isLoggingIn = true;
// 延迟执行登录,确保依赖已初始化
setTimeout(async () => {
try {
// 如果是切换用户,先退出当前用户
const userStore = sheep.$store('user');
if (isParamChanged && userStore && userStore.isLogin) {
await userStore.logout();
uni.removeStorageSync('token');
uni.removeStorageSync('userInfo');
}
// 显示loading
const loadingTitle = isParamChanged ? '切换用户中...' : '建行登录中...';
uni.showLoading({
title: loadingTitle,
mask: true,
});
// 调用建行登录API
const result = await sheep.$api.third.ccbLogin({
ccbParamSJ: ccbParamSJ,
cityid: cityid || '360100',
CITYID: cityid || '360100',
});
uni.hideLoading();
if (result.code === 1) {
console.log('[CCB] 登录成功');
// 获取用户store
const userStore = sheep.$store('user');
// ⭐ 立即同步设置用户信息到store避免页面显示延迟
if (result.data.user_info) {
userStore.userInfo = result.data.user_info;
console.log('[CCB] 用户信息已同步到store:', result.data.user_info.nickname);
}
// ⭐ 如果后端返回了订单数据,也立即同步(避免页面显示'--'
if (result.data.num_data) {
userStore.numData = result.data.num_data;
console.log('[CCB] 订单数据已同步到store:', result.data.num_data);
}
// 保存到本地存储
uni.setStorageSync('userInfo', result.data.user_info);
uni.setStorageSync('lastCcbParamSJ', ccbParamSJ);
// 设置token这会触发loginAfter异步加载完整数据
// 注意不使用await让它在后台加载不阻塞UI
userStore.setToken(result.data.token);
// 显示欢迎提示
uni.showToast({
title: `登录成功`,
icon: 'success',
duration: 2000,
});
// 清除URL中的敏感参数
const cleanUrl = window.location.origin + '/pages/index/index';
window.history.replaceState({}, '', cleanUrl);
} else {
throw new Error(result.msg || '登录失败');
}
} catch (error) {
console.error('[CCB] 登录失败:', error.message || error.msg);
uni.hideLoading();
uni.showModal({
title: isParamChanged ? '切换用户失败' : '登录失败',
content: error.message || error.msg || '请检查网络连接',
showCancel: false,
complete: () => {
const cleanUrl = window.location.origin + '/pages/index/index';
window.history.replaceState({}, '', cleanUrl);
},
});
} finally {
isLoggingIn = false;
}
}, 1200);
}
} catch (error) {
console.error('[CCB] 参数解析错误:', error);
}
// #endif
};
</script>
<style lang="scss">
@import '@/sheep/scss/index.scss';
</style>