diff --git a/docs/api/media/video.md b/docs/api/media/video.md index 17489e2937814ca2b847d56b6502970b9ee2904b..b0dfd8998057995b82b26a56f06f5f3dfe64ba83 100644 --- a/docs/api/media/video.md +++ b/docs/api/media/video.md @@ -256,14 +256,14 @@ export default { |参数名 |类型 |说明 |平台差异说明| |:- |:- |:- || -|orientation|string |画面方向 |微信小程序| -|type |string |视频格式 |微信小程序| -|duration |number |视频长度 |微信小程序、App、H5| -|size |number |视频大小,单位 kB |微信小程序、App、H5| -|height |number |视频的长,单位 px |微信小程序、App、H5| -|width |number |视频的宽,单位 px |微信小程序、App、H5| -|fps |number |视频帧率 |微信小程序、App| -|bitrate |number |视频码率,单位 kbps|微信小程序| +|orientation|string |画面方向 |微信小程序、App(3.1.14+)| +|type |string |视频格式 |微信小程序、App(3.1.14+)| +|duration |number |视频长度 |微信小程序、App(3.1.10+)、H5| +|size |number |视频大小,单位 kB |微信小程序、App(3.1.10+)、H5| +|height |number |视频的长,单位 px |微信小程序、App(3.1.10+)、H5| +|width |number |视频的宽,单位 px |微信小程序、App(3.1.10+)、H5| +|fps |number |视频帧率 |微信小程序、App(3.1.14+)| +|bitrate |number |视频码率,单位 kbps|微信小程序、App(3.1.14+)| **res.orientation参数说明** diff --git a/docs/api/plugins/login.md b/docs/api/plugins/login.md index b88593eb14ab64f5324982b36b3b65c0a9148a0c..7cd694bdc6fc8069b8f1057d595cee43387967b7 100644 --- a/docs/api/plugins/login.md +++ b/docs/api/plugins/login.md @@ -12,6 +12,9 @@ H5平台登录注意事项: - 普通浏览器上实现微信登录,并非开放API,需要向微信申请,仅个别开发者有此权限 - H5平台的其他登录,比如QQ登录、微博登录,uni-app未封装,请在条件编译里按普通H5写法编写。 +百度小程序登录注意事项: +- 百度小程序平台需要在button组件的@login事件后再调用 uni.login ,[详见](https://smartprogram.baidu.com/docs/develop/function/login/),否则会返回“请登录”的错误信息,建议在@login事件中调用。 + **OBJECT 参数说明** |参数名|类型|必填|说明|平台差异说明| @@ -91,7 +94,7 @@ uni.login({ **OBJECT 参数说明** |参数名|类型|必填|说明|平台差异说明| -|:-|:-|:-|:-|:-|:-| +|:-|:-|:-|:-|:-| |provider|String|否|登录服务提供商,通过 uni.getProvider 获取|| |withCredentials|Boolean|否|是否带上登录态信息。|微信小程序、字节跳动小程序| |lang|String|否|指定返回用户信息的语言,默认为 en。更多值请参考下面的说明。|微信小程序| @@ -108,12 +111,12 @@ uni.login({ |zh_TW|繁体中文| |en|英文| -**注意:**在小程序 withCredentials 为 true 时或是在 App 调用 uni.getUserInfo,要求此前有调用过 uni.login 且登录态尚未过期。 +**注意:**在小程序 withCredentials 为 true 时或是在 App 调用 uni.getUserInfo,要求此前有调用过 uni.login 且登录态尚未过期。微信基础库2.10.4版本对用户信息相关接口进行了调整,使用 uni.getUserInfo 获取得到的 userInfo 为匿名数据,建议使用 uni.getUserProfile 获取用户信息。 **success 返回参数说明** |参数|类型|说明|平台差异说明| -|:-|:-|:-|| +|:-|:-|:-|:-| |userInfo|OBJECT|用户信息对象|| |rawData|String|不包括敏感信息的原始数据字符串,用于计算签名。|| |signature|String|使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息。|微信小程序、字节跳动小程序| @@ -124,7 +127,7 @@ uni.login({ **userInfo 参数说明** |参数|类型|说明|平台差异说明| -|:-|:-|:-|| +|:-|:-|:-|:-| |nickName|String|用户昵称|| |openId|String|该服务商唯一用户标识|App| |avatarUrl|String|用户头像| | @@ -166,6 +169,82 @@ uni.login({ 1. [支付宝登录](https://ext.dcloud.net.cn/search?q=%E6%94%AF%E4%BB%98%E5%AE%9D%E7%99%BB%E9%99%86)、[淘宝登录](https://ext.dcloud.net.cn/search?q=%E7%99%BE%E5%B7%9D)、[抖音登录](https://ext.dcloud.net.cn/search?q=%E6%8A%96%E9%9F%B3%E7%99%BB%E5%BD%95)、[facebook登录](https://ext.dcloud.net.cn/search?q=facebook%E7%99%BB%E5%BD%95)等在插件市场均已有插件,还有[sharesdk](https://ext.dcloud.net.cn/search?q=sharesdk)等专业集成多家登录分享的插件。 2. 也可以内嵌web-view组件,使用web登录模式集成这些三方登录 + +### uni.getUserProfile(OBJECT) + +获取用户信息。每次请求都会弹出授权窗口,用户同意后返回 userInfo。 + + + +**平台差异说明** + +|App|H5|微信小程序(基础库2.10.4)|支付宝小程序|百度小程序|字节跳动小程序|QQ小程序| +|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +|x|x|√|x|x|x|x| + +**注意:** 该API仅支持微信小程序端,微信小程序调整了相关接口(详见[《小程序登录、用户信息相关接口调整说明》](https://developers.weixin.qq.com/community/develop/doc/000cacfa20ce88df04cb468bc52801?highLine=getUserProfile%253Afail))。每次触发 uni.getUserProfile 均会弹出授权窗口,用户授权后可成功获取用户信息。 + +**OBJECT 参数说明** + +|参数名|类型|必填|说明| +|:-|:-|:-|:-| +|desc|String|是|声明获取用户个人信息后的用途,不超过30个字符| +|lang|String|否|指定返回用户信息的语言,默认为 en。更多值请参考下面的说明。| +|success|Function|否|接口调用成功的回调| +|fail|Function|否|接口调用失败的回调函数| +|complete|Function|否|接口调用结束的回调函数(调用成功、失败都会执行)| + +**lang 值说明** + +|值|说明| +|:-|:-| +|zh_CN|简体中文| +|zh_TW|繁体中文| +|en|英文| + +**注意:**可以使用 if(uni.getUserProfile) 判断uni.getUserProfile是否可用。 + +**success 返回参数说明** + +|参数|类型|说明| +|:-|:-|:-| +|userInfo|OBJECT|用户信息对象| +|rawData|String|不包括敏感信息的原始数据字符串,用于计算签名。| +|signature|String|使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息。| +|encryptedData|String|包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法。| +|iv|String|加密算法的初始向量,详细见加密数据解密算法。| +|cloudID|String|敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据,详细见云调用直接获取开放数据| +|errMsg|String|描述信息| + +**userInfo 参数说明** + +|参数|类型|说明|平台差异说明(仅支持微信小程序)| +|:-|:-|:-|| +|nickName|String|用户昵称|| +|avatarUrl|String|用户头像| | +|gender|Number|用户性别|| +|country|String|用户所在国家|| +|province|String|用户所在省份|| +|city|String|用户所在城市|| +|language|String|显示 country,province,city 所用的语言|| + +**gender 的合法值** + +|值|说明| +|:-|:-| +|0|未知| +|1|男性| +|2|女性| + +**language 的合法值** + +|值|说明| +|:-|:-| +|en|英文| +|zh_CN|简体中文| +|zh_TW|繁体中文| + + ### uni.preLogin(OBJECT) 预登录。 diff --git a/docs/component/progress.md b/docs/component/progress.md index af418acee09cc28582039c7c61717306f9d152a8..09cd4ae23f750a27764806f04595476cb1daa86f 100644 --- a/docs/component/progress.md +++ b/docs/component/progress.md @@ -14,7 +14,7 @@ |backgroundColor|Color |#EBEBEB |未选择的进度条的颜色 | | |active |Boolean |false |进度条从左往右的动画 | | |active-mode |String |backwards |backwards: 动画从头播;forwards:动画从上次结束点接着播|App、H5、微信小程序、QQ小程序 | -|duration|number|30|进度增加1%所需毫秒数|App-nvue2.6.1+、微信基础库2.8.2+| +|duration|number|30|进度增加1%所需毫秒数|App-nvue2.6.1+、微信基础库2.8.2+、H5 3.1.11+| |@activeend |EventHandle| |动画完成事件 |微信小程序 | **示例** [查看演示](https://hellouniapp.dcloud.net.cn/pages/component/progress/progress) diff --git a/lib/apis.js b/lib/apis.js index d9e6d7188cae1934fc979274d88fe101c9215225..385be3b9ee57ea657146e9d64c0450e388b63e38 100644 --- a/lib/apis.js +++ b/lib/apis.js @@ -214,6 +214,7 @@ const third = [ 'login', 'checkSession', 'getUserInfo', + 'getUserProfile', 'preLogin', 'closeAuthView', 'share', @@ -240,8 +241,9 @@ const third = [ const ad = [ 'createRewardedVideoAd', - 'createFullScreenVideoAd', - 'createInterstitialAd' + 'createFullScreenVideoAd', + 'createInterstitialAd', + 'createInteractiveAd' ] const apis = [ diff --git a/lib/modules.json b/lib/modules.json index dd0c32dfd69472c0f4d767d69f8a42c0777aa519..2386842b81dc019e735e8e810b727f86995fc9ca 100644 --- a/lib/modules.json +++ b/lib/modules.json @@ -206,6 +206,7 @@ "uni.login": true, "uni.checkSession": true, "uni.getUserInfo": true, + "uni.getUserProfile": true, "uni.share": true, "uni.showShareMenu": true, "uni.hideShareMenu": true, @@ -223,7 +224,8 @@ "title": "广告", "apiList": { "uni.createRewardedVideoAd": true, - "uni.createFullScreenVideoAd": true, - "uni.'createInterstitialAd'": true + "uni.createFullScreenVideoAd": true, + "uni.'createInterstitialAd'": true, + "uni.'createInteractiveAd'": true } }] diff --git a/packages/uni-app-plus/dist/index.js b/packages/uni-app-plus/dist/index.js index 8be7a3e5a32ed9ac9b808bdcb6cf437f07b74960..05b3ff576f5316773a8e8f3085dc3ddb7780b78a 100644 --- a/packages/uni-app-plus/dist/index.js +++ b/packages/uni-app-plus/dist/index.js @@ -1,5 +1,55 @@ import Vue from 'vue'; +function b64DecodeUnicode (str) { + return decodeURIComponent(atob(str).split('').map(function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) + }).join('')) +} + +function getCurrentUserInfo () { + const token = (uni ).getStorageSync('uni_id_token') || ''; + const tokenArr = token.split('.'); + if (!token || tokenArr.length !== 3) { + return { + uid: null, + role: [], + permission: [], + tokenExpired: 0 + } + } + let userInfo; + try { + userInfo = JSON.parse(b64DecodeUnicode(tokenArr[1])); + } catch (error) { + throw new Error('获取当前用户信息出错,详细错误信息为:' + error.message) + } + userInfo.tokenExpired = userInfo.exp * 1000; + delete userInfo.exp; + delete userInfo.iat; + return userInfo +} + +function uniIdMixin (Vue) { + Vue.prototype.uniIDHasRole = function (roleId) { + const { + role + } = getCurrentUserInfo(); + return role.indexOf(roleId) > -1 + }; + Vue.prototype.uniIDHasPermission = function (permissionId) { + const { + permission + } = getCurrentUserInfo(); + return this.uniIDHasRole('admin') || permission.indexOf(permissionId) > -1 + }; + Vue.prototype.uniIDTokenValid = function () { + const { + tokenExpired + } = getCurrentUserInfo(); + return tokenExpired > Date.now() + }; +} + const _toString = Object.prototype.toString; const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -411,7 +461,7 @@ function processReturnValue (methodName, res, returnValue, keepReturnValue = fal return processArgs(methodName, res, returnValue, {}, keepReturnValue) } -function wrapper (methodName, method) { +function wrapper$2 (methodName, method) { if (hasOwn(protocols, methodName)) { const protocol = protocols[methodName]; if (!protocol) { // 暂不支持的 api @@ -899,7 +949,7 @@ function initProperties (props, isBehavior = false, file = '') { return properties } -function wrapper$2 (event) { +function wrapper (event) { // TODO 又得兼容 mpvue 的 mp 对象 try { event.mp = JSON.parse(JSON.stringify(event)); @@ -1092,7 +1142,7 @@ function getContextVm (vm) { } function handleEvent (event) { - event = wrapper$2(event); + event = wrapper(event); // [['tap',[['handle',[1,2,a]],['handle1',[1,2,a]]]]] const dataset = (event.currentTarget || event.target).dataset; @@ -1258,7 +1308,7 @@ function getEventChannel (id) { return eventChannelStack.shift() } -const hooks = [ +const hooks$3 = [ 'onShow', 'onHide', 'onError', @@ -1292,6 +1342,7 @@ function parseBaseApp (vm, { if (vm.$options.store) { Vue.prototype.$store = vm.$options.store; } + uniIdMixin(Vue); Vue.prototype.mpHost = "app-plus"; @@ -1358,7 +1409,7 @@ function parseBaseApp (vm, { }); } - initHooks(appOptions, hooks); + initHooks(appOptions, hooks$3); return appOptions } @@ -1443,27 +1494,27 @@ function handleLink (event) { vueOptions.parent = parentVm; } -function parseApp (vm) { +function parseApp$1 (vm) { return parseBaseApp(vm, { mocks, initRefs }) } -const hooks$1 = [ +const hooks$2 = [ 'onUniNViewMessage' ]; -function parseApp$1 (vm) { - const appOptions = parseApp(vm); +function parseApp (vm) { + const appOptions = parseApp$1(vm); - initHooks(appOptions, hooks$1); + initHooks(appOptions, hooks$2); return appOptions } function createApp (vm) { - App(parseApp$1(vm)); + App(parseApp(vm)); return vm } @@ -1602,15 +1653,15 @@ function parseBaseComponent (vueComponentOptions, { return [componentOptions, VueComponent] } -function parseComponent (vueComponentOptions) { +function parseComponent$1 (vueComponentOptions) { return parseBaseComponent(vueComponentOptions, { isPage, initRelation }) } -function parseComponent$1 (vueComponentOptions) { - const componentOptions = parseComponent(vueComponentOptions); +function parseComponent (vueComponentOptions) { + const componentOptions = parseComponent$1(vueComponentOptions); componentOptions.methods.$getAppWebview = function () { return plus.webview.getWebviewById(`${this.__wxWebviewId__}`) @@ -1618,21 +1669,21 @@ function parseComponent$1 (vueComponentOptions) { return componentOptions } -const hooks$2 = [ +const hooks$1 = [ 'onShow', 'onHide', 'onUnload' ]; -hooks$2.push(...PAGE_EVENT_HOOKS); +hooks$1.push(...PAGE_EVENT_HOOKS); function parseBasePage (vuePageOptions, { isPage, initRelation }) { - const pageOptions = parseComponent$1(vuePageOptions); + const pageOptions = parseComponent(vuePageOptions); - initHooks(pageOptions.methods, hooks$2, vuePageOptions); + initHooks(pageOptions.methods, hooks$1, vuePageOptions); pageOptions.methods.onLoad = function (query) { this.options = query; @@ -1648,14 +1699,14 @@ function parseBasePage (vuePageOptions, { return pageOptions } -function parsePage (vuePageOptions) { +function parsePage$1 (vuePageOptions) { return parseBasePage(vuePageOptions, { isPage, initRelation }) } -const hooks$3 = [ +const hooks = [ 'onBackPress', 'onNavigationBarButtonTap', 'onNavigationBarSearchInputChanged', @@ -1664,28 +1715,28 @@ const hooks$3 = [ 'onNavigationBarSearchInputFocusChanged' ]; -function parsePage$1 (vuePageOptions) { - const pageOptions = parsePage(vuePageOptions); +function parsePage (vuePageOptions) { + const pageOptions = parsePage$1(vuePageOptions); - initHooks(pageOptions.methods, hooks$3); + initHooks(pageOptions.methods, hooks); return pageOptions } function createPage (vuePageOptions) { { - return Component(parsePage$1(vuePageOptions)) + return Component(parsePage(vuePageOptions)) } } function createComponent (vueOptions) { { - return Component(parseComponent$1(vueOptions)) + return Component(parseComponent(vueOptions)) } } function createSubpackageApp (vm) { - const appOptions = parseApp$1(vm); + const appOptions = parseApp(vm); const app = getApp({ allowDefault: true }); @@ -1720,7 +1771,7 @@ function createSubpackageApp (vm) { } function createPlugin (vm) { - const appOptions = parseApp$1(vm); + const appOptions = parseApp(vm); if (isFn(appOptions.onShow) && wx.onAppShow) { wx.onAppShow((...args) => { appOptions.onShow.apply(vm, args); @@ -1750,10 +1801,10 @@ canIUses.forEach(canIUseApi => { } }); -let uni = {}; +let uni$1 = {}; if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') { - uni = new Proxy({}, { + uni$1 = new Proxy({}, { get (target, name) { if (hasOwn(target, name)) { return target[name] @@ -1770,7 +1821,7 @@ if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') { if (!hasOwn(wx, name) && !hasOwn(protocols, name)) { return } - return promisify(name, wrapper(name, wx[name])) + return promisify(name, wrapper$2(name, wx[name])) }, set (target, name, value) { target[name] = value; @@ -1779,27 +1830,27 @@ if (typeof Proxy !== 'undefined' && "app-plus" !== 'app-plus') { }); } else { Object.keys(baseApi).forEach(name => { - uni[name] = baseApi[name]; + uni$1[name] = baseApi[name]; }); Object.keys(eventApi).forEach(name => { - uni[name] = eventApi[name]; + uni$1[name] = eventApi[name]; }); Object.keys(api).forEach(name => { - uni[name] = promisify(name, api[name]); + uni$1[name] = promisify(name, api[name]); }); Object.keys(wx).forEach(name => { if (hasOwn(wx, name) || hasOwn(protocols, name)) { - uni[name] = promisify(name, wrapper(name, wx[name])); + uni$1[name] = promisify(name, wrapper$2(name, wx[name])); } }); } { if (typeof global !== 'undefined') { - global.uni = uni; + global.uni = uni$1; global.UniEmitter = eventApi; } } @@ -1810,7 +1861,7 @@ wx.createComponent = createComponent; wx.createSubpackageApp = createSubpackageApp; wx.createPlugin = createPlugin; -var uni$1 = uni; +var uni$2 = uni$1; -export default uni$1; +export default uni$2; export { createApp, createComponent, createPage, createPlugin, createSubpackageApp }; diff --git a/packages/uni-template-compiler/__tests__/compiler-extra.spec.js b/packages/uni-template-compiler/__tests__/compiler-extra.spec.js index 052e92b38a9649d4290f72e93edf20cfc338c171..b8863cf8ac62ec8e209bb5edd55af2d3f247ea6b 100644 --- a/packages/uni-template-compiler/__tests__/compiler-extra.spec.js +++ b/packages/uni-template-compiler/__tests__/compiler-extra.spec.js @@ -727,6 +727,16 @@ describe('mp:compiler-extra', () => { '{{item2+"+"+index}}', 'with(this){if(!_isMounted){e0=function($event,item2){var _temp=arguments[arguments.length-1].currentTarget.dataset,_temp2=_temp.eventParams||_temp["event-params"],item2=_temp2.item2;var _temp,_temp2;return test(item2)}}}' ) + assertCodegen( + '', + '', + 'with(this){var l0=array();$mp.data=Object.assign({},{$root:{l0:l0}})}' + ) + assertCodegen( + '', + '', + 'with(this){var l0=array();if(!_isMounted){e0=function($event,item){var _temp=arguments[arguments.length-1].currentTarget.dataset,_temp2=_temp.eventParams||_temp["event-params"],item=_temp2.item;var _temp,_temp2;return test(item)}}$mp.data=Object.assign({},{$root:{l0:l0}})}' + ) }) it('generate bool attr', () => { assertCodegen( diff --git a/packages/uni-template-compiler/lib/script/traverse/data/event.js b/packages/uni-template-compiler/lib/script/traverse/data/event.js index ce784af4f6d868b2cacab9a61bbf262f1f9d7c97..c9b601cdf2f60100402898c46f007d574fc67b8e 100644 --- a/packages/uni-template-compiler/lib/script/traverse/data/event.js +++ b/packages/uni-template-compiler/lib/script/traverse/data/event.js @@ -206,6 +206,22 @@ function isValuePath (path) { return path.key !== 'key' && path.key !== 'id' && (path.key !== 'property' || path.parent.computed) && !(path.key === 'value' && path.parentPath.parentPath.isObjectPattern()) && !(path.key === 'left' && path.parentPath.parentPath.parentPath.isObjectPattern()) } +/** + * 判断 v-for 中是否包含复杂表达式:数组、对象、方法 + */ +const isSafeScoped = (state) => { + const scopedArray = state.scoped + for (let index = 0; index < scopedArray.length; index++) { + const scoped = scopedArray[index] + const arrayExtra = scoped.forExtra[0].elements[0].value + // 简易判断 + if (typeof arrayExtra === 'string' && (arrayExtra.startsWith('[') || arrayExtra.startsWith('{') || /\(.*\)/.test(arrayExtra))) { + return false + } + } + return true +} + function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, tagName, ret) { const key = keyPath.node let type = key.value || key.name || '' @@ -304,18 +320,9 @@ function parseEvent (keyPath, valuePath, state, isComponent, isNativeOn = false, } } - // 判断是否是复杂表达式 数组 或 对象 - const isNotDynamicExpression = (state) => { - if (!(state.scoped[0])) { - return true - } - const value = state.scoped[0].forExtra[0].elements[0].value - return !(typeof value === 'string' && (value.startsWith('[') || value.startsWith('}'))) - } - - // 如果v-for遍历的值为 数组、对象 则进入复杂表达式 - if (isNotDynamicExpression(state)) { - anonymous && funcPath.traverse({ + // 如果 v-for 遍历的值为 数组、对象、方法 则进入底部匿名表达式处理 + if (anonymous && isSafeScoped(state)) { + funcPath.traverse({ noScope: true, MemberExpression (path) { if (path.node.object.name === '$event' && path.node.property.name === diff --git a/packages/uni-template-compiler/lib/script/traverse/render-slot.js b/packages/uni-template-compiler/lib/script/traverse/render-slot.js index d02dcce3a5d7f8eb03211060b1b97e826b462226..4c82bd56be6931408d6ce4952e424187d665a3b9 100644 --- a/packages/uni-template-compiler/lib/script/traverse/render-slot.js +++ b/packages/uni-template-compiler/lib/script/traverse/render-slot.js @@ -30,5 +30,4 @@ module.exports = function getRenderSlot (path, state) { state.renderSlotStatementArray.push(t.expressionStatement(t.callExpression(t.identifier('$setScopedSlotsParams'), [t.stringLiteral(name.node.value), valueNode]))) } // TODO 组件嵌套 - path.skip() } diff --git a/packages/vue-cli-plugin-uni/lib/options.js b/packages/vue-cli-plugin-uni/lib/options.js index 67ad1e654dba946deb85ad6d19bca651d80f94c4..06e0634ae5d8f939ead02114c41faf95644640f4 100644 --- a/packages/vue-cli-plugin-uni/lib/options.js +++ b/packages/vue-cli-plugin-uni/lib/options.js @@ -26,6 +26,7 @@ module.exports = function initOptions (options) { // 增加 src/node_modules 解析 options.transpileDependencies.push(genTranspileDepRegex(path.resolve(process.env.UNI_INPUT_DIR, 'node_modules'))) options.transpileDependencies.push('@dcloudio/uni-' + process.env.UNI_PLATFORM) + options.transpileDependencies.push('@dcloudio/uni-i18n') options.transpileDependencies.push('@dcloudio/uni-stat') options.transpileDependencies.push('@dcloudio/vue-cli-plugin-uni/packages/uni-cloud') @@ -85,7 +86,7 @@ module.exports = function initOptions (options) { if (sassLoaderVersion < 8) { options.css.loaderOptions.sass.data = sassData - } else { + } else { const name = sassLoaderVersion >= 9 ? 'additionalData' : 'prependData' options.css.loaderOptions.sass[name] = sassData } diff --git a/packages/vue-cli-plugin-uni/packages/@vue/component-compiler-utils/dist/compileStyle.js b/packages/vue-cli-plugin-uni/packages/@vue/component-compiler-utils/dist/compileStyle.js index adaffdd92f32c9214f219295fce480da7dff9ad6..53d427312c66b6e1ea8df6a892e36d714a8844ec 100644 --- a/packages/vue-cli-plugin-uni/packages/@vue/component-compiler-utils/dist/compileStyle.js +++ b/packages/vue-cli-plugin-uni/packages/@vue/component-compiler-utils/dist/compileStyle.js @@ -8,6 +8,11 @@ const trim_1 = __importDefault(require("./stylePlugins/trim")); const scoped_1 = __importDefault(require("./stylePlugins/scoped")); const styleProcessors_1 = require("./styleProcessors"); const removeScoped_1 = __importDefault(require("./stylePlugins/remove-scoped")); +let comments; +try{ + comments = require('postcss-discard-comments') +}catch(e){} + function compileStyle(options) { return doCompileStyle(Object.assign({}, options, { isAsync: false })); } @@ -31,6 +36,12 @@ function doCompileStyle(options) { } else { // fixed by xxxxxx plugins.push(removeScoped_1.default(id)); } + // fixed by xxxxxx + if (process.env.UNI_PLATFORM === 'app-plus' && process.env.NODE_ENV === 'production') { + if (comments) { + plugins.push(comments); + } + } const postCSSOptions = Object.assign({}, postcssOptions, { to: filename, from: filename }); if (map) { postCSSOptions.map = { diff --git a/packages/webpack-uni-pages-loader/lib/platforms/mp-alipay.js b/packages/webpack-uni-pages-loader/lib/platforms/mp-alipay.js index e3eaa5fa15d43b7b5e1bcc78eca1868d7e472ef6..4d98fffc75b19d9a1f57680d15383e49de989abb 100644 --- a/packages/webpack-uni-pages-loader/lib/platforms/mp-alipay.js +++ b/packages/webpack-uni-pages-loader/lib/platforms/mp-alipay.js @@ -12,6 +12,10 @@ const { parseTabBar } = require('../util') +function defaultCopy (name, value, json) { + json[name] = value +} + const pagesJson2AppJson = { globalStyle: function (name, value, json) { json.window = parseStyle(value) @@ -22,7 +26,8 @@ const pagesJson2AppJson = { }, tabBar: function (name, value, json) { json.tabBar = parseTabBar(value) - } + }, + preloadRule: defaultCopy } function copyToJson (json, fromJson, options) { @@ -62,19 +67,19 @@ module.exports = function (pagesJson, manifestJson) { app.subPackages.push(subPackages[root]) }) - copyToJson(app, pagesJson, pagesJson2AppJson) - - const platformJson = manifestJson['mp-alipay'] || {} - if (hasOwn(platformJson, 'plugins')) { - app.plugins = platformJson.plugins - } + copyToJson(app, pagesJson, pagesJson2AppJson) + + const platformJson = manifestJson['mp-alipay'] || {} + if (hasOwn(platformJson, 'plugins')) { + app.plugins = platformJson.plugins + } if (app.usingComponents) { updateAppJsonUsingComponents(app.usingComponents) } const project = Object.assign({}, manifestJson['mp-alipay'] || {}) - delete project.usingComponents + delete project.usingComponents delete project.plugins return [{ @@ -84,4 +89,4 @@ module.exports = function (pagesJson, manifestJson) { name: 'mini.project', content: project }] -} +} diff --git a/src/core/service/plugins/index.js b/src/core/service/plugins/index.js index 01aa6e1d88615fcd65b7754b130eb9d7b7761347..78d9521fdde4968f1d67e57fb622ad4a6712f40d 100644 --- a/src/core/service/plugins/index.js +++ b/src/core/service/plugins/index.js @@ -24,6 +24,10 @@ import { getTabBarScrollPosition } from './app/router-guard' +import { + uniIdMixin +} from 'uni-shared' + function getMinId (routes) { let minId = 0 routes.forEach(route => { @@ -74,6 +78,8 @@ export default { lifecycleMixin(Vue) + uniIdMixin(Vue) + /* eslint-disable no-undef */ if (typeof __UNI_ROUTER_BASE__ !== 'undefined') { __uniConfig.router.base = __UNI_ROUTER_BASE__ diff --git a/src/core/view/components/image/index.vue b/src/core/view/components/image/index.vue index c065eb8cc22d7dfe2e1486c8890248035bcd484b..c0a50d2c785140ed20245b9992d91b7e652b0326 100644 --- a/src/core/view/components/image/index.vue +++ b/src/core/view/components/image/index.vue @@ -196,9 +196,9 @@ export default { img.src = realImagePath } else { this._clearImage() + this._resetData() // 与微信小程序保持一致,保留之前样式 - // this._resetData() - this._resetSize() + // this._resetSize() } }, _clearImage () { diff --git a/src/core/view/components/progress/index.vue b/src/core/view/components/progress/index.vue index a43bc8d9f3b8284f87bea5ba64dd76a2c831fe2b..70f374ea94b556789b5fa41ee2847096bdc18422 100644 --- a/src/core/view/components/progress/index.vue +++ b/src/core/view/components/progress/index.vue @@ -1,20 +1,20 @@ - - - - - {{ currentPercent }}% + + {{ currentPercent }}% @@ -65,6 +65,13 @@ export default { activeMode: { type: String, default: VALUES.activeMode + }, + duration: { + type: [Number, String], + default: 30, + validator(value) { + return !isNaN(parseFloat(value, 10)) + } } }, data () { @@ -117,7 +124,7 @@ export default { } else { this.currentPercent += 1 } - }, 30) + }, parseFloat(this.duration)) } else { this.currentPercent = this.realPercent } @@ -154,4 +161,4 @@ export default { margin-left: 15px; font-size: 16px; } - + diff --git a/src/platforms/app-plus/service/api/ad/ad-base.js b/src/platforms/app-plus/service/api/ad/ad-base.js index 4d210eae0ca5b7cb8b0c83165ece159a151af788..11e9096dad93c2000ab8a060494d44002ca46a29 100644 --- a/src/platforms/app-plus/service/api/ad/ad-base.js +++ b/src/platforms/app-plus/service/api/ad/ad-base.js @@ -152,5 +152,7 @@ class AdBase { } export { + eventTypes, + eventNames, AdBase } diff --git a/src/platforms/app-plus/service/api/ad/interactive-ad.js b/src/platforms/app-plus/service/api/ad/interactive-ad.js new file mode 100644 index 0000000000000000000000000000000000000000..49b4df46276c7d2277201ee012f5f173853cfed0 --- /dev/null +++ b/src/platforms/app-plus/service/api/ad/interactive-ad.js @@ -0,0 +1,237 @@ +import { + requireNativePlugin +} from '../../bridge' + +import { + eventTypes, + eventNames +} from './ad-base.js' + +const sdkCache = {} +const sdkQueue = {} + +function initSDK (options) { + const provider = options.provider + if (typeof sdkCache[provider] === 'object') { + options.success(sdkCache[provider]) + return + } + + if (!sdkQueue[provider]) { + sdkQueue[provider] = [] + } + sdkQueue[provider].push(options) + + if (sdkCache[provider] === true) { + return + } + sdkCache[provider] = true + + const plugin = requireNativePlugin(provider) + if (!plugin || !plugin.initSDK) { + sdkQueue[provider].forEach((item) => { + item.fail({ + code: -1, + message: 'provider [' + provider + '] invalid' + }) + }) + sdkQueue[provider].length = 0 + sdkCache[provider] = false + return + } + + options.__plugin = plugin + plugin.initSDK((res) => { + const isSuccess = (res.code === 1 || res.code === '1') + if (isSuccess) { + sdkCache[provider] = plugin + } else { + sdkCache[provider] = false + } + sdkQueue[provider].forEach((item) => { + if (isSuccess) { + item.success(item.__plugin) + } else { + item.fail(res) + } + }) + sdkQueue[provider].length = 0 + }) +} + +class InteractiveAd { + constructor (options) { + const _callbacks = this._callbacks = {} + eventNames.forEach(item => { + _callbacks[item] = [] + const name = item[0].toUpperCase() + item.substr(1) + this[`on${name}`] = function (callback) { + _callbacks[item].push(callback) + } + }) + + this._ad = null + this._adError = '' + this._adpid = options.adpid + this._provider = options.provider + this._isLoaded = false + this._isLoading = false + this._loadPromiseResolve = null + this._loadPromiseReject = null + this._showPromiseResolve = null + this._showPromiseReject = null + + setTimeout(() => { + this._init() + }) + } + + _init () { + this._adError = '' + initSDK({ + provider: this._provider, + success: (res) => { + this._ad = res + this._loadAd() + }, + fail: (err) => { + this._adError = err + this._dispatchEvent(eventTypes.error, err) + } + }) + } + + getProvider () { + return this._provider + } + + load () { + return new Promise((resolve, reject) => { + this._loadPromiseResolve = resolve + this._loadPromiseReject = reject + if (this._isLoading) { + return + } + + if (this._adError) { + this._init() + return + } + + if (this._isLoaded) { + resolve() + } else { + this._loadAd() + } + }) + } + + show () { + return new Promise((resolve, reject) => { + this._showPromiseResolve = resolve + this._showPromiseReject = reject + + if (this._isLoading) { + return + } + + if (this._adError) { + this._init() + return + } + + if (this._isLoaded) { + this._showAd() + resolve() + } else { + this._loadAd() + } + }) + } + + destroy () { + if (this._ad !== null && this._ad.destroy) { + this._ad.destroy({ + adpid: this._adpid + }) + } + } + + _loadAd () { + if (this._ad !== null) { + if (this._isLoading === true) { + return + } + this._isLoading = true + + this._ad.loadData({ + adpid: this._adpid + }, (res) => { + this._isLoaded = true + this._isLoading = false + this._dispatchEvent(eventTypes.load, res) + + if (this._loadPromiseResolve != null) { + this._loadPromiseResolve() + this._loadPromiseResolve = null + } + if (this._showPromiseResolve != null) { + this._showPromiseResolve() + this._showPromiseResolve = null + this._showAd() + } + }, (err) => { + this._isLoading = false + this._dispatchEvent(eventTypes.error, err) + + if (this._showPromiseReject != null) { + this._showPromiseReject(this._createError(err)) + this._showPromiseReject = null + } + }) + } + } + + _showAd () { + if (this._ad !== null && this._isLoaded === true) { + this._ad.show({ + adpid: this._adpid + }, (res) => { + this._isLoaded = false + }, (err) => { + this._isLoaded = false + this._dispatchEvent(eventTypes.error, err) + + if (this._showPromiseReject != null) { + this._showPromiseReject(this._createError(err)) + this._showPromiseReject = null + } + }) + } + } + + _createError (err) { + const error = new Error(JSON.stringify(err)) + error.code = err.code + error.errMsg = err.message + return error + } + + _dispatchEvent (name, data) { + this._callbacks[name].forEach(callback => { + if (typeof callback === 'function') { + callback(data || {}) + } + }) + } +} + +export function createInteractiveAd (options) { + if (!options.provider) { + return new Error('provider invalid') + } + if (!options.adpid) { + return new Error('adpid invalid') + } + return new InteractiveAd(options) +} diff --git a/src/platforms/app-plus/service/api/ad/interstitial-ad.js b/src/platforms/app-plus/service/api/ad/interstitial-ad.js index adbc4143d06107b31aaf356488284e1902aa29d5..bdba8a3743976f7271bbc1924ef9c01d81fc1f65 100644 --- a/src/platforms/app-plus/service/api/ad/interstitial-ad.js +++ b/src/platforms/app-plus/service/api/ad/interstitial-ad.js @@ -6,7 +6,7 @@ class InterstitialAd extends AdBase { constructor (options = {}) { super(plus.ad.createInterstitialAd(options), options) - this.load() + this._loadAd() } } diff --git a/src/platforms/app-plus/service/api/index.js b/src/platforms/app-plus/service/api/index.js index 6d650abbe9a456aa1b31d6cff6d74469c9d30ade..94c78beb58f377ec0fe41b4531e7dac3f4a8e006 100644 --- a/src/platforms/app-plus/service/api/index.js +++ b/src/platforms/app-plus/service/api/index.js @@ -82,3 +82,4 @@ export * from './ad/ad' export * from './ad/rewarded-video-ad' export * from './ad/full-screen-video-ad' export * from './ad/interstitial-ad' +export * from './ad/interactive-ad' diff --git a/src/platforms/app-plus/service/api/media/get-video-info.js b/src/platforms/app-plus/service/api/media/get-video-info.js index b940e034dacf91687e0508d58b2ea81ddb45c1f8..a51850e868ba199ab48cd69f252ed0e71b1cf21a 100644 --- a/src/platforms/app-plus/service/api/media/get-video-info.js +++ b/src/platforms/app-plus/service/api/media/get-video-info.js @@ -7,10 +7,13 @@ export const getVideoInfo = warpPlusMethod('io', 'getVideoInfo', options => { return options }, data => { return { + orientation: data.orientation, + type: data.type, duration: data.duration, - fps: data.fps || 30, + size: data.size, height: data.height, width: data.width, - size: data.size + fps: data.fps || 30, + bitrate: data.bitrate, } }) diff --git a/src/platforms/app-plus/service/api/network/request.js b/src/platforms/app-plus/service/api/network/request.js index 7341ecf8dc1eae8cdb9b4e365b430c459c289034..470eecc8d9c2def3bbd4ce44d3c38ad266c335f3 100644 --- a/src/platforms/app-plus/service/api/network/request.js +++ b/src/platforms/app-plus/service/api/network/request.js @@ -46,6 +46,7 @@ export function createRequestTaskById (requestTaskId, { responseType, sslVerify = true, firstIpv4 = false, + tls, timeout = (__uniConfig.networkTimeout && __uniConfig.networkTimeout.request) || 60 * 1000 } = {}) { const stream = requireNativePlugin('stream') @@ -99,7 +100,8 @@ export function createRequestTaskById (requestTaskId, { timeout: timeout || 6e5, // 配置和weex模块内相反 sslVerify: !sslVerify, - firstIpv4: firstIpv4 + firstIpv4: firstIpv4, + tls } if (method !== 'GET') { options.body = typeof data === 'string' ? data : JSON.stringify(data) diff --git a/src/platforms/app-plus/service/api/plugin/oauth.js b/src/platforms/app-plus/service/api/plugin/oauth.js index e07b8738f5450464cabd8d7f9e36decc6ebd9360..b3ac6168a24961b1dbc4fdcbecf94a500707f69c 100644 --- a/src/platforms/app-plus/service/api/plugin/oauth.js +++ b/src/platforms/app-plus/service/api/plugin/oauth.js @@ -99,6 +99,12 @@ export function getUserInfo (params, callbackId) { }) }) } +/** + * 获取用户信息-兼容 + */ +export function getUserProfile (params, callbackId) { + return getUserInfo(params, callbackId) +} /** * 获取用户信息 diff --git a/src/platforms/app-plus/service/framework/plugins/index.js b/src/platforms/app-plus/service/framework/plugins/index.js index 1cbe96dd616d92d5bc6826ad412e3605ea350ca8..d87bc80968fab15e57f1e1afca3911a5793976db 100644 --- a/src/platforms/app-plus/service/framework/plugins/index.js +++ b/src/platforms/app-plus/service/framework/plugins/index.js @@ -22,6 +22,10 @@ import { vdSyncCallbacks } from '../subscribe-handlers/on-vd-sync-callback' +import { + uniIdMixin +} from 'uni-shared' + export default { install (Vue, options) { initVue(Vue) @@ -31,6 +35,8 @@ export default { initPolyfill(Vue) + uniIdMixin(Vue) + Vue.prototype.getOpenerEventChannel = function () { if (!this.$root.$scope.eventChannel) { this.$root.$scope.eventChannel = new EventChannel() @@ -94,4 +100,4 @@ export default { return callback ? undefined : result } } -} +} diff --git a/src/platforms/h5/view/bridge/subscribe/index.js b/src/platforms/h5/view/bridge/subscribe/index.js index 900d2f2c5bfceb8f83928558f346664c1030e800..7c51cc5ec33295dedb8400c0550e4f0ca505f847 100644 --- a/src/platforms/h5/view/bridge/subscribe/index.js +++ b/src/platforms/h5/view/bridge/subscribe/index.js @@ -23,10 +23,11 @@ const passiveOptions = supportsPassive ? { function updateCssVar (vm) { if (uni.canIUse('css.var')) { + const uniConfigTabbarHeight = parseFloat(__uniConfig.tabBar.height) const pageVm = vm.$parent.$parent const navigationBarType = pageVm.navigationBar.type const windowTopValue = navigationBarType === 'default' || navigationBarType === 'float' ? NAVBAR_HEIGHT : 0 - const windowBottomValue = getApp().$children[0].showTabBar ? TABBAR_HEIGHT : 0 + const windowBottomValue = getApp().$children[0].showTabBar ? isNaN(uniConfigTabbarHeight) ? TABBAR_HEIGHT : uniConfigTabbarHeight : 0 const envMethod = uni.canIUse('css.env') ? 'env' : (uni.canIUse('css.constant') ? 'constant' : '') const windowTop = windowTopValue && envMethod ? `calc(${windowTopValue}px + ${envMethod}(safe-area-inset-top))` : `${windowTopValue}px` @@ -87,4 +88,4 @@ export default function initSubscribe (subscribe) { }) } }) -} +} diff --git a/src/platforms/h5/view/components/video/index.vue b/src/platforms/h5/view/components/video/index.vue index 8fdf78433ed09756aba41c4ad22e2a3e613c3640..8ac52a0e9309bb752e2a77cfa9416d9a10c27a36 100644 --- a/src/platforms/h5/view/components/video/index.vue +++ b/src/platforms/h5/view/components/video/index.vue @@ -364,7 +364,7 @@ export default { } const danmuList = this.otherData.danmuList = JSON.parse(JSON.stringify(this.danmuList || [])) danmuList.sort(function (a, b) { - return (a.time || 0) - (a.time || 0) + return (a.time || 0) - (b.time || 0) }) }, mounted () { diff --git a/src/platforms/mp-alipay/runtime/api/protocols.js b/src/platforms/mp-alipay/runtime/api/protocols.js index 80cae6382da64c4d1283e3f3c6b1839ee0cff628..658459e0bcd525f7826758e672c437eabb481484 100644 --- a/src/platforms/mp-alipay/runtime/api/protocols.js +++ b/src/platforms/mp-alipay/runtime/api/protocols.js @@ -381,6 +381,23 @@ const protocols = { // 需要做转换的 API 列表 } } }, + getUserProfile: { + name: my.canIUse('getOpenUserInfo') ? 'getOpenUserInfo' : 'getAuthUserInfo', + returnValue (result) { + if (my.canIUse('getOpenUserInfo')) { + let response = {} + try { + response = JSON.parse(result.response).response + } catch (e) {} + result.nickName = response.nickName + result.avatar = response.avatar + } + result.userInfo = { + nickName: result.nickName, + avatarUrl: result.avatar + } + } + }, requestPayment: { name: 'tradePay', args: { diff --git a/src/platforms/mp-baidu/runtime/api/protocols.js b/src/platforms/mp-baidu/runtime/api/protocols.js index 6739ba5fcc9148a123a387dd0d1beef238249e7b..a094ce94c2ed5542908eabf6a709cd87f26c8f6f 100644 --- a/src/platforms/mp-baidu/runtime/api/protocols.js +++ b/src/platforms/mp-baidu/runtime/api/protocols.js @@ -2,6 +2,7 @@ import navigateTo from 'uni-helpers/navigate-to' import redirectTo from '../../../mp-weixin/helpers/redirect-to' import previewImage from '../../../mp-weixin/helpers/normalize-preview-image' import getSystemInfo from '../../../mp-weixin/helpers/system-info' +import getUserProfile from '../../../mp-weixin/helpers/get-user-profile' // 不支持的 API 列表 const todos = [ @@ -89,6 +90,7 @@ const protocols = { previewImage, getSystemInfo, getSystemInfoSync: getSystemInfo, + getUserProfile, getRecorderManager: { returnValue (fromRet) { fromRet.onFrameRecorded = createTodoMethod('RecorderManager', 'onFrameRecorded') @@ -122,6 +124,9 @@ const protocols = { getAccountInfoSync: { name: 'getEnvInfoSync', returnValue: _handleEnvInfo + }, + login:{ + name:'getLoginCode' } } diff --git a/src/platforms/mp-kuaishou/runtime/api/protocols.js b/src/platforms/mp-kuaishou/runtime/api/protocols.js index 06d3e8ad6b3011745915f533e8328b8fd53c48fc..fd596f57ee81d449adf33a95c783a2358c07d688 100644 --- a/src/platforms/mp-kuaishou/runtime/api/protocols.js +++ b/src/platforms/mp-kuaishou/runtime/api/protocols.js @@ -2,13 +2,15 @@ import navigateTo from 'uni-helpers/navigate-to' import redirectTo from '../../../mp-weixin/helpers/redirect-to' import previewImage from '../../../mp-weixin/helpers/normalize-preview-image' import getSystemInfo from '../../../mp-weixin/helpers/system-info' +import getUserProfile from '../../../mp-weixin/helpers/get-user-profile' export const protocols = { navigateTo, redirectTo, previewImage, getSystemInfo, - getSystemInfoSync: getSystemInfo + getSystemInfoSync: getSystemInfo, + getUserProfile } export const todos = [ 'vibrate' diff --git a/src/platforms/mp-qq/runtime/api/protocols.js b/src/platforms/mp-qq/runtime/api/protocols.js index 8d9061d4cd910b4ec9ff1114d06f4579b184b3ea..04986c6c283709d985212addc0624f6ebcbffda6 100644 --- a/src/platforms/mp-qq/runtime/api/protocols.js +++ b/src/platforms/mp-qq/runtime/api/protocols.js @@ -2,13 +2,15 @@ import navigateTo from 'uni-helpers/navigate-to' import redirectTo from '../../../mp-weixin/helpers/redirect-to' import previewImage from '../../../mp-weixin/helpers/normalize-preview-image' import getSystemInfo from '../../../mp-weixin/helpers/system-info' +import getUserProfile from '../../../mp-weixin/helpers/get-user-profile' export const protocols = { navigateTo, redirectTo, previewImage, getSystemInfo, - getSystemInfoSync: getSystemInfo + getSystemInfoSync: getSystemInfo, + getUserProfile } export const todos = [ 'preloadPage', diff --git a/src/platforms/mp-toutiao/runtime/api/protocols.js b/src/platforms/mp-toutiao/runtime/api/protocols.js index f40ace0526584d0251dc748a52ea55a16d857206..e09f87a101236aa5e8c26235d03dbf0cf361eb9b 100644 --- a/src/platforms/mp-toutiao/runtime/api/protocols.js +++ b/src/platforms/mp-toutiao/runtime/api/protocols.js @@ -2,6 +2,7 @@ import navigateTo from 'uni-helpers/navigate-to' import redirectTo from '../../../mp-weixin/helpers/redirect-to' import previewImage from '../../../mp-weixin/helpers/normalize-preview-image' import getSystemInfo from '../../../mp-weixin/helpers/system-info' +import getUserProfile from '../../../mp-weixin/helpers/get-user-profile' // 不支持的 API 列表 const todos = [ @@ -107,6 +108,7 @@ const protocols = { previewImage, getSystemInfo, getSystemInfoSync: getSystemInfo, + getUserProfile, connectSocket: { args: { method: false diff --git a/src/platforms/mp-weixin/helpers/get-user-profile.js b/src/platforms/mp-weixin/helpers/get-user-profile.js new file mode 100644 index 0000000000000000000000000000000000000000..c7695a8fb5d29a49511c344adc9cfb3e4aa38956 --- /dev/null +++ b/src/platforms/mp-weixin/helpers/get-user-profile.js @@ -0,0 +1,6 @@ +const oName = 'getUserInfo' +const nName = 'getUserProfile' + +export default { + name: __GLOBAL__.canIUse(nName) ? nName : oName +} diff --git a/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js b/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js index aa346c27edc92e6c7e9b059dbb6ee2f0b4693da8..ed8b57f1806fa64463b49fde04b497cc699c7340 100644 --- a/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js +++ b/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js @@ -11,6 +11,10 @@ import { getEventChannel } from 'uni-helpers/navigate-to' +import { + uniIdMixin +} from 'uni-shared' + const hooks = [ 'onShow', 'onHide', @@ -101,6 +105,7 @@ export default function parseBaseApp (vm, { if (vm.$options.store) { Vue.prototype.$store = vm.$options.store } + uniIdMixin(Vue) Vue.prototype.mpHost = __PLATFORM__ diff --git a/src/shared/uni-id-mixin.js b/src/shared/uni-id-mixin.js new file mode 100644 index 0000000000000000000000000000000000000000..3fae66c6fd18b154c02e8cd3e0dd40e60b9e4d36 --- /dev/null +++ b/src/shared/uni-id-mixin.js @@ -0,0 +1,49 @@ +function b64DecodeUnicode (str) { + return decodeURIComponent(atob(str).split('').map(function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) + }).join('')) +} + +function getCurrentUserInfo () { + const token = (__PLATFORM__ === 'h5' || __PLATFORM__ === 'app-plus' ? uni : __GLOBAL__).getStorageSync('uni_id_token') || '' + const tokenArr = token.split('.') + if (!token || tokenArr.length !== 3) { + return { + uid: null, + role: [], + permission: [], + tokenExpired: 0 + } + } + let userInfo + try { + userInfo = JSON.parse(b64DecodeUnicode(tokenArr[1])) + } catch (error) { + throw new Error('获取当前用户信息出错,详细错误信息为:' + error.message) + } + userInfo.tokenExpired = userInfo.exp * 1000 + delete userInfo.exp + delete userInfo.iat + return userInfo +} + +export function uniIdMixin (Vue) { + Vue.prototype.uniIDHasRole = function (roleId) { + const { + role + } = getCurrentUserInfo() + return role.indexOf(roleId) > -1 + } + Vue.prototype.uniIDHasPermission = function (permissionId) { + const { + permission + } = getCurrentUserInfo() + return this.uniIDHasRole('admin') || permission.indexOf(permissionId) > -1 + } + Vue.prototype.uniIDTokenValid = function () { + const { + tokenExpired + } = getCurrentUserInfo() + return tokenExpired > Date.now() + } +} diff --git a/src/shared/util.js b/src/shared/util.js index b1d99934bcb53970229fb72e7334a0c6326f6e49..e62e68952c8a05eb156cd7dd8bdfb6601228d567 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -193,3 +193,5 @@ export function deepClone (vnodes, createElement) { return vnodes.map(cloneVNode) } + +export * from './uni-id-mixin'
- {{ currentPercent }}% +
+ {{ currentPercent }}%