From ab605e22b04819ebd5f1c58a738b280a6f0c0eb2 Mon Sep 17 00:00:00 2001 From: VK <370725567@qq.com> Date: Fri, 23 Oct 2020 11:52:44 +0800 Subject: [PATCH] 1.4.6 --- README.md | 8 +- README/1.4/1.4.5.md | 9 +++ README/1.4/1.4.6.md | 7 ++ .../router/package-lock.json | 46 ++++++------ cloudfunctions-aliyun/router/package.json | 2 +- .../router/service/user/kh/setAvatar.js | 21 +++++- main.js | 4 + pages_template/uni-id/util/util.vue | 1 + pages_template/vuex/vuex.vue | 57 ++++++++++++-- store/index.js | 74 ++++++++++++++++--- store/mixin/mixin.js | 37 ++++++++++ store/modules/{user.js => $user.js} | 46 ++++++------ 12 files changed, 244 insertions(+), 68 deletions(-) create mode 100644 README/1.4/1.4.5.md create mode 100644 README/1.4/1.4.6.md create mode 100644 store/mixin/mixin.js rename store/modules/{user.js => $user.js} (61%) diff --git a/README.md b/README.md index a939cea..4f054b9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ### uniCloud云函数路由框架研究Q群:22466457 如有问题或建议可以在群内讨论。 ### 插件名称:`vk-unicloud-router` ### 作者:VK -### 更新时间:2020-10-21 +### 更新时间:2020-10-23 ## 主要功能 以及 对开发者的价值 #### 1、实现云函数路由模式 @@ -46,9 +46,11 @@ #### 11、【1.3.8 新增】 `商品SKU选择器组件`(打造uni插件市场功能最全的SKU选择器组件) #### 12、【1.4.3 新增】 全网首家云函数临时缓存功能(数据储存在内存中,不依赖云数据库,也不依赖redis等缓存数据库) -#### 13、作者亲自在群内解答框架使用问题,让你轻松上手`uniCloud云开发`。 +#### 13、【1.4.6 新增】对 `Vuex` 进行了深度封装(支持持久化),现在可以很方便的使用Vuex进行读取和储存。 -#### 14、其他好处… +#### 14、作者亲自在群内解答框架使用问题,让你轻松上手`uniCloud云开发`。 + +#### 15、其他好处… ##### 插件首页体验地址 diff --git a/README/1.4/1.4.5.md b/README/1.4/1.4.5.md new file mode 100644 index 0000000..04c0e28 --- /dev/null +++ b/README/1.4/1.4.5.md @@ -0,0 +1,9 @@ +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +##### gitee公共仓库地址:https://gitee.com/vk-uni/vk-uni-cloud-router.git +### 更新内容 针对1.4.4的演示页面重新优化了下。 +#### 1、【优化】`vk.callFunctionUtil.uploadFile` 上传文件到unicloud云存储API `/pages_template/uni-id/util/util`下有使用示例 +#### 2、【新增】`/pages_template/uni-id/util/util` 页面下的上传文件使用示例 +#### 3、【新增】集成了 `Vuex` 做全局状态管理(选择性集成,不影响插件使用)(详情请见根目录下的`store`目录) +#### 4、【优化】Vuex演示页面 `pages_template/vuex/vuex` + +### 你也可以在评论区发布留言交流心得。 \ No newline at end of file diff --git a/README/1.4/1.4.6.md b/README/1.4/1.4.6.md new file mode 100644 index 0000000..a1b62b0 --- /dev/null +++ b/README/1.4/1.4.6.md @@ -0,0 +1,7 @@ +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +##### gitee公共仓库地址:https://gitee.com/vk-uni/vk-uni-cloud-router.git +### 更新内容 +##### 1、【优化】`vk.userCenter.setAvatar` 增加参数`deleteOldFile` 为 `true` 时 上传新头像会自动删除旧头像的云储存文件 +##### 2、【优化】对 `Vuex` 进行了深度封装(支持持久化),现在可以很方便的使用Vuex进行读取和储存。(选择性集成,不影响插件使用)(详见演示页面`pages_template/vuex/vuex`) + +### 你也可以在评论区发布留言交流心得。 \ No newline at end of file diff --git a/cloudfunctions-aliyun/router/package-lock.json b/cloudfunctions-aliyun/router/package-lock.json index 3bec1c3..697afd4 100644 --- a/cloudfunctions-aliyun/router/package-lock.json +++ b/cloudfunctions-aliyun/router/package-lock.json @@ -5,21 +5,21 @@ "requires": true, "dependencies": { "@alicloud/pop-core": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/@alicloud/pop-core/-/pop-core-1.7.9.tgz", - "integrity": "sha512-WKeil0O51ee1EbCcYt65vPYo6eWcDn7dfmXlCMb/GbNDq0MvVheQVS/uAeeUipRXt8jGMc58FXeQxXfsFqlRZg==", + "version": "1.7.10", + "resolved": "https://registry.npmjs.org/@alicloud/pop-core/-/pop-core-1.7.10.tgz", + "integrity": "sha512-9/aLWgmgaAdB1ERNTpdOvF7wueLY5CDTRxKZr93x542iuYRA1NDpcKslFqLOy5CUOa0CbopET3JGaHSAz5qv9g==", "requires": { "debug": "^3.1.0", "httpx": "^2.1.2", - "json-bigint": "^0.2.3", + "json-bigint": "^1.0.0", "kitx": "^1.2.1", "xml2js": "^0.4.17" } }, "@types/node": { - "version": "12.12.67", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.67.tgz", - "integrity": "sha512-R48tgL2izApf+9rYNH+3RBMbRpPeW3N8f0I9HMhggeq4UXwBDqumJ14SDs4ctTMhG11pIOduZ4z3QWGOiMc9Vg==" + "version": "12.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.1.tgz", + "integrity": "sha512-/xaVmBBjOGh55WCqumLAHXU9VhjGtmyTGqJzFBXRWZzByOXI5JAJNx9xPVGEsNizrNwcec92fQMj458MWfjN1A==" }, "asynckit": { "version": "0.4.0", @@ -27,9 +27,9 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "bignumber.js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", - "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" }, "combined-stream": { "version": "1.0.8", @@ -66,9 +66,9 @@ } }, "httpx": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/httpx/-/httpx-2.2.4.tgz", - "integrity": "sha512-looS7tQlnLtXCxV5s/L9hshrrFiY/8IDQ2mIt7FnK/Bll2qDEjWPLsuRmZ6ZOXJZZZ1turs5Pf0d9vzUrPkqOw==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/httpx/-/httpx-2.2.6.tgz", + "integrity": "sha512-7tAcdbpR7xbYP/4aon0QTwT1TVHQs1TK66fRYzPomLavHSB9VEeoZstZqa0k4rzj2/4MAM9syfJ8k0/JOAtqmA==", "requires": { "@types/node": "^12.0.2", "debug": "^4.1.1" @@ -85,11 +85,11 @@ } }, "json-bigint": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.2.3.tgz", - "integrity": "sha1-EY1/b/HThlnxn5TPc+ZKdaP5iKg=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "requires": { - "bignumber.js": "^4.0.0" + "bignumber.js": "^9.0.0" } }, "kitx": { @@ -116,9 +116,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "nodemailer": { - "version": "6.4.13", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.13.tgz", - "integrity": "sha512-XmtiiKza2Cqtr+ZRMchMZn9s2nmwQDeakbf+yL0ODsIXOv58UZgk/MKPOkDKqY+mvxHs87PrJK7Nf/tcpKHqYQ==" + "version": "6.4.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.14.tgz", + "integrity": "sha512-0AQHOOT+nRAOK6QnksNaK7+5vjviVvEBzmZytKU7XSA+Vze2NLykTx/05ti1uJgXFTWrMq08u3j3x4r4OE6PAA==" }, "sax": { "version": "1.2.4", @@ -129,9 +129,9 @@ "version": "file:../common/uni-id" }, "vk-unicloud": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vk-unicloud/-/vk-unicloud-1.5.0.tgz", - "integrity": "sha512-dsN0KtLdeocSxvSx5rep+n9kibmSEexdQkfs3oKePwrXMmeeflzFC4cJ5OKasx6yNTosfjsw3yuBf7whTC6kcw==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/vk-unicloud/-/vk-unicloud-1.6.8.tgz", + "integrity": "sha512-pTjCYrRFNkBjNaX3laK/Ck/an7JlnJcLfh9NK/2G80jsLcxVGEQCPL5DXxzl5oazCMZnS8jB1996LNj0SWhKRg==", "requires": { "@alicloud/pop-core": "^1.7.9", "form-data": "^3.0.0", diff --git a/cloudfunctions-aliyun/router/package.json b/cloudfunctions-aliyun/router/package.json index 3399d92..06ffccd 100644 --- a/cloudfunctions-aliyun/router/package.json +++ b/cloudfunctions-aliyun/router/package.json @@ -12,7 +12,7 @@ "dependencies": { "config": "file:../common/config", "uni-id": "file:../common/uni-id", - "vk-unicloud": "^1.6.7" + "vk-unicloud": "^1.6.8" }, "private": true } diff --git a/cloudfunctions-aliyun/router/service/user/kh/setAvatar.js b/cloudfunctions-aliyun/router/service/user/kh/setAvatar.js index 5ba5541..8c93d64 100644 --- a/cloudfunctions-aliyun/router/service/user/kh/setAvatar.js +++ b/cloudfunctions-aliyun/router/service/user/kh/setAvatar.js @@ -9,15 +9,32 @@ module.exports = { * data 请求参数 说明 * @params {String} uid 用户Id,可以通过checkToken返回 * @params {String} avatar 用户头像URL + * @params {Boolean} deleteOldFile 是否同时删除云储存内的头像文件 * res 返回参数说明 * @params {Number} code 错误码,0表示成功 * @params {String} msg 详细信息 */ main: async (event) => { - let {uniID} = event.util; - let res = {}; + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; // 业务逻辑开始----------------------------------------------------------- + let { avatar, deleteOldFile } = data; + // 设置头像 res = await uniID.setAvatar(event.data); + // 判断是否需要删除旧头像的云储存文件 + if(res.code ===0 && deleteOldFile && userInfo.avatar){ + try { + await uniCloud.deleteFile({ + fileList: [ + userInfo.avatar + ] + }); + }catch(err){ + res.deleteFileErr = err; + } + } // 业务逻辑结束----------------------------------------------------------- return res; } diff --git a/main.js b/main.js index 08ad980..eca0bb6 100644 --- a/main.js +++ b/main.js @@ -8,6 +8,10 @@ Vue.use(uView); import vk from 'vk-unicloud-page'; Vue.use(vk); +// 引入vk实例提供的对vuex的简写法文件 +import mixin from './store/mixin/mixin.js' +Vue.mixin(mixin); + // 自定义云函数路由配置 Vue.prototype.vk.callFunctionUtil.setConfig({ debug:true, diff --git a/pages_template/uni-id/util/util.vue b/pages_template/uni-id/util/util.vue index 1780a31..7b555c4 100644 --- a/pages_template/uni-id/util/util.vue +++ b/pages_template/uni-id/util/util.vue @@ -113,6 +113,7 @@ vk.userCenter.setAvatar({ data: { avatar: res.fileID, + deleteOldFile:true }, success() { that.avatar = res.fileID; diff --git a/pages_template/vuex/vuex.vue b/pages_template/vuex/vuex.vue index 1482698..8068682 100644 --- a/pages_template/vuex/vuex.vue +++ b/pages_template/vuex/vuex.vue @@ -4,14 +4,28 @@ Vuex可以用来做全局状态管理。 而此例子是演示将当前登录用户信息存入Vuex,以便于在其他页面中也能直接渲染或获取用户信息 - - 当前登录用户:{{ $store.state.user.userInfo.nickname || $store.state.user.userInfo.username}} + + 说明: + + 1、$user 对应 store/modules 目录下的js文件,同理,你可以在store/modules目录下新建一个$cart.js文件来专门储存购物车信息
+ 2、页面上直接渲染Vuex数据:
+ $user.userInfo
+ 3、js 内获得Vuex数据:
+ let userInfo = vk.state('$user').userInfo;
+ 4、js 内更新Vuex数据:
+ vk.vuex('$user.userInfo.avatar', avatar);
+
+
+ + 当前登录用户:{{ $user.userInfo.nickname || $user.userInfo.username}} + +
@@ -52,7 +66,7 @@ data:form1, success:function(data){ // 登录成功后将用户信息写入$store - that.$store.dispatch('user/setUserInfo',data.userInfo); + vk.vuex('$user.userInfo', data.userInfo); vk.alert("登陆成功!"); } }); @@ -62,11 +76,43 @@ vk.userCenter.logout({ success:function(data){ // 退出成功后清楚$store的用户信息 - that.$store.dispatch('user/setUserInfo',""); + vk.vuex('$user.userInfo', ''); vk.alert("退出成功"); } }); }, + // 上传头像到云储存,并设置为头像 + uploadAvatar(){ + // 选择图片 + uni.chooseImage({ + count: 1, + sizeType: ['compressed'], + success: function (res) { + // 上传图片到云储存 + vk.callFunctionUtil.uploadFile({ + title:"上传中...", + filePath: res.tempFilePaths[0], + fileType: "image", + success(res) { + // 执行绑定头像 + vk.userCenter.setAvatar({ + data: { + avatar: res.fileID, + }, + success() { + // 修改Vuex用户状态 + vk.vuex('$user.userInfo.avatar', res.fileID); + } + }); + } + }); + } + }); + } + }, + // 计算属性 + computed:{ + } } @@ -100,5 +146,4 @@ color: #999999; margin-bottom: 20px; } - - + \ No newline at end of file diff --git a/store/index.js b/store/index.js index dfd1745..4a59da5 100644 --- a/store/index.js +++ b/store/index.js @@ -2,18 +2,72 @@ import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) + +// 定义不需要永久存储的目录,即下次APP启动数据会自动清空,值为在modules目录下的文件名 +let notSaveStateKeys = ['$test']; + + +let lifeData = uni.getStorageSync('lifeData') || {}; + +const modulesFiles = require.context('./modules', true, /\.js$/); + +modulesFiles.keys().map((modulePath, index) => { + let moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') + if(notSaveStateKeys.indexOf(moduleName) === -1) { + if(!lifeData[moduleName]) lifeData[moduleName] = {}; + } +}); +uni.setStorageSync('lifeData', lifeData); + +// 保存变量到本地存储中 +const saveLifeData = function(key, value){ + // 判断变量名是否在需要存储的数组中 + if(notSaveStateKeys.indexOf(key) === -1) { + // 获取本地存储的lifeData对象,将变量添加到对象中 + let tmp = uni.getStorageSync('lifeData'); + // 第一次打开APP,不存在lifeData变量,故放一个{}空对象 + tmp = tmp ? tmp : {}; + tmp[key] = value; + // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中 + uni.setStorageSync('lifeData', tmp); + } +} + // 加载modules目录下所有文件(分模块) -const modulesFiles = require.context('./modules', true, /\.js$/) const modules = modulesFiles.keys().reduce((modules, modulePath) => { - const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') - const value = modulesFiles(modulePath) - modules[moduleName] = value.default - return modules -}, {}) + const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') + const value = modulesFiles(modulePath) + modules[moduleName] = value.default + return modules +}, {}); const store = new Vuex.Store({ - modules, - // 如果是开发环境,则开启严格模式 - strict: process.env.NODE_ENV === 'development' + modules, + // 如果是开发环境,则开启严格模式 + strict: process.env.NODE_ENV === 'development', + // 公共 mutations + mutations: { + updateStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + let nameArr = payload.name.split('.'); + let saveKey = ''; + let len = nameArr.length; + if(len >= 2) { + let obj = state[nameArr[0]]; + for(let i = 1; i < len - 1; i ++) { + obj = obj[nameArr[i]]; + } + //Vue.set(obj,nameArr[len - 1],payload.value) + obj[nameArr[len - 1]] = JSON.parse(JSON.stringify(payload.value)); + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = JSON.parse(JSON.stringify(payload.value)); + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]) + } + } }) -export default store +export default store \ No newline at end of file diff --git a/store/mixin/mixin.js b/store/mixin/mixin.js new file mode 100644 index 0000000..9c7ec2a --- /dev/null +++ b/store/mixin/mixin.js @@ -0,0 +1,37 @@ +import { mapState, mapGetters } from 'vuex' +import store from "@/store" + +// 尝试将用户在根目录中的store/index.js的vuex的state变量,全部加载到全局变量中 +let mapStateKey = store.state ? Object.keys(store.state) : []; +let mapGettersArr = store.getters ? Object.keys(store.getters) : []; + +let mapGettersKey = {}; +for(let index in mapGettersArr){ + let key = mapGettersArr[index].replace('/', '_'); + mapGettersKey[key] = mapGettersArr[index]; +} + +module.exports = { + beforeCreate() { + // 将vuex方法挂在到vk实例中 + // 使用方法为:如果要修改vuex的state中的user.name变量为"史诗" => this.vk.vuex('user.name', '史诗') + // 如果要修改vuex的state的version变量为1.0.1 => this.vk.vuex('version', '1.0.1') + this.vk.vuex = (name, value) => { + this.$store.commit('updateStore', { + name, + value + }) + }; + this.vk.state = (name) => { + let value = this.$store.state[name]; + return JSON.parse(JSON.stringify(value)); + }; + this.mapGetters = mapGetters; + }, + computed: { + // 将vuex的state中的所有变量,解构到全局混入的mixin中 + ...mapState(mapStateKey), + // 将vuex的getters中的所有函数,解构到全局混入的mixin中 + ...mapGetters(mapGettersKey) + } +} \ No newline at end of file diff --git a/store/modules/user.js b/store/modules/$user.js similarity index 61% rename from store/modules/user.js rename to store/modules/$user.js index fa70a67..5613486 100644 --- a/store/modules/user.js +++ b/store/modules/$user.js @@ -1,25 +1,38 @@ /** * vuex 用户状态管理模块 - * import store from "@/store"; */ +let lifeData = uni.getStorageSync('lifeData') || {}; + export default { // 通过添加 namespaced: true 的方式使其成为带命名空间的模块 namespaced: true, /** * vuex的基本数据,用来存储变量 - * 调用示例 - * that.$store.state.user.userInfo */ state: { - // 登录用户的信息 - userInfo: uni.getStorageSync("uni_id_user_info") + /** + * 登录用户信息 + * js调用示例 + * (推荐) vk.state('$user').userInfo; + * 或 that.$store.state.$user.userInfo; + * 页面上直接使用示例 + * {{ $user.userInfo }} + * js更新示例 + * vk.vuex('$user.userInfo.avatar', res.fileID); + */ + userInfo: lifeData.$user.userInfo }, /** * 从基本数据(state)派生的数据,相当于state的计算属性 - * 调用示例 - * that.$store.getters['user/getUserInfo'] */ getters: { + /** + * 获取用户信息(使用计算属性获取) + * js调用示例 + * that.$store.getters['$user/getUserInfo']; + * 页面上直接使用示例 + * {{ $user_getUserInfo }} + */ getUserInfo: (state) => { return state.userInfo; } @@ -28,29 +41,16 @@ export default { * 提交更新数据的方法,必须是同步的(如果需要异步使用action)。 * 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 * 回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。 - * 调用示例 - that.$store.commit('user/setUserInfo',{ - username:"admin" - }); */ mutations: { - setUserInfo: (state, userInfo) => { - state.userInfo = userInfo - } + }, /** * 和mutation的功能大致相同,不同之处在于 ==》 * 1. Action 提交的是 mutation,而不是直接变更状态。 * 2. Action 可以包含任意异步操作。 - * 调用示例 - that.$store.dispatch('user/setUserInfo',{ - username:"admin" - }); */ actions: { - setUserInfo (context, userInfo) { - uni.setStorageSync("uni_id_user_info", userInfo); - context.commit('setUserInfo',userInfo) - } + } -} +} \ No newline at end of file -- GitLab