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
|
// #endif
|
||||||
import wechat from './provider/wechat/index.js';
|
import wechat from './provider/wechat/index.js';
|
||||||
import apple from './provider/apple';
|
import apple from './provider/apple';
|
||||||
|
import ccblife from './provider/ccblife/index.js';
|
||||||
import share from './share';
|
import share from './share';
|
||||||
import Pay from './pay';
|
import Pay from './pay';
|
||||||
|
|
||||||
@ -28,7 +29,14 @@ let platform = '';
|
|||||||
let isWechatInstalled = true;
|
let isWechatInstalled = true;
|
||||||
|
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
if (isWxBrowser()) {
|
// 先检测建行生活环境
|
||||||
|
ccblife.detectEnvironment();
|
||||||
|
|
||||||
|
if (ccblife.isInCcbApp) {
|
||||||
|
name = 'CcbLife';
|
||||||
|
provider = 'ccb';
|
||||||
|
platform = 'ccblife';
|
||||||
|
} else if (isWxBrowser()) {
|
||||||
name = 'WechatOfficialAccount';
|
name = 'WechatOfficialAccount';
|
||||||
provider = 'wechat';
|
provider = 'wechat';
|
||||||
platform = 'officialAccount';
|
platform = 'officialAccount';
|
||||||
@ -65,13 +73,19 @@ const load = () => {
|
|||||||
if (provider === 'wechat') {
|
if (provider === 'wechat') {
|
||||||
wechat.load();
|
wechat.load();
|
||||||
}
|
}
|
||||||
|
if (provider === 'ccb') {
|
||||||
|
ccblife.init();
|
||||||
|
// 处理URL跳转登录
|
||||||
|
ccblife.handleUrlLogin();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple'
|
// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple' | 'ccb'
|
||||||
const useProvider = (_provider = '') => {
|
const useProvider = (_provider = '') => {
|
||||||
if (_provider === '') _provider = provider;
|
if (_provider === '') _provider = provider;
|
||||||
if (_provider === 'wechat') return wechat;
|
if (_provider === 'wechat') return wechat;
|
||||||
if (_provider === 'apple') return apple;
|
if (_provider === 'apple') return apple;
|
||||||
|
if (_provider === 'ccb') return ccblife;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 支付服务转发
|
// 支付服务转发
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
|
|||||||
import {
|
import {
|
||||||
getRootUrl
|
getRootUrl
|
||||||
} from '@/sheep/helper';
|
} from '@/sheep/helper';
|
||||||
|
import CcbLifePlatform from './provider/ccblife/index';
|
||||||
|
import ccbApi from './provider/ccblife/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付
|
* 支付
|
||||||
@ -31,6 +33,9 @@ export default class SheepPay {
|
|||||||
alipay: () => {
|
alipay: () => {
|
||||||
this.redirectPay(); // 现在公众号可以直接跳转支付宝页面
|
this.redirectPay(); // 现在公众号可以直接跳转支付宝页面
|
||||||
},
|
},
|
||||||
|
ccb: () => {
|
||||||
|
this.ccbPay(); // 建行支付
|
||||||
|
},
|
||||||
money: () => {
|
money: () => {
|
||||||
this.moneyPay();
|
this.moneyPay();
|
||||||
},
|
},
|
||||||
@ -45,6 +50,9 @@ export default class SheepPay {
|
|||||||
alipay: () => {
|
alipay: () => {
|
||||||
this.copyPayLink();
|
this.copyPayLink();
|
||||||
},
|
},
|
||||||
|
ccb: () => {
|
||||||
|
sheep.$helper.toast('小程序暂不支持建行支付');
|
||||||
|
},
|
||||||
money: () => {
|
money: () => {
|
||||||
this.moneyPay();
|
this.moneyPay();
|
||||||
},
|
},
|
||||||
@ -59,6 +67,9 @@ export default class SheepPay {
|
|||||||
alipay: () => {
|
alipay: () => {
|
||||||
this.alipay();
|
this.alipay();
|
||||||
},
|
},
|
||||||
|
ccb: () => {
|
||||||
|
this.ccbPay(); // 建行支付
|
||||||
|
},
|
||||||
money: () => {
|
money: () => {
|
||||||
this.moneyPay();
|
this.moneyPay();
|
||||||
},
|
},
|
||||||
@ -68,11 +79,19 @@ export default class SheepPay {
|
|||||||
},
|
},
|
||||||
H5: {
|
H5: {
|
||||||
wechat: () => {
|
wechat: () => {
|
||||||
|
// 如果在建行App内,使用建行支付
|
||||||
|
if (CcbLifePlatform.isInCcbApp) {
|
||||||
|
this.ccbPay();
|
||||||
|
} else {
|
||||||
this.wechatWapPay();
|
this.wechatWapPay();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
alipay: () => {
|
alipay: () => {
|
||||||
this.redirectPay();
|
this.redirectPay();
|
||||||
},
|
},
|
||||||
|
ccb: () => {
|
||||||
|
this.ccbPay(); // 建行支付
|
||||||
|
},
|
||||||
money: () => {
|
money: () => {
|
||||||
this.moneyPay();
|
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:失败
|
// 支付结果跳转,success:成功,fail:失败
|
||||||
payResult(resultType) {
|
payResult(resultType) {
|
||||||
sheep.$router.redirect('/pages/pay/result', {
|
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