0.2.3 • Published 9 months ago
mobileportalui v0.2.3
bsoft-mobilePortal
切换到公司镜像才可安装
一.引用
npm i mobileportal
二.配置
1、拷贝node_modules中mobileportal的文件到项目uni_modules/bsoft-mobilePortal,在build/gen-uni-config.js文件copyMobilePortalFile()函数。
function copyMobilePortalFile() {
let fileNames = ['assets', 'utils', 'vendor', 'pages'];
fileNames.forEach(name => {
let sourcePath = path.resolve(rootPath, 'node_modules/mobileportal', name);
let destPath = path.resolve(rootPath, 'src/uni_modules/bsoft-mobilePortal', name);
if (pathExist(destPath)) {
return;
}
if (pathExist(sourcePath)) {
fs.copySync(sourcePath, destPath);
} else {
console.error('请安装mobileportal依赖');
}
});
}
function genRoute(obj) {
copyMobilePortalFile(); //拷贝node_modules中mobileportal的文件到项目
...
}
2、pages.json配置
pages.json中引入要使用的uni_modules/bsoft-mobilePortal正确的界面路径
{
"easycom":
{
"^u-(.*)": "@/uni_modules/bsoft-mobilePortal/vendor/uview-ui/components/u-$1/u-$1.vue"
},
"condition":
{
"current": 0,
"list":
[
]
},
"pages":
[
{
"path": "uni_modules/bsoft-mobilePortal/pages/home/home",
"meta": {
"auth": true
},
"style": {
"navigationBarTitleText": "首页",
"enablePullDownRefresh": true,
"onReachBottomDistance": 50,
"app-plus": {
"pullToRefresh":
{
"support": true,
"color": "#fa436a",
"style": "default"
},
"bounce": "none"
}
}
},
{
"path": "uni_modules/bsoft-mobilePortal/pages/message/message",
"meta": {
"auth": true
},
"style": {
"navigationBarTitleText": "消息",
"enablePullDownRefresh": true,
"onReachBottomDistance": 50,
"app-plus": {
"pullToRefresh":
{
"support": true,
"color": "#fa436a",
"style": "default"
},
"bounce": "none"
}
}
},
{
"path": "uni_modules/bsoft-mobilePortal/pages/user/user",
"meta": {
"auth": true
},
"style": {
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "uni_modules/bsoft-mobilePortal/pages/login/login",
"meta": {
"auth": false
},
"style": {
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
}
],
"subPackages":
[
{
"root": "uni_modules/bsoft-mobilePortal/pages/my",
"pages": [
{
"path": "about",
"meta": {
"auth": false
},
"style": {
"navigationBarTitleText": "关于我们"
}
},
{
"path": "forgetPwd",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "找回登录密码"
}
},
{
"path": "modifyPwd",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "找回登录密码"
}
},
{
"path": "resetPwd",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "找回登录密码"
}
},
{
"path": "userInfo",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "个人信息"
}
},
{
"path": "textArea",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "个人信息"
}
},
{
"path": "safeCenter",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "安全中心"
}
},
{
"path": "myWeb",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "服务协议"
}
},
{
"path": "set",
"meta": {
"auth": false
},
"style":
{
"navigationBarTitleText": "设置"
}
}
]
}
],
"tabBar":
{
"color": "#7a7e83",
"selectedColor": "#0faeff",
"backgroundColor": "#ffffff",
"list":
[
{
"pagePath": "uni_modules/bsoft-mobilePortal/pages/home/home",
"text": "首页",
"iconPath": "/static/img/ic_menu_home@2x.png",
"selectedIconPath": "/static/img/ic_menu_home_sel@2x.png"
},
{
"pagePath": "uni_modules/bsoft-mobilePortal/pages/message/message",
"text": "消息",
"iconPath": "/static/img/ic_menu_message@2x.png",
"selectedIconPath": "/static/img/ic_menu_message_sel@2x.png"
},
{
"pagePath": "uni_modules/bsoft-mobilePortal/pages/user/user",
"text": "我的",
"iconPath": "/static/img/ic_menu_mine@2x.png",
"selectedIconPath": "/static/img/ic_menu_mine_sel@2x.png"
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#FFFFFF",
"sitemapLocation": "sitemap.json",
"app-plus": {
"titleNView": false
}
}
}
3.接口请求url配置
(1)以下时webpack配置说明示例:
config_proj_main.js文件中serviceUrl配置接口请求地址
serviceUrl: {
develop: "http://10.10.2.124:8080/bbp-server", //本地联调环境
build_develop: "http://uop.bsoft.com.cn/gw", //测试环境
build_publish: "https://app.nure.bshcn.com.cn", //发布环境
},
//图片地址前缀
imgPreviewUrl: {
develop: "http://10.10.2.124:8080/bbp-server",
build_develop: "http://uop.bsoft.com.cn/upload/image",
build_publish: "https://app.nure.bshcn.com.cn/upload/image",
},
(2)项目utils/config.js配置说明
let cfg= JSON.parse(project_cfg);
let base = cfg.serviceUrl; //生成产品用 开发或者提交都用这个地址
let config = {}
config=cfg;
config.baseUrl = base;
config.commonUrl = `${base}/*.jsonRequest`; //通用的请求地址
config.imgPreviewUrl = cfg.imgPreviewUrl+"/";
config.wxTitle= cfg.title;
config.isSceneTenant=false;
export default config;
(3)框架中的utils/api.js中引用了项目的utils/config.js,并且全局接口请求配置的请求域名是baseUrl,故需要上面两步设置
4.菜单功能配置
(1)登录bbp管理后台->权限管理->功能配置中配置首页菜单功能和我的页面菜单功能,其中"首页"编码配置成bsmp-index,"我的"编码配置成bsmp-mine,具体的功能配置见下图3(需配置跳转的路由地址和功能菜单图标)
(2)首页菜单显示如下
(3)我的菜单显示如下
三.初始化
入口App.vue中引入import BSMP from "@/uni_modules/bsoft-mobilePortal/utils/BSMP"
onLaunch(){
//初始化,主要用于h5与宿主通信
租户编码配置、应用名称、用户协议、隐私政策
let cfg = {
tenantId: '', //租户id(必填)
appName: '', //应用名称
privacyUrl: '', //隐私政策url
userAgreementUrl: '' //用户协议url
}
BSMP.init(cfg);
//需项目处理的界面跳转(处理系统消息跳转)
uni.$on('page',res=>{
//type类型 message消息
//data数据 消息中心界面跳转需要的数据
let {type='',data=''} = res;
if(type == 'message'){
}
})
}
四.使用
import BSMP from "@/uni_modules/bsoft-mobilePortal/utils/BSMP"
BSMP提供了定位、支付、APP分享、判断是否已登录、登录用户ID,登录用户信息方法
1、定位功能,
(1)manifest.json开启定位功能配置
H5增加如下配置(腾讯地图为例,其它地图配置详见uniapp文档)
"h5":
{
"sdkConfigs":
{
"maps":
{
"qqmap":
{
"key": "xxxx-xxxx"
}
}
},
"permission":
{
"scope.userLocation":
{
"desc": "使用地理位置信息的描述"
}
},
}
微信小程序增加配置
"mp-weixin":
{
"permission":
{
"scope.userLocation":
{
"desc": "使用地理位置信息的描述"
}
},
"requiredPrivateInfos":
[
"getLocation"
]
},
(2)使用定位
BSMP.location('gcj02',false).then(({err,res})=>{
if(!err){
// 定位成功,res对象如下
// latitude 纬度,浮点数,范围为-90~90,负数表示南纬
// longitude 经度,浮点数,范围为-180~180,负数表示西经
// speed 速度,浮点数,单位m/s
// accuracy 位置的精确度
// altitude 高度,单位 m
// verticalAccuracy 垂直精度,单位 m(Android 无法获取,返回 0)
// horizontalAccuracy 水平精度,单位 m
// address 地址信息(仅App端支持,需配置geocode为true)
}else{
//定位失败
}
})
2、支付
(1)在App端要申请微信的App支付,而小程序端申请微信的小程序支付。
(2)iOS和Android原生支付需要在项目中配置相关包名和appId
(3)manifest.json开启支付配置
(4)出入参说明
* @params provider 服务提供商(wxpay微信支付 alipay支付宝 mpPay微信小程序 appleiap苹果支付)
* @params orderInfo 订单数据(支付宝支付orderInfo 为 String 类型 微信支付 orderInfo 为 Object 类型)
* @params jumpUrl (微信H5支付为String类型,跳转支付url 嵌入到微信小程序的h5,支付需要跳转的微信小程序的路径,由小程序根据参数处理支付请求)
* @params callback 回调结果(result: success支付成功 fail支付失败 complete支付完成,不知道支付结果,需要自己查询)
(5)使用
例:支付宝支付
let orderPay = "alipay_sdk=alipay-sdk-java-3.3.49.ALL&app_id=2021002199655419&biz_content=%7B%22body%22%3A%22%E4%BD%8F%E9%99%A2%E9%99%AA%E6%8A%A4-%E6%85%A7%E5%BA%B7%E4%BA%92%E8%81%94%E6%8A%A4%E7%90%86%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8%22%2C%22goods_type%22%3A%221%22%2C%22out_trade_no%22%3A%22nure_721029251477798912%22%2C%22subject%22%3A%22%E4%BD%8F%E9%99%A2%E9%99%AA%E6%8A%A4-%E6%85%A7%E5%BA%B7%E4%BA%92%E8%81%94%E6%8A%A4%E7%90%86%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8%22%2C%22timeout_express%22%3A%2230m%22%2C%22total_amount%22%3A%220.01%22%7D&charset=utf-8&format=json&method=alipay.trade.app.pay¬ify_url=https%3A%2F%2Fnpay-nure.bshcn.com.cn%2Falipay%2Fnotify&sign=P3BkJLWZxCf7i9oMZSK7BbRask3SWcasTOH%2FIoYJuH91wC38wXz2QqRjoR%2B%2F2vOEIG1YM8WlmWLpIvVE493yVNb4O6z27T4VWRYhCehbI7JO0MgRrgNPH3vznMCPRjxkdaUFoBYJRraTi9CfkWq5NXAZIj7FLZnRkQVFFTY8tyBt1H%2F6w%2F2DG2jqWrgKSju%2FzjsnKj1wvrng2%2Br4NiBlYrkSqwt4PnQDFA5x4xhYE6P0F%2FoKsfDRo0Qyqr5ZD4VD534BFCGxx%2BwYAckWbLyUhA0Orzt8E3HII1z5RLLfJhT7o0O1VNkQF8olWqYeZHnnU3M513dH6hmp8LdABEr%2Fxw%3D%3D&sign_type=RSA2×tamp=2023-08-10+14%3A05%3A47&version=1.0"
BSMP.requestPayment('alipay', orderPay, null, (res => {
}));
(6)说明:H5支付支付结果不会通知到,目前做法的是弹窗让用户确认,然后由宿主自己查询支付结果
3、APP分享(微信小程序分享详见uniapp文档)
(1)manifest.json分享相关配置
(2)使用
入参参考https://uniapp.dcloud.net.cn/api/plugins/share.html
let shareObj = {
provider: 'weixin',
scene: 'WXSceneSession',
type: 1,
summary: '我正在使用HBuilderX开发uni-app,赶紧跟我一起来体验!',
};
BSMP.appShare(shareObj,
function(res) {
//分享成功
},
function(err) {
//分享失败
})
4、判断是否已登录
(1)使用
let hasLogin = BSMP.hasLogin(); //true已登录 false未登录
5、登录用户ID
(1)使用
let userId = BSMP.getUserId();
6、登录用户信息方法
(1)使用
let userInfo = BSMP.getUserInfo();
7、获取当前登录用户token
let token = BSMP.getToken();
8、获取首页菜单
let menu = BSMP.getHomeMenu();
9、获取我的菜单
let menu = BSMP.getMineMenu();
五.宿主App与uni小程序通讯
1.宿主App向uni小程序发送事件
[self.uniMPInstance sendUniMPEvent:@event data:@data];
uni小程序项目在入口App.vue中接受事件,由项目处理或者交给BSMP处理
uni.onNativeEventReceive((event,data)=>{
console.log('接收到宿主App消息:' + event + data);
//BSMP处理
BSMP.dealNativeEvent(event,data);
})
BSMP支持以下事件:
(1)跳转到小程序界面
event: 'mp_page'
data: {
path: '/xx/xx/xx', //uni小程序路由界面
extData: {} //传给小程序的数据
}
(2)打开支付
event: 'mp_pay'
data: {
provider: '', //服务提供商(wxpay微信支付 alipay支付宝 mpPay微信小程序 appleiap苹果支付)
orderInfo: {} //订单数据(支付宝支付orderInfo 为 String 类型 微信支付 orderInfo 为 Object 类型)
jumpUrl: '' (微信H5支付为String类型,跳转支付url 嵌入到微信小程序的h5,支付需要跳转的微信小程序的路径,由小程序根据参数处理支付请求)
}
(3)调用分享
event: 'mp_share'
data: {
provider: 'weixin',
scene: 'WXSceneSession',
type: 1,
summary: '我正在使用HBuilderX开发uni-app,赶紧跟我一起来体验!',
}
(4)用户登录信息
event: 'mp_userInfo'
data: userInfo //需包含用户token
(5)用户退出登录
event: 'mp_loginout'
2.uni小程序向宿主发送事件
uni.sendNativeEvent(event, data
, ret => {
console.log('宿主App回传的数据:' + ret);
})
(1)支付结果回调
event: 'mp_payResult',
res:{result: 'success'}
//res回调结果(result: success支付成功 fail支付失败 complete支付完成,不知道支付结果,需要自己查询)
uni.sendNativeEvent('mp_payResult', res
, ret => {
console.log('宿主App回传的数据:' + ret);
})
(2)分享结果回调
event: 'mp_shareResult',
res:{result: 'success'}
//res回调结果(result: success支付成功 fail支付失败)
uni.sendNativeEvent('mp_payResult', res
, ret => {
console.log('宿主App回传的数据:' + ret);
})
六.门户H5与嵌入H5交互
1.说明:通过postMessage实现跨域通信和界面间数据通信
3.宿主H5接受消息
uniapp开发示例:
js核心代码:
onReady(){
// #ifdef H5
// 接收消息
window.addEventListener("message", this.handleMessage,false);
//#endif
},
methods: {
handleMessage(evt) {
// #ifdef H5
console.log('接收到h5的消息:数据:' + JSON.stringify(evt.data));
console.log("evt===========");
console.log(evt);
var origin = "";
origin = window.location.protocol+"//"+window.location.hostname+":"+window.location.port;
console.log(origin);
//首先最好判断evt的来源
if (!evt.data.data || evt.origin==origin){
return;
}
let data=evt.data.data.arg;
if ('object' == typeof data){
this.handleH5Action(data,evt);
}
// #endif
// #ifdef APP-PLUS
let params=JSON.stringify(evt.detail.data);
console.log('接收到的消息:' + params);
let reqData=evt.detail.data[0];
if ('object' == typeof reqData){
this.handleH5Action(reqData,evt);
}
// #endif
},
handleH5Action(reqData,evt){
let action=reqData.action; //请求事件
let callbackFunc = reqData.callback; //回调函数
let params=reqData.data; //请求参数对象
if (action == 'login'){
//登录
let hasLogin = true;
if(!hasLogin){
//未登录
let that = this;
uni.$on("loginSuccess", (data) => {
let info = {}; //当前登录用户数据
let result = {
code:200,
msg:'登陆成功',
data: info
}
that.doCallback(action,result,callbackFunc,evt);
});
//跳转到宿主登录界面,登录成功后结果回传loginSuccess,然后调用doCallback方法
}else{
let info = {}; //当前登录用户数据
let result = {
code:200,
msg:'登陆成功',
data: info
}
this.doCallback(action,result,callbackFunc,evt);
}
}else if (action == 'silenceLogin'){
//静默登录
let info = that.$userTools.thirdUserInfoResult();
if(info){
result ={
code:200,
msg:'登陆成功',
data: info
}
}
this.doCallback(action,result,callbackFunc,evt);
}else if(action == 'nativePay'){
//处理native支付请求
//请求参数{channel:1//支付渠道 1支付宝 2微信
//,tradeInfo:"调起支付参数"//channel=1时为支付宝支付参数字符串,当=2时为partnerid=xxx&prepayid=xxx&noncestr=xxx×tamp=xxx&sign=xxx&appid=xxx}
let that = this;
//宿主实现支付请求,并发送支付结果到门户H5
this.thridCallPay(params).then(({ err, msg }) => {
let result={
code: 200,
msg: msg,
};
if(err){
result={
code: 500,
msg: msg,
};
}
that.doCallback(action,result,callbackFunc,evt);
});
}
},
doCallback(action,result,callbackFunc,evt){
//debugger
let backData={
isEventCallback:true,
action:action,
callback:callbackFunc,
data:result,
};
let backText=JSON.stringify(backData);
//{"isEventCallback":true,"action":"login","callback":"bshc.bsEventCallback","data":{"code":200,"msg":"登陆成功","data":{"name":"测试","uid":"xhkksdksdhk"}}}
console.log("回调数据对象:"+backText);
// #ifdef APP-PLUS
let callback=callbackFunc+"("+backText+")";
//此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效,非v3编译模式使用this.$mp.page.$getAppWebview()
let currentWebview = this.$scope.$getAppWebview()
let webView = currentWebview.children()[0];
webView.evalJS(callback);
// #endif
// #ifdef H5
evt.source.postMessage(backData,evt.origin);
// #endif
},
}
七.宿主小程序与门户H5交互
1.说明: 由于小程序没有api去实现小程序->webview的通讯,只能通过改变页面的hash传递消息,改变hash并不会导致webview刷新,跳转至小程序过渡页面处理相关
2.详见目录三初始化时,入参pagePath和mode必填,入参路由路径xx/xx/xx,mode=1,即BSMP.init(xx/xx/xx,1);
3.由初始的路由路径xx/xx/xx接受并处理门户H5传递的消息,
uniapp开发示例,xx/xx/xx页面代码如下:
<template>
<view class="content">
<view class="loading">请求处理中...</view>
</view>
</template>
<script>
export default {
data() {
return {
href:'',
hash:'',
uuid:'',
action:'',
params:{},
triggered:false
};
},
onLoad(option) {
console.log("option="+JSON.stringify(option));
this.setupParams(option);
},
onUnload() {
// 页面销毁, 还没执行过回调,默认失败
if (!this.triggered) {
this.pageCallBack({
href: this.href,
hash: this.hash,
uuid: this.uuid,
},{
code:500,
msg:'内部错误',
});
}
},
onReady(){
let action=this.action;
console.log("action====="+action);
let reqData={
href: this.href,
hash: this.hash,
uuid: this.uuid,
};
if (action == 'login'){
let that = this;
let hasLogin = true;
if(!hasLogin){
uni.$off("loginSuccess");
uni.$on("loginSuccess", (data) => {
let info = {};
var result = {
code: -1,
msg:'用户信息获取失败',
}
if(info){
result ={
code:200,
msg:'登陆成功',
data: info
}
}
console.log('login result:'+JSON.stringify(result));
that.pageCallBack(reqData,result);
});
//跳转到宿主登录界面,登录成功后结果回传loginSuccess,然后调用doCallback方法
}else{
let info = {};
var result = {
code: -1,
msg:'用户信息获取失败',
}
if(info){
result ={
code:200,
msg:'登陆成功',
data: info
}
}
console.log('login result:'+JSON.stringify(result));
that.pageCallBack(reqData,result);
}
}else if (action == 'silenceLogin'){
//静默登录,接入方进去页面时会调用,如果当前未登录则直接返回未登录状态码
let info = {};
let result ={
code:200,
msg:'登陆成功',
data: info
}
console.log('login result:'+JSON.stringify(result));
this.pageCallBack(reqData,result);
}else if(action == 'nativePay'){
//处理微信小程序支付请求
//请求参数{channel:1//支付渠道 1支付宝 2微信
//,tradeInfo:"调起支付参数"//channel=1时为支付宝支付参数字符串,当=2时为partnerid=xxx&prepayid=xxx&noncestr=xxx×tamp=xxx&sign=xxx&appid=xxx}
console.log("params==");
if(!this.params || !this.params.tradeInfo){
this.$toast("支付参数返回错误");
return;
}
console.log(this.params);
let tradeInfo = this.params.tradeInfo;
let wxPramas = tradeInfo;
if(typeof tradeInfo == "string"){
if(tradeInfo.indexOf("&") !=-1){
wxPramas = this.$tools.getStrParameters(this.params.tradeInfo);
}else{
wxPramas = JSON.parse(tradeInfo);
if(!wxPramas.timeStamp){
wxPramas.timeStamp = wxPramas.timestamp;
}
if(!wxPramas.package){
wxPramas.package = wxPramas.pg;
}
}
}
console.log(wxPramas);
console.log(typeof wxPramas,"type====")
let that = this;
wx.requestPayment({
appId: wxPramas.appId, //公众号名称,由商户传入
timeStamp: wxPramas.timeStamp, //时间戳,自1970年以来的秒数
nonceStr: wxPramas.nonceStr, //随机串
package: wxPramas.package, //prepay_id用等式的格式
signType: wxPramas.signType, //微信签名方式:
paySign: wxPramas.paySign, //微信签名
success: function (res) {
},
fai: function (res) {
},
complete: function (res) {
console.log("payresult===========");
console.log(res);
var result={
code: 500,
msg:'支付失败',
};
if(res.errMsg == "requestPayment:ok"){
result={
code: 200,
msg:'支付成功',
};
}
that.pageCallBack(reqData,result);
},
});
}else{
this.close();
}
},
methods: {
setupParams(option) {
let title = option.title || '';
uni.setNavigationBarTitle({
title: title
});
let action = option.action;
if (action){
this.action=decodeURIComponent(action);
}
let href = option.href;
if (href) {
this.href = decodeURIComponent(href);
}
let hash = option.hash;
if (hash) {
this.hash = decodeURIComponent(hash);
}
let uuid = option.uuid;
if (uuid) {
this.uuid = decodeURIComponent(uuid);
}
let params = option.data;
if (params && params != 'null') {
this.params = JSON.parse(decodeURIComponent(params));
}
},
pageCallBack(data,result){
this.triggered = true;
var pages = getCurrentPages();
console.log("我是获取的pages栈----------------------", pages);
var currPage = pages[pages.length - 1]; //当前页面
//上一个页面 (index page)
var prevPage = pages[pages.length - 2];
let {
href,
hash,
uuid
} = data;
let visitUrl = this.getWebviewHref(href, hash, uuid, result);
console.log(`设置webview的url为:${visitUrl}`);
prevPage.setData({
url:visitUrl,
});
// 关闭当前页面
this.close();
},
getWebviewHref(href, hash, uuid, result){
// 取url的query参数
// 单独处理hash的query参数
let temp=hash.split("?");
//let query = Qs.parse(hash.split("?")[1]);
let query = '';
if(temp.length>1){
query=temp[1];
}
if (typeof result === "object") result = JSON.stringify(result);
// Object.assign(query, {
// uuid,
// result,
// });
if (query.length>0){
query = "&uuid=" + encodeURIComponent(uuid) + "&result=" + encodeURIComponent(result);
}else{
query = "uuid=" + encodeURIComponent(uuid) + "&result=" + encodeURIComponent(result);
}
hash = temp[0];
// 防止当前webview的url不存在hash出错
hash = hash || "#";
hash += "?" + query;
return href + hash;
},
close(){
uni.navigateBack({
delta: 1
});
}
},
}
</script>