fengketrade/public/assets/js/ccblife-bridge.js
2025-10-17 17:18:15 +08:00

437 lines
13 KiB
JavaScript

/**
* 建行生活 JSBridge 集成库
*
* 功能说明:
* 1. 检测是否在建行生活 App 内运行
* 2. 获取建行用户信息
* 3. 调起建行支付
* 4. 处理 URL 参数解密
*
* @author Billy
* @date 2025-01-17
*/
(function(window) {
'use strict';
// 建行生活 JSBridge 对象
var CcbLifeBridge = {
// 配置信息
config: {
// API 基础地址
apiBaseUrl: '/addons/shopro',
// 调试模式
debug: false,
// 超时时间(毫秒)
timeout: 10000,
// 重试次数
retryTimes: 3
},
// 初始化状态
isReady: false,
readyCallbacks: [],
/**
* 初始化
* @param {Object} options 配置选项
*/
init: function(options) {
// 合并配置
if (options) {
Object.assign(this.config, options);
}
// 监听 JSBridge 就绪事件
this.setupBridge();
// 自动登录(如果在建行 App 内)
if (this.isInCcbApp()) {
this.autoLogin();
}
this.log('CcbLifeBridge 初始化完成');
},
/**
* 设置 JSBridge
*/
setupBridge: function() {
var self = this;
// iOS WebViewJavascriptBridge
if (window.WebViewJavascriptBridge) {
self.bridge = window.WebViewJavascriptBridge;
self.onBridgeReady();
} else {
document.addEventListener('WebViewJavascriptBridgeReady', function() {
self.bridge = window.WebViewJavascriptBridge;
self.onBridgeReady();
}, false);
}
// Android 直接通过 window 对象调用
if (window.mbspay && !self.bridge) {
self.bridge = window.mbspay;
self.onBridgeReady();
}
// 设置超时检查
setTimeout(function() {
if (!self.isReady) {
self.log('JSBridge 未就绪,可能不在建行 App 内');
}
}, 3000);
},
/**
* Bridge 就绪回调
*/
onBridgeReady: function() {
this.isReady = true;
this.log('JSBridge 已就绪');
// 执行所有等待的回调
this.readyCallbacks.forEach(function(callback) {
callback();
});
this.readyCallbacks = [];
},
/**
* 等待 Bridge 就绪
* @param {Function} callback 回调函数
*/
ready: function(callback) {
if (this.isReady) {
callback();
} else {
this.readyCallbacks.push(callback);
}
},
/**
* 检测是否在建行生活 App 内
* @returns {Boolean}
*/
isInCcbApp: function() {
var ua = navigator.userAgent.toLowerCase();
// 检查 User-Agent
if (ua.indexOf('ccblife') > -1 || ua.indexOf('ccb') > -1) {
return true;
}
// 检查 URL 参数
var urlParams = this.getUrlParams();
if (urlParams.ccbParamSJ || urlParams.from === 'ccblife') {
return true;
}
// 检查是否有 JSBridge
if (window.WebViewJavascriptBridge || window.mbspay) {
return true;
}
return false;
},
/**
* 获取 URL 参数
* @returns {Object}
*/
getUrlParams: function() {
var params = {};
var search = window.location.search.substring(1);
if (search) {
var pairs = search.split('&');
pairs.forEach(function(pair) {
var parts = pair.split('=');
if (parts.length === 2) {
params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
});
}
return params;
},
/**
* 获取建行用户信息
* @param {Function} callback 回调函数
*/
getUserInfo: function(callback) {
var self = this;
if (!this.isInCcbApp()) {
callback({
success: false,
error: '不在建行生活 App 内'
});
return;
}
this.ready(function() {
self.callNative('getUserInfo', {}, function(result) {
if (result && result.userid) {
callback({
success: true,
data: {
ccb_user_id: result.userid,
mobile: result.mobile || '',
nickname: result.nickname || '',
avatar: result.avatar || ''
}
});
} else {
callback({
success: false,
error: '获取用户信息失败'
});
}
});
});
},
/**
* 自动登录
*/
autoLogin: function() {
var self = this;
// 检查是否已登录
if (localStorage.getItem('ccb_token')) {
this.log('用户已登录');
return;
}
// 获取用户信息并登录
this.getUserInfo(function(result) {
if (result.success) {
self.doLogin(result.data);
} else {
self.log('获取用户信息失败:' + result.error);
}
});
},
/**
* 执行登录
* @param {Object} userInfo 用户信息
*/
doLogin: function(userInfo) {
var self = this;
// 调用后端登录接口
this.ajax({
url: this.config.apiBaseUrl + '/ccblife/autoLogin',
method: 'POST',
data: userInfo,
success: function(response) {
if (response.code === 1) {
// 保存 Token
localStorage.setItem('ccb_token', response.data.token);
localStorage.setItem('ccb_user_info', JSON.stringify(response.data.userInfo));
self.log('自动登录成功');
// 触发登录成功事件
self.triggerEvent('ccb:login:success', response.data);
} else {
self.log('登录失败:' + response.msg);
}
},
error: function(error) {
self.log('登录请求失败:' + error);
}
});
},
/**
* 调起建行支付
* @param {Object} options 支付参数
* @param {Function} callback 回调函数
*/
payment: function(options, callback) {
var self = this;
if (!this.isInCcbApp()) {
callback({
success: false,
error: '不在建行生活 App 内'
});
return;
}
// 必需参数检查
if (!options.payment_string) {
callback({
success: false,
error: '缺少支付串参数'
});
return;
}
this.ready(function() {
// 区分 iOS 和 Android
if (self.isIOS()) {
// iOS 使用 URL Scheme
self.paymentForIOS(options, callback);
} else {
// Android 使用 JSBridge
self.paymentForAndroid(options, callback);
}
});
},
/**
* iOS 支付
*/
paymentForIOS: function(options, callback) {
var paymentUrl = 'comccbpay://pay?' + options.payment_string;
// 尝试打开支付页面
window.location.href = paymentUrl;
// 设置回调检查
setTimeout(function() {
callback({
success: true,
message: '已调起支付,请在建行 App 内完成支付'
});
}, 1000);
},
/**
* Android 支付
*/
paymentForAndroid: function(options, callback) {
var self = this;
// 调用原生支付方法
this.callNative('payment', {
payment_string: options.payment_string
}, function(result) {
if (result && result.success) {
callback({
success: true,
data: result
});
} else {
callback({
success: false,
error: result ? result.error : '支付失败'
});
}
});
},
/**
* 调用原生方法
* @param {String} method 方法名
* @param {Object} params 参数
* @param {Function} callback 回调函数
*/
callNative: function(method, params, callback) {
var self = this;
try {
if (this.isIOS() && this.bridge && this.bridge.callHandler) {
// iOS WebViewJavascriptBridge
this.bridge.callHandler(method, params, callback);
} else if (window.mbspay && window.mbspay[method]) {
// Android 直接调用
var result = window.mbspay[method](JSON.stringify(params));
if (callback) {
callback(typeof result === 'string' ? JSON.parse(result) : result);
}
} else {
self.log('原生方法不存在:' + method);
if (callback) {
callback({
success: false,
error: '原生方法不存在'
});
}
}
} catch (e) {
self.log('调用原生方法失败:' + e.message);
if (callback) {
callback({
success: false,
error: e.message
});
}
}
},
/**
* 判断是否 iOS
*/
isIOS: function() {
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
},
/**
* 触发事件
*/
triggerEvent: function(eventName, data) {
var event = new CustomEvent(eventName, {
detail: data
});
window.dispatchEvent(event);
},
/**
* AJAX 请求
*/
ajax: function(options) {
var xhr = new XMLHttpRequest();
var self = this;
xhr.open(options.method || 'GET', options.url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
// 添加 Token
var token = localStorage.getItem('ccb_token');
if (token) {
xhr.setRequestHeader('token', token);
}
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
var response = JSON.parse(xhr.responseText);
if (options.success) {
options.success(response);
}
} else {
if (options.error) {
options.error('请求失败:' + xhr.status);
}
}
};
xhr.onerror = function() {
if (options.error) {
options.error('网络错误');
}
};
xhr.send(options.data ? JSON.stringify(options.data) : null);
},
/**
* 日志输出
*/
log: function(message) {
if (this.config.debug) {
console.log('[CcbLifeBridge] ' + message);
}
}
};
// 暴露到全局
window.CcbLifeBridge = CcbLifeBridge;
})(window);