初始化移动端提交

This commit is contained in:
chenbowen
2025-09-30 00:08:23 +08:00
parent 08784ca8f3
commit f2ffc65094
406 changed files with 55626 additions and 93 deletions

168
sheep/platform/index.js Normal file
View File

@@ -0,0 +1,168 @@
/**
* Shopro 第三方平台功能聚合
* @version 1.0.3
* @author lidongtony
* @param {String} name - 厂商+平台名称
* @param {String} provider - 厂商
* @param {String} platform - 平台名称
* @param {String} os - 系统型号
* @param {Object} device - 设备信息
*/
import { isEmpty } from 'lodash-es';
// #ifdef H5
import { isWxBrowser } from '@/sheep/helper/utils';
// #endif
import wechat from './provider/wechat/index.js';
import apple from './provider/apple';
import share from './share';
const device = uni.getWindowInfo();
const os = uni.getDeviceInfo().platform;
let name = '';
let provider = '';
let platform = '';
let isWechatInstalled = true;
// #ifdef H5
if (isWxBrowser()) {
name = 'WechatOfficialAccount';
provider = 'wechat';
platform = 'officialAccount';
} else {
name = 'H5';
platform = 'h5';
}
// #endif
// #ifdef APP-PLUS
name = 'App';
platform = 'openPlatform';
// 检查微信客户端是否安装否则AppleStore会因此拒绝上架
if (os === 'ios') {
isWechatInstalled = plus.ios.import('WXApi').isWXAppInstalled();
}
// #endif
// #ifdef MP-WEIXIN
name = 'WechatMiniProgram';
platform = 'miniProgram';
provider = 'wechat';
// #endif
if (isEmpty(name)) {
uni.showToast({
title: '暂不支持该平台',
icon: 'none',
});
}
// 加载当前平台前置行为
const load = () => {
if (provider === 'wechat') {
wechat.load();
}
};
// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple'
const useProvider = (_provider = '') => {
if (_provider === '') _provider = provider;
if (_provider === 'wechat') return wechat;
if (_provider === 'apple') return apple;
};
/**
* 检查更新 (只检查小程序和App)
* @param {Boolean} silence - 静默检查
*/
const checkUpdate = (silence = false) => {
let canUpdate;
// #ifdef MP-WEIXIN
useProvider().checkUpdate(silence);
// #endif
// #ifdef APP-PLUS
// TODO: 热更新
// #endif
};
/**
* 检查网络
* @param {Boolean} silence - 静默检查
*/
async function checkNetwork() {
const networkStatus = await uni.getNetworkType();
if (networkStatus.networkType == 'none') {
return Promise.resolve(false);
}
return Promise.resolve(true);
}
// 获取小程序胶囊信息
const getCapsule = () => {
// #ifdef MP
let capsule = uni.getMenuButtonBoundingClientRect();
if (!capsule) {
capsule = {
bottom: 56,
height: 32,
left: 278,
right: 365,
top: 24,
width: 87,
};
}
return capsule;
// #endif
// #ifndef MP
return {
bottom: 56,
height: 32,
left: 278,
right: 365,
top: 24,
width: 87,
};
// #endif
};
const capsule = getCapsule();
// 标题栏高度
const getNavBar = () => {
return device.statusBarHeight + 44;
};
const navbar = getNavBar();
function getLandingPage() {
let page = '';
// #ifdef H5
page = location.href.split('?')[0];
// #endif
return page;
}
// 设置ios+公众号网页落地页 解决微信sdk签名问题
const landingPage = getLandingPage();
const _platform = {
name,
device,
os,
provider,
platform,
useProvider,
checkUpdate,
checkNetwork,
share,
load,
capsule,
navbar,
landingPage,
isWechatInstalled,
};
export default _platform;

View File

@@ -0,0 +1,36 @@
// import third from '@/sheep/api/third';
// TODO 芋艿:等后面搞 App 再弄
const login = () => {
return new Promise(async (resolve, reject) => {
const loginRes = await uni.login({
provider: 'apple',
success: () => {
uni.getUserInfo({
provider: 'apple',
success: async (res) => {
if (res.errMsg === 'getUserInfo:ok') {
const payload = res.userInfo;
const { error } = await third.apple.login({
payload,
shareInfo: uni.getStorageSync('shareLog') || {},
});
if (error === 0) {
resolve(true);
} else {
resolve(false);
}
}
},
});
},
fail: (err) => {
resolve(false);
},
});
});
};
export default {
login,
};

View File

@@ -0,0 +1,9 @@
// #ifdef APP-PLUS
import service from './app';
// #endif
let apple = {};
if (typeof service !== 'undefined') {
apple = service;
}
export default apple;

View File

@@ -0,0 +1,15 @@
// #ifdef H5
import service from './officialAccount';
// #endif
// #ifdef MP-WEIXIN
import service from './miniProgram';
// #endif
// #ifdef APP-PLUS
import service from './openPlatform';
// #endif
const wechat = service;
export default wechat;

View File

@@ -0,0 +1,241 @@
import AuthUtil from '@/sheep/api/system/auth';
import SocialApi from '@/sheep/api/system/social';
import UserApi from '@/sheep/api/system/user';
import sheep from '@/sheep';
const socialType = 34; // 社交类型 - 微信小程序
let subscribeEventList = [];
// 加载微信小程序
function load() {
checkUpdate();
getSubscribeTemplate();
}
// 微信小程序静默授权登陆
const login = async () => {
return new Promise(async (resolve, reject) => {
// 1. 获得微信 code
const codeResult = await uni.login();
if (codeResult.errMsg !== 'login:ok') {
return resolve(false);
}
// 2. 社交登录
const loginResult = await AuthUtil.socialLogin(socialType, codeResult.code, 'default');
if (loginResult.code === 0) {
setOpenid(loginResult.data.openid);
return resolve(true);
} else {
return resolve(false);
}
});
};
// 微信小程序手机号授权登陆
const mobileLogin = async (e) => {
return new Promise(async (resolve, reject) => {
if (e.errMsg !== 'getPhoneNumber:ok') {
return resolve(false);
}
// 1. 获得微信 code
const codeResult = await uni.login();
if (codeResult.errMsg !== 'login:ok') {
return resolve(false);
}
// 2. 一键登录
const loginResult = await AuthUtil.weixinMiniAppLogin(e.code, codeResult.code, 'default');
if (loginResult.code === 0) {
setOpenid(loginResult.data.openid);
return resolve(true);
} else {
return resolve(false);
}
});
};
// 微信小程序绑定
const bind = () => {
return new Promise(async (resolve, reject) => {
// 1. 获得微信 code
const codeResult = await uni.login();
if (codeResult.errMsg !== 'login:ok') {
return resolve(false);
}
// 2. 绑定账号
const bindResult = await SocialApi.socialBind(socialType, codeResult.code, 'default');
if (bindResult.code === 0) {
setOpenid(bindResult.data);
return resolve(true);
} else {
return resolve(false);
}
});
};
// 微信小程序解除绑定
const unbind = async (openid) => {
const { code } = await SocialApi.socialUnbind(socialType, openid);
return code === 0;
};
// 绑定用户手机号
const bindUserPhoneNumber = (e) => {
return new Promise(async (resolve, reject) => {
const { code } = await UserApi.updateUserMobileByWeixin(e.code);
if (code === 0) {
resolve(true);
}
resolve(false);
});
};
// 设置 openid 到本地存储,目前只有 pay 支付时会使用
function setOpenid(openid) {
uni.setStorageSync('openid', openid);
}
// 获得 openid
async function getOpenid(force = false) {
let openid = uni.getStorageSync('openid');
if (!openid && force) {
const info = await getInfo();
if (info && info.openid) {
openid = info.openid;
setOpenid(openid);
}
}
return openid;
}
// 获得社交信息
async function getInfo() {
const { code, data } = await SocialApi.getSocialUser(socialType);
if (code !== 0) {
return undefined;
}
return data;
}
// ========== 非登录相关的逻辑 ==========
// 小程序更新
const checkUpdate = async (silence = true) => {
if (uni.canIUse('getUpdateManager')) {
const updateManager = uni.getUpdateManager();
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
if (res.hasUpdate) {
updateManager.onUpdateReady(function () {
uni.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success: function (res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate();
}
},
});
});
updateManager.onUpdateFailed(function () {
// 新的版本下载失败
// uni.showModal({
// title: '已经有新版本了哟~',
// content: '新版本已经上线啦,请您删除当前小程序,重新搜索打开~',
// });
});
} else {
if (!silence) {
uni.showModal({
title: '当前为最新版本',
showCancel: false,
});
}
}
});
}
};
// 获取订阅消息模板
async function getSubscribeTemplate() {
const { code, data } = await SocialApi.getSubscribeTemplateList();
if (code === 0) {
subscribeEventList = data;
}
}
// 订阅消息
function subscribeMessage(event, callback = undefined) {
let tmplIds = [];
if (typeof event === 'string') {
const temp = subscribeEventList.find((item) => item.title.includes(event));
if (temp) {
tmplIds.push(temp.id);
}
}
if (typeof event === 'object') {
event.forEach((e) => {
const temp = subscribeEventList.find((item) => item.title.includes(e));
if (temp) {
tmplIds.push(temp.id);
}
});
}
if (tmplIds.length === 0) return;
uni.requestSubscribeMessage({
tmplIds,
success: () => {
// 不管是拒绝还是同意都触发
callback && callback();
},
fail: (err) => {
console.log(err);
},
});
}
// 商家转账用户确认模式下,拉起页面请求用户确认收款 Transfer
function requestMerchantTransfer(mchId, packageInfo, successCallback, failCallback) {
if (!wx.canIUse('requestMerchantTransfer')) {
wx.showModal({
content: '你的微信版本过低,请更新至最新版本。',
showCancel: false,
});
return;
}
wx.requestMerchantTransfer({
mchId: mchId,
appId: wx.getAccountInfoSync().miniProgram.appId,
package: packageInfo,
success: (res) => {
// res.err_msg 将在页面展示成功后返回应用时返回 ok并不代表付款成功
console.log('success:', res);
successCallback && successCallback(res);
},
fail: (res) => {
console.log('fail:', res);
sheep.$helper.toast(res.errMsg);
failCallback && failCallback(res);
},
});
}
export default {
load,
login,
bind,
unbind,
bindUserPhoneNumber,
mobileLogin,
getInfo,
getOpenid,
subscribeMessage,
checkUpdate,
requestMerchantTransfer,
};

View File

@@ -0,0 +1,105 @@
import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
import { getRootUrl } from '@/sheep/helper';
import AuthUtil from '@/sheep/api/system/auth';
import SocialApi from '@/sheep/api/system/social';
const socialType = 31; // 社交类型 - 微信公众号
// 加载微信公众号JSSDK
async function load() {
$wxsdk.init();
}
// 微信公众号登陆
async function login(code = '', state = '') {
// 情况一:没有 code 时,去获取 code
if (!code) {
const loginUrl = await getLoginUrl();
if (loginUrl) {
uni.setStorageSync('returnUrl', location.href);
window.location = loginUrl;
}
// 情况二:有 code 时,使用 code 去自动登录
} else {
// 解密 code 发起登陆
const loginResult = await AuthUtil.socialLogin(socialType, code, state);
if (loginResult.code === 0) {
setOpenid(loginResult.data.openid);
return loginResult;
}
}
return false;
}
// 微信公众号绑定
async function bind(code = '', state = '') {
// 情况一:没有 code 时,去获取 code
if (code === '') {
const loginUrl = await getLoginUrl('bind');
if (loginUrl) {
uni.setStorageSync('returnUrl', location.href);
window.location = loginUrl;
}
} else {
// 情况二:有 code 时,使用 code 去自动绑定
const loginResult = await SocialApi.socialBind(socialType, code, state);
if (loginResult.code === 0) {
setOpenid(loginResult.data);
return loginResult;
}
}
return false;
}
// 微信公众号解除绑定
const unbind = async (openid) => {
const { code } = await SocialApi.socialUnbind(socialType, openid);
return code === 0;
};
// 获取公众号登陆地址
async function getLoginUrl(event = 'login') {
const page = getRootUrl() + 'pages/index/login' + '?event=' + event; // event 目的,区分是 login 还是 bind
const { code, data } = await AuthUtil.socialAuthRedirect(socialType, page);
if (code !== 0) {
return undefined;
}
return data;
}
// 设置 openid 到本地存储,目前只有 pay 支付时会使用
function setOpenid(openid) {
uni.setStorageSync('openid', openid);
}
// 获得 openid
async function getOpenid(force = false) {
let openid = uni.getStorageSync('openid');
if (!openid && force) {
const info = await getInfo();
if (info && info.openid) {
openid = info.openid;
setOpenid(openid);
}
}
return openid;
}
// 获得社交信息
async function getInfo() {
const { code, data } = await SocialApi.getSocialUser(socialType);
if (code !== 0) {
return undefined;
}
return data;
}
export default {
load,
login,
bind,
unbind,
getInfo,
getOpenid,
jsWxSdk: $wxsdk,
};

View File

@@ -0,0 +1,64 @@
// 登录
import third from '@/sheep/api/migration/third';
import SocialApi from '@/sheep/api/system/social';
import $share from '@/sheep/platform/share';
// TODO 芋艿:等后面搞 App 再弄
const socialType = 32; // 社交类型 - 微信开放平台
const load = async () => {};
// 微信开放平台移动应用授权登陆
const login = () => {
return new Promise(async (resolve, reject) => {
const loginRes = await uni.login({
provider: 'weixin',
onlyAuthorize: true,
});
debugger
if (loginRes.errMsg == 'login:ok') {
// TODO third.wechat.login 函数未实现
const res = await third.wechat.login({
platform: 'openPlatform',
shareInfo: uni.getStorageSync('shareLog') || {},
payload: encodeURIComponent(
JSON.stringify({
code: loginRes.code,
}),
),
});
if (res.error === 0) {
$share.bindBrokerageUser()
resolve(true);
}
} else {
uni.showToast({
icon: 'none',
title: loginRes.errMsg,
});
}
resolve(false);
});
};
// 微信 App 解除绑定
const unbind = async (openid) => {
const { code } = await SocialApi.socialUnbind(socialType, openid);
return code === 0;
};
// 获得社交信息
async function getInfo() {
const { code, data } = await SocialApi.getSocialUser(socialType);
if (code !== 0) {
return undefined;
}
return data;
}
export default {
load,
login,
getInfo
};

184
sheep/platform/share.js Normal file
View File

@@ -0,0 +1,184 @@
import $store from '@/sheep/store';
import $platform from '@/sheep/platform';
import $router from '@/sheep/router';
import $url from '@/sheep/url';
import { SharePageEnum } from '@/sheep/helper/const';
// #ifdef H5
import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
// #endif
// 设置分享的平台渠道: 1=H5,2=微信公众号网页,3=微信小程序,4=App,...按需扩展
const platformMap = ['H5', 'WechatOfficialAccount', 'WechatMiniProgram', 'App'];
// 设置分享方式: 1=直接转发,2=海报,3=复制链接,...按需扩展
const fromMap = ['forward', 'poster', 'link'];
// 设置分享信息参数
const getShareInfo = (
scene = {
title: '', // 自定义分享标题
desc: '', // 自定义描述
image: '', // 自定义分享图片
params: {}, // 自定义分享参数
},
poster = {
// 自定义海报数据
type: 'user',
},
) => {
const shareInfo = {
title: '', // 分享标题
desc: '', // 描述
image: '', // 分享图片
path: '', // 分享页面+参数
link: '', // 分享Url+参数
query: '', // 分享参数
poster, // 海报所需数据
forward: {}, // 转发所需参数
};
shareInfo.title = scene.title;
shareInfo.image = $url.cdn(scene.image);
shareInfo.desc = scene.desc;
const app = $store('app');
const shareConfig = app.platform.share;
// 自动拼接分享用户参数
const query = buildSpmQuery(scene.params);
shareInfo.query = query;
// 配置分享链接地址
shareInfo.link = buildSpmLink(query, shareConfig.linkAddress);
// 配置页面地址带参数
shareInfo.path = buildSpmPath();
// 配置页面转发参数
if (shareConfig.methods.includes('forward')) {
shareInfo.forward.path = buildSpmPath(query);
}
return shareInfo;
};
/**
* 构造 spm 分享参数
*
* @param params json 格式其中包含1shareId 分享用户的编号2page 页面类型3query 页面 ID参数4platform 平台类型5from 分享来源类型。
* @return 分享串 `spm=${shareId}.${page}.${query}.${platform}.${from}`
*/
const buildSpmQuery = (params) => {
const user = $store('user');
let shareId = '0'; // 设置分享者用户ID
if (typeof params.shareId === 'undefined') {
if (user.isLogin) {
shareId = user.userInfo.id;
}
}
let page = SharePageEnum.HOME.value; // 页面类型,默认首页
if (typeof params.page !== 'undefined') {
page = params.page;
}
let query = '0'; // 设置页面ID: 如商品ID、拼团ID等
if (typeof params.query !== 'undefined') {
query = params.query;
}
let platform = platformMap.indexOf($platform.name) + 1;
let from = '1';
if (typeof params.from !== 'undefined') {
from = platformMap.indexOf(params.from) + 1;
}
// spmParams = ... 可按需扩展
return `spm=${shareId}.${page}.${query}.${platform}.${from}`;
};
// 构造页面分享参数: 所有的分享都先到首页进行 spm 参数解析
const buildSpmPath = (query) => {
// 默认是主页,页面 page例如 pages/index/index根路径前不要填加 /
// 不能携带参数参数请放在scene字段里如果不填写这个字段默认跳主页面。scancode_time为系统保留参数不允许配置
// 页面分享时参数使用 ? 拼接
return typeof query === 'undefined' ? `pages/index/index` : `pages/index/index?${query}`;
};
// 构造分享链接
const buildSpmLink = (query, linkAddress = '') => {
return `${linkAddress}?${query}`;
};
// 解析Spm
const decryptSpm = (spm) => {
const user = $store('user');
let shareParamsArray = spm.split('.');
let shareParams = {
spm,
shareId: 0,
page: '',
query: {},
platform: '',
from: '',
};
let query;
shareParams.shareId = shareParamsArray[0];
switch (shareParamsArray[1]) {
case SharePageEnum.HOME.value:
// 默认首页不跳转
shareParams.page = SharePageEnum.HOME.page;
break;
case SharePageEnum.GOODS.value:
// 普通商品
shareParams.page = SharePageEnum.GOODS.page;
shareParams.query = {
id: shareParamsArray[2], // 设置活动编号
};
break;
}
shareParams.platform = platformMap[shareParamsArray[3] - 1];
shareParams.from = fromMap[shareParamsArray[4] - 1];
if (shareParams.shareId !== 0) {
// 记录分享者编号
uni.setStorageSync('shareId', shareParams.shareId);
// 已登录 绑定推广员
if (!!user.isLogin) {
bindBrokerageUser(shareParams.shareId);
}
}
if (shareParams.page !== SharePageEnum.HOME.page) {
$router.go(shareParams.page, shareParams.query);
}
return shareParams;
};
// 绑定推广员
const bindBrokerageUser = async (val = undefined) => {
try {
const shareId = val || uni.getStorageSync('shareId');
if (!shareId) {
return;
}
// 绑定成功返回 true失败返回 false
const { data } = await BrokerageApi.bindBrokerageUser({ bindUserId: shareId });
// 绑定成功后清除缓存
if (data) {
uni.removeStorageSync('shareId');
}
} catch (e) {
console.error(e);
}
};
// 更新公众号分享sdk
const updateShareInfo = (shareInfo) => {
// #ifdef H5
if ($platform.name === 'WechatOfficialAccount') {
$wxsdk.updateShareInfo(shareInfo);
}
// #endif
};
export default {
getShareInfo,
updateShareInfo,
decryptSpm,
bindBrokerageUser,
};