mirror of
https://gitee.com/liuxioabin/fengketrade.git
synced 2026-04-17 21:03:17 +08:00
前端修改
This commit is contained in:
parent
fd51bd8e8e
commit
537647ec74
427
frontend/pages/ccblife/index.vue
Normal file
427
frontend/pages/ccblife/index.vue
Normal file
@ -0,0 +1,427 @@
|
||||
<template>
|
||||
<s-layout title="建行生活" :bgStyle="{ color: 'rgb(245,28,19)' }">
|
||||
<!-- 顶部banner -->
|
||||
<view class="ccb-banner">
|
||||
<image
|
||||
src="https://via.placeholder.com/750x300"
|
||||
mode="widthFix"
|
||||
class="banner-img"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-section" v-if="userInfo.ccb_user_id">
|
||||
<view class="user-card">
|
||||
<view class="user-avatar">
|
||||
<image :src="userInfo.avatar || '/static/img/shop/avatar/default.png'" mode="aspectFill"/>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<view class="user-nickname">{{ userInfo.nickname || '建行用户' }}</view>
|
||||
<view class="user-id">建行ID: {{ userInfo.ccb_user_id }}</view>
|
||||
</view>
|
||||
<view class="user-badge">
|
||||
<text class="badge-text">建行专享</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 建行专属活动 -->
|
||||
<view class="activity-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">建行专享优惠</text>
|
||||
<text class="more-text" @tap="goToMore">查看更多 ></text>
|
||||
</view>
|
||||
|
||||
<view class="activity-list">
|
||||
<view
|
||||
class="activity-item"
|
||||
v-for="(item, index) in activities"
|
||||
:key="index"
|
||||
@tap="goToActivity(item)"
|
||||
>
|
||||
<image :src="item.image" class="activity-img" mode="aspectFill"/>
|
||||
<view class="activity-info">
|
||||
<view class="activity-title">{{ item.title }}</view>
|
||||
<view class="activity-desc">{{ item.desc }}</view>
|
||||
<view class="activity-tag">
|
||||
<text class="tag-text">{{ item.tag }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 热门商品 -->
|
||||
<view class="goods-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">建行用户专享商品</text>
|
||||
</view>
|
||||
|
||||
<view class="goods-list">
|
||||
<view
|
||||
class="goods-item"
|
||||
v-for="item in goodsList"
|
||||
:key="item.id"
|
||||
@tap="sheep.$router.go('/pages/goods/index', { id: item.id })"
|
||||
>
|
||||
<image :src="item.image" class="goods-img" mode="aspectFill"/>
|
||||
<view class="goods-info">
|
||||
<view class="goods-title">{{ item.title }}</view>
|
||||
<view class="goods-price">
|
||||
<text class="price-unit">¥</text>
|
||||
<text class="price-value">{{ item.price }}</text>
|
||||
<text class="price-old">¥{{ item.originalPrice }}</text>
|
||||
</view>
|
||||
<view class="goods-tag">
|
||||
<text class="tag-ccb">建行专享</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部提示 -->
|
||||
<view class="bottom-tips">
|
||||
<view class="tips-text">— 建行生活,让生活更美好 —</view>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, onMounted } from 'vue';
|
||||
import sheep from '@/sheep';
|
||||
import ccbApi from '@/sheep/platform/provider/ccblife/api';
|
||||
|
||||
// 用户信息
|
||||
const userInfo = reactive({
|
||||
ccb_user_id: '',
|
||||
nickname: '',
|
||||
avatar: '',
|
||||
mobile: ''
|
||||
});
|
||||
|
||||
// 活动列表
|
||||
const activities = reactive([
|
||||
{
|
||||
id: 1,
|
||||
title: '建行信用卡满减活动',
|
||||
desc: '使用建行信用卡支付满100减20',
|
||||
tag: '限时优惠',
|
||||
image: 'https://via.placeholder.com/200x100',
|
||||
url: '/pages/activity/detail?id=1'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '新用户专享礼包',
|
||||
desc: '建行新用户首单立减50元',
|
||||
tag: '新人福利',
|
||||
image: 'https://via.placeholder.com/200x100',
|
||||
url: '/pages/activity/detail?id=2'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '建行积分兑换',
|
||||
desc: '建行积分可兑换商城优惠券',
|
||||
tag: '积分兑换',
|
||||
image: 'https://via.placeholder.com/200x100',
|
||||
url: '/pages/activity/detail?id=3'
|
||||
}
|
||||
]);
|
||||
|
||||
// 商品列表
|
||||
const goodsList = reactive([
|
||||
{
|
||||
id: 1,
|
||||
title: '建行专享商品一',
|
||||
price: '88.00',
|
||||
originalPrice: '128.00',
|
||||
image: 'https://via.placeholder.com/180x180'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '建行专享商品二',
|
||||
price: '168.00',
|
||||
originalPrice: '228.00',
|
||||
image: 'https://via.placeholder.com/180x180'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '建行专享商品三',
|
||||
price: '268.00',
|
||||
originalPrice: '368.00',
|
||||
image: 'https://via.placeholder.com/180x180'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '建行专享商品四',
|
||||
price: '99.00',
|
||||
originalPrice: '159.00',
|
||||
image: 'https://via.placeholder.com/180x180'
|
||||
}
|
||||
]);
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
// 获取用户信息
|
||||
const storedUserInfo = uni.getStorageSync('userInfo');
|
||||
if (storedUserInfo) {
|
||||
Object.assign(userInfo, storedUserInfo);
|
||||
}
|
||||
|
||||
// 检查是否在建行App内
|
||||
if (!sheep.$platform.provider === 'ccb') {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '请在建行生活App内访问此页面',
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
uni.navigateBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 加载建行专属活动和商品
|
||||
loadCcbActivities();
|
||||
loadCcbGoods();
|
||||
});
|
||||
|
||||
// 加载建行活动
|
||||
const loadCcbActivities = async () => {
|
||||
// TODO: 调用API获取建行专属活动
|
||||
console.log('加载建行活动');
|
||||
};
|
||||
|
||||
// 加载建行商品
|
||||
const loadCcbGoods = async () => {
|
||||
// TODO: 调用API获取建行专属商品
|
||||
console.log('加载建行商品');
|
||||
};
|
||||
|
||||
// 跳转到活动详情
|
||||
const goToActivity = (item) => {
|
||||
sheep.$router.go(item.url);
|
||||
};
|
||||
|
||||
// 查看更多
|
||||
const goToMore = () => {
|
||||
sheep.$router.go('/pages/activity/list', { type: 'ccb' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ccb-banner {
|
||||
width: 100%;
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.user-section {
|
||||
padding: 20rpx;
|
||||
background: linear-gradient(180deg, rgb(245,28,19) 0%, #fff 100%);
|
||||
|
||||
.user-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.1);
|
||||
|
||||
.user-avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-right: 20rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
|
||||
.user-nickname {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.user-badge {
|
||||
padding: 10rpx 20rpx;
|
||||
background: linear-gradient(135deg, #ff6b6b 0%, #ff3333 100%);
|
||||
border-radius: 30rpx;
|
||||
|
||||
.badge-text {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activity-section,
|
||||
.goods-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 2rpx solid #f5f5f5;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.title-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.more-text {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activity-list {
|
||||
.activity-item {
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.activity-img {
|
||||
width: 200rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.activity-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.activity-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.activity-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
.activity-tag {
|
||||
.tag-text {
|
||||
display: inline-block;
|
||||
padding: 4rpx 12rpx;
|
||||
background: #fff5f5;
|
||||
color: #ff3333;
|
||||
font-size: 22rpx;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.goods-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.goods-item {
|
||||
width: 48%;
|
||||
margin-bottom: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 10rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.goods-img {
|
||||
width: 100%;
|
||||
height: 350rpx;
|
||||
}
|
||||
|
||||
.goods-info {
|
||||
padding: 20rpx;
|
||||
|
||||
.goods-title {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.goods-price {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.price-unit {
|
||||
font-size: 22rpx;
|
||||
color: #ff3333;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: 32rpx;
|
||||
color: #ff3333;
|
||||
font-weight: bold;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.price-old {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-tag {
|
||||
.tag-ccb {
|
||||
display: inline-block;
|
||||
padding: 4rpx 12rpx;
|
||||
background: linear-gradient(135deg, #ff6b6b 0%, #ff3333 100%);
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-tips {
|
||||
padding: 40rpx 0;
|
||||
text-align: center;
|
||||
|
||||
.tips-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -15,6 +15,7 @@ import { isWxBrowser } from '@/sheep/helper/utils';
|
||||
// #endif
|
||||
import wechat from './provider/wechat/index.js';
|
||||
import apple from './provider/apple';
|
||||
import ccblife from './provider/ccblife/index.js';
|
||||
import share from './share';
|
||||
import Pay from './pay';
|
||||
|
||||
@ -28,7 +29,14 @@ let platform = '';
|
||||
let isWechatInstalled = true;
|
||||
|
||||
// #ifdef H5
|
||||
if (isWxBrowser()) {
|
||||
// 先检测建行生活环境
|
||||
ccblife.detectEnvironment();
|
||||
|
||||
if (ccblife.isInCcbApp) {
|
||||
name = 'CcbLife';
|
||||
provider = 'ccb';
|
||||
platform = 'ccblife';
|
||||
} else if (isWxBrowser()) {
|
||||
name = 'WechatOfficialAccount';
|
||||
provider = 'wechat';
|
||||
platform = 'officialAccount';
|
||||
@ -65,13 +73,19 @@ const load = () => {
|
||||
if (provider === 'wechat') {
|
||||
wechat.load();
|
||||
}
|
||||
if (provider === 'ccb') {
|
||||
ccblife.init();
|
||||
// 处理URL跳转登录
|
||||
ccblife.handleUrlLogin();
|
||||
}
|
||||
};
|
||||
|
||||
// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple'
|
||||
// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple' | 'ccb'
|
||||
const useProvider = (_provider = '') => {
|
||||
if (_provider === '') _provider = provider;
|
||||
if (_provider === 'wechat') return wechat;
|
||||
if (_provider === 'apple') return apple;
|
||||
if (_provider === 'ccb') return ccblife;
|
||||
};
|
||||
|
||||
// 支付服务转发
|
||||
|
||||
@ -5,6 +5,8 @@ import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
|
||||
import {
|
||||
getRootUrl
|
||||
} from '@/sheep/helper';
|
||||
import CcbLifePlatform from './provider/ccblife/index';
|
||||
import ccbApi from './provider/ccblife/api';
|
||||
|
||||
/**
|
||||
* 支付
|
||||
@ -31,6 +33,9 @@ export default class SheepPay {
|
||||
alipay: () => {
|
||||
this.redirectPay(); // 现在公众号可以直接跳转支付宝页面
|
||||
},
|
||||
ccb: () => {
|
||||
this.ccbPay(); // 建行支付
|
||||
},
|
||||
money: () => {
|
||||
this.moneyPay();
|
||||
},
|
||||
@ -45,6 +50,9 @@ export default class SheepPay {
|
||||
alipay: () => {
|
||||
this.copyPayLink();
|
||||
},
|
||||
ccb: () => {
|
||||
sheep.$helper.toast('小程序暂不支持建行支付');
|
||||
},
|
||||
money: () => {
|
||||
this.moneyPay();
|
||||
},
|
||||
@ -59,6 +67,9 @@ export default class SheepPay {
|
||||
alipay: () => {
|
||||
this.alipay();
|
||||
},
|
||||
ccb: () => {
|
||||
this.ccbPay(); // 建行支付
|
||||
},
|
||||
money: () => {
|
||||
this.moneyPay();
|
||||
},
|
||||
@ -68,11 +79,19 @@ export default class SheepPay {
|
||||
},
|
||||
H5: {
|
||||
wechat: () => {
|
||||
this.wechatWapPay();
|
||||
// 如果在建行App内,使用建行支付
|
||||
if (CcbLifePlatform.isInCcbApp) {
|
||||
this.ccbPay();
|
||||
} else {
|
||||
this.wechatWapPay();
|
||||
}
|
||||
},
|
||||
alipay: () => {
|
||||
this.redirectPay();
|
||||
},
|
||||
ccb: () => {
|
||||
this.ccbPay(); // 建行支付
|
||||
},
|
||||
money: () => {
|
||||
this.moneyPay();
|
||||
},
|
||||
@ -268,6 +287,69 @@ export default class SheepPay {
|
||||
}
|
||||
}
|
||||
|
||||
// 建行生活支付
|
||||
async ccbPay() {
|
||||
let that = this;
|
||||
|
||||
// 检查是否在建行App内
|
||||
if (!CcbLifePlatform.isInCcbApp) {
|
||||
sheep.$helper.toast('请在建行生活App内使用建行支付');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取订单ID(从订单号查询)
|
||||
const orderInfo = await sheep.$api.order.detail(this.orderSN);
|
||||
if (!orderInfo || orderInfo.code !== 1) {
|
||||
sheep.$helper.toast('获取订单信息失败');
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用后端生成支付串
|
||||
const paymentResult = await ccbApi.createPayment(orderInfo.data.id);
|
||||
|
||||
if (paymentResult.code !== 1) {
|
||||
sheep.$helper.toast(paymentResult.msg || '生成支付串失败');
|
||||
return;
|
||||
}
|
||||
|
||||
// 调起建行支付
|
||||
try {
|
||||
const result = await CcbLifePlatform.payment({
|
||||
payment_string: paymentResult.data.payment_string,
|
||||
order_id: orderInfo.data.id,
|
||||
order_sn: this.orderSN
|
||||
});
|
||||
|
||||
if (result.code === 0) {
|
||||
// 支付成功,通知后端
|
||||
const callbackResult = await ccbApi.paymentCallback({
|
||||
order_id: orderInfo.data.id,
|
||||
trans_id: result.data?.trans_id || '',
|
||||
pay_time: new Date().getTime()
|
||||
});
|
||||
|
||||
if (callbackResult.code === 1) {
|
||||
that.payResult('success');
|
||||
} else {
|
||||
sheep.$helper.toast('支付确认失败,请联系客服');
|
||||
that.payResult('fail');
|
||||
}
|
||||
} else {
|
||||
// 支付失败或取消
|
||||
if (result.msg && result.msg.includes('取消')) {
|
||||
sheep.$helper.toast('支付已取消');
|
||||
} else {
|
||||
sheep.$helper.toast(result.msg || '支付失败');
|
||||
that.payResult('fail');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[建行支付] 错误:', error);
|
||||
sheep.$helper.toast('支付失败');
|
||||
that.payResult('fail');
|
||||
}
|
||||
}
|
||||
|
||||
// 支付结果跳转,success:成功,fail:失败
|
||||
payResult(resultType) {
|
||||
sheep.$router.redirect('/pages/pay/result', {
|
||||
|
||||
78
frontend/sheep/platform/provider/ccblife/api.js
Normal file
78
frontend/sheep/platform/provider/ccblife/api.js
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 建行生活 API 接口
|
||||
*
|
||||
* @author Billy
|
||||
* @date 2025-01-17
|
||||
*/
|
||||
|
||||
import request from '@/sheep/request';
|
||||
|
||||
const ccbApi = {
|
||||
/**
|
||||
* URL跳转登录
|
||||
* 建行App会携带加密参数跳转到此地址
|
||||
*/
|
||||
login: (params) => {
|
||||
return request({
|
||||
url: '/ccblife/login',
|
||||
method: 'GET',
|
||||
params: params,
|
||||
custom: {
|
||||
showLoading: true,
|
||||
auth: false
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 自动登录(JSBridge方式)
|
||||
* H5在建行App内打开时,通过JSBridge获取用户信息后调用
|
||||
*/
|
||||
autoLogin: (data) => {
|
||||
return request({
|
||||
url: '/ccblife/autoLogin',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
custom: {
|
||||
showLoading: true,
|
||||
auth: false
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成支付串
|
||||
* 用于调起建行收银台
|
||||
*/
|
||||
createPayment: (orderId) => {
|
||||
return request({
|
||||
url: '/ccbpayment/createPayment',
|
||||
method: 'POST',
|
||||
data: {
|
||||
order_id: orderId
|
||||
},
|
||||
custom: {
|
||||
showLoading: true,
|
||||
auth: true
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 支付回调
|
||||
* 支付完成后通知后端
|
||||
*/
|
||||
paymentCallback: (data) => {
|
||||
return request({
|
||||
url: '/ccbpayment/callback',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
custom: {
|
||||
showLoading: false,
|
||||
auth: true
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default ccbApi;
|
||||
440
frontend/sheep/platform/provider/ccblife/index.js
Normal file
440
frontend/sheep/platform/provider/ccblife/index.js
Normal file
@ -0,0 +1,440 @@
|
||||
/**
|
||||
* 建行生活平台集成模块
|
||||
*
|
||||
* @author Billy
|
||||
* @date 2025-01-17
|
||||
*/
|
||||
|
||||
import sheep from '@/sheep';
|
||||
import ccbApi from './api';
|
||||
|
||||
// 建行生活配置
|
||||
const config = {
|
||||
// 是否开启调试
|
||||
debug: true,
|
||||
// API基础路径
|
||||
apiBaseUrl: '/addons/shopro',
|
||||
// 超时时间
|
||||
timeout: 10000,
|
||||
};
|
||||
|
||||
// 建行生活平台对象
|
||||
const CcbLifePlatform = {
|
||||
// 平台标识
|
||||
platform: 'ccblife',
|
||||
|
||||
// 平台名称
|
||||
name: '建行生活',
|
||||
|
||||
// 是否在建行生活环境中
|
||||
isInCcbApp: false,
|
||||
|
||||
// JSBridge 对象
|
||||
bridge: null,
|
||||
|
||||
// 就绪状态
|
||||
isReady: false,
|
||||
|
||||
// 就绪回调队列
|
||||
readyCallbacks: [],
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init() {
|
||||
// 检测环境
|
||||
this.detectEnvironment();
|
||||
|
||||
// 如果在建行App内,初始化JSBridge
|
||||
if (this.isInCcbApp) {
|
||||
this.setupBridge();
|
||||
// 自动登录
|
||||
this.autoLogin();
|
||||
}
|
||||
|
||||
console.log('[CcbLife] 初始化完成, 是否在建行App内:', this.isInCcbApp);
|
||||
},
|
||||
|
||||
/**
|
||||
* 检测运行环境
|
||||
*/
|
||||
detectEnvironment() {
|
||||
// #ifdef H5
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
|
||||
// 检查User-Agent
|
||||
if (ua.indexOf('ccblife') > -1 || ua.indexOf('ccb') > -1) {
|
||||
this.isInCcbApp = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查URL参数
|
||||
const urlParams = this.getUrlParams();
|
||||
if (urlParams.ccbParamSJ || urlParams.from === 'ccblife') {
|
||||
this.isInCcbApp = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查JSBridge
|
||||
if (window.WebViewJavascriptBridge || window.mbspay) {
|
||||
this.isInCcbApp = true;
|
||||
return;
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
// 在APP中也可能通过插件方式集成建行SDK
|
||||
// TODO: 检测建行SDK插件
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 小程序环境不支持建行生活
|
||||
this.isInCcbApp = false;
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置JSBridge
|
||||
*/
|
||||
setupBridge() {
|
||||
// #ifdef H5
|
||||
const 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(() => {
|
||||
if (!self.isReady) {
|
||||
console.warn('[CcbLife] JSBridge 未就绪');
|
||||
}
|
||||
}, 3000);
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* Bridge就绪回调
|
||||
*/
|
||||
onBridgeReady() {
|
||||
this.isReady = true;
|
||||
console.log('[CcbLife] JSBridge 已就绪');
|
||||
|
||||
// 执行所有等待的回调
|
||||
this.readyCallbacks.forEach(callback => callback());
|
||||
this.readyCallbacks = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* 等待Bridge就绪
|
||||
*/
|
||||
ready(callback) {
|
||||
if (this.isReady) {
|
||||
callback();
|
||||
} else {
|
||||
this.readyCallbacks.push(callback);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取URL参数
|
||||
*/
|
||||
getUrlParams() {
|
||||
const params = {};
|
||||
// #ifdef H5
|
||||
const search = window.location.search.substring(1);
|
||||
if (search) {
|
||||
const pairs = search.split('&');
|
||||
pairs.forEach(pair => {
|
||||
const parts = pair.split('=');
|
||||
if (parts.length === 2) {
|
||||
params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
|
||||
}
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取建行用户信息
|
||||
*/
|
||||
async getUserInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInCcbApp) {
|
||||
reject({
|
||||
code: -1,
|
||||
msg: '不在建行生活App内'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.ready(() => {
|
||||
this.callNative('getUserInfo', {}, (result) => {
|
||||
if (result && result.userid) {
|
||||
resolve({
|
||||
code: 0,
|
||||
data: {
|
||||
ccb_user_id: result.userid,
|
||||
mobile: result.mobile || '',
|
||||
nickname: result.nickname || '',
|
||||
avatar: result.avatar || ''
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reject({
|
||||
code: -1,
|
||||
msg: '获取用户信息失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 自动登录
|
||||
*/
|
||||
async autoLogin() {
|
||||
try {
|
||||
// 检查是否已登录
|
||||
const token = uni.getStorageSync('token');
|
||||
if (token) {
|
||||
console.log('[CcbLife] 用户已登录');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
const userResult = await this.getUserInfo();
|
||||
if (userResult.code !== 0) {
|
||||
throw new Error(userResult.msg);
|
||||
}
|
||||
|
||||
// 调用后端登录接口
|
||||
const loginResult = await ccbApi.autoLogin(userResult.data);
|
||||
|
||||
if (loginResult.code === 1) {
|
||||
// 保存Token和用户信息
|
||||
uni.setStorageSync('token', loginResult.data.token);
|
||||
uni.setStorageSync('userInfo', loginResult.data.userInfo);
|
||||
|
||||
// 更新Shopro用户状态
|
||||
sheep.$store('user').getInfo();
|
||||
|
||||
console.log('[CcbLife] 自动登录成功');
|
||||
|
||||
// 触发登录成功事件
|
||||
uni.$emit('ccb:login:success', loginResult.data);
|
||||
} else {
|
||||
throw new Error(loginResult.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[CcbLife] 自动登录失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 调起建行支付
|
||||
*/
|
||||
async payment(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInCcbApp) {
|
||||
reject({
|
||||
code: -1,
|
||||
msg: '不在建行生活App内'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 必需参数检查
|
||||
if (!options.payment_string) {
|
||||
reject({
|
||||
code: -1,
|
||||
msg: '缺少支付串参数'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.ready(() => {
|
||||
// #ifdef H5
|
||||
// 区分iOS和Android
|
||||
if (this.isIOS()) {
|
||||
// iOS使用URL Scheme
|
||||
this.paymentForIOS(options, resolve, reject);
|
||||
} else {
|
||||
// Android使用JSBridge
|
||||
this.paymentForAndroid(options, resolve, reject);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
// APP中调用原生插件
|
||||
this.paymentForApp(options, resolve, reject);
|
||||
// #endif
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* iOS支付
|
||||
*/
|
||||
paymentForIOS(options, resolve, reject) {
|
||||
// #ifdef H5
|
||||
const paymentUrl = 'comccbpay://pay?' + options.payment_string;
|
||||
|
||||
// 尝试打开支付页面
|
||||
window.location.href = paymentUrl;
|
||||
|
||||
// 设置回调检查
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
code: 0,
|
||||
msg: '已调起支付,请在建行App内完成支付'
|
||||
});
|
||||
}, 1000);
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* Android支付
|
||||
*/
|
||||
paymentForAndroid(options, resolve, reject) {
|
||||
this.callNative('payment', {
|
||||
payment_string: options.payment_string
|
||||
}, (result) => {
|
||||
if (result && result.success) {
|
||||
resolve({
|
||||
code: 0,
|
||||
data: result
|
||||
});
|
||||
} else {
|
||||
reject({
|
||||
code: -1,
|
||||
msg: result ? result.error : '支付失败'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* APP支付
|
||||
*/
|
||||
paymentForApp(options, resolve, reject) {
|
||||
// #ifdef APP-PLUS
|
||||
// TODO: 调用建行SDK插件
|
||||
uni.showToast({
|
||||
title: 'APP支付暂未实现',
|
||||
icon: 'none'
|
||||
});
|
||||
reject({
|
||||
code: -1,
|
||||
msg: 'APP支付暂未实现'
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 调用原生方法
|
||||
*/
|
||||
callNative(method, params, callback) {
|
||||
// #ifdef H5
|
||||
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直接调用
|
||||
const result = window.mbspay[method](JSON.stringify(params));
|
||||
if (callback) {
|
||||
callback(typeof result === 'string' ? JSON.parse(result) : result);
|
||||
}
|
||||
} else {
|
||||
console.warn('[CcbLife] 原生方法不存在:', method);
|
||||
if (callback) {
|
||||
callback({
|
||||
success: false,
|
||||
error: '原生方法不存在'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[CcbLife] 调用原生方法失败:', e);
|
||||
if (callback) {
|
||||
callback({
|
||||
success: false,
|
||||
error: e.message
|
||||
});
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断是否iOS
|
||||
*/
|
||||
isIOS() {
|
||||
// #ifdef H5
|
||||
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
return uni.getSystemInfoSync().platform === 'ios';
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理URL跳转登录
|
||||
*/
|
||||
async handleUrlLogin() {
|
||||
const params = this.getUrlParams();
|
||||
|
||||
// 如果有ccbParamSJ参数,说明是从建行跳转过来的
|
||||
if (params.ccbParamSJ) {
|
||||
try {
|
||||
// 调用后端解密并登录
|
||||
const result = await ccbApi.login(params);
|
||||
|
||||
if (result.code === 1) {
|
||||
// 保存Token和用户信息
|
||||
uni.setStorageSync('token', result.data.token);
|
||||
uni.setStorageSync('userInfo', result.data.user_info);
|
||||
|
||||
// 更新用户状态
|
||||
sheep.$store('user').getInfo();
|
||||
|
||||
// 跳转到指定页面
|
||||
const redirectUrl = result.data.redirect_url || '/pages/index/index';
|
||||
uni.reLaunch({
|
||||
url: redirectUrl
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.msg || '登录失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[CcbLife] URL登录失败:', error);
|
||||
uni.showToast({
|
||||
title: '登录失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 导出平台对象
|
||||
export default CcbLifePlatform;
|
||||
Loading…
x
Reference in New Issue
Block a user