diff --git a/manifest.json b/manifest.json index 82270bfb609f14a7cc78f051a222a9c30a5c3d36..c1bda1a5133b7cc02bbc04b928ae92e41de7f3a4 100644 --- a/manifest.json +++ b/manifest.json @@ -128,7 +128,7 @@ "uniStatistics" : { "enable" : false }, - "vueVersion" : "2", + "vueVersion" : "3", "h5" : { "unipush" : { "enable" : false diff --git a/uni_modules/uni-badge/changelog.md b/uni_modules/uni-badge/changelog.md index 1aecf782deffececa99ab5f5463e419bc508f19c..56581c4eee26d01227b094831bf8c03aaecf5ebc 100644 --- a/uni_modules/uni-badge/changelog.md +++ b/uni_modules/uni-badge/changelog.md @@ -1,29 +1,31 @@ +## 1.2.1(2022-09-05) +- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473) ## 1.2.0(2021-11-19) - 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) - 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge) -## 1.1.7(2021-11-08) -- 优化 升级ui -- 修改 size 属性默认值调整为 small -- 修改 type 属性,默认值调整为 error,info 替换 default -## 1.1.6(2021-09-22) -- 修复 在字节小程序上样式不生效的 bug -## 1.1.5(2021-07-30) -- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) -## 1.1.4(2021-07-29) -- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性 -## 1.1.3(2021-06-24) -- 优化 示例项目 -## 1.1.1(2021-05-12) -- 新增 组件示例地址 -## 1.1.0(2021-05-12) -- 新增 uni-badge 的 absolute 属性,支持定位 -- 新增 uni-badge 的 offset 属性,支持定位偏移 -- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点 -- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+ -- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式 -## 1.0.7(2021-05-07) -- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug -- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug -- 新增 uni-badge 属性 custom-style, 支持自定义样式 -## 1.0.6(2021-02-04) -- 调整为uni_modules目录规范 +## 1.1.7(2021-11-08) +- 优化 升级ui +- 修改 size 属性默认值调整为 small +- 修改 type 属性,默认值调整为 error,info 替换 default +## 1.1.6(2021-09-22) +- 修复 在字节小程序上样式不生效的 bug +## 1.1.5(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.4(2021-07-29) +- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性 +## 1.1.3(2021-06-24) +- 优化 示例项目 +## 1.1.1(2021-05-12) +- 新增 组件示例地址 +## 1.1.0(2021-05-12) +- 新增 uni-badge 的 absolute 属性,支持定位 +- 新增 uni-badge 的 offset 属性,支持定位偏移 +- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点 +- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+ +- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式 +## 1.0.7(2021-05-07) +- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug +- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug +- 新增 uni-badge 属性 custom-style, 支持自定义样式 +## 1.0.6(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-badge/components/uni-badge/uni-badge.vue b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue index 5e11cc693d32f4d7d30a46654d24fcd2f6c73e2f..664dc370bfa3d192570df854b490b1f80b4aa01a 100644 --- a/uni_modules/uni-badge/components/uni-badge/uni-badge.vue +++ b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue @@ -1,7 +1,7 @@ @@ -21,11 +21,11 @@ * @value error 红色 * @property {String} inverted = [true|false] 是否无需背景颜色 * @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+ - * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上 + * @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上 * @value rightTop 右上 * @value rightBottom 右下 * @value leftTop 左上 - * @value leftBottom 左下 + * @value leftBottom 左下 * @property {Array[number]} offset 距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px * @property {String} isDot = [true|false] 是否显示为一个小点 * @event {Function} click 点击 Badge 触发事件 @@ -130,16 +130,13 @@ const match = whiteList[this.absolute] return match ? match : whiteList['rightTop'] }, - badgeWidth() { - return { - width: `${this.width}px` - } - }, dotStyle() { if (!this.isDot) return {} return { width: '10px', + minWidth: '0', height: '10px', + padding: '0', borderRadius: '10px' } }, @@ -160,7 +157,7 @@ }; - + diff --git a/uni_modules/uni-badge/package.json b/uni_modules/uni-badge/package.json index 52bd1c9393df524ffebc9ad3ddcc31521cb3881c..7a34d9c3e1a0c3604f2dea26843e10e77eb616f2 100644 --- a/uni_modules/uni-badge/package.json +++ b/uni_modules/uni-badge/package.json @@ -1,88 +1,85 @@ -{ - "id": "uni-badge", - "displayName": "uni-badge 数字角标", - "version": "1.2.0", - "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。", - "keywords": [ - "", - "badge", - "uni-ui", - "uniui", - "数字角标", - "徽章" -], - "repository": "https://github.com/dcloudio/uni-ui", - "engines": { - "HBuilderX": "" - }, - "directories": { - "example": "../../temps/example_temps" - }, - "dcloudext": { - "category": [ - "前端组件", - "通用组件" - ], - "sale": { - "regular": { - "price": "0.00" - }, - "sourcecode": { - "price": "0.00" - } - }, - "contact": { - "qq": "" - }, - "declaration": { - "ads": "无", - "data": "无", - "permissions": "无" - }, - "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" - }, - "uni_modules": { - "dependencies": [], - "encrypt": [], - "platforms": { - "cloud": { - "tcb": "y", - "aliyun": "y" - }, - "client": { - "App": { - "app-vue": "y", - "app-nvue": "y" - }, - "H5-mobile": { - "Safari": "y", - "Android Browser": "y", - "微信浏览器(Android)": "y", - "QQ浏览器(Android)": "y" - }, - "H5-pc": { - "Chrome": "y", - "IE": "y", - "Edge": "y", - "Firefox": "y", - "Safari": "y" - }, - "小程序": { - "微信": "y", - "阿里": "y", - "百度": "y", - "字节跳动": "y", - "QQ": "y" - }, - "快应用": { - "华为": "y", - "联盟": "y" - }, - "Vue": { - "vue2": "y", - "vue3": "y" - } - } - } - } +{ + "id": "uni-badge", + "displayName": "uni-badge 数字角标", + "version": "1.2.1", + "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。", + "keywords": [ + "", + "badge", + "uni-ui", + "uniui", + "数字角标", + "徽章" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } } \ No newline at end of file diff --git a/uni_modules/uni-data-checkbox/changelog.md b/uni_modules/uni-data-checkbox/changelog.md index d8f420b9a6cfec68b7fd755ab516f26f8f2dfd39..c7a468a286ce21077d7e86f6cafc34e47a67c935 100644 --- a/uni_modules/uni-data-checkbox/changelog.md +++ b/uni_modules/uni-data-checkbox/changelog.md @@ -1,3 +1,7 @@ +## 1.0.3(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.2(2022-06-30) +- 优化 在 uni-forms 中的依赖注入方式 ## 1.0.1(2022-02-07) - 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug ## 1.0.0(2021-11-19) diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue index 300cb5fe6e7e31a60b2bc2c9a15b48dc15ac4315..341a4af4bab8ef163dbbc0a008ecfa177be4f0ee 100644 --- a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue +++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue @@ -155,17 +155,17 @@ value(newVal) { this.dataList = this.getDataList(newVal) // fix by mehaotian is_reset 在 uni-forms 中定义 - if(!this.is_reset){ - this.is_reset = false - this.formItem && this.formItem.setValue(newVal) - } + // if(!this.is_reset){ + // this.is_reset = false + // this.formItem && this.formItem.setValue(newVal) + // } }, modelValue(newVal) { this.dataList = this.getDataList(newVal); - if(!this.is_reset){ - this.is_reset = false - this.formItem && this.formItem.setValue(newVal) - } + // if(!this.is_reset){ + // this.is_reset = false + // this.formItem && this.formItem.setValue(newVal) + // } } }, data() { @@ -193,22 +193,22 @@ } }, created() { - this.form = this.getForm('uniForms') - this.formItem = this.getForm('uniFormsItem') + // this.form = this.getForm('uniForms') + // this.formItem = this.getForm('uniFormsItem') // this.formItem && this.formItem.setValue(this.value) - if (this.formItem) { - this.isTop = 6 - if (this.formItem.name) { - // 如果存在name添加默认值,否则formData 中不存在这个字段不校验 - if(!this.is_reset){ - this.is_reset = false - this.formItem.setValue(this.dataValue) - } - this.rename = this.formItem.name - this.form.inputChildrens.push(this) - } - } + // if (this.formItem) { + // this.isTop = 6 + // if (this.formItem.name) { + // // 如果存在name添加默认值,否则formData 中不存在这个字段不校验 + // if(!this.is_reset){ + // this.is_reset = false + // this.formItem.setValue(this.dataValue) + // } + // this.rename = this.formItem.name + // this.form.inputChildrens.push(this) + // } + // } if (this.localdata && this.localdata.length !== 0) { this.isLocal = true @@ -273,7 +273,7 @@ } } } - this.formItem && this.formItem.setValue(detail.value) + // this.formItem && this.formItem.setValue(detail.value) // TODO 兼容 vue2 this.$emit('input', detail.value); // // TOTO 兼容 vue3 @@ -375,7 +375,7 @@ selectedArr.push(item[this.map.value]) } }) - return this.dataValue && this.dataValue.length > 0 ? this.dataValue : selectedArr + return this.dataValue.length > 0 ? this.dataValue : selectedArr }, /** @@ -383,12 +383,14 @@ */ setStyleBackgroud(item) { let styles = {} - let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' - if (this.mode !== 'list') { - styles['border-color'] = item.selected?selectedColor:'#DCDFE6' - } - if (this.mode === 'tag') { - styles['background-color'] = item.selected? selectedColor:'#f5f5f5' + let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' + if (this.selectedColor) { + if (this.mode !== 'list') { + styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + } + if (this.mode === 'tag') { + styles['background-color'] = item.selected? selectedColor:'#f5f5f5' + } } let classles = '' for (let i in styles) { @@ -398,16 +400,17 @@ }, setStyleIcon(item) { let styles = {} - let classles = '' - let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' - styles['background-color'] = item.selected?selectedColor:'#fff' - styles['border-color'] = item.selected?selectedColor:'#DCDFE6' - - if(!item.selected && item.disabled){ - styles['background-color'] = '#F2F6FC' - styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + let classles = '' + if (this.selectedColor) { + let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' + styles['background-color'] = item.selected?selectedColor:'#fff' + styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + + if(!item.selected && item.disabled){ + styles['background-color'] = '#F2F6FC' + styles['border-color'] = item.selected?selectedColor:'#DCDFE6' + } } - for (let i in styles) { classles += `${i}:${styles[i]};` } @@ -415,17 +418,18 @@ }, setStyleIconText(item) { let styles = {} - let classles = '' - let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' - if (this.mode === 'tag') { - styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666' - } else { - styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666' - } - if(!item.selected && item.disabled){ - styles.color = '#999' + let classles = '' + if (this.selectedColor) { + let selectedColor = this.selectedColor?this.selectedColor:'#2979ff' + if (this.mode === 'tag') { + styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666' + } else { + styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666' + } + if(!item.selected && item.disabled){ + styles.color = '#999' + } } - for (let i in styles) { classles += `${i}:${styles[i]};` } @@ -448,7 +452,7 @@ + diff --git a/uni_modules/uni-easyinput/package.json b/uni_modules/uni-easyinput/package.json index 67e4e04cb1bc4cea5ea58572f3f7c2f286a5c399..a11be70ca9ead15fb7b792a2d632026fe419271c 100644 --- a/uni_modules/uni-easyinput/package.json +++ b/uni_modules/uni-easyinput/package.json @@ -1,7 +1,7 @@ { "id": "uni-easyinput", "displayName": "uni-easyinput 增强输入框", - "version": "1.0.3", + "version": "1.1.1", "description": "Easyinput 组件是对原生input组件的增强", "keywords": [ "uni-ui", @@ -17,11 +17,7 @@ "directories": { "example": "../../temps/example_temps" }, - "dcloudext": { - "category": [ - "前端组件", - "通用组件" - ], +"dcloudext": { "sale": { "regular": { "price": "0.00" @@ -38,7 +34,8 @@ "data": "无", "permissions": "无" }, - "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" }, "uni_modules": { "dependencies": [ diff --git a/uni_modules/uni-forms/changelog.md b/uni_modules/uni-forms/changelog.md index 26e120b5c0878e5d3bc2916063da30603f3c87a7..c358a21abbe9d9c871febe80fb8b141f23561e1d 100644 --- a/uni_modules/uni-forms/changelog.md +++ b/uni_modules/uni-forms/changelog.md @@ -1,3 +1,33 @@ +## 1.4.8(2022-08-23) +- 优化 根据 rules 自动添加 required 的问题 +## 1.4.7(2022-08-22) +- 修复 item 未设置 require 属性,rules 设置 require 后,星号也显示的 bug,详见:[https://ask.dcloud.net.cn/question/151540](https://ask.dcloud.net.cn/question/151540) +## 1.4.6(2022-07-13) +- 修复 model 需要校验的值没有声明对应字段时,导致第一次不触发校验的bug +## 1.4.5(2022-07-05) +- 新增 更多表单示例 +- 优化 子表单组件过期提示的问题 +- 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式 +## 1.4.4(2022-07-04) +- 更新 删除组件日志 +## 1.4.3(2022-07-04) +- 修复 由 1.4.0 引发的 label 插槽不生效的bug +## 1.4.2(2022-07-04) +- 修复 子组件找不到 setValue 报错的bug +## 1.4.1(2022-07-04) +- 修复 uni-data-picker 在 uni-forms-item 中报错的bug +- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +## 1.4.0(2022-06-30) +- 【重要】组件逻辑重构,部分用法用旧版本不兼容,请注意兼容问题 +- 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力 +- 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃 +- 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效 +- 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法 +- 新增 子表单的 setRules 方法,配合自定义校验函数使用 +- 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则 +- 优化 动态表单校验方式,废弃拼接name的方式 +## 1.3.3(2022-06-22) +- 修复 表单校验顺序无序问题 ## 1.3.2(2021-12-09) - ## 1.3.1(2021-11-19) diff --git a/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue index 679b12f9349692459f9fcce0932668a43a5dfa90..349ee7012350798a177b7ec94a5b9be3bfd4ef42 100644 --- a/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue +++ b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue @@ -1,213 +1,325 @@ - diff --git a/uni_modules/uni-forms/components/uni-forms/uni-forms.vue b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue index dff823bb09d7681708bfe3f1be932dcdfb09efe0..21aee1a4605ef58b757af2c66645ae16164b098f 100644 --- a/uni_modules/uni-forms/components/uni-forms/uni-forms.vue +++ b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue @@ -1,13 +1,27 @@ - + diff --git a/uni_modules/uni-forms/components/uni-forms/utils.js b/uni_modules/uni-forms/components/uni-forms/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..31d57f41031ee6b5ebd01d0a091a17611ae270c3 --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/utils.js @@ -0,0 +1,293 @@ +/** + * 简单处理对象拷贝 + * @param {Obejct} 被拷贝对象 + * @@return {Object} 拷贝对象 + */ +export const deepCopy = (val) => { + return JSON.parse(JSON.stringify(val)) +} +/** + * 过滤数字类型 + * @param {String} format 数字类型 + * @@return {Boolean} 返回是否为数字类型 + */ +export const typeFilter = (format) => { + return format === 'int' || format === 'double' || format === 'number' || format === 'timestamp'; +} + +/** + * 把 value 转换成指定的类型,用于处理初始值,原因是初始值需要入库不能为 undefined + * @param {String} key 字段名 + * @param {any} value 字段值 + * @param {Object} rules 表单校验规则 + */ +export const getValue = (key, value, rules) => { + const isRuleNumType = rules.find(val => val.format && typeFilter(val.format)); + const isRuleBoolType = rules.find(val => (val.format && val.format === 'boolean') || val.format === 'bool'); + // 输入类型为 number + if (!!isRuleNumType) { + if (!value && value !== 0) { + value = null + } else { + value = isNumber(Number(value)) ? Number(value) : value + } + } + + // 输入类型为 boolean + if (!!isRuleBoolType) { + value = isBoolean(value) ? value : false + } + + return value; +} + +/** + * 获取表单数据 + * @param {String|Array} name 真实名称,需要使用 realName 获取 + * @param {Object} data 原始数据 + * @param {any} value 需要设置的值 + */ +export const setDataValue = (field, formdata, value) => { + formdata[field] = value + return value || '' +} + +/** + * 获取表单数据 + * @param {String|Array} field 真实名称,需要使用 realName 获取 + * @param {Object} data 原始数据 + */ +export const getDataValue = (field, data) => { + return objGet(data, field) +} + +/** + * 获取表单类型 + * @param {String|Array} field 真实名称,需要使用 realName 获取 + */ +export const getDataValueType = (field, data) => { + const value = getDataValue(field, data) + return { + type: type(value), + value + } +} + +/** + * 获取表单可用的真实name + * @param {String|Array} name 表单name + * @@return {String} 表单可用的真实name + */ +export const realName = (name, data = {}) => { + const base_name = _basePath(name) + if (typeof base_name === 'object' && Array.isArray(base_name) && base_name.length > 1) { + const realname = base_name.reduce((a, b) => a += `#${b}`, '_formdata_') + return realname + } + return base_name[0] || name +} + +/** + * 判断是否表单可用的真实name + * @param {String|Array} name 表单name + * @@return {String} 表单可用的真实name + */ +export const isRealName = (name) => { + const reg = /^_formdata_#*/ + return reg.test(name) +} + +/** + * 获取表单数据的原始格式 + * @@return {Object|Array} object 需要解析的数据 + */ +export const rawData = (object = {}, name) => { + let newData = JSON.parse(JSON.stringify(object)) + let formData = {} + for(let i in newData){ + let path = name2arr(i) + objSet(formData,path,newData[i]) + } + return formData +} + +/** + * 真实name还原为 array + * @param {*} name + */ +export const name2arr = (name) => { + let field = name.replace('_formdata_#', '') + field = field.split('#').map(v => (isNumber(v) ? Number(v) : v)) + return field +} + +/** + * 对象中设置值 + * @param {Object|Array} object 源数据 + * @param {String| Array} path 'a.b.c' 或 ['a',0,'b','c'] + * @param {String} value 需要设置的值 + */ +export const objSet = (object, path, value) => { + if (typeof object !== 'object') return object; + _basePath(path).reduce((o, k, i, _) => { + if (i === _.length - 1) { + // 若遍历结束直接赋值 + o[k] = value + return null + } else if (k in o) { + // 若存在对应路径,则返回找到的对象,进行下一次遍历 + return o[k] + } else { + // 若不存在对应路径,则创建对应对象,若下一路径是数字,新对象赋值为空数组,否则赋值为空对象 + o[k] = /^[0-9]{1,}$/.test(_[i + 1]) ? [] : {} + return o[k] + } + }, object) + // 返回object + return object; +} + +// 处理 path, path有三种形式:'a[0].b.c'、'a.0.b.c' 和 ['a','0','b','c'],需要统一处理成数组,便于后续使用 +function _basePath(path) { + // 若是数组,则直接返回 + if (Array.isArray(path)) return path + // 若有 '[',']',则替换成将 '[' 替换成 '.',去掉 ']' + return path.replace(/\[/g, '.').replace(/\]/g, '').split('.') +} + +/** + * 从对象中获取值 + * @param {Object|Array} object 源数据 + * @param {String| Array} path 'a.b.c' 或 ['a',0,'b','c'] + * @param {String} defaultVal 如果无法从调用链中获取值的默认值 + */ +export const objGet = (object, path, defaultVal = 'undefined') => { + // 先将path处理成统一格式 + let newPath = _basePath(path) + // 递归处理,返回最后结果 + let val = newPath.reduce((o, k) => { + return (o || {})[k] + }, object); + return !val || val !== undefined ? val : defaultVal +} + + +/** + * 是否为 number 类型 + * @param {any} num 需要判断的值 + * @return {Boolean} 是否为 number + */ +export const isNumber = (num) => { + return !isNaN(Number(num)) +} + +/** + * 是否为 boolean 类型 + * @param {any} bool 需要判断的值 + * @return {Boolean} 是否为 boolean + */ +export const isBoolean = (bool) => { + return (typeof bool === 'boolean') +} +/** + * 是否有必填字段 + * @param {Object} rules 规则 + * @return {Boolean} 是否有必填字段 + */ +export const isRequiredField = (rules) => { + let isNoField = false; + for (let i = 0; i < rules.length; i++) { + const ruleData = rules[i]; + if (ruleData.required) { + isNoField = true; + break; + } + } + return isNoField; +} + + +/** + * 获取数据类型 + * @param {Any} obj 需要获取数据类型的值 + */ +export const type = (obj) => { + var class2type = {}; + + // 生成class2type映射 + "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) { + class2type["[object " + item + "]"] = item.toLowerCase(); + }) + if (obj == null) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[Object.prototype.toString.call(obj)] || "object" : + typeof obj; +} + +/** + * 判断两个值是否相等 + * @param {any} a 值 + * @param {any} b 值 + * @return {Boolean} 是否相等 + */ +export const isEqual = (a, b) => { + //如果a和b本来就全等 + if (a === b) { + //判断是否为0和-0 + return a !== 0 || 1 / a === 1 / b; + } + //判断是否为null和undefined + if (a == null || b == null) { + return a === b; + } + //接下来判断a和b的数据类型 + var classNameA = toString.call(a), + classNameB = toString.call(b); + //如果数据类型不相等,则返回false + if (classNameA !== classNameB) { + return false; + } + //如果数据类型相等,再根据不同数据类型分别判断 + switch (classNameA) { + case '[object RegExp]': + case '[object String]': + //进行字符串转换比较 + return '' + a === '' + b; + case '[object Number]': + //进行数字转换比较,判断是否为NaN + if (+a !== +a) { + return +b !== +b; + } + //判断是否为0或-0 + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + return +a === +b; + } + //如果是对象类型 + if (classNameA == '[object Object]') { + //获取a和b的属性长度 + var propsA = Object.getOwnPropertyNames(a), + propsB = Object.getOwnPropertyNames(b); + if (propsA.length != propsB.length) { + return false; + } + for (var i = 0; i < propsA.length; i++) { + var propName = propsA[i]; + //如果对应属性对应值不相等,则返回false + if (a[propName] !== b[propName]) { + return false; + } + } + return true; + } + //如果是数组类型 + if (classNameA == '[object Array]') { + if (a.toString() == b.toString()) { + return true; + } + return false; + } +} diff --git a/uni_modules/uni-forms/package.json b/uni_modules/uni-forms/package.json index dfa7af4c459063564c2ad3942a96a79503e6a905..e3736c45357f4a5f8061a1d0aeea79e89c7f6a1e 100644 --- a/uni_modules/uni-forms/package.json +++ b/uni_modules/uni-forms/package.json @@ -1,7 +1,7 @@ { "id": "uni-forms", "displayName": "uni-forms 表单", - "version": "1.3.2", + "version": "1.4.8", "description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据", "keywords": [ "uni-ui", @@ -17,11 +17,7 @@ "directories": { "example": "../../temps/example_temps" }, - "dcloudext": { - "category": [ - "前端组件", - "通用组件" - ], +"dcloudext": { "sale": { "regular": { "price": "0.00" @@ -38,7 +34,8 @@ "data": "无", "permissions": "无" }, - "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" }, "uni_modules": { "dependencies": [ @@ -74,7 +71,8 @@ "阿里": "y", "百度": "y", "字节跳动": "y", - "QQ": "y" + "QQ": "y", + "京东": "u" }, "快应用": { "华为": "u", diff --git a/uni_modules/uni-id-pages/changelog.md b/uni_modules/uni-id-pages/changelog.md index 29cbb7d574d54f882ad197e4a71b16793e344c16..65b345bdaac9cf0f5d40e4aa27ff22e7adaffc0d 100644 --- a/uni_modules/uni-id-pages/changelog.md +++ b/uni_modules/uni-id-pages/changelog.md @@ -1,3 +1,11 @@ +## 1.0.22(2022-09-23) +- 修复 某些情况下,修改密码报“两次输入密码不一致”的bug +## 1.0.21(2022-09-21) +- 修复 store.hasLogin的值在某些情况下会出错的bug +## 1.0.20(2022-09-21) +- 新增 store 账号信息状态管理,详情:用户中心页面 路径:`/uni_modules/uni-id-pages/pages/userinfo/userinfo` +## 1.0.19(2022-09-20) +- 修复 小程序端,使用将自定义节点设置成[虚拟节点](https://uniapp.dcloud.net.cn/tutorial/vue-api.html#%E5%85%B6%E4%BB%96%E9%85%8D%E7%BD%AE)的uni-ui组件,样式错乱的问题 ## 1.0.18(2022-09-20) - 修复 微信小程序端 WXSS 编译报错的bug ## 1.0.17(2022.09-19) diff --git a/uni_modules/uni-id-pages/common/common.js b/uni_modules/uni-id-pages/common/common.js deleted file mode 100644 index a67266056a32aca3c5778642e09c804a834c9321..0000000000000000000000000000000000000000 --- a/uni_modules/uni-id-pages/common/common.js +++ /dev/null @@ -1,13 +0,0 @@ -import pagesJson from '@/pages.json' -const uniIdCo = uniCloud.importObject("uni-id-co") -export default { - async logout() { - await uniIdCo.logout() - uni.removeStorageSync('uni_id_token'); - uni.setStorageSync('uni_id_token_expired', 0) - uni.redirectTo({ - url: `/${pagesJson.uniIdRouter?.loginPage ?? 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`, - }); - uni.$emit('uni-id-pages-logout') - }, -} diff --git a/uni_modules/uni-id-pages/common/login-page.mixin.js b/uni_modules/uni-id-pages/common/login-page.mixin.js index 130647f8344f1015ff258f82fe3ac38339bda2d0..b5164a3510f7b327b03b4bd7cc65702334e9a9aa 100644 --- a/uni_modules/uni-id-pages/common/login-page.mixin.js +++ b/uni_modules/uni-id-pages/common/login-page.mixin.js @@ -1,4 +1,7 @@ -import loginSuccess from './loginSuccess.js'; +import { + store, + mutations + } from '@/uni_modules/uni-id-pages/common/store.js' import config from '@/uni_modules/uni-id-pages/config.js' let mixin = { data() { @@ -75,7 +78,7 @@ let mixin = { }, methods: { loginSuccess(e) { - loginSuccess({ + mutations.loginSuccess({ ...e, uniIdRedirectUrl: this.uniIdRedirectUrl }) diff --git a/uni_modules/uni-id-pages/common/login-page.scss b/uni_modules/uni-id-pages/common/login-page.scss index 2bd6c9e16725040bcea28713be6134f60ae09e75..3f5516681ddcb703e42770857530597a2a6df22a 100644 --- a/uni_modules/uni-id-pages/common/login-page.scss +++ b/uni_modules/uni-id-pages/common/login-page.scss @@ -51,7 +51,12 @@ .register-back{ display: none; - } + } + + uni-button{ + padding-bottom: 1px; + } + /* #endif */ } @@ -79,17 +84,23 @@ font-size: 11px; margin: 6px 0; } + + +/* #ifndef APP-NVUE */ +// 解决小程序端开启虚拟节点virtualHost引起的 class = input-box丢失的问题 [详情参考](https://uniapp.dcloud.net.cn/matter.html#%E5%90%84%E5%AE%B6%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6%E4%B8%8D%E5%90%8C-%E5%8F%AF%E8%83%BD%E5%AD%98%E5%9C%A8%E7%9A%84%E5%B9%B3%E5%8F%B0%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98) +.uni-content ::v-deep .uni-easyinput__content, +/* #endif */ .input-box { - padding: 4px; - background-color: #F8F8F8; + height: 44px; + background-color: #F8F8F8 !important; border-radius: 0; font-size: 14px; /* #ifndef APP-NVUE */ display: flex; /* #endif */ flex: 1; -} +} .link { color: #04498c; diff --git a/uni_modules/uni-id-pages/common/loginSuccess.js b/uni_modules/uni-id-pages/common/loginSuccess.js deleted file mode 100644 index 9f356cfe74c0415aed63657379e6de7951ae2d3e..0000000000000000000000000000000000000000 --- a/uni_modules/uni-id-pages/common/loginSuccess.js +++ /dev/null @@ -1,51 +0,0 @@ -import pagesJson from '@/pages.json' - -export default function(e = {}) { - const { - showToast = true, toastText = '登录成功', autoBack = true, uniIdRedirectUrl = '' - } = e - console.log({ - toastText, - autoBack - }); - if (showToast) { - uni.showToast({ - title: toastText, - icon: 'none' - }); - } - if (autoBack) { - let delta = 0; //判断需要返回几层 - let pages = getCurrentPages(); - uni.$emit('uni-id-pages-login-success',pages) - console.log(pages); - pages.forEach((page, index) => { - if (pages[pages.length - index - 1].route.split('/')[3] == 'login') { - delta++ - } - }) - console.log('判断需要返回几层:',pages, delta); - if (uniIdRedirectUrl) { - return uni.reLaunch({ - url: uniIdRedirectUrl - }) - } - // #ifdef H5 - if(e.loginType == 'weixin'){ - console.log('window.history',window.history); - return window.history.go(-3) - } - // #endif - - if (delta) { - const page = pagesJson.pages[0] - return uni.reLaunch({ - url: `/${page.path}` - }) - } - - uni.navigateBack({ - delta - }) - } -} diff --git a/uni_modules/uni-id-pages/common/password.js b/uni_modules/uni-id-pages/common/password.js index c3f677a79568d08bf5b375dde78a4e18dcdf3971..3e57c7add997f5a19c1b60914f7534d3cfb8c6db 100644 --- a/uni_modules/uni-id-pages/common/password.js +++ b/uni_modules/uni-id-pages/common/password.js @@ -66,7 +66,7 @@ function getPwdRules(pwdName = 'password', rePwdName = 'password2') { }, { validateFunction: function(rule, value, data, callback) { - if (value != data.password) { + if (value != data[pwdName]) { callback(ERROR.normal.rePwdErr) } return true diff --git a/uni_modules/uni-id-pages/common/store.js b/uni_modules/uni-id-pages/common/store.js new file mode 100644 index 0000000000000000000000000000000000000000..6b2a5bfe497154850c97e78d43fd0156028218b0 --- /dev/null +++ b/uni_modules/uni-id-pages/common/store.js @@ -0,0 +1,137 @@ +import pagesJson from '@/pages.json' +const uniIdCo = uniCloud.importObject("uni-id-co") +const db = uniCloud.database(); +const usersTable = db.collection('uni-id-users') + + + +let hostUserInfo = uni.getStorageSync('uni-id-pages-userInfo')||{} +console.log( hostUserInfo); +const data = { + userInfo: hostUserInfo, + hasLogin: Object.keys(hostUserInfo).length != 0 +} + +console.log('data', data); +// 定义 mutations, 修改属性 +export const mutations = { + // data不为空,表示传递要更新的值(注意不是覆盖是合并),什么也不传时,直接查库获取更新 + async updateUserInfo(data = false) { + if (data) { + usersTable.where('_id==$env.uid').update(data).then(e => { + console.log(e); + if (e.result.updated) { + uni.showToast({ + title: "更新成功", + icon: 'none' + }); + this.setUserInfo(data) + } else { + uni.showToast({ + title: "没有改变", + icon: 'none' + }); + } + }) + + } else { + try { + let res = await usersTable.where("'_id' == $cloudEnv_uid") + .field('mobile,nickname,username,email,avatar_file') + .get() + console.log('fromDbData',res.result.data); + this.setUserInfo(res.result.data[0]) + } catch (e) { + this.setUserInfo({},{cover:true}) + console.error(e.message, e.errCode); + } + } + }, + async setUserInfo(data, {cover}={cover:false}) { + console.log('set-userInfo', data); + let userInfo = cover?data:Object.assign(store.userInfo,data) + store.userInfo = Object.assign({},userInfo) + store.hasLogin = Object.keys(store.userInfo).length != 0 + console.log('store.userInfo', store.userInfo); + uni.setStorage({ + key: "uni-id-pages-userInfo", + data:store.userInfo + }) + return data + }, + async logout() { + await uniIdCo.logout() + uni.removeStorageSync('uni_id_token'); + uni.setStorageSync('uni_id_token_expired', 0) + uni.redirectTo({ + url: `/${pagesJson.uniIdRouter?.loginPage ?? 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`, + }); + uni.$emit('uni-id-pages-logout') + this.setUserInfo({},{cover:true}) + }, + loginSuccess(e){ + const { + showToast = true, toastText = '登录成功', autoBack = true, uniIdRedirectUrl = '' + } = e + console.log({ + toastText, + autoBack + }); + if (showToast) { + uni.showToast({ + title: toastText, + icon: 'none' + }); + } + this.updateUserInfo() + uni.$emit('uni-id-pages-login-success') + if (autoBack) { + let delta = 0; //判断需要返回几层 + let pages = getCurrentPages(); + // console.log(pages); + pages.forEach((page, index) => { + if (pages[pages.length - index - 1].route.split('/')[3] == 'login') { + delta++ + } + }) + console.log('判断需要返回几层:', pages, delta); + if (uniIdRedirectUrl) { + return uni.reLaunch({ + url: uniIdRedirectUrl + }) + } + // #ifdef H5 + if (e.loginType == 'weixin') { + console.log('window.history', window.history); + return window.history.go(-3) + } + // #endif + + if (delta) { + const page = pagesJson.pages[0] + return uni.reLaunch({ + url: `/${page.path}` + }) + } + + uni.navigateBack({ + delta + }) + } + } + +} + +// #ifdef VUE2 +import Vue from 'vue' +// 通过Vue.observable创建一个可响应的对象 +export const store = Vue.observable(data) +// #endif + +// #ifdef VUE3 +import { + reactive +} from 'vue' +// 通过Vue.observable创建一个可响应的对象 +export const store = reactive(data) +// #endif diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue b/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue index 2e1e0d360b83e5e8ac010369fd846ea5d474c682..d2660a939588e0e77cf9c28383b7f98d51aa321c 100644 --- a/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue +++ b/uni_modules/uni-id-pages/components/uni-id-pages-agreements/uni-id-pages-agreements.vue @@ -67,7 +67,7 @@ }, methods: { popupConfirm(){ - console.log("popupConfirm"); + // console.log("popupConfirm"); this.isAgree = true retryFun() // this.$emit('popupConfirm') diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue b/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue index 898bbaaa84f5246de6bb263c54a0f3675a7fc9f1..3f452388b5d1fe1b0e035efd29ca86b5726cc820 100644 --- a/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue +++ b/uni_modules/uni-id-pages/components/uni-id-pages-avatar/uni-id-pages-avatar.vue @@ -1,5 +1,5 @@ - diff --git a/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue b/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue index b6ae82af4728cd760daa65404dc65bd666bcac09..b0af426cea9163800c3609eedf41d2b323068470 100644 --- a/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue +++ b/uni_modules/uni-id-pages/components/uni-id-pages-fab-login/uni-id-pages-fab-login.vue @@ -14,8 +14,11 @@ - - diff --git a/uni_modules/uni-id-pages/pages/register/register-by-email.vue b/uni_modules/uni-id-pages/pages/register/register-by-email.vue index 1a345149c21d9d054a2c48348d0a724aedf7d8ed..f45dc57ad8004b95ee01b3a74c851ad8e0218e30 100644 --- a/uni_modules/uni-id-pages/pages/register/register-by-email.vue +++ b/uni_modules/uni-id-pages/pages/register/register-by-email.vue @@ -191,7 +191,7 @@ @media screen and (min-width: 690px) { .uni-content{ padding: 30px 40px; - max-height: 550px; + max-height: 650px; } .link-box { /* #ifndef APP-NVUE */ diff --git a/uni_modules/uni-id-pages/pages/register/register.vue b/uni_modules/uni-id-pages/pages/register/register.vue index abd1de11e77e8549df60edd1314419a750bb5bf0..28c5d12aad8d102064c2f87fef9ee28bea5786ac 100644 --- a/uni_modules/uni-id-pages/pages/register/register.vue +++ b/uni_modules/uni-id-pages/pages/register/register.vue @@ -1,175 +1,186 @@ - - - - - - diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue index 8671463dc1c8125e250818d507f7b2e731707ab5..71ca8fe70fa20f5cfc0ecf181ca5e405c0afd756 100644 --- a/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email.vue @@ -204,6 +204,7 @@ @media screen and (min-width: 690px) { .uni-content{ padding: 30px 40px 40px; + max-height: 650px; } .link-box { diff --git a/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue index 20eea225171bc295dd6c87ef164a12204a5a5450..74ed220cf68fb2192702f7e0aee07f895a173912 100644 --- a/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue +++ b/uni_modules/uni-id-pages/pages/retrieve/retrieve.vue @@ -228,6 +228,7 @@ @media screen and (min-width: 690px) { .uni-content{ padding: 30px 40px 40px; + max-height: 650px; } .link-box { /* #ifndef APP-NVUE */ diff --git a/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue index 22912d10d7dc076b01cf30e8efca046cc8ecc55c..15d68ebfff5b87fa8c02d0684190f400490ade4c 100644 --- a/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue +++ b/uni_modules/uni-id-pages/pages/userinfo/bind-mobile/bind-mobile.vue @@ -19,6 +19,10 @@ + diff --git a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue index a56c8be7b28c782bd44d5a3621d345b620c5121b..04e56b82f9902b0a23740e69d93e46133cc5ea7a 100644 --- a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue +++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue @@ -7,7 +7,7 @@ - + @@ -217,10 +217,10 @@ }; - + diff --git a/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue index 3f667af15ca2e63e5863cfb73dc0d525ea80d425..2c7d9ea7cec731113cce0f3e76301e6f5e37b181 100644 --- a/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue +++ b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue @@ -1,260 +1,267 @@ - - - - + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-list.vue b/uni_modules/uni-list/components/uni-list/uni-list.vue index a5bc80fab779d04d5470de230c80eafee476accf..7940afc4c1da9f3f5f8a1876249b8963d8a41cf9 100644 --- a/uni_modules/uni-list/components/uni-list/uni-list.vue +++ b/uni_modules/uni-list/components/uni-list/uni-list.vue @@ -54,8 +54,8 @@ export default { } }; - + diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.vue b/uni_modules/uni-list/components/uni-list/uni-refresh.vue index 2c64158a6293c4c9d67c8e551d8365a90fcfcd80..3b4c5a230061935d31d8332663b8a511b5143759 100644 --- a/uni_modules/uni-list/components/uni-list/uni-refresh.vue +++ b/uni_modules/uni-list/components/uni-list/uni-refresh.vue @@ -1,65 +1,65 @@ - - - - - + + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.wxs b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs index 9ef364e092dbae2ec45dcd6a279a27263c890103..818a6b721b1172073d91c1f6a456d2b54d772f77 100644 --- a/uni_modules/uni-list/components/uni-list/uni-refresh.wxs +++ b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs @@ -1,87 +1,87 @@ -var pullDown = { - threshold: 95, - maxHeight: 200, - callRefresh: 'onrefresh', - callPullingDown: 'onpullingdown', - refreshSelector: '.uni-refresh' -}; - -function ready(newValue, oldValue, ownerInstance, instance) { - var state = instance.getState() - state.canPullDown = newValue; - // console.log(newValue); -} - -function touchStart(e, instance) { - var state = instance.getState(); - state.refreshInstance = instance.selectComponent(pullDown.refreshSelector); - state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined); - if (!state.canPullDown) { - return - } - - // console.log("touchStart"); - - state.height = 0; - state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY; - state.refreshInstance.setStyle({ - 'height': 0 - }); - state.refreshInstance.callMethod("onchange", true); -} - -function touchMove(e, ownerInstance) { - var instance = e.instance; - var state = instance.getState(); - if (!state.canPullDown) { - return - } - - var oldHeight = state.height; - var endY = e.touches[0].pageY || e.changedTouches[0].pageY; - var height = endY - state.touchStartY; - if (height > pullDown.maxHeight) { - return; - } - - var refreshInstance = state.refreshInstance; - refreshInstance.setStyle({ - 'height': height + 'px' - }); - - height = height < pullDown.maxHeight ? height : pullDown.maxHeight; - state.height = height; - refreshInstance.callMethod(pullDown.callPullingDown, { - height: height - }); -} - -function touchEnd(e, ownerInstance) { - var state = e.instance.getState(); - if (!state.canPullDown) { - return - } - - state.refreshInstance.callMethod("onchange", false); - - var refreshInstance = state.refreshInstance; - if (state.height > pullDown.threshold) { - refreshInstance.callMethod(pullDown.callRefresh); - return; - } - - refreshInstance.setStyle({ - 'height': 0 - }); -} - -function propObserver(newValue, oldValue, instance) { - pullDown = newValue; -} - -module.exports = { - touchmove: touchMove, - touchstart: touchStart, - touchend: touchEnd, - propObserver: propObserver -} +var pullDown = { + threshold: 95, + maxHeight: 200, + callRefresh: 'onrefresh', + callPullingDown: 'onpullingdown', + refreshSelector: '.uni-refresh' +}; + +function ready(newValue, oldValue, ownerInstance, instance) { + var state = instance.getState() + state.canPullDown = newValue; + // console.log(newValue); +} + +function touchStart(e, instance) { + var state = instance.getState(); + state.refreshInstance = instance.selectComponent(pullDown.refreshSelector); + state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined); + if (!state.canPullDown) { + return + } + + // console.log("touchStart"); + + state.height = 0; + state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY; + state.refreshInstance.setStyle({ + 'height': 0 + }); + state.refreshInstance.callMethod("onchange", true); +} + +function touchMove(e, ownerInstance) { + var instance = e.instance; + var state = instance.getState(); + if (!state.canPullDown) { + return + } + + var oldHeight = state.height; + var endY = e.touches[0].pageY || e.changedTouches[0].pageY; + var height = endY - state.touchStartY; + if (height > pullDown.maxHeight) { + return; + } + + var refreshInstance = state.refreshInstance; + refreshInstance.setStyle({ + 'height': height + 'px' + }); + + height = height < pullDown.maxHeight ? height : pullDown.maxHeight; + state.height = height; + refreshInstance.callMethod(pullDown.callPullingDown, { + height: height + }); +} + +function touchEnd(e, ownerInstance) { + var state = e.instance.getState(); + if (!state.canPullDown) { + return + } + + state.refreshInstance.callMethod("onchange", false); + + var refreshInstance = state.refreshInstance; + if (state.height > pullDown.threshold) { + refreshInstance.callMethod(pullDown.callRefresh); + return; + } + + refreshInstance.setStyle({ + 'height': 0 + }); +} + +function propObserver(newValue, oldValue, instance) { + pullDown = newValue; +} + +module.exports = { + touchmove: touchMove, + touchstart: touchStart, + touchend: touchEnd, + propObserver: propObserver +} diff --git a/uni_modules/uni-list/package.json b/uni_modules/uni-list/package.json index 9349a7eec1f7d48a4fe1ee5ededce0f663813ead..66e8bef0c687903d3d0ca857ac97450f34a07565 100644 --- a/uni_modules/uni-list/package.json +++ b/uni_modules/uni-list/package.json @@ -1,91 +1,91 @@ -{ - "id": "uni-list", - "displayName": "uni-list 列表", - "version": "1.2.0", - "description": "List 组件 ,帮助使用者快速构建列表。", - "keywords": [ - "", - "uni-ui", - "uniui", - "列表", - "", - "list" -], - "repository": "https://github.com/dcloudio/uni-ui", - "engines": { - "HBuilderX": "" - }, - "directories": { - "example": "../../temps/example_temps" - }, - "dcloudext": { - "category": [ - "前端组件", - "通用组件" - ], - "sale": { - "regular": { - "price": "0.00" - }, - "sourcecode": { - "price": "0.00" - } - }, - "contact": { - "qq": "" - }, - "declaration": { - "ads": "无", - "data": "无", - "permissions": "无" - }, - "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" - }, - "uni_modules": { - "dependencies": [ - "uni-badge", - "uni-icons" - ], - "encrypt": [], - "platforms": { - "cloud": { - "tcb": "y", - "aliyun": "y" - }, - "client": { - "App": { - "app-vue": "y", - "app-nvue": "y" - }, - "H5-mobile": { - "Safari": "y", - "Android Browser": "y", - "微信浏览器(Android)": "y", - "QQ浏览器(Android)": "y" - }, - "H5-pc": { - "Chrome": "y", - "IE": "y", - "Edge": "y", - "Firefox": "y", - "Safari": "y" - }, - "小程序": { - "微信": "y", - "阿里": "y", - "百度": "y", - "字节跳动": "y", - "QQ": "y" - }, - "快应用": { - "华为": "u", - "联盟": "u" - }, - "Vue": { - "vue2": "y", - "vue3": "y" - } - } - } - } +{ + "id": "uni-list", + "displayName": "uni-list 列表", + "version": "1.2.1", + "description": "List 组件 ,帮助使用者快速构建列表。", + "keywords": [ + "", + "uni-ui", + "uniui", + "列表", + "", + "list" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [ + "uni-badge", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } } \ No newline at end of file diff --git a/uni_modules/uni-list/readme.md b/uni_modules/uni-list/readme.md index 1bc5b951abd0a7d7554ca572a0a6f489fb58d658..32c28654eb9654bfa833a5de6012f44c4fe854db 100644 --- a/uni_modules/uni-list/readme.md +++ b/uni_modules/uni-list/readme.md @@ -1,347 +1,346 @@ - - -## List 列表 -> **组件名:uni-list** -> 代码块: `uList`、`uListItem` -> 关联组件:`uni-list-item`、`uni-badge`、`uni-icons`、`uni-list-chat`、`uni-list-ad` - - -List 列表组件,包含基本列表样式、可扩展插槽机制、长列表性能优化、多端兼容。 - -在vue页面里,它默认使用页面级滚动。在app-nvue页面里,它默认使用原生list组件滚动。这样的长列表,在滚动出屏幕外后,系统会回收不可见区域的渲染内存资源,不会造成滚动越长手机越卡的问题。 - -uni-list组件是父容器,里面的核心是uni-list-item子组件,它代表列表中的一个可重复行,子组件可以无限循环。 - -uni-list-item有很多风格,uni-list-item组件通过内置的属性,满足一些常用的场景。当内置属性不满足需求时,可以通过扩展插槽来自定义列表内容。 - -内置属性可以覆盖的场景包括:导航列表、设置列表、小图标列表、通信录列表、聊天记录列表。 - -涉及很多大图或丰富内容的列表,比如类今日头条的新闻列表、类淘宝的电商列表,需要通过扩展插槽实现。 - -下文均有样例给出。 - -uni-list不包含下拉刷新和上拉翻页。上拉翻页另见组件:[uni-load-more](https://ext.dcloud.net.cn/plugin?id=29) - - -### 安装方式 - -本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。 - -如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55) - -> **注意事项** -> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 -> - 组件需要依赖 `sass` 插件 ,请自行手动安装 -> - 组件内部依赖 `'uni-icons'` 、`uni-badge` 组件 -> - `uni-list` 和 `uni-list-item` 需要配套使用,暂不支持单独使用 `uni-list-item` -> - 只有开启点击反馈后,会有点击选中效果 -> - 使用插槽时,可以完全自定义内容 -> - note 、rightText 属性暂时没做限制,不支持文字溢出隐藏,使用时应该控制长度显示或通过默认插槽自行扩展 -> - 支付宝小程序平台需要在支付宝小程序开发者工具里开启 component2 编译模式,开启方式: 详情 --> 项目配置 --> 启用 component2 编译 -> - 如果需要修改 `switch`、`badge` 样式,请使用插槽自定义 -> - 在 `HBuilderX` 低版本中,可能会出现组件显示 `undefined` 的问题,请升级最新的 `HBuilderX` 或者 `cli` -> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 - - -### 基本用法 - -- 设置 `title` 属性,可以显示列表标题 -- 设置 `disabled` 属性,可以禁用当前项 - -```html - - - - - -``` - -### 多行内容显示 - -- 设置 `note` 属性 ,可以在第二行显示描述文本信息 - -```html - - - - - -``` - -### 右侧显示角标、switch - -- 设置 `show-badge` 属性 ,可以显示角标内容 -- 设置 `show-switch` 属性,可以显示 switch 开关 - -```html - - - - - -``` - -### 左侧显示略缩图、图标 - -- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图 -- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标 - -```html - - - - -``` - -### 开启点击反馈和右侧箭头 -- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 -- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头 -- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` - -```html - - - - - - - -``` - - -### 聊天列表示例 -- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 -- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` -- 设置 `to` 属性,可以跳转页面 -- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示 -- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效 -- 可以通过默认插槽自定义列表右侧内容 - -```html - - - - - - - - - - - - - - - - - 刚刚 - - - - - - - -``` - -```javascript - -export default { - components: {}, - data() { - return { - avatarList: [{ - url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' - }, { - url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' - }, { - url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' - }] - } - } -} - -``` - - -```css - -.chat-custom-right { - flex: 1; - /* #ifndef APP-NVUE */ - display: flex; - /* #endif */ - flex-direction: column; - justify-content: space-between; - align-items: flex-end; -} - -.chat-custom-text { - font-size: 12px; - color: #999; -} - -``` - -## API - -### List Props - -属性名 |类型 |默认值 | 说明 -:-: |:-: |:-: | :-: -border |Boolean |true | 是否显示边框 - - -### ListItem Props - -属性名 |类型 |默认值 | 说明 -:-: |:-: |:-: | :-: -title |String |- | 标题 -note |String |- | 描述 -ellipsis |Number |0 | title 是否溢出隐藏,可选值,0:默认; 1:显示一行; 2:显示两行;【nvue 暂不支持】 -thumb |String |- | 左侧缩略图,若thumb有值,则不会显示扩展图标 -thumbSize |String |medium | 略缩图尺寸,可选值,lg:大图; medium:一般; sm:小图; -showBadge |Boolean |false | 是否显示数字角标 -badgeText |String |- | 数字角标内容 -badgeType |String |- | 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21) -rightText |String |- | 右侧文字内容 -disabled |Boolean |false | 是否禁用 -showArrow |Boolean |true | 是否显示箭头图标 -link |String |navigateTo | 新页面跳转方式,可选值见下表 -to |String |- | 新页面跳转地址,如填写此属性,click 会返回页面是否跳转成功 -clickable |Boolean |false | 是否开启点击反馈 -showSwitch |Boolean |false | 是否显示Switch -switchChecked |Boolean |false | Switch是否被选中 -showExtraIcon |Boolean |false | 左侧是否显示扩展图标 -extraIcon |Object |- | 扩展图标参数,格式为 ``{color: '#4cd964',size: '22',type: 'spinner'}``,参考 [uni-icons](https://ext.dcloud.net.cn/plugin?id=28) -direction | String |row | 排版方向,可选值,row:水平排列; column:垂直排列; 3个插槽是水平排还是垂直排,也受此属性控制 - - -#### Link Options - -属性名 | 说明 -:-: | :-: -navigateTo | 同 uni.navigateTo() -redirectTo | 同 uni.reLaunch() -reLaunch | 同 uni.reLaunch() -switchTab | 同 uni.switchTab() - -### ListItem Events - -事件称名 |说明 |返回参数 -:-: |:-: |:-: -click |点击 uniListItem 触发事件,需开启点击反馈 |- -switchChange |点击切换 Switch 时触发,需显示 switch |e={value:checked} - - - -### ListItem Slots - -名称 | 说明 -:-: | :-: -header | 左/上内容插槽,可完全自定义默认显示 -body | 中间内容插槽,可完全自定义中间内容 -footer | 右/下内容插槽,可完全自定义右侧内容 - - -> **通过插槽扩展** -> 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现 -> 如果 `uni-list-item` 组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。 -> uni-list-item提供了3个可扩展的插槽:`header`、`body`、`footer` -> - 当 `direction` 属性为 `row` 时表示水平排列,此时 `header` 表示列表的左边部分,`body` 表示列表的中间部分,`footer` 表示列表的右边部分 -> - 当 `direction` 属性为 `column` 时表示垂直排列,此时 `header` 表示列表的上边部分,`body` 表示列表的中间部分,`footer` 表示列表的下边部分 -> 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。 - - -**示例** - -```html - - - - - - - - - 自定义插槽 - - - - -``` - - - - - -### ListItemChat Props - -属性名 |类型 |默认值 | 说明 -:-: |:-: |:-: | :-: -title |String |- | 标题 -note |String |- | 描述 -clickable |Boolean |false | 是否开启点击反馈 -badgeText |String |- | 数字角标内容,设置为 `dot` 将显示圆点 -badgePositon |String |right | 角标位置 -link |String |navigateTo | 是否展示右侧箭头并开启点击反馈,可选值见下表 -clickable |Boolean |false | 是否开启点击反馈 -to |String |- | 跳转页面地址,如填写此属性,click 会返回页面是否跳转成功 -time |String |- | 右侧时间显示 -avatarCircle |Boolean |false | 是否显示圆形头像 -avatar |String |- | 头像地址,avatarCircle 不填时生效 -avatarList |Array |- | 头像组,格式为 [{url:''}] - -#### Link Options - -属性名 | 说明 -:-: | :-: -navigateTo | 同 uni.navigateTo() -redirectTo | 同 uni.reLaunch() -reLaunch | 同 uni.reLaunch() -switchTab | 同 uni.switchTab() - -### ListItemChat Slots - -名称 | 说明 -:- | :- -default | 自定义列表右侧内容(包括时间和角标显示) - -### ListItemChat Events -事件称名 | 说明 | 返回参数 -:-: | :-: | :-: -@click | 点击 uniListChat 触发事件 | {data:{}} ,如有 to 属性,会返回页面跳转信息 - - - - - - -## 基于uni-list扩展的页面模板 - -通过扩展插槽,可实现多种常见样式的列表 - -**新闻列表类** - -1. 云端一体混合布局:[https://ext.dcloud.net.cn/plugin?id=2546](https://ext.dcloud.net.cn/plugin?id=2546) -2. 云端一体垂直布局,大图模式:[https://ext.dcloud.net.cn/plugin?id=2583](https://ext.dcloud.net.cn/plugin?id=2583) -3. 云端一体垂直布局,多行图文混排:[https://ext.dcloud.net.cn/plugin?id=2584](https://ext.dcloud.net.cn/plugin?id=2584) -4. 云端一体垂直布局,多图模式:[https://ext.dcloud.net.cn/plugin?id=2585](https://ext.dcloud.net.cn/plugin?id=2585) -5. 云端一体水平布局,左图右文:[https://ext.dcloud.net.cn/plugin?id=2586](https://ext.dcloud.net.cn/plugin?id=2586) -6. 云端一体水平布局,左文右图:[https://ext.dcloud.net.cn/plugin?id=2587](https://ext.dcloud.net.cn/plugin?id=2587) -7. 云端一体垂直布局,无图模式,主标题+副标题:[https://ext.dcloud.net.cn/plugin?id=2588](https://ext.dcloud.net.cn/plugin?id=2588) - -**商品列表类** - -1. 云端一体列表/宫格视图互切:[https://ext.dcloud.net.cn/plugin?id=2651](https://ext.dcloud.net.cn/plugin?id=2651) -2. 云端一体列表(宫格模式):[https://ext.dcloud.net.cn/plugin?id=2671](https://ext.dcloud.net.cn/plugin?id=2671) -3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672) - -## 组件示例 - +## List 列表 +> **组件名:uni-list** +> 代码块: `uList`、`uListItem` +> 关联组件:`uni-list-item`、`uni-badge`、`uni-icons`、`uni-list-chat`、`uni-list-ad` + + +List 列表组件,包含基本列表样式、可扩展插槽机制、长列表性能优化、多端兼容。 + +在vue页面里,它默认使用页面级滚动。在app-nvue页面里,它默认使用原生list组件滚动。这样的长列表,在滚动出屏幕外后,系统会回收不可见区域的渲染内存资源,不会造成滚动越长手机越卡的问题。 + +uni-list组件是父容器,里面的核心是uni-list-item子组件,它代表列表中的一个可重复行,子组件可以无限循环。 + +uni-list-item有很多风格,uni-list-item组件通过内置的属性,满足一些常用的场景。当内置属性不满足需求时,可以通过扩展插槽来自定义列表内容。 + +内置属性可以覆盖的场景包括:导航列表、设置列表、小图标列表、通信录列表、聊天记录列表。 + +涉及很多大图或丰富内容的列表,比如类今日头条的新闻列表、类淘宝的电商列表,需要通过扩展插槽实现。 + +下文均有样例给出。 + +uni-list不包含下拉刷新和上拉翻页。上拉翻页另见组件:[uni-load-more](https://ext.dcloud.net.cn/plugin?id=29) + + +### 安装方式 + +本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。 + +如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55) + +> **注意事项** +> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 +> - 组件需要依赖 `sass` 插件 ,请自行手动安装 +> - 组件内部依赖 `'uni-icons'` 、`uni-badge` 组件 +> - `uni-list` 和 `uni-list-item` 需要配套使用,暂不支持单独使用 `uni-list-item` +> - 只有开启点击反馈后,会有点击选中效果 +> - 使用插槽时,可以完全自定义内容 +> - note 、rightText 属性暂时没做限制,不支持文字溢出隐藏,使用时应该控制长度显示或通过默认插槽自行扩展 +> - 支付宝小程序平台需要在支付宝小程序开发者工具里开启 component2 编译模式,开启方式: 详情 --> 项目配置 --> 启用 component2 编译 +> - 如果需要修改 `switch`、`badge` 样式,请使用插槽自定义 +> - 在 `HBuilderX` 低版本中,可能会出现组件显示 `undefined` 的问题,请升级最新的 `HBuilderX` 或者 `cli` +> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + +### 基本用法 + +- 设置 `title` 属性,可以显示列表标题 +- 设置 `disabled` 属性,可以禁用当前项 + +```html + + + + + +``` + +### 多行内容显示 + +- 设置 `note` 属性 ,可以在第二行显示描述文本信息 + +```html + + + + + +``` + +### 右侧显示角标、switch + +- 设置 `show-badge` 属性 ,可以显示角标内容 +- 设置 `show-switch` 属性,可以显示 switch 开关 + +```html + + + + + +``` + +### 左侧显示略缩图、图标 + +- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图 +- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标 + +```html + + + + +``` + +### 开启点击反馈和右侧箭头 +- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 +- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头 +- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` + +```html + + + + + + + +``` + + +### 聊天列表示例 +- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件 +- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo` +- 设置 `to` 属性,可以跳转页面 +- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示 +- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效 +- 可以通过默认插槽自定义列表右侧内容 + +```html + + + + + + + + + + + + + + + + + 刚刚 + + + + + + + +``` + +```javascript + +export default { + components: {}, + data() { + return { + avatarList: [{ + url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' + }, { + url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' + }, { + url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png' + }] + } + } +} + +``` + + +```css + +.chat-custom-right { + flex: 1; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: column; + justify-content: space-between; + align-items: flex-end; +} + +.chat-custom-text { + font-size: 12px; + color: #999; +} + +``` + +## API + +### List Props + +属性名 |类型 |默认值 | 说明 +:-: |:-: |:-: | :-: +border |Boolean |true | 是否显示边框 + + +### ListItem Props + +属性名 |类型 |默认值 | 说明 +:-: |:-: |:-: | :-: +title |String |- | 标题 +note |String |- | 描述 +ellipsis |Number |0 | title 是否溢出隐藏,可选值,0:默认; 1:显示一行; 2:显示两行;【nvue 暂不支持】 +thumb |String |- | 左侧缩略图,若thumb有值,则不会显示扩展图标 +thumbSize |String |medium | 略缩图尺寸,可选值,lg:大图; medium:一般; sm:小图; +showBadge |Boolean |false | 是否显示数字角标 +badgeText |String |- | 数字角标内容 +badgeType |String |- | 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21) +badgeStyle |Object |- | 数字角标样式,使用uni-badge的custom-style参数 +rightText |String |- | 右侧文字内容 +disabled |Boolean |false | 是否禁用 +showArrow |Boolean |true | 是否显示箭头图标 +link |String |navigateTo | 新页面跳转方式,可选值见下表 +to |String |- | 新页面跳转地址,如填写此属性,click 会返回页面是否跳转成功 +clickable |Boolean |false | 是否开启点击反馈 +showSwitch |Boolean |false | 是否显示Switch +switchChecked |Boolean |false | Switch是否被选中 +showExtraIcon |Boolean |false | 左侧是否显示扩展图标 +extraIcon |Object |- | 扩展图标参数,格式为 ``{color: '#4cd964',size: '22',type: 'spinner'}``,参考 [uni-icons](https://ext.dcloud.net.cn/plugin?id=28) +direction | String |row | 排版方向,可选值,row:水平排列; column:垂直排列; 3个插槽是水平排还是垂直排,也受此属性控制 + + +#### Link Options + +属性名 | 说明 +:-: | :-: +navigateTo | 同 uni.navigateTo() +redirectTo | 同 uni.reLaunch() +reLaunch | 同 uni.reLaunch() +switchTab | 同 uni.switchTab() + +### ListItem Events + +事件称名 |说明 |返回参数 +:-: |:-: |:-: +click |点击 uniListItem 触发事件,需开启点击反馈 |- +switchChange |点击切换 Switch 时触发,需显示 switch |e={value:checked} + + + +### ListItem Slots + +名称 | 说明 +:-: | :-: +header | 左/上内容插槽,可完全自定义默认显示 +body | 中间内容插槽,可完全自定义中间内容 +footer | 右/下内容插槽,可完全自定义右侧内容 + + +> **通过插槽扩展** +> 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现 +> 如果 `uni-list-item` 组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。 +> uni-list-item提供了3个可扩展的插槽:`header`、`body`、`footer` +> - 当 `direction` 属性为 `row` 时表示水平排列,此时 `header` 表示列表的左边部分,`body` 表示列表的中间部分,`footer` 表示列表的右边部分 +> - 当 `direction` 属性为 `column` 时表示垂直排列,此时 `header` 表示列表的上边部分,`body` 表示列表的中间部分,`footer` 表示列表的下边部分 +> 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。 + + +**示例** + +```html + + + + + + + + + 自定义插槽 + + + + +``` + + + + + +### ListItemChat Props + +属性名 |类型 |默认值 | 说明 +:-: |:-: |:-: | :-: +title |String |- | 标题 +note |String |- | 描述 +clickable |Boolean |false | 是否开启点击反馈 +badgeText |String |- | 数字角标内容,设置为 `dot` 将显示圆点 +badgePositon |String |right | 角标位置 +link |String |navigateTo | 是否展示右侧箭头并开启点击反馈,可选值见下表 +clickable |Boolean |false | 是否开启点击反馈 +to |String |- | 跳转页面地址,如填写此属性,click 会返回页面是否跳转成功 +time |String |- | 右侧时间显示 +avatarCircle |Boolean |false | 是否显示圆形头像 +avatar |String |- | 头像地址,avatarCircle 不填时生效 +avatarList |Array |- | 头像组,格式为 [{url:''}] + +#### Link Options + +属性名 | 说明 +:-: | :-: +navigateTo | 同 uni.navigateTo() +redirectTo | 同 uni.reLaunch() +reLaunch | 同 uni.reLaunch() +switchTab | 同 uni.switchTab() + +### ListItemChat Slots + +名称 | 说明 +:- | :- +default | 自定义列表右侧内容(包括时间和角标显示) + +### ListItemChat Events +事件称名 | 说明 | 返回参数 +:-: | :-: | :-: +@click | 点击 uniListChat 触发事件 | {data:{}} ,如有 to 属性,会返回页面跳转信息 + + + + + + +## 基于uni-list扩展的页面模板 + +通过扩展插槽,可实现多种常见样式的列表 + +**新闻列表类** + +1. 云端一体混合布局:[https://ext.dcloud.net.cn/plugin?id=2546](https://ext.dcloud.net.cn/plugin?id=2546) +2. 云端一体垂直布局,大图模式:[https://ext.dcloud.net.cn/plugin?id=2583](https://ext.dcloud.net.cn/plugin?id=2583) +3. 云端一体垂直布局,多行图文混排:[https://ext.dcloud.net.cn/plugin?id=2584](https://ext.dcloud.net.cn/plugin?id=2584) +4. 云端一体垂直布局,多图模式:[https://ext.dcloud.net.cn/plugin?id=2585](https://ext.dcloud.net.cn/plugin?id=2585) +5. 云端一体水平布局,左图右文:[https://ext.dcloud.net.cn/plugin?id=2586](https://ext.dcloud.net.cn/plugin?id=2586) +6. 云端一体水平布局,左文右图:[https://ext.dcloud.net.cn/plugin?id=2587](https://ext.dcloud.net.cn/plugin?id=2587) +7. 云端一体垂直布局,无图模式,主标题+副标题:[https://ext.dcloud.net.cn/plugin?id=2588](https://ext.dcloud.net.cn/plugin?id=2588) + +**商品列表类** + +1. 云端一体列表/宫格视图互切:[https://ext.dcloud.net.cn/plugin?id=2651](https://ext.dcloud.net.cn/plugin?id=2651) +2. 云端一体列表(宫格模式):[https://ext.dcloud.net.cn/plugin?id=2671](https://ext.dcloud.net.cn/plugin?id=2671) +3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672) + +## 组件示例 + 点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/list/list](https://hellouniapp.dcloud.net.cn/pages/extUI/list/list) \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/changelog.md b/uni_modules/uni-open-bridge-common/changelog.md index 63c36938b2a91fc57354ac133d062614d6bb7ec1..01489ce387670cd3409db7d864b21e19816eb358 100644 --- a/uni_modules/uni-open-bridge-common/changelog.md +++ b/uni_modules/uni-open-bridge-common/changelog.md @@ -1,3 +1,5 @@ +## 1.0.3(2022-09-06) +- 修复 过期时间问题,容错 AccessToken 默认 fallback 逻辑,当微信服务器没有返回过期时间时设置为2小时后过期 ## 1.0.2(2022-09-02) - 新增 依赖数据表schema opendb-open-data ## 1.0.0(2022-08-22) diff --git a/uni_modules/uni-open-bridge-common/package.json b/uni_modules/uni-open-bridge-common/package.json index 65aadf371a7a2ad73b2da37a3711286451fea453..2a3f9b6235bef634e6d75378563e55be0d6af69b 100644 --- a/uni_modules/uni-open-bridge-common/package.json +++ b/uni_modules/uni-open-bridge-common/package.json @@ -1,7 +1,7 @@ { "id": "uni-open-bridge-common", "displayName": "uni-open-bridge-common", - "version": "1.0.2", + "version": "1.0.3", "description": "统一接管微信等三方平台认证凭据", "keywords": [ "uni-open-bridge-common", diff --git a/uni_modules/uni-open-bridge-common/readme.md b/uni_modules/uni-open-bridge-common/readme.md index 3892384764fe33d38c9ae74fc2b5deca7b850898..de28c36e067fb692b8f4cd23bc80941ea956e305 100644 --- a/uni_modules/uni-open-bridge-common/readme.md +++ b/uni_modules/uni-open-bridge-common/readme.md @@ -1,5 +1,5 @@ -# uni-open-bridge-common - -`uni-open-bridge-common` 是统一接管微信等三方平台认证凭据(包括但不限于`access_token`、`session_key`、`encrypt_key`、`ticket`)的开源库。 - -文档链接 [https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common) +# uni-open-bridge-common + +`uni-open-bridge-common` 是统一接管微信等三方平台认证凭据(包括但不限于`access_token`、`session_key`、`encrypt_key`、`ticket`)的开源库。 + +文档链接 [https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common) diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js index 95160a4390ade5693feaf7aa226a7d9d13765db1..b6cfe66170d1958f57cee2e3715fc4984682c379 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js @@ -1,4 +1,4 @@ -'use strict'; +'use strict'; class BridgeError extends Error { @@ -20,7 +20,7 @@ class BridgeError extends Error { return this.message } } - -module.exports = { - BridgeError + +module.exports = { + BridgeError } diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js index 2fb7d7b050baa9e6af2b38af9fe8725c311a7aed..a08f9973d0b1215db4832bb79b294f733947d652 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js @@ -1,95 +1,95 @@ -'use strict'; - -const { - PlatformType -} = require('./consts.js') - -const configCenter = require('uni-config-center') - -const OauthConfig = { - 'weixin-mp': ['mp-weixin', 'oauth', 'weixin'], - 'weixin-h5': ['web', 'oauth', 'weixin-h5'] -} - -class ConfigBase { - - constructor() { - this._ready = false - this._uniId = null - - const uniIdConfig = configCenter({ - pluginId: 'uni-id' - }) - - this._uniId = uniIdConfig.config() - - this._ready = true - } - - getAppConfig(appid) { - if (Array.isArray(this._uniId)) { - return this._uniId.find((item) => { - return (item.dcloudAppid === appid) - }) - } - return this._uniId - } - - get ready() { - return this._ready - } -} - -class AppConfig extends ConfigBase { - - constructor() { - super() - } - - get(appid, platform) { - if (!this.isSupport(platform)) { - return null - } - - let appConfig = this.getAppConfig(appid) - if (!appConfig) { - return null - } - - return this.getOauthConfig(appConfig, platform) - } - - isSupport(platformName) { - return (AppConfig.Support_Platforms.indexOf(platformName) >= 0) - } - - getOauthConfig(appConfig, platformName) { - let tree = OauthConfig[platformName] - let node = appConfig - for (let i = 0; i < tree.length; i++) { - let nodeName = tree[i] - if (node[nodeName]) { - node = node[nodeName] - } else { - node = null - break - } - } - - if (node && node.appid && node.appsecret) { - return { - appid: node.appid, - secret: node.appsecret - } - } - - return null - } -} - -AppConfig.Support_Platforms = [PlatformType.WEIXIN_MP, PlatformType.WEIXIN_H5] - - -module.exports = { - AppConfig +'use strict'; + +const { + PlatformType +} = require('./consts.js') + +const configCenter = require('uni-config-center') + +const OauthConfig = { + 'weixin-mp': ['mp-weixin', 'oauth', 'weixin'], + 'weixin-h5': ['web', 'oauth', 'weixin-h5'] +} + +class ConfigBase { + + constructor() { + this._ready = false + this._uniId = null + + const uniIdConfig = configCenter({ + pluginId: 'uni-id' + }) + + this._uniId = uniIdConfig.config() + + this._ready = true + } + + getAppConfig(appid) { + if (Array.isArray(this._uniId)) { + return this._uniId.find((item) => { + return (item.dcloudAppid === appid) + }) + } + return this._uniId + } + + get ready() { + return this._ready + } +} + +class AppConfig extends ConfigBase { + + constructor() { + super() + } + + get(appid, platform) { + if (!this.isSupport(platform)) { + return null + } + + let appConfig = this.getAppConfig(appid) + if (!appConfig) { + return null + } + + return this.getOauthConfig(appConfig, platform) + } + + isSupport(platformName) { + return (AppConfig.Support_Platforms.indexOf(platformName) >= 0) + } + + getOauthConfig(appConfig, platformName) { + let tree = OauthConfig[platformName] + let node = appConfig + for (let i = 0; i < tree.length; i++) { + let nodeName = tree[i] + if (node[nodeName]) { + node = node[nodeName] + } else { + node = null + break + } + } + + if (node && node.appid && node.appsecret) { + return { + appid: node.appid, + secret: node.appsecret + } + } + + return null + } +} + +AppConfig.Support_Platforms = [PlatformType.WEIXIN_MP, PlatformType.WEIXIN_H5] + + +module.exports = { + AppConfig }; diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js index 6da817b9620336453e06025815a12d378249ebde..943de1253ecac2953a9ec437d307a7ce04945064 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js @@ -1,26 +1,26 @@ -'use strict'; - -const TAG = "UNI_OPEN_BRIDGE" - -const HTTP_STATUS = { - SUCCESS: 200 -} - -const PlatformType = { - WEIXIN_MP: 'weixin-mp', - WEIXIN_H5: 'weixin-h5', - WEIXIN_APP: 'weixin-app', - WEIXIN_WEB: 'weixin-web', - QQ_MP: 'qq-mp', - QQ_APP: 'qq-app' -} - -const ErrorCodeType = { - SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" -} - -module.exports = { - HTTP_STATUS, - PlatformType, - ErrorCodeType +'use strict'; + +const TAG = "UNI_OPEN_BRIDGE" + +const HTTP_STATUS = { + SUCCESS: 200 +} + +const PlatformType = { + WEIXIN_MP: 'weixin-mp', + WEIXIN_H5: 'weixin-h5', + WEIXIN_APP: 'weixin-app', + WEIXIN_WEB: 'weixin-web', + QQ_MP: 'qq-mp', + QQ_APP: 'qq-app' +} + +const ErrorCodeType = { + SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" +} + +module.exports = { + HTTP_STATUS, + PlatformType, + ErrorCodeType } diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js index c6b3daff15392b1d351235a769f2011ed8e2e314..caf2a496bdcda906a91add9fcc51a043241a33bb 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js @@ -1,219 +1,219 @@ -'use strict'; - -const { - PlatformType, - ErrorCodeType -} = require('./consts.js') - -const { - AppConfig -} = require('./config.js') - -const { - Storage, - Factory -} = require('./storage.js') - -const { - BridgeError -} = require('./bridge-error.js') - -const { - WeixinServer -} = require('./weixin-server.js') - -const appConfig = new AppConfig() - -class AccessToken extends Storage { - - constructor() { - super('access-token', ['dcloudAppid', 'platform']) - } - - async fallback(parameters) { - const oauthConfig = appConfig.get(parameters.dcloudAppid, parameters.platform) - let methodName - if (parameters.platform === PlatformType.WEIXIN_MP) { - methodName = 'GetMPAccessTokenData' - } else if (parameters.platform === PlatformType.WEIXIN_H5) { - methodName = 'GetH5AccessTokenData' - } else { - throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "platform invalid") - } - - const responseData = await WeixinServer[methodName](oauthConfig) - - const duration = responseData.expires_in - delete responseData.expires_in - - return { - value: responseData, - duration - } - } -} - -class UserAccessToken extends Storage { - - constructor() { - super('user-access-token', ['dcloudAppid', 'platform', 'openid']) - } -} - -class SessionKey extends Storage { - - constructor() { - super('session-key', ['dcloudAppid', 'platform', 'openid']) - } -} - -class Encryptkey extends Storage { - - constructor() { - super('encrypt-key', ['dcloudAppid', 'platform', 'openid']) - } - - getKeyString(key) { - return `${super.getKeyString(key)}-${key.version}` - } - - getExpiresIn(value) { - if (value <= 0) { - return 60 - } - return value - } - - async fallback(parameters) { - const accessToken = await Factory.Get(AccessToken, parameters) - const userSession = await Factory.Get(SessionKey, parameters) - - const responseData = await WeixinServer.GetUserEncryptKeyData({ - openid: parameters.openid, - access_token: accessToken.access_token, - session_key: userSession.session_key - }) - - const keyInfo = responseData.key_info_list.find((item) => { - return item.version = parameters.version - }) - - const value = { - encrypt_key: keyInfo.encrypt_key, - iv: keyInfo.iv - } - - return { - value, - duration: keyInfo.expire_in - } - } -} - -class Ticket extends Storage { - - constructor() { - super('ticket', ['dcloudAppid', 'platform']) - } - - async fallback(parameters) { - const accessToken = await Factory.Get(AccessToken, { - dcloudAppid: parameters.dcloudAppid, - platform: PlatformType.WEIXIN_H5 - }) - - const responseData = await WeixinServer.GetH5TicketData(accessToken) - - const duration = responseData.expires_in - delete responseData.expires_in - - return { - value: responseData, - duration - } - } -} - - -// exports - -async function getAccessToken(key, fallback) { - return await Factory.Get(AccessToken, key, fallback) -} - -async function setAccessToken(key, value, expiresIn) { - await Factory.Set(AccessToken, key, value, expiresIn) -} - -async function removeAccessToken(key) { - await Factory.Remove(AccessToken, key) -} - -async function getUserAccessToken(key, fallback) { - return await Factory.Get(UserAccessToken, key, fallback) -} - -async function setUserAccessToken(key, value, expiresIn) { - await Factory.Set(UserAccessToken, key, value, expiresIn) -} - -async function removeUserAccessToken(key) { - await Factory.Remove(UserAccessToken, key) -} - -async function getSessionKey(key, fallback) { - return await Factory.Get(SessionKey, key, fallback) -} - -async function setSessionKey(key, value, expiresIn) { - await Factory.Set(SessionKey, key, value, expiresIn) -} - -async function removeSessionKey(key) { - await Factory.Remove(SessionKey, key) -} - -async function getEncryptKey(key, fallback) { - return await Factory.Get(Encryptkey, key, fallback) -} - -async function setEncryptKey(key, value, expiresIn) { - await Factory.Set(Encryptkey, key, value, expiresIn) -} - -async function removeEncryptKey(key) { - await Factory.Remove(Encryptkey, key) -} - -async function getTicket(key, fallback) { - return await Factory.Get(Ticket, key, fallback) -} - -async function setTicket(key, value, expiresIn) { - await Factory.Set(Ticket, key, value, expiresIn) -} - -async function removeTicket(key) { - await Factory.Remove(Ticket, key) -} - -module.exports = { - getAccessToken, - setAccessToken, - removeAccessToken, - getUserAccessToken, - setUserAccessToken, - removeUserAccessToken, - getSessionKey, - setSessionKey, - removeSessionKey, - getEncryptKey, - setEncryptKey, - removeEncryptKey, - getTicket, - setTicket, - removeTicket, - PlatformType, - WeixinServer, - ErrorCodeType +'use strict'; + +const { + PlatformType, + ErrorCodeType +} = require('./consts.js') + +const { + AppConfig +} = require('./config.js') + +const { + Storage, + Factory +} = require('./storage.js') + +const { + BridgeError +} = require('./bridge-error.js') + +const { + WeixinServer +} = require('./weixin-server.js') + +const appConfig = new AppConfig() + +class AccessToken extends Storage { + + constructor() { + super('access-token', ['dcloudAppid', 'platform']) + } + + async fallback(parameters) { + const oauthConfig = appConfig.get(parameters.dcloudAppid, parameters.platform) + let methodName + if (parameters.platform === PlatformType.WEIXIN_MP) { + methodName = 'GetMPAccessTokenData' + } else if (parameters.platform === PlatformType.WEIXIN_H5) { + methodName = 'GetH5AccessTokenData' + } else { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "platform invalid") + } + + const responseData = await WeixinServer[methodName](oauthConfig) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + + return { + value: responseData, + duration + } + } +} + +class UserAccessToken extends Storage { + + constructor() { + super('user-access-token', ['dcloudAppid', 'platform', 'openid']) + } +} + +class SessionKey extends Storage { + + constructor() { + super('session-key', ['dcloudAppid', 'platform', 'openid']) + } +} + +class Encryptkey extends Storage { + + constructor() { + super('encrypt-key', ['dcloudAppid', 'platform', 'openid']) + } + + getKeyString(key) { + return `${super.getKeyString(key)}-${key.version}` + } + + getExpiresIn(value) { + if (value <= 0) { + return 60 + } + return value + } + + async fallback(parameters) { + const accessToken = await Factory.Get(AccessToken, parameters) + const userSession = await Factory.Get(SessionKey, parameters) + + const responseData = await WeixinServer.GetUserEncryptKeyData({ + openid: parameters.openid, + access_token: accessToken.access_token, + session_key: userSession.session_key + }) + + const keyInfo = responseData.key_info_list.find((item) => { + return item.version = parameters.version + }) + + const value = { + encrypt_key: keyInfo.encrypt_key, + iv: keyInfo.iv + } + + return { + value, + duration: keyInfo.expire_in + } + } +} + +class Ticket extends Storage { + + constructor() { + super('ticket', ['dcloudAppid', 'platform']) + } + + async fallback(parameters) { + const accessToken = await Factory.Get(AccessToken, { + dcloudAppid: parameters.dcloudAppid, + platform: PlatformType.WEIXIN_H5 + }) + + const responseData = await WeixinServer.GetH5TicketData(accessToken) + + const duration = responseData.expires_in + delete responseData.expires_in + + return { + value: responseData, + duration + } + } +} + + +// exports + +async function getAccessToken(key, fallback) { + return await Factory.Get(AccessToken, key, fallback) +} + +async function setAccessToken(key, value, expiresIn) { + await Factory.Set(AccessToken, key, value, expiresIn) +} + +async function removeAccessToken(key) { + await Factory.Remove(AccessToken, key) +} + +async function getUserAccessToken(key, fallback) { + return await Factory.Get(UserAccessToken, key, fallback) +} + +async function setUserAccessToken(key, value, expiresIn) { + await Factory.Set(UserAccessToken, key, value, expiresIn) +} + +async function removeUserAccessToken(key) { + await Factory.Remove(UserAccessToken, key) +} + +async function getSessionKey(key, fallback) { + return await Factory.Get(SessionKey, key, fallback) +} + +async function setSessionKey(key, value, expiresIn) { + await Factory.Set(SessionKey, key, value, expiresIn) +} + +async function removeSessionKey(key) { + await Factory.Remove(SessionKey, key) +} + +async function getEncryptKey(key, fallback) { + return await Factory.Get(Encryptkey, key, fallback) +} + +async function setEncryptKey(key, value, expiresIn) { + await Factory.Set(Encryptkey, key, value, expiresIn) +} + +async function removeEncryptKey(key) { + await Factory.Remove(Encryptkey, key) +} + +async function getTicket(key, fallback) { + return await Factory.Get(Ticket, key, fallback) +} + +async function setTicket(key, value, expiresIn) { + await Factory.Set(Ticket, key, value, expiresIn) +} + +async function removeTicket(key) { + await Factory.Remove(Ticket, key) +} + +module.exports = { + getAccessToken, + setAccessToken, + removeAccessToken, + getUserAccessToken, + setUserAccessToken, + removeUserAccessToken, + getSessionKey, + setSessionKey, + removeSessionKey, + getEncryptKey, + setEncryptKey, + removeEncryptKey, + getTicket, + setTicket, + removeTicket, + PlatformType, + WeixinServer, + ErrorCodeType } diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js index b7395602c50e8e0a626c9b22f791c99835d2f2a8..8345be39c7032bab675371443610261377a8f9ef 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js @@ -1,117 +1,117 @@ -'use strict'; - -const { - Validator -} = require('./validator.js') - -const { - CacheKeyCascade -} = require('./uni-cloud-cache.js') - -class Storage { - - constructor(type, keys) { - this._type = type || null - this._keys = keys || [] - } - - async get(key, fallback) { - this.validateKey(key) - const result = await this.create(key, fallback).get() - return result.value - } - - async set(key, value, expiresIn) { - this.validateKey(key) - this.validateValue(value) - const expires_in = this.getExpiresIn(expiresIn) - if (expires_in !== 0) { - await this.create(key).set(this.getValue(value), expires_in) - } - } - - async remove(key) { - this.validateKey(key) - await this.create(key).remove() - } - - async ttl(key) { - this.validateKey(key) - // 后续考虑支持 - } - - getKeyString(key) { - const keyArray = [Storage.Prefix] - this._keys.forEach((name) => { - keyArray.push(key[name]) - }) - keyArray.push(this._type) - return keyArray.join(':') - } - - getValue(value) { - return value - } - - getExpiresIn(value) { - if (value !== undefined) { - return value - } - return -1 - } - - validateKey(key) { - Validator.Key(this._keys, key) - } - - validateValue(value) { - Validator.Value(value) - } - - create(key, fallback) { - const keyString = this.getKeyString(key) - const options = { - layers: [{ - type: 'database', - key: keyString - }, { - type: 'redis', - key: keyString - }] - } - if (fallback !== null) { - const fallbackFunction = fallback || this.fallback - if (fallbackFunction) { - options.fallback = async () => { - return await fallbackFunction(key) - } - } - } - return new CacheKeyCascade(options) - } -} -Storage.Prefix = "uni-id" - -const Factory = { - - async Get(T, key, fallback) { - return await Factory.MakeUnique(T).get(key, fallback) - }, - - async Set(T, key, value, expiresIn) { - await Factory.MakeUnique(T).set(key, value, expiresIn) - }, - - async Remove(T, key) { - await Factory.MakeUnique(T).remove(key) - }, - - MakeUnique(T) { - return new T() - } -} - -module.exports = { - Storage, - Factory +'use strict'; + +const { + Validator +} = require('./validator.js') + +const { + CacheKeyCascade +} = require('./uni-cloud-cache.js') + +class Storage { + + constructor(type, keys) { + this._type = type || null + this._keys = keys || [] + } + + async get(key, fallback) { + this.validateKey(key) + const result = await this.create(key, fallback).get() + return result.value + } + + async set(key, value, expiresIn) { + this.validateKey(key) + this.validateValue(value) + const expires_in = this.getExpiresIn(expiresIn) + if (expires_in !== 0) { + await this.create(key).set(this.getValue(value), expires_in) + } + } + + async remove(key) { + this.validateKey(key) + await this.create(key).remove() + } + + async ttl(key) { + this.validateKey(key) + // 后续考虑支持 + } + + getKeyString(key) { + const keyArray = [Storage.Prefix] + this._keys.forEach((name) => { + keyArray.push(key[name]) + }) + keyArray.push(this._type) + return keyArray.join(':') + } + + getValue(value) { + return value + } + + getExpiresIn(value) { + if (value !== undefined) { + return value + } + return -1 + } + + validateKey(key) { + Validator.Key(this._keys, key) + } + + validateValue(value) { + Validator.Value(value) + } + + create(key, fallback) { + const keyString = this.getKeyString(key) + const options = { + layers: [{ + type: 'database', + key: keyString + }, { + type: 'redis', + key: keyString + }] + } + if (fallback !== null) { + const fallbackFunction = fallback || this.fallback + if (fallbackFunction) { + options.fallback = async () => { + return await fallbackFunction(key) + } + } + } + return new CacheKeyCascade(options) + } +} +Storage.Prefix = "uni-id" + +const Factory = { + + async Get(T, key, fallback) { + return await Factory.MakeUnique(T).get(key, fallback) + }, + + async Set(T, key, value, expiresIn) { + await Factory.MakeUnique(T).set(key, value, expiresIn) + }, + + async Remove(T, key) { + await Factory.MakeUnique(T).remove(key) + }, + + MakeUnique(T) { + return new T() + } +} + +module.exports = { + Storage, + Factory }; diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js index 075093273414e8b8da1c3250b491a7896f7a1ae2..bde572ea87b9ad0c9db9a939ecaeb87cea50d8b8 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js @@ -1,324 +1,324 @@ -const db = uniCloud.database() - -function getType(value) { - return Object.prototype.toString.call(value).slice(8, -1).toLowerCase() -} - -const validator = { - key: function(value) { - const err = new Error('Invalid key') - if (typeof value !== 'string') { - throw err - } - const valueTrim = value.trim() - if (!valueTrim || valueTrim !== value) { - throw err - } - }, - value: function(value) { - // 仅作简单校验 - const type = getType(value) - const validValueType = ['null', 'number', 'string', 'array', 'object'] - if (validValueType.indexOf(type) === -1) { - throw new Error('Invalid value type') - } - }, - duration: function(value) { - const err = new Error('Invalid duration') - if (value === undefined) { - return - } - if (typeof value !== 'number' || value === 0) { - throw err - } - } -} - -/** - * 入库时 expired 为过期时间对应的时间戳,永不过期用-1表示 - * 返回结果时 与redis对齐,-1表示永不过期,-2表示已过期或不存在 - */ -class DatabaseCache { - constructor({ - collection = 'opendb-open-data' - } = {}) { - this.type = 'db' - this.collection = db.collection(collection) - } - - _serializeValue(value) { - return value === undefined ? null : JSON.stringify(value) - } - - _deserializeValue(value) { - return value ? JSON.parse(value) : value - } - - async set(key, value, duration) { - validator.key(key) - validator.value(value) - validator.duration(duration) - value = this._serializeValue(value) - await this.collection.doc(key).set({ - value, - expired: duration && duration !== -1 ? Date.now() + duration : -1 - }) - } - - async _getWithDuration(key) { - const getKeyRes = await this.collection.doc(key).get() - const record = getKeyRes.data[0] - if (!record) { - return { - value: null, - duration: -2 - } - } - const value = this._deserializeValue(record.value) - const expired = record.expired - if (expired === -1) { - return { - value, - duration: -1 - } - } - const duration = expired - Date.now() - if (duration <= 0) { - await this.remove(key) - return { - value: null, - duration: -2 - } - } - return { - value, - duration: Math.floor(duration / 1000) - } - } - - async get(key, { - withDuration = true - } = {}) { - const result = await this._getWithDuration(key) - if (!withDuration) { - delete result.duration - } - return result - } - - async remove(key) { - await this.collection.doc(key).remove() - } -} - -class RedisCache { - constructor() { - this.type = 'redis' - this.redis = uniCloud.redis() - } - - _serializeValue(value) { - return value === undefined ? null : JSON.stringify(value) - } - - _deserializeValue(value) { - return value ? JSON.parse(value) : value - } - - async set(key, value, duration) { - validator.key(key) - validator.value(value) - validator.duration(duration) - value = this._serializeValue(value) - if (!duration || duration === -1) { - await this.redis.set(key, value) - } else { - await this.redis.set(key, value, 'EX', duration) - } - } - - async get(key, { - withDuration = false - } = {}) { - let value = await this.redis.get(key) - value = this._deserializeValue(value) - if (!withDuration) { - return { - value - } - } - const durationSecond = await this.redis.ttl(key) - let duration - switch (durationSecond) { - case -1: - duration = -1 - break - case -2: - duration = -2 - break - default: - duration = durationSecond - break - } - return { - value, - duration - } - } - - async remove(key) { - await this.redis.del(key) - } -} - -class Cache { - constructor({ - type, - collection - } = {}) { - if (type === 'database') { - return new DatabaseCache({ - collection - }) - } else if (type === 'redis') { - return new RedisCache() - } else { - throw new Error('Invalid cache type') - } - } -} - -class CacheKey { - constructor({ - type, - collection, - cache, - key, - fallback - } = {}) { - this.cache = cache || new Cache({ - type, - collection - }) - this.key = key - this.fallback = fallback - } - - async set(value, duration) { - await this.cache.set(this.key, value, duration) - } - - async setWithSync(value, duration, syncMethod) { - await Promise.all([ - this.set(this.key, value, duration), - syncMethod(value, duration) - ]) - } - - async get() { - let { - value, - duration - } = await this.cache.get(this.key) - if (value !== null && value !== undefined) { - return { - value, - duration - } - } - if (!this.fallback) { - return { - value: null, - duration: -2 - } - } - const fallbackResult = await this.fallback() - value = fallbackResult.value - duration = fallbackResult.duration - if (value !== null && duration !== undefined) { - await this.cache.set(this.key, value, duration) - } - return { - value, - duration - } - } - - async remove() { - await this.cache.remove(this.key) - } -} - -class CacheKeyCascade { - constructor({ - layers, // [{cache, type, collection, key}] 从低级到高级排序,[DbCacheKey, RedisCacheKey] - fallback - } = {}) { - this.layers = layers - this.cacheLayers = [] - let lastCacheKey - for (let i = 0; i < layers.length; i++) { - const { - type, - cache, - collection, - key - } = layers[i] - const lastCacheKeyTemp = lastCacheKey - try { - const currentCacheKey = new CacheKey({ - type, - collection, - cache, - key, - fallback: i === 0 ? fallback : function() { - return lastCacheKeyTemp.get() - } - }) - this.cacheLayers.push(currentCacheKey) - lastCacheKey = currentCacheKey - } catch (e) {} - } - this.highLevelCache = lastCacheKey - } - - async set(value, duration) { - return Promise.all( - this.cacheLayers.map(item => { - return item.set(value, duration) - }) - ) - } - - async setWithSync(value, duration, syncMethod) { - const setPromise = this.cacheLayers.map(item => { - return item.set(value, duration) - }) - return Promise.all( - [ - ...setPromise, - syncMethod(value, duration) - ] - ) - } - - async get() { - return this.highLevelCache.get() - } - - async remove() { - await Promise.all( - this.cacheLayers.map(cacheKeyItem => { - return cacheKeyItem.remove() - }) - ) - } -} - -module.exports = { - Cache, - DatabaseCache, - RedisCache, - CacheKey, - CacheKeyCascade +const db = uniCloud.database() + +function getType(value) { + return Object.prototype.toString.call(value).slice(8, -1).toLowerCase() +} + +const validator = { + key: function(value) { + const err = new Error('Invalid key') + if (typeof value !== 'string') { + throw err + } + const valueTrim = value.trim() + if (!valueTrim || valueTrim !== value) { + throw err + } + }, + value: function(value) { + // 仅作简单校验 + const type = getType(value) + const validValueType = ['null', 'number', 'string', 'array', 'object'] + if (validValueType.indexOf(type) === -1) { + throw new Error('Invalid value type') + } + }, + duration: function(value) { + const err = new Error('Invalid duration') + if (value === undefined) { + return + } + if (typeof value !== 'number' || value === 0) { + throw err + } + } +} + +/** + * 入库时 expired 为过期时间对应的时间戳,永不过期用-1表示 + * 返回结果时 与redis对齐,-1表示永不过期,-2表示已过期或不存在 + */ +class DatabaseCache { + constructor({ + collection = 'opendb-open-data' + } = {}) { + this.type = 'db' + this.collection = db.collection(collection) + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + await this.collection.doc(key).set({ + value, + expired: duration && duration !== -1 ? Date.now() + (duration * 1000) : -1 + }) + } + + async _getWithDuration(key) { + const getKeyRes = await this.collection.doc(key).get() + const record = getKeyRes.data[0] + if (!record) { + return { + value: null, + duration: -2 + } + } + const value = this._deserializeValue(record.value) + const expired = record.expired + if (expired === -1) { + return { + value, + duration: -1 + } + } + const duration = expired - Date.now() + if (duration <= 0) { + await this.remove(key) + return { + value: null, + duration: -2 + } + } + return { + value, + duration: Math.floor(duration / 1000) + } + } + + async get(key, { + withDuration = true + } = {}) { + const result = await this._getWithDuration(key) + if (!withDuration) { + delete result.duration + } + return result + } + + async remove(key) { + await this.collection.doc(key).remove() + } +} + +class RedisCache { + constructor() { + this.type = 'redis' + this.redis = uniCloud.redis() + } + + _serializeValue(value) { + return value === undefined ? null : JSON.stringify(value) + } + + _deserializeValue(value) { + return value ? JSON.parse(value) : value + } + + async set(key, value, duration) { + validator.key(key) + validator.value(value) + validator.duration(duration) + value = this._serializeValue(value) + if (!duration || duration === -1) { + await this.redis.set(key, value) + } else { + await this.redis.set(key, value, 'EX', duration) + } + } + + async get(key, { + withDuration = false + } = {}) { + let value = await this.redis.get(key) + value = this._deserializeValue(value) + if (!withDuration) { + return { + value + } + } + const durationSecond = await this.redis.ttl(key) + let duration + switch (durationSecond) { + case -1: + duration = -1 + break + case -2: + duration = -2 + break + default: + duration = durationSecond + break + } + return { + value, + duration + } + } + + async remove(key) { + await this.redis.del(key) + } +} + +class Cache { + constructor({ + type, + collection + } = {}) { + if (type === 'database') { + return new DatabaseCache({ + collection + }) + } else if (type === 'redis') { + return new RedisCache() + } else { + throw new Error('Invalid cache type') + } + } +} + +class CacheKey { + constructor({ + type, + collection, + cache, + key, + fallback + } = {}) { + this.cache = cache || new Cache({ + type, + collection + }) + this.key = key + this.fallback = fallback + } + + async set(value, duration) { + await this.cache.set(this.key, value, duration) + } + + async setWithSync(value, duration, syncMethod) { + await Promise.all([ + this.set(this.key, value, duration), + syncMethod(value, duration) + ]) + } + + async get() { + let { + value, + duration + } = await this.cache.get(this.key) + if (value !== null && value !== undefined) { + return { + value, + duration + } + } + if (!this.fallback) { + return { + value: null, + duration: -2 + } + } + const fallbackResult = await this.fallback() + value = fallbackResult.value + duration = fallbackResult.duration + if (value !== null && duration !== undefined) { + await this.cache.set(this.key, value, duration) + } + return { + value, + duration + } + } + + async remove() { + await this.cache.remove(this.key) + } +} + +class CacheKeyCascade { + constructor({ + layers, // [{cache, type, collection, key}] 从低级到高级排序,[DbCacheKey, RedisCacheKey] + fallback + } = {}) { + this.layers = layers + this.cacheLayers = [] + let lastCacheKey + for (let i = 0; i < layers.length; i++) { + const { + type, + cache, + collection, + key + } = layers[i] + const lastCacheKeyTemp = lastCacheKey + try { + const currentCacheKey = new CacheKey({ + type, + collection, + cache, + key, + fallback: i === 0 ? fallback : function() { + return lastCacheKeyTemp.get() + } + }) + this.cacheLayers.push(currentCacheKey) + lastCacheKey = currentCacheKey + } catch (e) {} + } + this.highLevelCache = lastCacheKey + } + + async set(value, duration) { + return Promise.all( + this.cacheLayers.map(item => { + return item.set(value, duration) + }) + ) + } + + async setWithSync(value, duration, syncMethod) { + const setPromise = this.cacheLayers.map(item => { + return item.set(value, duration) + }) + return Promise.all( + [ + ...setPromise, + syncMethod(value, duration) + ] + ) + } + + async get() { + return this.highLevelCache.get() + } + + async remove() { + await Promise.all( + this.cacheLayers.map(cacheKeyItem => { + return cacheKeyItem.remove() + }) + ) + } +} + +module.exports = { + Cache, + DatabaseCache, + RedisCache, + CacheKey, + CacheKeyCascade } diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js index 47a455b15a479ce608838731287f5776985e191c..231dc8b14e84201e4a16a7de2366c4d137eb781f 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js @@ -1,31 +1,31 @@ -const Validator = { - - Key(keyArray, parameters) { - for (let i = 0; i < keyArray.length; i++) { - const keyName = keyArray[i] - if (typeof parameters[keyName] !== 'string') { - Validator.ThrowNewError(`Invalid ${keyName}`) - } - if (parameters[keyName].length < 1) { - Validator.ThrowNewError(`Invalid ${keyName}`) - } - } - }, - - Value(value) { - if (value === undefined) { - Validator.ThrowNewError('Invalid Value') - } - if (typeof value !== 'object') { - Validator.ThrowNewError('Invalid Value Type') - } - }, - - ThrowNewError(message) { - throw new Error(message) - } -} - -module.exports = { - Validator +const Validator = { + + Key(keyArray, parameters) { + for (let i = 0; i < keyArray.length; i++) { + const keyName = keyArray[i] + if (typeof parameters[keyName] !== 'string') { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + if (parameters[keyName].length < 1) { + Validator.ThrowNewError(`Invalid ${keyName}`) + } + } + }, + + Value(value) { + if (value === undefined) { + Validator.ThrowNewError('Invalid Value') + } + if (typeof value !== 'object') { + Validator.ThrowNewError('Invalid Value Type') + } + }, + + ThrowNewError(message) { + throw new Error(message) + } +} + +module.exports = { + Validator } diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js index f405bc2c21d631cc9a27cb6b5ebf0f2f53f2d509..28d695d74794fbc48095d962abb44ec9f0e1cc78 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js @@ -1,161 +1,161 @@ -'use strict'; - -const crypto = require('crypto') - -const { - HTTP_STATUS -} = require('./consts.js') - -const { - BridgeError -} = require('./bridge-error.js') - -class WeixinServer { - - constructor(options = {}) { - this._appid = options.appid - this._secret = options.secret - } - - getAccessToken() { - return uniCloud.httpclient.request(WeixinServer.AccessToken_Url, { - dataType: 'json', - method: 'POST', - data: { - appid: this._appid, - secret: this._secret, - grant_type: "client_credential" - } - }) - } - - // 使用客户端获取的 code 从微信服务器换取 openid,code 仅可使用一次 - codeToSession(code) { - return uniCloud.httpclient.request(WeixinServer.Code2Session_Url, { - dataType: 'json', - data: { - appid: this._appid, - secret: this._secret, - js_code: code, - grant_type: 'authorization_code' - } - }) - } - - getUserEncryptKey({ - access_token, - openid, - session_key - }) { - console.log(access_token, openid, session_key); - const signature = crypto.createHmac('sha256', session_key).update('').digest('hex') - return uniCloud.httpclient.request(WeixinServer.User_Encrypt_Key_Url, { - dataType: 'json', - method: 'POST', - dataAsQueryString: true, - data: { - access_token, - openid: openid, - signature: signature, - sig_method: 'hmac_sha256' - } - }) - } - - getAccessTokenH5() { - return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { - dataType: 'json', - method: 'GET', - data: { - appid: this._appid, - secret: this._secret, - grant_type: "client_credential" - } - }) - } - - getTicket(access_token) { - return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { - dataType: 'json', - dataAsQueryString: true, - method: 'POST', - data: { - access_token - } - }) - } -} - -WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/token' -WeixinServer.Code2Session_Url = 'https://api.weixin.qq.com/sns/jscode2session' -WeixinServer.User_Encrypt_Key_Url = 'https://api.weixin.qq.com/wxa/business/getuserencryptkey' -WeixinServer.AccessToken_H5_Url = 'https://api.weixin.qq.com/cgi-bin/token' -WeixinServer.Ticket_Url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi' - -WeixinServer.GetMPAccessToken = function(options) { - return new WeixinServer(options).getAccessToken() -} - -WeixinServer.GetCodeToSession = function(options) { - return new WeixinServer(options).codeToSession(options.code) -} - -WeixinServer.GetUserEncryptKey = function(options) { - return new WeixinServer(options).getUserEncryptKey(options) -} - -WeixinServer.GetH5AccessToken = function(options) { - return new WeixinServer(options).getAccessTokenH5() -} - -WeixinServer.GetH5Ticket = function(options) { - return new WeixinServer(options).getTicket(options.access_token) -} - -//////////////////////////////////////////////////////////////// - -WeixinServer.GetResponseData = function(response) { - console.log("WeixinServer::response", response) - - if (response.status !== HTTP_STATUS.SUCCESS) { - throw new BridgeError(response.status, response.status) - } - - const responseData = response.data - - if (responseData.errcode !== undefined && responseData.errcode !== 0) { - throw new BridgeError(responseData.errcode, responseData.errmsg) - } - - return responseData -} - -WeixinServer.GetMPAccessTokenData = async function(options) { - const response = await new WeixinServer(options).getAccessToken() - return WeixinServer.GetResponseData(response) -} - -WeixinServer.GetCodeToSessionData = async function(options) { - const response = await new WeixinServer(options).codeToSession(options.code) - return WeixinServer.GetResponseData(response) -} - -WeixinServer.GetUserEncryptKeyData = async function(options) { - const response = await new WeixinServer(options).getUserEncryptKey(options) - return WeixinServer.GetResponseData(response) -} - -WeixinServer.GetH5AccessTokenData = async function(options) { - const response = await new WeixinServer(options).getAccessTokenH5() - return WeixinServer.GetResponseData(response) -} - -WeixinServer.GetH5TicketData = async function(options) { - const response = await new WeixinServer(options).getTicket(options.access_token) - return WeixinServer.GetResponseData(response) -} - - -module.exports = { - WeixinServer +'use strict'; + +const crypto = require('crypto') + +const { + HTTP_STATUS +} = require('./consts.js') + +const { + BridgeError +} = require('./bridge-error.js') + +class WeixinServer { + + constructor(options = {}) { + this._appid = options.appid + this._secret = options.secret + } + + getAccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_Url, { + dataType: 'json', + method: 'POST', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + // 使用客户端获取的 code 从微信服务器换取 openid,code 仅可使用一次 + codeToSession(code) { + return uniCloud.httpclient.request(WeixinServer.Code2Session_Url, { + dataType: 'json', + data: { + appid: this._appid, + secret: this._secret, + js_code: code, + grant_type: 'authorization_code' + } + }) + } + + getUserEncryptKey({ + access_token, + openid, + session_key + }) { + console.log(access_token, openid, session_key); + const signature = crypto.createHmac('sha256', session_key).update('').digest('hex') + return uniCloud.httpclient.request(WeixinServer.User_Encrypt_Key_Url, { + dataType: 'json', + method: 'POST', + dataAsQueryString: true, + data: { + access_token, + openid: openid, + signature: signature, + sig_method: 'hmac_sha256' + } + }) + } + + getAccessTokenH5() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { + dataType: 'json', + method: 'GET', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + getTicket(access_token) { + return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { + dataType: 'json', + dataAsQueryString: true, + method: 'POST', + data: { + access_token + } + }) + } +} + +WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Code2Session_Url = 'https://api.weixin.qq.com/sns/jscode2session' +WeixinServer.User_Encrypt_Key_Url = 'https://api.weixin.qq.com/wxa/business/getuserencryptkey' +WeixinServer.AccessToken_H5_Url = 'https://api.weixin.qq.com/cgi-bin/token' +WeixinServer.Ticket_Url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi' + +WeixinServer.GetMPAccessToken = function(options) { + return new WeixinServer(options).getAccessToken() +} + +WeixinServer.GetCodeToSession = function(options) { + return new WeixinServer(options).codeToSession(options.code) +} + +WeixinServer.GetUserEncryptKey = function(options) { + return new WeixinServer(options).getUserEncryptKey(options) +} + +WeixinServer.GetH5AccessToken = function(options) { + return new WeixinServer(options).getAccessTokenH5() +} + +WeixinServer.GetH5Ticket = function(options) { + return new WeixinServer(options).getTicket(options.access_token) +} + +//////////////////////////////////////////////////////////////// + +WeixinServer.GetResponseData = function(response) { + console.log("WeixinServer::response", response) + + if (response.status !== HTTP_STATUS.SUCCESS) { + throw new BridgeError(response.status, response.status) + } + + const responseData = response.data + + if (responseData.errcode !== undefined && responseData.errcode !== 0) { + throw new BridgeError(responseData.errcode, responseData.errmsg) + } + + return responseData +} + +WeixinServer.GetMPAccessTokenData = async function(options) { + const response = await new WeixinServer(options).getAccessToken() + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetCodeToSessionData = async function(options) { + const response = await new WeixinServer(options).codeToSession(options.code) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetUserEncryptKeyData = async function(options) { + const response = await new WeixinServer(options).getUserEncryptKey(options) + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5AccessTokenData = async function(options) { + const response = await new WeixinServer(options).getAccessTokenH5() + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5TicketData = async function(options) { + const response = await new WeixinServer(options).getTicket(options.access_token) + return WeixinServer.GetResponseData(response) +} + + +module.exports = { + WeixinServer } diff --git a/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json b/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json index 9fc8bf91dbcaab05633f09b3706eb7a1e21bc931..68c0ebbe8679276a1df500c07f8d9b67eb5e3caa 100644 --- a/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json +++ b/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json @@ -1,19 +1,19 @@ -// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema -{ - "bsonType": "object", - "required": ["_id", "value"], - "properties": { - "_id": { - "bsonType": "string", - "description": "key,格式:uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]" - }, - "value": { - "bsonType": "object", - "description": "字段_id对应的值" - }, - "expired": { - "bsonType": "date", - "description": "过期时间" - } - } +// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema +{ + "bsonType": "object", + "required": ["_id", "value"], + "properties": { + "_id": { + "bsonType": "string", + "description": "key,格式:uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]" + }, + "value": { + "bsonType": "object", + "description": "字段_id对应的值" + }, + "expired": { + "bsonType": "date", + "description": "过期时间" + } + } }