diff --git a/.gitignore b/.gitignore index a19f004..b86a9d2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,142 @@ # TODO: where does this rule come from? docs/_book +task_detail_**.md + # TODO: where does this rule come from? test/ +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release +unpackage +unpackage/** + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..ae21fc2 --- /dev/null +++ b/App.vue @@ -0,0 +1,153 @@ + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c75f232 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 DCloud + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 15f65a0..0d1c6a3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,129 @@ -# wz-uniapp - -uniapp 版本 # 3.4.9(2025-06-25)的套webview demo 传参数版本,后端使用Golang,自用做模板开发 \ No newline at end of file +# hello-uniapp + +`uni-app`框架示例,一套代码,同时发行到iOS、Android、H5、小程序等多个平台,请使用手机在下方扫码快速体验`uni-app`的强大功能。[官方文档](https://uniapp.dcloud.net.cn/) + +## 快速上手 +hello-uniapp 示例工程可以通过两种方式创建, 一种是 HBuilderX, 配套 IDE,集成开发;另一种是 CLI 创建;推荐前者。 +### 通过 HBuilderX 可视化界面创建(推荐) + +可视化的方式比较简单,HBuilderX内置相关环境,开箱即用,无需配置nodejs。 + +开始之前,开发者需先下载安装如下工具: + +- HBuilderX:[官方IDE下载地址](https://www.dcloud.io/hbuilderx.html) + +HBuilderX是通用的前端开发工具,但为`uni-app`做了特别强化,请下载App开发版。 + +由于截图在 github 不便浏览,参见官方文档 [HBuilderX 可视化界面创建](https://uniapp.dcloud.net.cn/quickstart?id=_1-%e9%80%9a%e8%bf%87-hbuilderx-%e5%8f%af%e8%a7%86%e5%8c%96%e7%95%8c%e9%9d%a2) + +### 通过 vue-cli 创建 + +``` +npm install -g @vue/cli +``` + +#### 创建uni-app + +**使用正式版**(对应HBuilderX最新正式版) + +``` +vue create -p dcloudio/uni-preset-vue my-project +``` + +**使用alpha版**(对应HBuilderX最新alpha版) + +``` +vue create -p dcloudio/uni-preset-vue#alpha my-alpha-project +``` + +此时,会提示选择项目模板,选择 `hello uni-app` 项目模板,如下所示: + +
+ +
+ +创建好后,进入项目目录 +``` +cd my-project +``` + +执行该命令运行到 h5 端 +``` +npm run dev:h5 +``` + +欢迎提 issues,推荐到[官方社区](https://ask.dcloud.net.cn/explore/)提问。 + +## 扫码体验 + +
+

一套代码编到10个平台,这不是梦想。眼见为实,扫描10个二维码,亲自体验最全面的跨平台效果!

+
+ +
+ +
+ Android版 +
+ +
+ +
+ iOS版 +
+ +
+ +
+ H5版 +
+ +
+ 微信小程序版 +
+ +
+ 支付宝小程序版 +
+
+
+ +
+ 百度小程序版 +
+ +
+ +
+ 字节跳动小程序版 +
+ +
+ +
+ QQ小程序版 +
+ +
+ +
+ 快应用 +
+ +
+ +
+ 360小程序 +
+
+

+ 注:某些平台不能提交简单demo,故补充了一些其他功能;hello uni-app示例代码可从[github](https://github.com/dcloudio/hello-uniapp)获取
+ 快应用仅支持 vivo 、oppo、华为
+ 360小程序仅 windows平台支持,需要在360浏览器中打开
+

+
+ +`uni-app`官网文档详见[https://uniapp.dcloud.io](https://uniapp.dcloud.io) + +更多uni-app的模板、示例详见[插件市场](https://ext.dcloud.net.cn/) + diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..0340482 --- /dev/null +++ b/changelog.md @@ -0,0 +1,186 @@ +## 3.4.9(2025-06-25) +- 适配 鸿蒙元服务 +- 更新 uni-swipe-action +- 新增 crypto 示例和测试例 +- 新增 css 变量示例和测试例 +- 新增 web-view点击位置偏移测试例 +## 3.4.8(2025-04-10) +- 调整 renderjs示例的平台兼容性 +## 3.4.7(2025-01-08) +- 新增 uni-calendar显示 +- 更新 uniui 组件 +- 更新uni-id至3.3.33版本 +- 替换示例中失效图片资源地址 +## 3.4.6(2023-06-30) +- 更新 video组件引用的视频链接 +## 3.4.4(2022-07-25) +- 新增 同步 uni-ui@1.4.20 + - uni-forms 【重要】组件逻辑重构,部分用法旧版本不兼容,请注意兼容问题 + - uni-section 新增组件 +## 3.4.3(2022-07-14) +- 修复 HBuilderX 拉取 hello uni-app 项目直接运行提示无服务空间关联的bug +## 3.4.2(2022-07-06) +- 新增 同步 uni-ui@1.4.18 + - uni-forms 【重要】组件逻辑重构,部分用法旧版本不兼容,请注意兼容问题 + - uni-forms 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力 + - uni-forms 新增 更多表单示例 + - uni-forms 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃 + - uni-forms 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效 + - uni-forms 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法 + - uni-forms 新增 子表单的 setRules 方法,配合自定义校验函数使用 + - uni-forms 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则 + - uni-forms 修复 由 1.4.0 引发的 label 插槽不生效的bug + - uni-forms 修复 子组件找不到 setValue 报错的bug + - uni-forms 修复 uni-data-picker 在 uni-forms-item 中报错的bug + - uni-forms 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug + - uni-forms 修复 表单校验顺序无序问题 + - uni-forms 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式 + - uni-forms 优化 动态表单校验方式,废弃拼接name的方式 + - uni-breadcrumb 修复 微信小程序 separator 不显示问题 + - uni-data-checkbox 优化 在 uni-forms 中的依赖注入方式 + - uni-data-picker 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug + - uni-data-picker 优化 显示样式 + - uni-data-select 优化 显示样式 + - uni-datetime-picker 修复 日历顶部年月及底部确认未国际化 bug + - uni-datetime-picker 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致 + - uni-easyinput 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容 + - uni-easyinput 新增 clear 事件,点击右侧叉号图标触发 + - uni-easyinput 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发 + - uni-easyinput 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等 + - uni-easyinput 优化 clearable 显示策略 + - uni-file-picker 修复 在uni-forms下样式不生效的bug + - uni-nav-bar 修复 组件示例中插槽用法无法显示内容的bug + - uni-swipe-action 修复 vue3 下使用组件不能正常运行的Bug + - uni-swipe-action 修复 h5端点击click触发两次的Bug + - uni-table 修复 微信小程序存在无使用组件的问题 +## 3.4.1(2022-06-30) +- 新增 支持 ios 安全区 +## 3.3.8(2022-05-08) +- 新增 同步 uni-ui@1.4.15 + - uni-data-picker 修复 字节小程序 本地数据无法选择下一级的Bug + - uni-data-select 新增 记住上次的选项(仅 collection 存在时有效) + - uni-search-bar 修复 vue3 input 事件不生效的bug + - uni-search-bar 修复 多余代码导致的bug + - uni-tooltip 更新 text 属性变更为 content + - uni-tooltip 更新 移除 width 属性 + - uni-tooltip 修复 组件根 text 嵌套组件 warning +## 3.3.7(2022-04-06) +- 新增 更新扩展组件 uni-nav-bar、uni-list 的展示页面 +## 3.3.6(2022-03-31) +- 更新 uni-ui 组件及示例 +## 3.3.5(2022-03-30) +- 修复 插槽兼容 vue3, slot -> v-slot +- 新增 更新 uni-ui +## 3.3.4(2022-02-25) +- 修复 编译到 App 平台的控制台报错 +## 3.3.3(2022-02-23) +- 修复 模板城市选择 vue3 报错的bug +- 修复 删除 map.nvue 中多余的 enableOverlooking 变量 +- 修复 swipe-dot.nvue 中条件编译媒体查询 +## 3.3.2(2022-01-26) +- 修复 默认运行到 vue2 +## 3.3.1(2022-01-26) +- 新增 同步 uni-ui@1.4.11 + - uni-collapse 修复 微信小程序resize后组件收起的bug + - uni-countdown 修复 在微信小程序中样式不生效的bug + - uni-countdown 新增 update 方法 ,在动态更新时间后,刷新组件 + - uni-load-more 新增 showText属性 ,是否显示文本 + - uni-load-more 修复 nvue 平台下不显示文本的bug + - uni-load-more 修复 微信小程序平台样式选择器报警告的问题 + - uni-nav-bar 修复 在vue下,标题不垂直居中的bug + - uni-nav-bar 修复 height 属性类型错误 + - uni-nav-bar 新增 height 属性,可修改组件高度 + - uni-nav-bar 新增 dark 属性可可开启暗黑模式 + - uni-nav-bar 优化 标题字数过多显示省略号 + - uni-nav-bar 优化 插槽,插入内容可完全覆盖 + - uni-popup 修复 isMaskClick 失效的bug + - uni-popup 新增 cancelText \ confirmText 属性 ,可自定义文本 + - uni-popup 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 + - uni-popup 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 +## 3.3.0(2022-01-04) +- 修复 开发时在 vue3 下由 pc 端切换到手机端,不能返回上一级页面的 bug +- 优化 去掉 pc 端 topwindow 右上角用于演示的 url 导航 +## 3.2.12(2021-12-20) +- 新增 适配京东小程序 +## 3.2.11(2021-12-07) +- 修复 uni-ui 在 hello-uniapp 中丢失图标、ui 受到公共样式影响等问题 +- 修复 微信登录取值报错的问题 +## 3.2.10(2021-11-30) +- 修复 map 组件示例不显示的 bug +## 3.2.9(2021-11-19) +- 新增 uni-ui 以 uni_modules 方式引入,方便开发者从 hello-uniapp 中 copy 组件及示例 +- 优化 uni-ui 示例页面,完善组件示例 +## 3.2.8(2021-11-10) +- 新增 适配飞书平台(lark) +## 3.2.7(2021-10-26) +- 修复 uni-popup 示例的 button 文字在 iPhone 5 上换行的 bug +- 修复 uni-table 示例,页面顶部距离不对的 bug +- 修复 GlobalData示例,在vue3是无效的 bug +- 优化 删除无用的 project.swan.json 文件 +## 3.2.6(2021-10-08) +- 由于体验问题,暂时撤销 uni-ui 以 uni_modules 方式引入的修改 + +## 3.2.4(2021-09-07) +- 修复 vue3 在 H5 编译报错的 bug +- 新增 同步 uni-ui + - 新增 uni-ui 组件支持国际化 i18n + - uni-data-checkbox 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题 + - uni-datetime-picker 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次 + - uni-datetime-picker 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法 + - uni-datetime-picker 优化 调整字号大小,美化日历界面 + - uni-datetime-picker 修复 因国际化导致的 placeholder 失效的 bug + - uni-file-picker 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug + - uni-file-picker 新增 参数中返回 fileID 字段 + - uni-file-picker 修复 腾讯云传入fileID 不能回显的bug + - uni-file-picker 修复 选择图片后,不能放大的问题 + - uni-link 修复 在 nvue 下不显示的 bug + - uni-list 修复 在vue3中to属性在发行应用的时候报错的bug + - uni-search-bar 修复 value 属性与 modelValue 属性不兼容的Bug + - uni-swipe-action 优化 close-all 方法 + - uni-collapse 优化 show-arrow 属性默认为true + - uni-collapse 新增 show-arrow 属性,控制是否显示右侧箭头 + - uni-data-checkbox 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 + - uni-easyinput 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug + - uni-file-picker 修复 由于 0.2.11 版本引起的不能回显图片的Bug + - uni-file-picker 新增 clearFiles(index) 方法,可以手动删除指定文件 + - uni-file-picker 修复 v-model 值设为 null 报错的Bug + - uni-swipe-action 新增 close-all 方法,关闭所有已打开的组件 + - uni-swipe-action 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件 + - uni-swipe-action 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 + - uni-swipe-action 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题 + + +## 3.2.3(2021-08-27) +- 优化 tabbar 页面移除 vuex 相关代码 +- 新增 适配 vue3 (app) +## 3.2.2(2021-08-10) +- 新增 适配快手小程序 +- 新增 同步 uni-ui + - uni-datetime-picker 新增 return-type 属性支持返回 date 日期对象 + - uni-file-picker 修复 fileExtname属性不指定值报错的Bug + - uni-file-picker 修复 在某种场景下图片不回显的Bug + - uni-link 支持自定义插槽 + - uni-calendar 修复 弹出层被 tabbar 遮盖 bug + - uni-dateformat 调整 默认时间不再是当前时间,而是显示'-'字符 + - uni-datetime-picker 新增 适配 vue3 + - uni-datetime-picker 新增 支持作为 uni-forms 子组件相关功能 + - uni-datetime-picker 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug + - uni-datetime-picker 修复 type 属性动态赋值无效的 bug + - uni-datetime-picker 修复 ‘确认’按钮被 tabbar 遮盖 bug + - uni-datetime-picker 修复 组件未赋值时范围选左、右日历相同的 bug + - uni-datetime-picker 修复 范围选未正确显示当前值的 bug + - uni-datetime-picker 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug + - uni-file-picker 修复 auto-upload 属性失效的Bug +## 3.2.1(2021-07-31) +- 新增 同步 uni-ui@1.3.8 +## 3.2.0(2021-07-30) +- 新增 同时兼容 vue2 & vue3 +## 3.1.20(2021-07-30) +- 新增 同时兼容 vue2 & vue3 +## 3.1.17(2021-05-26) +- 修复 3.1.16 依赖 sass 的问题 +- 条件编译 nuve 不支持 css 属性 +## 3.1.16(2021-05-26) +- 修复 uni-data-checkbox 不关联服务空间的情况下组件报错的 Bug +## 3.1.12(2021-05-07) +- hello-uniapp 发布插件市场 diff --git a/common/airport.js b/common/airport.js new file mode 100644 index 0000000..adc05b4 --- /dev/null +++ b/common/airport.js @@ -0,0 +1,262 @@ +export default { + "list": [{ + "letter": "A", + "data": [ + "阿克苏机场", + "阿拉山口机场", + "阿勒泰机场", + "阿里昆莎机场", + "安庆天柱山机场", + "澳门国际机场" + ] + }, { + "letter": "B", + "data": [ + "保山机场", + "包头机场", + "北海福成机场", + "北京南苑机场", + "北京首都国际机场" + ] + }, { + "letter": "C", + "data": [ + "长白山机场", + "长春龙嘉国际机场", + "常德桃花源机场", + "昌都邦达机场", + "长沙黄花国际机场", + "长治王村机场", + "常州奔牛机场", + "成都双流国际机场", + "赤峰机场" + ] + }, { + "letter": "D", + "data": [ + "大理机场", + "大连周水子国际机场", + "大庆萨尔图机场", + "大同东王庄机场", + "达州河市机场", + "丹东浪头机场", + "德宏芒市机场", + "迪庆香格里拉机场", + "东营机场", + "敦煌机场" + ] + }, { + "letter": "E", + "data": [ + "鄂尔多斯机场", + "恩施许家坪机场", + "二连浩特赛乌苏国际机场" + ] + }, { + "letter": "F", + "data": [ + "阜阳西关机场", + "福州长乐国际机场" + ] + }, { + "letter": "G", + "data": [ + "赣州黄金机场", + "格尔木机场", + "固原六盘山机场", + "广元盘龙机场", + "广州白云国际机场", + "桂林两江国际机场", + "贵阳龙洞堡国际机场" + ] + }, { + "letter": "H", + "data": [ + "哈尔滨太平国际机场", + "哈密机场", + "海口美兰国际机场", + "海拉尔东山国际机场", + "邯郸机场", + "汉中机场", + "杭州萧山国际机场", + "合肥骆岗国际机场", + "和田机场", + "黑河机场", + "呼和浩特白塔国际机场", + "淮安涟水机场", + "黄山屯溪国际机场" + ] + }, { + "letter": "I", + "data": [] + }, { + "letter": "J", + "data": [ + "济南遥墙国际机场", + "济宁曲阜机场", + "鸡西兴凯湖机场", + "佳木斯东郊机场", + "嘉峪关机场", + "锦州小岭子机场", + "景德镇机场", + "井冈山机场", + "九江庐山机场", + "九寨黄龙机场" + ] + }, { + "letter": "K", + "data": [ + "喀什机场", + "克拉玛依机场", + "库车龟兹机场", + "库尔勒机场", + "昆明巫家坝国际机场" + ] + }, { + "letter": "L", + "data": [ + "拉萨贡嘎机场", + "兰州中川机场", + "丽江三义机场", + "黎平机场", + "连云港白塔埠机场", + "临沧机场", + "临沂机场", + "林芝米林机场", + "柳州白莲机场", + "龙岩冠豸山机场", + "泸州蓝田机场", + "洛阳北郊机场" + ] + }, { + "letter": "M", + "data": [ + "满洲里西郊机场", + "绵阳南郊机场", + "漠河古莲机场", + "牡丹江海浪机场" + ] + }, { + "letter": "N", + "data": [ + "南昌昌北国际机场", + "南充高坪机场", + "南京禄口国际机场", + "南宁吴圩机场", + "南通兴东机场", + "南阳姜营机场", + "宁波栎社国际机场" + ] + }, { + "letter": "O", + "data": [] + }, { + "letter": "P", + "data": [ + "普洱思茅机场" + ] + }, { + "letter": "Q", + "data": [ + "齐齐哈尔三家子机场", + "秦皇岛山海关机场", + "青岛流亭国际机场", + "衢州机场", + "泉州晋江机场" + ] + }, { + "letter": "R", + "data": [ + "日喀则和平机场" + ] + }, { + "letter": "S", + "data": [ + "三亚凤凰国际机场", + "汕头外砂机场", + "上海虹桥国际机场", + "上海浦东国际机场", + "深圳宝安国际机场", + "沈阳桃仙国际机场", + "石家庄正定国际机场", + "苏南硕放国际机场" + ] + }, { + "letter": "T", + "data": [ + "塔城机场", + "太原武宿国际机场", + "台州路桥机场 (黄岩机场)", + "唐山三女河机场", + "腾冲驼峰机场", + "天津滨海国际机场", + "通辽机场", + "铜仁凤凰机场" + ] + }, { + "letter": "U", + "data": [] + }, { + "letter": "V", + "data": [] + }, { + "letter": "W", + "data": [ + "万州五桥机场", + "潍坊机场", + "威海大水泊机场", + "文山普者黑机场", + "温州永强国际机场", + "乌海机场", + "武汉天河国际机场", + "乌兰浩特机场", + "乌鲁木齐地窝堡国际机场", + "武夷山机场", + "梧州长洲岛机场" + ] + }, { + "letter": "X", + "data": [ + "西安咸阳国际机场", + "西昌青山机场", + "锡林浩特机场", + "西宁曹家堡机场", + "西双版纳嘎洒机场", + "厦门高崎国际机场", + "香港国际机场", + "襄阳刘集机场", + "兴义机场", + "徐州观音机场" + ] + }, { + "letter": "Y", + "data": [ + "延安二十里堡机场", + "盐城机场", + "延吉朝阳川机场", + "烟台莱山国际机场", + "宜宾菜坝机场", + "宜昌三峡机场", + "伊春林都机场", + "伊宁机场", + "义乌机场", + "银川河东机场", + "永州零陵机场", + "榆林榆阳机场", + "玉树巴塘机场", + "运城张孝机场" + ] + }, { + "letter": "Z", + "data": [ + "湛江机场", + "昭通机场", + "郑州新郑国际机场", + "芷江机场", + "重庆江北国际机场", + "中卫香山机场", + "舟山朱家尖机场", + "珠海三灶机场" + ] + }] +} diff --git a/common/api.js b/common/api.js new file mode 100644 index 0000000..07939f9 --- /dev/null +++ b/common/api.js @@ -0,0 +1,5 @@ +export const API = { + WX_MINI_LOGIN: '/api/open/wechat/mini/login', + USER_PROFILE: '/api/user/profile', + USER_PASSWORD_LOGIN: '/api/open/user/login' +}; diff --git a/common/app-config.js b/common/app-config.js new file mode 100644 index 0000000..6f96310 --- /dev/null +++ b/common/app-config.js @@ -0,0 +1,249 @@ +import { ENV, STORAGE_KEYS } from './env'; +import { version as packageVersion } from '@/package.json'; + +const CACHE_KEY = STORAGE_KEYS.APP_CONFIG || 'app_config_cache'; +const DEFAULT_TTL_SECONDS = 3600; +let inFlight = null; +let lastConfig = null; + +function buildUrl(base, path) { + if (!base) return path; + const normalizedBase = String(base).replace(/\/$/, ''); + const normalizedPath = String(path || '').replace(/^\//, ''); + return `${normalizedBase}/${normalizedPath}`; +} + +function parseVersion(value) { + if (!value) return [0]; + return String(value) + .replace(/^v/i, '') + .split('.') + .map((item) => { + const num = Number.parseInt(item, 10); + return Number.isNaN(num) ? 0 : num; + }); +} + +function compareVersion(a, b) { + const left = parseVersion(a); + const right = parseVersion(b); + const maxLen = Math.max(left.length, right.length); + for (let i = 0; i < maxLen; i += 1) { + const l = left[i] || 0; + const r = right[i] || 0; + if (l > r) return 1; + if (l < r) return -1; + } + return 0; +} + +function getAppVersion() { + let current = packageVersion || '0.0.0'; + // #ifdef MP-WEIXIN + try { + const account = uni.getAccountInfoSync && uni.getAccountInfoSync(); + const mpVersion = account && account.miniProgram && account.miniProgram.version; + if (mpVersion) current = mpVersion; + } catch (e) { + // ignore + } + // #endif + return current || '0.0.0'; +} + +function getCache() { + try { + return uni.getStorageSync(CACHE_KEY); + } catch (e) { + return null; + } +} + +function setCache(config) { + const ttlSeconds = Number(config && config.ttlSeconds) || DEFAULT_TTL_SECONDS; + const now = Date.now(); + const cache = { + data: config.data, + cachedAt: now, + expireAt: now + ttlSeconds * 1000 + }; + uni.setStorageSync(CACHE_KEY, cache); + return cache; +} + +function isCacheValid(cache) { + if (!cache || !cache.expireAt) return false; + return Date.now() < cache.expireAt; +} + +function applyConfig(config) { + if (!config) return; + if (config.api && config.api.baseUrl) { + ENV.API_BASE_URL = config.api.baseUrl; + } + if (config.webview && config.webview.baseUrl) { + ENV.WEBVIEW_BASE_URL = config.webview.baseUrl; + } + lastConfig = config; +} + +function buildFailMessage(message) { + return message || '配置获取失败,请退出小程序重新打开。'; +} + +function showExitModal(message) { + uni.showModal({ + title: '提示', + content: message, + showCancel: false, + confirmText: '退出', + success: () => { + // #ifdef MP-WEIXIN + if (uni.exitMiniProgram) { + uni.exitMiniProgram(); + } + // #endif + // #ifdef APP-PLUS + if (typeof plus !== 'undefined' && plus.runtime && plus.runtime.quit) { + plus.runtime.quit(); + } + // #endif + } + }); +} + +function validateConfig(config) { + if (!config) { + return { ok: false, message: buildFailMessage('配置无效,请退出小程序重新打开。') }; + } + if (config.disabled) { + return { + ok: false, + message: config.disableReason || '服务暂不可用,请退出小程序重新打开。' + }; + } + + const currentVersion = getAppVersion(); + const app = config.app || {}; + const api = config.api || {}; + const webview = config.webview || {}; + + if (app.minVersion && compareVersion(currentVersion, app.minVersion) < 0) { + return { + ok: false, + message: '当前版本过低,请退出小程序重新打开。' + }; + } + if (api.version && webview.version && api.version !== webview.version) { + return { + ok: false, + message: '当前版本不一致,请退出小程序并重新打开以获取最新配置。' + }; + } + if (api.minClientVersion && compareVersion(currentVersion, api.minClientVersion) < 0) { + return { + ok: false, + message: '当前版本过低,请退出小程序重新打开。' + }; + } + if (webview.minClientVersion && compareVersion(currentVersion, webview.minClientVersion) < 0) { + return { + ok: false, + message: '当前版本过低,请退出小程序重新打开。' + }; + } + + return { ok: true, message: '' }; +} + +function requestConfig() { + const url = buildUrl(ENV.API_BASE_URL, '/api/open/app/config'); + return new Promise((resolve, reject) => { + uni.request({ + url, + method: 'GET', + timeout: 8000, + success: (res) => { + if (res.statusCode >= 200 && res.statusCode < 300 && res.data) { + resolve(res.data); + return; + } + reject({ message: '配置获取失败', response: res }); + }, + fail: (err) => reject(err) + }); + }); +} + +export async function initAppConfig(options = {}) { + if (inFlight) return inFlight; + const { force = false } = options; + inFlight = (async () => { + const cache = getCache(); + if (!force && isCacheValid(cache)) { + const validation = validateConfig(cache.data); + if (!validation.ok) { + showExitModal(validation.message); + throw new Error(validation.message); + } + applyConfig(cache.data); + return cache.data; + } + + try { + const config = await requestConfig(); + const validation = validateConfig(config); + if (!validation.ok) { + showExitModal(validation.message); + throw new Error(validation.message); + } + setCache(config); + applyConfig(config); + return config; + } catch (error) { + if (cache && isCacheValid(cache)) { + const validation = validateConfig(cache.data); + if (!validation.ok) { + showExitModal(validation.message); + throw new Error(validation.message); + } + applyConfig(cache.data); + return cache.data; + } + showExitModal(buildFailMessage()); + throw error; + } + })(); + + try { + return await inFlight; + } finally { + inFlight = null; + } +} + +export async function ensureAppConfig() { + const cache = getCache(); + console.log('【业务代码定位】', cache, new Error().stack); + if (cache && isCacheValid(cache)) { + const validation = validateConfig(cache.data); + if (!validation.ok) { + showExitModal(validation.message); + throw new Error(validation.message); + } + applyConfig(cache.data); + return cache.data; + } + return initAppConfig({ force: true }); +} + +export function getAppConfig() { + return lastConfig || (getCache() ? getCache().data : null); +} + +export function getWebviewBaseUrl() { + const config = getAppConfig(); + let webviewBaseUrl = (config && config.webview && config.webview.baseUrl) || ENV.WEBVIEW_BASE_URL || ''; + console.log(webviewBaseUrl); + return webviewBaseUrl; +} diff --git a/common/env.js b/common/env.js new file mode 100644 index 0000000..122c0d2 --- /dev/null +++ b/common/env.js @@ -0,0 +1,16 @@ +export const ENV = { + API_BASE_URL: 'http://192.168.1.106:8081', + WEBVIEW_BASE_URL: '', + REQUEST_TIMEOUT: 15000, + APP_NAME: '领航专昇本志愿通', + APP_SUBTITLE: '这里填写副标题', + PROJECT_CODE: 'UNIAPP_ZSB', + SECURITY_ENABLE: false, + SECURITY_SECRET_KEY: '' +}; + +export const STORAGE_KEYS = { + TOKEN: 'wx_token', + USER_INFO: 'user_info', + APP_CONFIG: 'app_config_cache' +}; diff --git a/common/graceChecker.js b/common/graceChecker.js new file mode 100644 index 0000000..682af99 --- /dev/null +++ b/common/graceChecker.js @@ -0,0 +1,97 @@ +/** +数据验证(表单验证) +来自 grace.hcoder.net +作者 hcoder 深海 +*/ +export default { + error:'', + check : function (data, rule){ + for(var i = 0; i < rule.length; i++){ + if (!rule[i].checkType){return true;} + if (!rule[i].name) {return true;} + if (!rule[i].errorMsg) {return true;} + if (!data[rule[i].name]) {this.error = rule[i].errorMsg; return false;} + switch (rule[i].checkType){ + case 'string': + var reg = new RegExp('^.{' + rule[i].checkRule + '}$'); + if(!reg.test(data[rule[i].name])) {this.error = rule[i].errorMsg; return false;} + break; + case 'int': + var reg = new RegExp('^(-[1-9]|[1-9])[0-9]{' + rule[i].checkRule + '}$'); + if(!reg.test(data[rule[i].name])) {this.error = rule[i].errorMsg; return false;} + break; + break; + case 'between': + if (!this.isNumber(data[rule[i].name])){ + this.error = rule[i].errorMsg; + return false; + } + var minMax = rule[i].checkRule.split(','); + minMax[0] = Number(minMax[0]); + minMax[1] = Number(minMax[1]); + if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { + this.error = rule[i].errorMsg; + return false; + } + break; + case 'betweenD': + var reg = /^-?[1-9][0-9]?$/; + if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } + var minMax = rule[i].checkRule.split(','); + minMax[0] = Number(minMax[0]); + minMax[1] = Number(minMax[1]); + if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { + this.error = rule[i].errorMsg; + return false; + } + break; + case 'betweenF': + var reg = /^-?[0-9][0-9]?.+[0-9]+$/; + if (!reg.test(data[rule[i].name])){this.error = rule[i].errorMsg; return false;} + var minMax = rule[i].checkRule.split(','); + minMax[0] = Number(minMax[0]); + minMax[1] = Number(minMax[1]); + if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { + this.error = rule[i].errorMsg; + return false; + } + break; + case 'same': + if (data[rule[i].name] != rule[i].checkRule) { this.error = rule[i].errorMsg; return false;} + break; + case 'notsame': + if (data[rule[i].name] == rule[i].checkRule) { this.error = rule[i].errorMsg; return false; } + break; + case 'email': + var reg = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; + if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } + break; + case 'phoneno': + var reg = /^1[0-9]{10,10}$/; + if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } + break; + case 'zipcode': + var reg = /^[0-9]{6}$/; + if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } + break; + case 'reg': + var reg = new RegExp(rule[i].checkRule); + if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } + break; + case 'in': + if(rule[i].checkRule.indexOf(data[rule[i].name]) == -1){ + this.error = rule[i].errorMsg; return false; + } + break; + case 'notnull': + if(data[rule[i].name] == null || data[rule[i].name].length < 1){this.error = rule[i].errorMsg; return false;} + break; + } + } + return true; + }, + isNumber : function (checkVal){ + var reg = /^-?[1-9][0-9]?.?[0-9]*$/; + return reg.test(checkVal); + } +} \ No newline at end of file diff --git a/common/html-parser.js b/common/html-parser.js new file mode 100644 index 0000000..fa2d38d --- /dev/null +++ b/common/html-parser.js @@ -0,0 +1,352 @@ +/* + * HTML5 Parser By Sam Blowes + * + * Designed for HTML5 documents + * + * Original code by John Resig (ejohn.org) + * http://ejohn.org/blog/pure-javascript-html-parser/ + * Original code by Erik Arvidsson, Mozilla Public License + * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js + * + * ---------------------------------------------------------------------------- + * License + * ---------------------------------------------------------------------------- + * + * This code is triple licensed using Apache Software License 2.0, + * Mozilla Public License or GNU Public License + * + * //////////////////////////////////////////////////////////////////////////// + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * //////////////////////////////////////////////////////////////////////////// + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Simple HTML Parser. + * + * The Initial Developer of the Original Code is Erik Arvidsson. + * Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights + * Reserved. + * + * //////////////////////////////////////////////////////////////////////////// + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ---------------------------------------------------------------------------- + * Usage + * ---------------------------------------------------------------------------- + * + * // Use like so: + * HTMLParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * // or to get an XML string: + * HTMLtoXML(htmlString); + * + * // or to get an XML DOM Document + * HTMLtoDOM(htmlString); + * + * // or to inject into an existing document/DOM node + * HTMLtoDOM(htmlString, document); + * HTMLtoDOM(htmlString, document.body); + * + */ +// Regular Expressions for parsing tags and attributes +var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; +var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/; +var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5 + +var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5 +// fixed by xxx 将 ins 标签从块级名单中移除 + +var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5 + +var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open +// (and which close themselves) + +var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled" + +var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything) + +var special = makeMap('script,style'); +function HTMLParser(html, handler) { + var index; + var chars; + var match; + var stack = []; + var last = html; + + stack.last = function () { + return this[this.length - 1]; + }; + + while (html) { + chars = true; // Make sure we're not in a script or style element + + if (!stack.last() || !special[stack.last()]) { + // Comment + if (html.indexOf(''); + + if (index >= 0) { + if (handler.comment) { + handler.comment(html.substring(4, index)); + } + + html = html.substring(index + 3); + chars = false; + } // end tag + + } else if (html.indexOf(']*>'), function (all, text) { + text = text.replace(/|/g, '$1$2'); + + if (handler.chars) { + handler.chars(text); + } + + return ''; + }); + parseEndTag('', stack.last()); + } + + if (html == last) { + throw 'Parse Error: ' + html; + } + + last = html; + } // Clean up any remaining tags + + + parseEndTag(); + + function parseStartTag(tag, tagName, rest, unary) { + tagName = tagName.toLowerCase(); + + if (block[tagName]) { + while (stack.last() && inline[stack.last()]) { + parseEndTag('', stack.last()); + } + } + + if (closeSelf[tagName] && stack.last() == tagName) { + parseEndTag('', tagName); + } + + unary = empty[tagName] || !!unary; + + if (!unary) { + stack.push(tagName); + } + + if (handler.start) { + var attrs = []; + rest.replace(attr, function (match, name) { + var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : ''; + attrs.push({ + name: name, + value: value, + escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // " + + }); + }); + + if (handler.start) { + handler.start(tagName, attrs, unary); + } + } + } + + function parseEndTag(tag, tagName) { + // If no tag name is provided, clean shop + if (!tagName) { + var pos = 0; + } // Find the closest opened tag of the same type + else { + for (var pos = stack.length - 1; pos >= 0; pos--) { + if (stack[pos] == tagName) { + break; + } + } + } + + if (pos >= 0) { + // Close all the open elements, up the stack + for (var i = stack.length - 1; i >= pos; i--) { + if (handler.end) { + handler.end(stack[i]); + } + } // Remove the open elements from the stack + + + stack.length = pos; + } + } +} + +function makeMap(str) { + var obj = {}; + var items = str.split(','); + + for (var i = 0; i < items.length; i++) { + obj[items[i]] = true; + } + + return obj; +} + +function removeDOCTYPE(html) { + return html.replace(/<\?xml.*\?>\n/, '').replace(/\n/, '').replace(/\n/, ''); +} + +function parseAttrs(attrs) { + return attrs.reduce(function (pre, attr) { + var value = attr.value; + var name = attr.name; + + if (pre[name]) { + pre[name] = pre[name] + " " + value; + } else { + pre[name] = value; + } + + return pre; + }, {}); +} + +function parseHtml(html) { + html = removeDOCTYPE(html); + var stacks = []; + var results = { + node: 'root', + children: [] + }; + HTMLParser(html, { + start: function start(tag, attrs, unary) { + var node = { + name: tag + }; + + if (attrs.length !== 0) { + node.attrs = parseAttrs(attrs); + } + + if (unary) { + var parent = stacks[0] || results; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } else { + stacks.unshift(node); + } + }, + end: function end(tag) { + var node = stacks.shift(); + if (node.name !== tag) console.error('invalid state: mismatch end tag'); + + if (stacks.length === 0) { + results.children.push(node); + } else { + var parent = stacks[0]; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } + }, + chars: function chars(text) { + var node = { + type: 'text', + text: text + }; + + if (stacks.length === 0) { + results.children.push(node); + } else { + var parent = stacks[0]; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } + }, + comment: function comment(text) { + var node = { + node: 'comment', + text: text + }; + var parent = stacks[0]; + + if (!parent.children) { + parent.children = []; + } + + parent.children.push(node); + } + }); + return results.children; +} + +export default parseHtml; diff --git a/common/md5.js b/common/md5.js new file mode 100644 index 0000000..4153e75 --- /dev/null +++ b/common/md5.js @@ -0,0 +1,161 @@ +function cmn(q, a, b, x, s, t) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); +} + +function ff(a, b, c, d, x, s, t) { + return cmn((b & c) | (~b & d), a, b, x, s, t); +} + +function gg(a, b, c, d, x, s, t) { + return cmn((b & d) | (c & ~d), a, b, x, s, t); +} + +function hh(a, b, c, d, x, s, t) { + return cmn(b ^ c ^ d, a, b, x, s, t); +} + +function ii(a, b, c, d, x, s, t) { + return cmn(c ^ (b | ~d), a, b, x, s, t); +} + +function md5cycle(state, x) { + let [a, b, c, d] = state; + + a = ff(a, b, c, d, x[0], 7, -680876936); + d = ff(d, a, b, c, x[1], 12, -389564586); + c = ff(c, d, a, b, x[2], 17, 606105819); + b = ff(b, c, d, a, x[3], 22, -1044525330); + a = ff(a, b, c, d, x[4], 7, -176418897); + d = ff(d, a, b, c, x[5], 12, 1200080426); + c = ff(c, d, a, b, x[6], 17, -1473231341); + b = ff(b, c, d, a, x[7], 22, -45705983); + a = ff(a, b, c, d, x[8], 7, 1770035416); + d = ff(d, a, b, c, x[9], 12, -1958414417); + c = ff(c, d, a, b, x[10], 17, -42063); + b = ff(b, c, d, a, x[11], 22, -1990404162); + a = ff(a, b, c, d, x[12], 7, 1804603682); + d = ff(d, a, b, c, x[13], 12, -40341101); + c = ff(c, d, a, b, x[14], 17, -1502002290); + b = ff(b, c, d, a, x[15], 22, 1236535329); + + a = gg(a, b, c, d, x[1], 5, -165796510); + d = gg(d, a, b, c, x[6], 9, -1069501632); + c = gg(c, d, a, b, x[11], 14, 643717713); + b = gg(b, c, d, a, x[0], 20, -373897302); + a = gg(a, b, c, d, x[5], 5, -701558691); + d = gg(d, a, b, c, x[10], 9, 38016083); + c = gg(c, d, a, b, x[15], 14, -660478335); + b = gg(b, c, d, a, x[4], 20, -405537848); + a = gg(a, b, c, d, x[9], 5, 568446438); + d = gg(d, a, b, c, x[14], 9, -1019803690); + c = gg(c, d, a, b, x[3], 14, -187363961); + b = gg(b, c, d, a, x[8], 20, 1163531501); + a = gg(a, b, c, d, x[13], 5, -1444681467); + d = gg(d, a, b, c, x[2], 9, -51403784); + c = gg(c, d, a, b, x[7], 14, 1735328473); + b = gg(b, c, d, a, x[12], 20, -1926607734); + + a = hh(a, b, c, d, x[5], 4, -378558); + d = hh(d, a, b, c, x[8], 11, -2022574463); + c = hh(c, d, a, b, x[11], 16, 1839030562); + b = hh(b, c, d, a, x[14], 23, -35309556); + a = hh(a, b, c, d, x[1], 4, -1530992060); + d = hh(d, a, b, c, x[4], 11, 1272893353); + c = hh(c, d, a, b, x[7], 16, -155497632); + b = hh(b, c, d, a, x[10], 23, -1094730640); + a = hh(a, b, c, d, x[13], 4, 681279174); + d = hh(d, a, b, c, x[0], 11, -358537222); + c = hh(c, d, a, b, x[3], 16, -722521979); + b = hh(b, c, d, a, x[6], 23, 76029189); + a = hh(a, b, c, d, x[9], 4, -640364487); + d = hh(d, a, b, c, x[12], 11, -421815835); + c = hh(c, d, a, b, x[15], 16, 530742520); + b = hh(b, c, d, a, x[2], 23, -995338651); + + a = ii(a, b, c, d, x[0], 6, -198630844); + d = ii(d, a, b, c, x[7], 10, 1126891415); + c = ii(c, d, a, b, x[14], 15, -1416354905); + b = ii(b, c, d, a, x[5], 21, -57434055); + a = ii(a, b, c, d, x[12], 6, 1700485571); + d = ii(d, a, b, c, x[3], 10, -1894986606); + c = ii(c, d, a, b, x[10], 15, -1051523); + b = ii(b, c, d, a, x[1], 21, -2054922799); + a = ii(a, b, c, d, x[8], 6, 1873313359); + d = ii(d, a, b, c, x[15], 10, -30611744); + c = ii(c, d, a, b, x[6], 15, -1560198380); + b = ii(b, c, d, a, x[13], 21, 1309151649); + a = ii(a, b, c, d, x[4], 6, -145523070); + d = ii(d, a, b, c, x[11], 10, -1120210379); + c = ii(c, d, a, b, x[2], 15, 718787259); + b = ii(b, c, d, a, x[9], 21, -343485551); + + state[0] = add32(a, state[0]); + state[1] = add32(b, state[1]); + state[2] = add32(c, state[2]); + state[3] = add32(d, state[3]); +} + +function md5blk(s) { + const blocks = []; + for (let i = 0; i < 64; i += 4) { + blocks[i >> 2] = + s.charCodeAt(i) + + (s.charCodeAt(i + 1) << 8) + + (s.charCodeAt(i + 2) << 16) + + (s.charCodeAt(i + 3) << 24); + } + return blocks; +} + +function md5blkTail(s, length) { + const blocks = Array(16).fill(0); + let i = 0; + for (; i < length; i++) { + blocks[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3); + } + blocks[i >> 2] |= 0x80 << ((i % 4) << 3); + blocks[14] = length * 8; + return blocks; +} + +function md51(str) { + let n = str.length; + let state = [1732584193, -271733879, -1732584194, 271733878]; + let i; + + for (i = 64; i <= n; i += 64) { + md5cycle(state, md5blk(str.substring(i - 64, i))); + } + + const remaining = str.substring(i - 64); + md5cycle(state, md5blkTail(remaining, remaining.length)); + + return state; +} + +function rhex(n) { + const hexChr = '0123456789abcdef'; + let s = ''; + for (let j = 0; j < 4; j++) { + s += + hexChr.charAt((n >> (j * 8 + 4)) & 0x0f) + + hexChr.charAt((n >> (j * 8)) & 0x0f); + } + return s; +} + +function hex(x) { + for (let i = 0; i < x.length; i++) { + x[i] = rhex(x[i]); + } + return x.join(''); +} + +function add32(a, b) { + return (a + b) & 0xffffffff; +} + +export function md5(str) { + return hex(md51(str)); +} diff --git a/common/permission.js b/common/permission.js new file mode 100644 index 0000000..717b6a3 --- /dev/null +++ b/common/permission.js @@ -0,0 +1,245 @@ +/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启 + +var isIOS + +function album() { + var result = 0; + var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary"); + var authStatus = PHPhotoLibrary.authorizationStatus(); + if (authStatus === 0) { + result = null; + } else if (authStatus == 3) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(PHPhotoLibrary); + return result; +} + +function camera() { + var result = 0; + var AVCaptureDevice = plus.ios.import("AVCaptureDevice"); + var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide'); + if (authStatus === 0) { + result = null; + } else if (authStatus == 3) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(AVCaptureDevice); + return result; +} + +function location() { + var result = 0; + var cllocationManger = plus.ios.import("CLLocationManager"); + var enable = cllocationManger.locationServicesEnabled(); + var status = cllocationManger.authorizationStatus(); + if (!enable) { + result = 2; + } else if (status === 0) { + result = null; + } else if (status === 3 || status === 4) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(cllocationManger); + return result; +} + +function push() { + var result = 0; + var UIApplication = plus.ios.import("UIApplication"); + var app = UIApplication.sharedApplication(); + var enabledTypes = 0; + if (app.currentUserNotificationSettings) { + var settings = app.currentUserNotificationSettings(); + enabledTypes = settings.plusGetAttribute("types"); + if (enabledTypes == 0) { + result = 0; + console.log("推送权限没有开启"); + } else { + result = 1; + console.log("已经开启推送功能!") + } + plus.ios.deleteObject(settings); + } else { + enabledTypes = app.enabledRemoteNotificationTypes(); + if (enabledTypes == 0) { + result = 3; + console.log("推送权限没有开启!"); + } else { + result = 4; + console.log("已经开启推送功能!") + } + } + plus.ios.deleteObject(app); + plus.ios.deleteObject(UIApplication); + return result; +} + +function contact() { + var result = 0; + var CNContactStore = plus.ios.import("CNContactStore"); + var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0); + if (cnAuthStatus === 0) { + result = null; + } else if (cnAuthStatus == 3) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(CNContactStore); + return result; +} + +function record() { + var result = null; + var avaudiosession = plus.ios.import("AVAudioSession"); + var avaudio = avaudiosession.sharedInstance(); + var status = avaudio.recordPermission(); + console.log("permissionStatus:" + status); + if (status === 1970168948) { + result = null; + } else if (status === 1735552628) { + result = 1; + } else { + result = 0; + } + plus.ios.deleteObject(avaudiosession); + return result; +} + +function calendar() { + var result = null; + var EKEventStore = plus.ios.import("EKEventStore"); + var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0); + if (ekAuthStatus == 3) { + result = 1; + console.log("日历权限已经开启"); + } else { + console.log("日历权限没有开启"); + } + plus.ios.deleteObject(EKEventStore); + return result; +} + +function memo() { + var result = null; + var EKEventStore = plus.ios.import("EKEventStore"); + var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1); + if (ekAuthStatus == 3) { + result = 1; + console.log("备忘录权限已经开启"); + } else { + console.log("备忘录权限没有开启"); + } + plus.ios.deleteObject(EKEventStore); + return result; +} + + +function requestIOS(permissionID) { + return new Promise((resolve, reject) => { + switch (permissionID) { + case "push": + resolve(push()); + break; + case "location": + resolve(location()); + break; + case "record": + resolve(record()); + break; + case "camera": + resolve(camera()); + break; + case "album": + resolve(album()); + break; + case "contact": + resolve(contact()); + break; + case "calendar": + resolve(calendar()); + break; + case "memo": + resolve(memo()); + break; + default: + resolve(0); + break; + } + }); +} + +function requestAndroid(permissionID) { + return new Promise((resolve, reject) => { + plus.android.requestPermissions( + [permissionID], + function(resultObj) { + var result = 0; + for (var i = 0; i < resultObj.granted.length; i++) { + var grantedPermission = resultObj.granted[i]; + console.log('已获取的权限:' + grantedPermission); + result = 1 + } + for (var i = 0; i < resultObj.deniedPresent.length; i++) { + var deniedPresentPermission = resultObj.deniedPresent[i]; + console.log('拒绝本次申请的权限:' + deniedPresentPermission); + result = 0 + } + for (var i = 0; i < resultObj.deniedAlways.length; i++) { + var deniedAlwaysPermission = resultObj.deniedAlways[i]; + console.log('永久拒绝申请的权限:' + deniedAlwaysPermission); + result = -1 + } + resolve(result); + }, + function(error) { + console.log('result error: ' + error.message) + resolve({ + code: error.code, + message: error.message + }); + } + ); + }); +} + +function gotoAppPermissionSetting() { + if (permission.isIOS) { + var UIApplication = plus.ios.import("UIApplication"); + var application2 = UIApplication.sharedApplication(); + var NSURL2 = plus.ios.import("NSURL"); + var setting2 = NSURL2.URLWithString("app-settings:"); + application2.openURL(setting2); + plus.ios.deleteObject(setting2); + plus.ios.deleteObject(NSURL2); + plus.ios.deleteObject(application2); + } else { + var Intent = plus.android.importClass("android.content.Intent"); + var Settings = plus.android.importClass("android.provider.Settings"); + var Uri = plus.android.importClass("android.net.Uri"); + var mainActivity = plus.android.runtimeMainActivity(); + var intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + var uri = Uri.fromParts("package", mainActivity.getPackageName(), null); + intent.setData(uri); + mainActivity.startActivity(intent); + } +} + +const permission = { + get isIOS(){ + return typeof isIOS === 'boolean' ? isIOS : (isIOS = uni.getSystemInfoSync().platform === 'ios') + }, + requestIOS: requestIOS, + requestAndroid: requestAndroid, + gotoAppSetting: gotoAppPermissionSetting +} + +export default permission diff --git a/common/request.js b/common/request.js new file mode 100644 index 0000000..30595d5 --- /dev/null +++ b/common/request.js @@ -0,0 +1,102 @@ +import { ENV, STORAGE_KEYS } from './env'; +import { md5 } from './md5'; + +const DEFAULT_TIMEOUT = ENV.REQUEST_TIMEOUT || 15000; + +function buildQuery(params = {}) { + const entries = Object.entries(params).filter(([, value]) => value !== undefined && value !== null); + if (!entries.length) return ''; + return entries + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`) + .join('&'); +} + +function combineUrl(base, path) { + if (/^https?:\/\//i.test(path)) return path; + const normalizedBase = (base || '').replace(/\/$/, ''); + const normalizedPath = (path || '').replace(/^\//, ''); + return `${normalizedBase}/${normalizedPath}`; +} + +function request(method, url, data = {}, options = {}) { + const isQuery = method === 'GET' || method === 'DELETE'; + const params = isQuery ? data : (options.params || {}); + let finalUrl = combineUrl(ENV.API_BASE_URL, url); + const queryString = buildQuery(params); + if (queryString) { + finalUrl += (finalUrl.includes('?') ? '&' : '?') + queryString; + } + + const header = Object.assign( + { 'content-type': 'application/json' }, + options.header || {} + ); + + if (ENV.SECURITY_ENABLE && ENV.SECURITY_SECRET_KEY) { + const timestamp = Date.now().toString(); + header['X-App-Timestamp'] = timestamp; + header['X-App-Sign'] = md5(timestamp + ENV.SECURITY_SECRET_KEY); + } + + const token = uni.getStorageSync(STORAGE_KEYS.TOKEN); + if (token) { + header.Authorization = `Bearer ${token}`; + } else if (!options.allowGuest) { + uni.showModal({ + title: '提示', + content: '未登录,请先登录', + showCancel: false, + success: () => { + uni.navigateTo({ url: '/pages/login/login' }); + } + }); + return Promise.reject({ message: '未登录' }); + } + + return new Promise((resolve, reject) => { + uni.request({ + url: finalUrl, + method, + data: isQuery ? {} : data, + header, + timeout: options.timeout || DEFAULT_TIMEOUT, + success: (res) => { + const { statusCode, data: resData } = res; + const businessCode = resData && typeof resData.code !== 'undefined' ? resData.code : null; + if (statusCode === 401 || businessCode === 401) { + uni.showModal({ + title: '提示', + content: '登录已失效,请重新登录', + showCancel: false, + success: () => { + uni.removeStorageSync(STORAGE_KEYS.TOKEN); + uni.removeStorageSync(STORAGE_KEYS.USER_INFO); + uni.navigateTo({ url: '/pages/login/login' }); + } + }); + reject({ message: '登录失效', statusCode, data: resData }); + return; + } + if (statusCode >= 200 && statusCode < 300) { + resolve(options.raw ? res : resData); + return; + } + reject({ + message: resData && (resData.msg || resData.message) ? (resData.msg || resData.message) : '请求失败', + statusCode, + data: resData + }); + }, + fail: (err) => { + reject(err); + } + }); + }); +} + +export const get = (url, params, options) => request('GET', url, params, options); +export const post = (url, data, options) => request('POST', url, data, options); +export const put = (url, data, options) => request('PUT', url, data, options); +export const del = (url, params, options) => request('DELETE', url, params, options); + +export default request; diff --git a/common/uni-nvue.css b/common/uni-nvue.css new file mode 100644 index 0000000..69e7411 --- /dev/null +++ b/common/uni-nvue.css @@ -0,0 +1,136 @@ +/* #ifndef APP-PLUS-NVUE */ +page { + min-height: 100%; + height: auto; +} +/* #endif */ + +/* 解决头条小程序字体图标不显示问题,因为头条运行时自动插入了span标签,且有全局字体 */ +/* #ifdef MP-TOUTIAO */ +/* text :not(view) { + font-family: uniicons; +} */ +/* #endif */ + +.uni-icon { + font-family: uniicons; + font-weight: normal; +} + +.uni-container { + padding: 15px; + background-color: #f8f8f8; +} + +.uni-header-logo { + /* #ifdef H5 */ + display: flex; + /* #endif */ + padding: 15px 15px; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 10rpx; +} + +.uni-header-image { + width: 80px; + height: 80px; +} + +.uni-hello-text { + margin-bottom: 20px; +} + +.hello-text { + color: #7A7E83; + font-size: 14px; + line-height: 20px; +} + +.hello-link { + color: #7A7E83; + font-size: 14px; + line-height: 20px; +} + +.uni-panel { + margin-bottom: 12px; +} + +.uni-panel-h { + /* #ifdef H5 */ + display: flex; + /* #endif */ + background-color: #ffffff; + flex-direction: row !important; + /* justify-content: space-between !important; */ + align-items: center !important; + padding: 12px; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ +} +/* +.uni-panel-h:active { + background-color: #f8f8f8; +} + */ +.uni-panel-h-on { + background-color: #f0f0f0; +} + +.uni-panel-text { + flex: 1; + color: #000000; + font-size: 14px; + font-weight: normal; +} + +.uni-panel-icon { + margin-left: 15px; + color: #999999; + font-size: 14px; + font-weight: normal; + transform: rotate(0deg); + transition-duration: 0s; + transition-property: transform; +} + +.uni-panel-icon-on { + transform: rotate(180deg); +} + +.uni-navigate-item { + /* #ifdef H5 */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + background-color: #FFFFFF; + border-top-style: solid; + border-top-color: #f0f0f0; + border-top-width: 1px; + padding: 12px; + /* #ifdef H5 */ + cursor: pointer; + /* #endif */ +} + +.uni-navigate-item:active { + background-color: #f8f8f8; +} + +.uni-navigate-text { + flex: 1; + color: #000000; + font-size: 14px; + font-weight: normal; +} + +.uni-navigate-icon { + margin-left: 15px; + color: #999999; + font-size: 14px; + font-weight: normal; +} diff --git a/common/uni.css b/common/uni.css new file mode 100644 index 0000000..f46f7fe --- /dev/null +++ b/common/uni.css @@ -0,0 +1,1458 @@ +@font-face { + font-family: uniicons; + font-weight: normal; + font-style: normal; + src: url('~@/static/uni.ttf') format('truetype'); +} + +/* #ifdef H5 */ +.fix-left-window { + padding-left: var(--window-left); +} +.pc-hide { + display: none !important; +} +/* #endif */ + +/*通用 */ + +/* view{ + font-size:28rpx; + line-height:1.8; +} */ +progress, checkbox-group{ + width: 100%; +} +form { + width: 100%; +} +.uni-flex { + display: flex; + flex-direction: row; +} +.uni-flex-item { + flex: 1; +} +.uni-row { + flex-direction: row; +} +.uni-column { + flex-direction: column; +} +.uni-link{ + color:#576B95; + font-size:26rpx; +} +.uni-center{ + text-align:center; +} +.uni-inline-item{ + display: flex; + flex-direction: row; + align-items:center; +} +.uni-inline-item text{ + margin-right: 20rpx; +} +.uni-inline-item text:last-child{ + margin-right: 0rpx; + margin-left: 20rpx; +} + +/* page */ +.common-page-head{ + padding:35rpx; + text-align: center; +} +.common-page-head-title { + display: inline-block; + padding: 0 40rpx; + font-size: 30rpx; + height: 88rpx; + line-height: 88rpx; + color: #BEBEBE; + box-sizing: border-box; + border-bottom: 2rpx solid #D8D8D8; +} + +.uni-padding-wrap{ + /* width:690rpx; */ + padding:0 30rpx; +} +.uni-word { + text-align: center; + padding:200rpx 100rpx; +} +.uni-title { + font-size:30rpx; + font-weight:500; + padding:20rpx 0; + line-height:1.5; +} +.uni-text{ + font-size:28rpx; +} +.uni-title text{ + font-size:24rpx; + color:#888; +} + +.uni-text-gray{ + color: #ccc; +} +.uni-text-small { + font-size:24rpx; +} +.uni-common-mb{ + margin-bottom:30rpx; +} +.uni-common-pb{ + padding-bottom:30rpx; +} +.uni-common-pl{ + padding-left:30rpx; +} +.uni-common-mt{ + margin-top:30rpx; +} +/* 背景色 */ +.uni-bg-red{ + background:#F76260; color:#FFF; +} +.uni-bg-green{ + background:#09BB07; color:#FFF; +} +.uni-bg-blue{ + background:#007AFF; color:#FFF; +} +/* 标题 */ +.uni-h1 {font-size: 80rpx; font-weight:700;} +.uni-h2 {font-size: 60rpx; font-weight:700;} +.uni-h3 {font-size: 48rpx; font-weight:700;} +.uni-h4 {font-size: 36rpx; font-weight:700;} +.uni-h5 {font-size: 28rpx; color: #8f8f94;} +.uni-h6 {font-size: 24rpx; color: #8f8f94;} +.uni-bold{font-weight:bold;} + +/* 文本溢出隐藏 */ +.uni-ellipsis {overflow: hidden; white-space: nowrap; text-overflow: ellipsis;} + +/* 竖向百分百按钮 */ +.uni-btn-v{ + padding:10rpx 0; +} +.uni-btn-v button{margin:20rpx 0;} + +/* 表单 */ +.uni-form-item{ + display:flex; + width:100%; + padding:10rpx 0; +} +.uni-form-item .title{ + padding:10rpx 25rpx; +} +.uni-label { + width: 210rpx; + word-wrap: break-word; + word-break: break-all; + text-indent:20rpx; +} +.uni-input { + height: 50rpx; + padding: 15rpx 25rpx; + line-height:50rpx; + font-size:28rpx; + background:#FFF; + flex: 1; +} +radio-group, checkbox-group{ + width:100%; +} +radio-group label, checkbox-group label{ + padding-right:20rpx; +} +.uni-form-item .with-fun{ + display:flex; + flex-wrap:nowrap; + background:#FFFFFF; +} +.uni-form-item .with-fun .uni-icon{ + width:40px; + height:80rpx; + line-height:80rpx; + flex-shrink:0; +} + +/* loadmore */ +.uni-loadmore{ + height:80rpx; + line-height:80rpx; + text-align:center; + padding-bottom:30rpx; +} +/*数字角标*/ +/* .uni-badge, +.uni-badge-default { + font-family: 'Helvetica Neue', Helvetica, sans-serif; + font-size: 12px; + line-height: 1; + display: inline-block; + padding: 3px 6px; + color: #333; + border-radius: 100px; + background-color: rgba(0, 0, 0, .15); +} */ +.uni-badge.uni-badge-inverted { + padding: 0 5px 0 0; + color: #929292; + background-color: transparent +} +.uni-badge-primary { + color: #fff; + background-color: #007aff +} +.uni-badge-blue.uni-badge-inverted, +.uni-badge-primary.uni-badge-inverted { + color: #007aff; + background-color: transparent +} +.uni-badge-green, +.uni-badge-success { + color: #fff; + background-color: #4cd964; +} +.uni-badge-green.uni-badge-inverted, +.uni-badge-success.uni-badge-inverted { + color: #4cd964; + background-color: transparent +} +.uni-badge-warning, +.uni-badge-yellow { + color: #fff; + background-color: #f0ad4e +} +.uni-badge-warning.uni-badge-inverted, +.uni-badge-yellow.uni-badge-inverted { + color: #f0ad4e; + background-color: transparent +} +.uni-badge-danger, +.uni-badge-red { + color: #fff; + background-color: #dd524d +} +.uni-badge-danger.uni-badge-inverted, +.uni-badge-red.uni-badge-inverted { + color: #dd524d; + background-color: transparent +} +.uni-badge-purple, +.uni-badge-royal { + color: #fff; + background-color: #8a6de9 +} +.uni-badge-purple.uni-badge-inverted, +.uni-badge-royal.uni-badge-inverted { + color: #8a6de9; + background-color: transparent +} + +/*折叠面板 */ +.uni-collapse-content { + height: 0; + width: 100%; + overflow: hidden; +} +.uni-collapse-content.uni-active { + height: auto; +} + +/*卡片视图 */ +.uni-card { + background: #fff; + border-radius: 8rpx; + margin:20rpx 0; + position: relative; + /* box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, .3); */ +} +.uni-card-content { + font-size: 30rpx; +} +.uni-card-content.image-view{ + width: 100%; + margin: 0; +} +.uni-card-content-inner { + position: relative; + padding: 30rpx; +} +.uni-card-footer, +.uni-card-header { + position: relative; + display: flex; + min-height: 50rpx; + padding: 20rpx 30rpx; + justify-content: space-between; + align-items: center; +} +.uni-card-header { + font-size: 36rpx; +} +.uni-card-footer { + color: #6d6d72; +} +.uni-card-footer:before, +.uni-card-header:after { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 2rpx; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: #c8c7cc; +} +.uni-card-header:after { + top: auto; + bottom: 0; +} +.uni-card-media { + justify-content: flex-start; +} +.uni-card-media-logo { + height: 84rpx; + width: 84rpx; + margin-right: 20rpx; +} +.uni-card-media-body { + height: 84rpx; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; +} +.uni-card-media-text-top { + line-height: 36rpx; + font-size: 34rpx; +} +.uni-card-media-text-bottom { + line-height: 30rpx; + font-size: 28rpx; + color: #8f8f94; +} +.uni-card-link { + color: #007AFF; +} + +/* 列表 */ +.uni-list { + background-color: #FFFFFF; + position: relative; + width: 100%; + display: flex; + flex-direction: column; +} +.uni-list:after { + position: absolute; + z-index: 10; + right: 0; + bottom: 0; + left: 0; + height: 1px; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: #c8c7cc; +} +/* .uni-list::before { + position: absolute; + z-index: 10; + right: 0; + top: 0; + left: 0; + height: 1px; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: #c8c7cc; +} */ +.uni-list-cell { + position: relative; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +} +.uni-list-cell-hover { + background-color: #eee; +} +.uni-list-cell-pd { + padding: 22rpx 30rpx; +} +.uni-list-cell-left { + white-space: nowrap; + font-size:28rpx; + padding: 0 30rpx; +} +.uni-list-cell-db, +.uni-list-cell-right { + flex: 1; +} +.uni-list-cell::after { + position: absolute; + z-index: 3; + right: 0; + bottom: 0; + left: 30rpx; + height: 1px; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: #c8c7cc; +} +.uni-list .uni-list-cell:last-child::after { + height: 0rpx; +} +.uni-list-cell-last.uni-list-cell::after { + height: 0rpx; +} +.uni-list-cell-divider { + position: relative; + display: flex; + color: #999; + background-color: #f7f7f7; + padding:15rpx 20rpx; +} +.uni-list-cell-divider::before { + position: absolute; + right: 0; + top: 0; + left: 0; + height: 1px; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: #c8c7cc; +} +.uni-list-cell-divider::after { + position: absolute; + right: 0; + bottom: 0; + left: 0rpx; + height: 1px; + content: ''; + -webkit-transform: scaleY(.5); + transform: scaleY(.5); + background-color: #c8c7cc; +} +.uni-list-cell-navigate { + font-size:30rpx; + padding: 22rpx 30rpx; + line-height: 48rpx; + position: relative; + display: flex; + box-sizing: border-box; + width: 100%; + flex: 1; + justify-content: space-between; + align-items: center; +} +.uni-list-cell-navigate { + padding-right: 36rpx; +} +.uni-navigate-badge { + padding-right: 50rpx; +} +.uni-list-cell-navigate.uni-navigate-right:after { + font-family: uniicons; + content: '\e583'; + position: absolute; + right: 24rpx; + top: 50%; + color: #bbb; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} +.uni-list-cell-navigate.uni-navigate-bottom:after { + font-family: uniicons; + content: '\e581'; + position: absolute; + right: 24rpx; + top: 50%; + color: #bbb; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} +.uni-list-cell-navigate.uni-navigate-bottom.uni-active::after { + font-family: uniicons; + content: '\e580'; + position: absolute; + right: 24rpx; + top: 50%; + color: #bbb; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} +.uni-collapse.uni-list-cell { + flex-direction: column; +} +.uni-list-cell-navigate.uni-active { + background: #eee; +} +.uni-list.uni-collapse { + box-sizing: border-box; + height: 0; + overflow: hidden; +} +.uni-collapse .uni-list-cell { + padding-left: 20rpx; +} +.uni-collapse .uni-list-cell::after { + left: 52rpx; +} +.uni-list.uni-active { + height: auto; +} + +/* 三行列表 */ +.uni-triplex-row { + display: flex; + flex: 1; + width: 100%; + box-sizing: border-box; + flex-direction: row; + padding: 22rpx 30rpx; +} +.uni-triplex-right, +.uni-triplex-left { + display: flex; + flex-direction: column; +} +.uni-triplex-left { + width: 84%; +} +.uni-triplex-left .uni-title{ + padding:8rpx 0; +} +.uni-triplex-left .uni-text, .uni-triplex-left .uni-text-small{color:#999999;} +.uni-triplex-right { + width: 16%; + text-align: right; +} + +/* 图文列表 */ +.uni-media-list { + padding: 22rpx 30rpx; + box-sizing: border-box; + display: flex; + width: 100%; + flex-direction: row; +} +.uni-navigate-right.uni-media-list { + padding-right: 74rpx; +} +.uni-pull-right { + flex-direction: row-reverse; +} +.uni-pull-right>.uni-media-list-logo { + margin-right: 0rpx; + margin-left: 20rpx; +} +.uni-media-list-logo { + height: 84rpx; + width: 84rpx; + margin-right: 20rpx; +} +.uni-media-list-logo image { + height: 100%; + width: 100%; +} +.uni-media-list-body { + height: 84rpx; + display: flex; + flex: 1; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + overflow: hidden; +} +.uni-media-list-text-top { + width: 100%; + line-height: 36rpx; + font-size: 30rpx; +} +.uni-media-list-text-bottom { + width: 100%; + line-height: 30rpx; + font-size: 26rpx; + color: #8f8f94; +} + +/* 九宫格 */ +.uni-grid-9 { + background: #f2f2f2; + width: 750rpx; + display: flex; + flex-direction: row; + flex-wrap: wrap; + border-top: 2rpx solid #eee; +} +.uni-grid-9-item { + width: 250rpx; + height: 200rpx; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + border-bottom: 2rpx solid; + border-right: 2rpx solid; + border-color: #eee; + box-sizing: border-box; +} +.no-border-right { + border-right: none; +} +.uni-grid-9-image { + width: 100rpx; + height: 100rpx; +} +.uni-grid-9-text { + width: 250rpx; + line-height: 4rpx; + height: 40rpx; + text-align: center; + font-size: 30rpx; +} +.uni-grid-9-item-hover { + background: rgba(0, 0, 0, 0.1); +} + +/* 上传 */ +.uni-uploader { + flex: 1; + flex-direction: column; +} +.uni-uploader-head { + display: flex; + flex-direction: row; + justify-content: space-between; +} +.uni-uploader-info { + color: #B2B2B2; +} +.uni-uploader-body { + margin-top: 16rpx; +} +.uni-uploader__files { + display: flex; + flex-direction: row; + flex-wrap: wrap; +} +.uni-uploader__file { + margin: 10rpx; + width: 210rpx; + height: 210rpx; +} +.uni-uploader__img { + display: block; + width: 210rpx; + height: 210rpx; +} +.uni-uploader__input-box { + position: relative; + margin:10rpx; + width: 208rpx; + height: 208rpx; + border: 2rpx solid #D9D9D9; +} +.uni-uploader__input-box:before, +.uni-uploader__input-box:after { + content: " "; + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + background-color: #D9D9D9; +} +.uni-uploader__input-box:before { + width: 4rpx; + height: 79rpx; +} +.uni-uploader__input-box:after { + width: 79rpx; + height: 4rpx; +} +.uni-uploader__input-box:active { + border-color: #999999; +} +.uni-uploader__input-box:active:before, +.uni-uploader__input-box:active:after { + background-color: #999999; +} +.uni-uploader__input { + position: absolute; + z-index: 1; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; +} + +/*问题反馈*/ +.feedback-title { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 20rpx; + color: #8f8f94; + font-size: 28rpx; +} +.feedback-star-view.feedback-title { + justify-content: flex-start; + margin: 0; +} +.feedback-quick { + position: relative; + padding-right: 40rpx; +} +.feedback-quick:after { + font-family: uniicons; + font-size: 40rpx; + content: '\e581'; + position: absolute; + right: 0; + top: 50%; + color: #bbb; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} +.feedback-body { + background: #fff; +} +.feedback-textare { + height: 200rpx; + font-size: 34rpx; + line-height: 50rpx; + width: 100%; + box-sizing: border-box; + padding: 20rpx 30rpx 0; +} +.feedback-input { + font-size: 34rpx; + height: 50rpx; + min-height: 50rpx; + padding: 15rpx 20rpx; + line-height: 50rpx; +} +.feedback-uploader { + padding: 22rpx 20rpx; +} +.feedback-star { + font-family: uniicons; + font-size: 40rpx; + margin-left: 6rpx; +} +.feedback-star-view { + margin-left: 20rpx; +} +.feedback-star:after { + content: '\e408'; +} +.feedback-star.active { + color: #FFB400; +} +.feedback-star.active:after { + content: '\e438'; +} +.feedback-submit { + background: #007AFF; + color: #FFFFFF; + margin: 20rpx; +} + +/* input group */ +.uni-input-group { + position: relative; + padding: 0; + border: 0; + background-color: #fff; +} + +.uni-input-group:before { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 2rpx; + content: ''; + transform: scaleY(.5); + background-color: #c8c7cc; +} + +.uni-input-group:after { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 2rpx; + content: ''; + transform: scaleY(.5); + background-color: #c8c7cc; +} + +.uni-input-row { + position: relative; + display: flex; + flex-direction: row; + font-size:28rpx; + padding: 22rpx 30rpx; + justify-content: space-between; +} + +.uni-input-group .uni-input-row:after { + position: absolute; + right: 0; + bottom: 0; + left: 30rpx; + height: 2rpx; + content: ''; + transform: scaleY(.5); + background-color: #c8c7cc; +} + +.uni-input-row label { + line-height: 70rpx; +} + +/* textarea */ +.uni-textarea{ + width:100%; + background:#FFF; +} +.uni-textarea textarea{ + width:96%; + padding:18rpx 2%; + line-height:1.6; + font-size:28rpx; + height:150rpx; +} + +/* tab bar */ +.uni-tab-bar { + display: flex; + flex: 1; + flex-direction: column; + overflow: hidden; + height: 100%; +} + +.uni-tab-bar .list { + width: 750rpx; + height: 100%; +} + +.uni-swiper-tab { + width: 100%; + white-space: nowrap; + line-height: 100rpx; + height: 100rpx; + border-bottom: 1px solid #c8c7cc; +} + +.swiper-tab-list { + font-size: 30rpx; + width: 150rpx; + display: inline-block; + text-align: center; + color: #555; +} + +.uni-tab-bar .active { + color: #007AFF; +} + +.uni-tab-bar .swiper-box { + flex: 1; + width: 100%; + height: calc(100% - 100rpx); +} + +.uni-tab-bar-loading{ + padding:20rpx 0; +} + +/* comment */ +.uni-comment{padding:5rpx 0; display: flex; flex-grow:1; flex-direction: column;} +.uni-comment-list{flex-wrap:nowrap; padding:10rpx 0; margin:10rpx 0; width:100%; display: flex;} +.uni-comment-face{width:70rpx; height:70rpx; border-radius:100%; margin-right:20rpx; flex-shrink:0; overflow:hidden;} +.uni-comment-face image{width:100%; border-radius:100%;} +.uni-comment-body{width:100%;} +.uni-comment-top{line-height:1.5em; justify-content:space-between;} +.uni-comment-top text{color:#0A98D5; font-size:24rpx;} +.uni-comment-date{line-height:38rpx; flex-direction:row; justify-content:space-between; display:flex !important; flex-grow:1;} +.uni-comment-date view{color:#666666; font-size:24rpx; line-height:38rpx;} +.uni-comment-content{line-height:1.6em; font-size:28rpx; padding:8rpx 0;} +.uni-comment-replay-btn{background:#FFF; font-size:24rpx; line-height:28rpx; padding:5rpx 20rpx; border-radius:30rpx; color:#333 !important; margin:0 10rpx;} + +/* swiper msg */ +.uni-swiper-msg{width:100%; padding:12rpx 0; flex-wrap:nowrap; display:flex;} +.uni-swiper-msg-icon{width:50rpx; margin-right:20rpx;} +.uni-swiper-msg-icon image{width:100%; flex-shrink:0;} +.uni-swiper-msg swiper{width:100%; height:50rpx;} +.uni-swiper-msg swiper-item{line-height:50rpx;} + +/* product */ +.uni-product-list { + display: flex; + width: 100%; + flex-wrap: wrap; + flex-direction: row; +} + +.uni-product { + padding: 20rpx; + display: flex; + flex-direction: column; +} + +.image-view { + height: 330rpx; + width: 330rpx; + margin:12rpx 0; +} + +.uni-product-image { + height: 330rpx; + width: 330rpx; +} + +.uni-product-title { + width: 300rpx; + word-break: break-all; + display: -webkit-box; + overflow: hidden; + line-height:1.5; + text-overflow: ellipsis; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.uni-product-price { + margin-top:10rpx; + font-size: 28rpx; + line-height:1.5; + position: relative; +} + +.uni-product-price-original { + color: #e80080; +} + +.uni-product-price-favour { + color: #888888; + text-decoration: line-through; + margin-left: 10rpx; +} + +.uni-product-tip { + position: absolute; + right: 10rpx; + background-color: #ff3333; + color: #ffffff; + padding: 0 10rpx; + border-radius: 5rpx; +} + +/* timeline */ +.uni-timeline { + margin: 35rpx 0; + display: flex; + flex-direction: column; + position: relative; + } + + + .uni-timeline-item { + display: flex; + flex-direction: row; + position: relative; + padding-bottom: 20rpx; + box-sizing: border-box; + overflow: hidden; + + } + + .uni-timeline-item .uni-timeline-item-keynode { + width: 160rpx; + flex-shrink: 0; + box-sizing: border-box; + padding-right: 20rpx; + text-align: right; + line-height: 65rpx; + } + + .uni-timeline-item .uni-timeline-item-divider { + flex-shrink: 0; + position: relative; + width: 30rpx; + height: 30rpx; + top: 15rpx; + border-radius: 50%; + background-color: #bbb; + } + + + + .uni-timeline-item-divider::before, + .uni-timeline-item-divider::after { + position: absolute; + left: 15rpx; + width: 1rpx; + height: 100vh; + content: ''; + background: inherit; + } + + .uni-timeline-item-divider::before { + bottom: 100%; + } + + .uni-timeline-item-divider::after { + top: 100%; + } + + + .uni-timeline-last-item .uni-timeline-item-divider:after { + display: none; + } + + .uni-timeline-first-item .uni-timeline-item-divider:before { + display: none; + } + + .uni-timeline-item .uni-timeline-item-content { + padding-left: 20rpx; + } + + .uni-timeline-last-item .bottom-border::after{ + display: none; + } + + .uni-timeline-item-content .datetime{ + color: #CCCCCC; + } + + /* 自定义节点颜色 */ + .uni-timeline-last-item .uni-timeline-item-divider{ + background-color: #1AAD19; + } + + +/* uni-icon */ + +.uni-icon { + font-family: uniicons; + font-size: 24px; + font-weight: normal; + font-style: normal; + line-height: 1; + display: inline-block; + text-decoration: none; + -webkit-font-smoothing: antialiased; +} + +.uni-icon.uni-active { + color: #007aff; +} + +.uni-icon-contact:before { + content: '\e100'; +} + +.uni-icon-person:before { + content: '\e101'; +} + +.uni-icon-personadd:before { + content: '\e102'; +} + +.uni-icon-contact-filled:before { + content: '\e130'; +} + +.uni-icon-person-filled:before { + content: '\e131'; +} + +.uni-icon-personadd-filled:before { + content: '\e132'; +} + +.uni-icon-phone:before { + content: '\e200'; +} + +.uni-icon-email:before { + content: '\e201'; +} + +.uni-icon-chatbubble:before { + content: '\e202'; +} + +.uni-icon-chatboxes:before { + content: '\e203'; +} + +.uni-icon-phone-filled:before { + content: '\e230'; +} + +.uni-icon-email-filled:before { + content: '\e231'; +} + +.uni-icon-chatbubble-filled:before { + content: '\e232'; +} + +.uni-icon-chatboxes-filled:before { + content: '\e233'; +} + +.uni-icon-weibo:before { + content: '\e260'; +} + +.uni-icon-weixin:before { + content: '\e261'; +} + +.uni-icon-pengyouquan:before { + content: '\e262'; +} + +.uni-icon-chat:before { + content: '\e263'; +} + +.uni-icon-qq:before { + content: '\e264'; +} + +.uni-icon-videocam:before { + content: '\e300'; +} + +.uni-icon-camera:before { + content: '\e301'; +} + +.uni-icon-mic:before { + content: '\e302'; +} + +.uni-icon-location:before { + content: '\e303'; +} + +.uni-icon-mic-filled:before, +.uni-icon-speech:before { + content: '\e332'; +} + +.uni-icon-location-filled:before { + content: '\e333'; +} + +.uni-icon-micoff:before { + content: '\e360'; +} + +.uni-icon-image:before { + content: '\e363'; +} + +.uni-icon-map:before { + content: '\e364'; +} + +.uni-icon-compose:before { + content: '\e400'; +} + +.uni-icon-trash:before { + content: '\e401'; +} + +.uni-icon-upload:before { + content: '\e402'; +} + +.uni-icon-download:before { + content: '\e403'; +} + +.uni-icon-close:before { + content: '\e404'; +} + +.uni-icon-redo:before { + content: '\e405'; +} + +.uni-icon-undo:before { + content: '\e406'; +} + +.uni-icon-refresh:before { + content: '\e407'; +} + +.uni-icon-star:before { + content: '\e408'; +} + +.uni-icon-plus:before { + content: '\e409'; +} + +.uni-icon-minus:before { + content: '\e410'; +} + +.uni-icon-circle:before, +.uni-icon-checkbox:before { + content: '\e411'; +} + +.uni-icon-close-filled:before, +.uni-icon-clear:before { + content: '\e434'; +} + +.uni-icon-refresh-filled:before { + content: '\e437'; +} + +.uni-icon-star-filled:before { + content: '\e438'; +} + +.uni-icon-plus-filled:before { + content: '\e439'; +} + +.uni-icon-minus-filled:before { + content: '\e440'; +} + +.uni-icon-circle-filled:before { + content: '\e441'; +} + +.uni-icon-checkbox-filled:before { + content: '\e442'; +} + +.uni-icon-closeempty:before { + content: '\e460'; +} + +.uni-icon-refreshempty:before { + content: '\e461'; +} + +.uni-icon-reload:before { + content: '\e462'; +} + +.uni-icon-starhalf:before { + content: '\e463'; +} + +.uni-icon-spinner:before { + content: '\e464'; +} + +.uni-icon-spinner-cycle:before { + content: '\e465'; +} + +.uni-icon-search:before { + content: '\e466'; +} + +.uni-icon-plusempty:before { + content: '\e468'; +} + +.uni-icon-forward:before { + content: '\e470'; +} + +.uni-icon-back:before, +.uni-icon-left-nav:before { + content: '\e471'; +} + +.uni-icon-checkmarkempty:before { + content: '\e472'; +} + +.uni-icon-home:before { + content: '\e500'; +} + +.uni-icon-navigate:before { + content: '\e501'; +} + +.uni-icon-gear:before { + content: '\e502'; +} + +.uni-icon-paperplane:before { + content: '\e503'; +} + +.uni-icon-info:before { + content: '\e504'; +} + +.uni-icon-help:before { + content: '\e505'; +} + +.uni-icon-locked:before { + content: '\e506'; +} + +.uni-icon-more:before { + content: '\e507'; +} + +.uni-icon-flag:before { + content: '\e508'; +} + +.uni-icon-home-filled:before { + content: '\e530'; +} + +.uni-icon-gear-filled:before { + content: '\e532'; +} + +.uni-icon-info-filled:before { + content: '\e534'; +} + +.uni-icon-help-filled:before { + content: '\e535'; +} + +.uni-icon-more-filled:before { + content: '\e537'; +} + +.uni-icon-settings:before { + content: '\e560'; +} + +.uni-icon-list:before { + content: '\e562'; +} + +.uni-icon-bars:before { + content: '\e563'; +} + +.uni-icon-loop:before { + content: '\e565'; +} + +.uni-icon-paperclip:before { + content: '\e567'; +} + +.uni-icon-eye:before { + content: '\e568'; +} + +.uni-icon-arrowup:before { + content: '\e580'; +} + +.uni-icon-arrowdown:before { + content: '\e581'; +} + +.uni-icon-arrowleft:before { + content: '\e582'; +} + +.uni-icon-arrowright:before { + content: '\e583'; +} + +.uni-icon-arrowthinup:before { + content: '\e584'; +} + +.uni-icon-arrowthindown:before { + content: '\e585'; +} + +.uni-icon-arrowthinleft:before { + content: '\e586'; +} + +.uni-icon-arrowthinright:before { + content: '\e587'; +} + +.uni-icon-pulldown:before { + content: '\e588'; +} + +.uni-icon-scan:before { + content: "\e612"; +} + +/* 分界线 */ +.uni-divider{ + height: 110rpx; + display: flex; + align-items:center; + justify-content: center; + position: relative; +} +.uni-divider__content{ + font-size: 28rpx; + color: #999; + padding: 0 20rpx; + position: relative; + z-index: 101; + background: #F4F5F6; +} +.uni-divider__line{ + background-color: #CCCCCC; + height: 1px; + width: 100%; + position: absolute; + z-index: 100; + top: 50%; + left: 0; + transform: translateY(50%); +} + +.left-win-active text{ + color: #007AFF !important; +} diff --git a/common/util.js b/common/util.js new file mode 100644 index 0000000..727069b --- /dev/null +++ b/common/util.js @@ -0,0 +1,73 @@ +function formatTime(time) { + if (typeof time !== 'number' || time < 0) { + return time + } + + var hour = parseInt(time / 3600) + time = time % 3600 + var minute = parseInt(time / 60) + time = time % 60 + var second = time + + return ([hour, minute, second]).map(function(n) { + n = n.toString() + return n[1] ? n : '0' + n + }).join(':') +} + +function formatLocation(longitude, latitude) { + if (typeof longitude === 'string' && typeof latitude === 'string') { + longitude = parseFloat(longitude) + latitude = parseFloat(latitude) + } + + longitude = longitude.toFixed(2) + latitude = latitude.toFixed(2) + + return { + longitude: longitude.toString().split('.'), + latitude: latitude.toString().split('.') + } +} +var dateUtils = { + UNITS: { + '年': 31557600000, + '月': 2629800000, + '天': 86400000, + '小时': 3600000, + '分钟': 60000, + '秒': 1000 + }, + humanize: function(milliseconds) { + var humanize = ''; + for (var key in this.UNITS) { + if (milliseconds >= this.UNITS[key]) { + humanize = Math.floor(milliseconds / this.UNITS[key]) + key + '前'; + break; + } + } + return humanize || '刚刚'; + }, + format: function(dateStr) { + var date = this.parse(dateStr) + var diff = Date.now() - date.getTime(); + if (diff < this.UNITS['天']) { + return this.humanize(diff); + } + var _format = function(number) { + return (number < 10 ? ('0' + number) : number); + }; + return date.getFullYear() + '/' + _format(date.getMonth() + 1) + '/' + _format(date.getDate()) + '-' + + _format(date.getHours()) + ':' + _format(date.getMinutes()); + }, + parse: function(str) { //将"yyyy-mm-dd HH:MM:ss"格式的字符串,转化为一个Date对象 + var a = str.split(/[^0-9]/); + return new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]); + } +}; + +export { + formatTime, + formatLocation, + dateUtils +} diff --git a/components/amap-wx/js/util.js b/components/amap-wx/js/util.js new file mode 100644 index 0000000..ca8524b --- /dev/null +++ b/components/amap-wx/js/util.js @@ -0,0 +1,181 @@ +import amap from '@/components/amap-wx/lib/amap-wx.js'; +// 地铁颜色图 +const line = { + '1号线': '#C43B33', + '2号线': '#016299', + '4号线/大兴线': '#008E9C', + '5号线': '#A42380', + '6号线': '#D09900', + '7号线': '#F2C172', + '8号线': '#009D6A', + '9号线': '#8FC41E', + '10号线': '#009DBE', + '13号线': '#F9E701', + '14号线东段': '#D4A7A2', + '14号线西段': '#D4A7A2', + '15号线': '#5D2D69', + '八通线': '#C33A32', + '昌平线': '#DE82B1', + '亦庄线': '#E40177', + '房山线': '#E66021', + '机场线': '#A29BBC', +} + +// 150500:地铁站 ,150700:公交站 , 190700:地名地址 +const typecode = [{ + id: '150500', + icon: 'icon-ditie' +}, { + id: '150700', + icon: 'icon-gongjiao' +}, { + id: '190700', + icon: 'icon-gonglu' +}]; + +const util = { + key:'b526b09b86cd2996e7732be8ab8c4430', + /** + * 初始化高德地图api + */ + mapInit() { + return new amap.AMapWX({ + key: this.key + }); + }, + // 服务状态吗 + typecode, + /** + * 获取地图颜色 + */ + lineColor(name) { + if (line[name]) { + return line[name]; + } else { + return '#ccc'; + } + }, + /** + * 关键字颜色变化 + */ + serachNmme(val, name) { + let namestr = new RegExp(val); + let nameresult = + `
+ ${name.replace(namestr, "" + val + '')} +
` + .trim(); + + return nameresult; + }, + /** + * 地址转地铁线路 + */ + addressToLine(address, type) { + let addr = address.split(';'); + let dt = ''; + addr.forEach(elm => { + let color = '#cccccc'; + if (type === typecode[0].id) { + color = this.lineColor(elm) + } else if (type === typecode[1].id) { + color = '#4075cb' + } + let style = 'margin:5px 0;margin-right:5px;padding:0 5px;background:' + color + + ';font-size:12px;color:#fff;border-radius:3px;'; + dt += `
${elm}
`; + + }); + return `
${dt}
`; + }, + /** + * 数据处理 + */ + dataHandle(item, val) { + // 改变字体颜色 + if (val) { + item.nameNodes = util.serachNmme(val, item.name); + } else { + item.nameNodes = `
${item.name}
`; + + } + // 地址解析 地铁 + if ( + item.typecode === util.typecode[0].id || + item.typecode === util.typecode[1].id + ) { + item.addressNodes = util.addressToLine(item.address, item.typecode); + if (item.typecode === util.typecode[0].id) { + item.icon = util.typecode[0].icon; + } else if (item.typecode === util.typecode[1].id) { + item.icon = util.typecode[1].icon; + } + } else { + item.addressNodes = `${item.district}${ + item.address.length > 0 ? '·' + item.address : '' + }`.trim(); + item.icon = 'icon-weizhi'; + } + + if (item.location && item.location.length === 0) { + item.icon = 'icon-sousuo'; + } + + return item; + }, + /** + * 存储历史数据 + * val [string | object]需要存储的内容 + */ + setHistory(val) { + let searchHistory = uni.getStorageSync('search:history'); + if (!searchHistory) searchHistory = []; + let serachData = {}; + if (typeof(val) === 'string') { + serachData = { + adcode: [], + address: [], + city: [], + district: [], + id: [], + location: [], + name: val, + typecode: [] + }; + } else { + serachData = val + } + + // 判断数组是否存在,如果存在,那么将放到最前面 + for (var i = 0; i < searchHistory.length; i++) { + if (searchHistory[i].name === serachData.name) { + searchHistory.splice(i, 1); + break; + } + } + + searchHistory.unshift(util.dataHandle(serachData)); + uni.setStorage({ + key: 'search:history', + data: searchHistory, + success: function() { + // console.log('success'); + } + }); + }, + getHistory() { + + }, + removeHistory() { + uni.removeStorage({ + key: 'search:history', + success: function(res) { + console.log('success'); + } + }); + return [] + } + +} + +export default util; diff --git a/components/amap-wx/lib/amap-wx.js b/components/amap-wx/lib/amap-wx.js new file mode 100644 index 0000000..652f8c1 --- /dev/null +++ b/components/amap-wx/lib/amap-wx.js @@ -0,0 +1 @@ +function AMapWX(a){this.key=a.key,this.requestConfig={key:a.key,s:"rsx",platform:"WXJS",appname:a.key,sdkversion:"1.2.0",logversion:"2.0"}}AMapWX.prototype.getWxLocation=function(a,b){wx.getLocation({type:"gcj02",success:function(a){var c=a.longitude+","+a.latitude;wx.setStorage({key:"userLocation",data:c}),b(c)},fail:function(c){wx.getStorage({key:"userLocation",success:function(a){a.data&&b(a.data)}}),a.fail({errCode:"0",errMsg:c.errMsg||""})}})},AMapWX.prototype.getRegeo=function(a){function c(c){var d=b.requestConfig;wx.request({url:"https://restapi.amap.com/v3/geocode/regeo",data:{key:b.key,location:c,extensions:"all",s:d.s,platform:d.platform,appname:b.key,sdkversion:d.sdkversion,logversion:d.logversion},method:"GET",header:{"content-type":"application/json"},success:function(b){var d,e,f,g,h,i,j,k,l;b.data.status&&"1"==b.data.status?(d=b.data.regeocode,e=d.addressComponent,f=[],g="",d&&d.roads[0]&&d.roads[0].name&&(g=d.roads[0].name+"附近"),h=c.split(",")[0],i=c.split(",")[1],d.pois&&d.pois[0]&&(g=d.pois[0].name+"附近",j=d.pois[0].location,j&&(h=parseFloat(j.split(",")[0]),i=parseFloat(j.split(",")[1]))),e.provice&&f.push(e.provice),e.city&&f.push(e.city),e.district&&f.push(e.district),e.streetNumber&&e.streetNumber.street&&e.streetNumber.number?(f.push(e.streetNumber.street),f.push(e.streetNumber.number)):(k="",d&&d.roads[0]&&d.roads[0].name&&(k=d.roads[0].name),f.push(k)),f=f.join(""),l=[{iconPath:a.iconPath,width:a.iconWidth,height:a.iconHeight,name:f,desc:g,longitude:h,latitude:i,id:0,regeocodeData:d}],a.success(l)):a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}var b=this;a.location?c(a.location):b.getWxLocation(a,function(a){c(a)})},AMapWX.prototype.getWeather=function(a){function d(d){var e="base";a.type&&"forecast"==a.type&&(e="all"),wx.request({url:"https://restapi.amap.com/v3/weather/weatherInfo",data:{key:b.key,city:d,extensions:e,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion},method:"GET",header:{"content-type":"application/json"},success:function(b){function c(a){var b={city:{text:"城市",data:a.city},weather:{text:"天气",data:a.weather},temperature:{text:"温度",data:a.temperature},winddirection:{text:"风向",data:a.winddirection+"风"},windpower:{text:"风力",data:a.windpower+"级"},humidity:{text:"湿度",data:a.humidity+"%"}};return b}var d,e;b.data.status&&"1"==b.data.status?b.data.lives?(d=b.data.lives,d&&d.length>0&&(d=d[0],e=c(d),e["liveData"]=d,a.success(e))):b.data.forecasts&&b.data.forecasts[0]&&a.success({forecast:b.data.forecasts[0]}):a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}function e(e){wx.request({url:"https://restapi.amap.com/v3/geocode/regeo",data:{key:b.key,location:e,extensions:"all",s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion},method:"GET",header:{"content-type":"application/json"},success:function(b){var c,e;b.data.status&&"1"==b.data.status?(e=b.data.regeocode,e.addressComponent?c=e.addressComponent.adcode:e.aois&&e.aois.length>0&&(c=e.aois[0].adcode),d(c)):a.fail({errCode:b.data.infocode,errMsg:b.data.info})},fail:function(b){a.fail({errCode:"0",errMsg:b.errMsg||""})}})}var b=this,c=b.requestConfig;a.city?d(a.city):b.getWxLocation(a,function(a){e(a)})},AMapWX.prototype.getPoiAround=function(a){function d(d){var e={key:b.key,location:d,s:c.s,platform:c.platform,appname:b.key,sdkversion:c.sdkversion,logversion:c.logversion};a.querytypes&&(e["types"]=a.querytypes),a.querykeywords&&(e["keywords"]=a.querykeywords),wx.request({url:"https://restapi.amap.com/v3/place/around",data:e,method:"GET",header:{"content-type":"application/json"},success:function(b){var c,d,e,f;if(b.data.status&&"1"==b.data.status){if(b=b.data,b&&b.pois){for(c=[],d=0;d + + + + + + + + + + + + + + + + + + diff --git a/components/marked/index.js b/components/marked/index.js new file mode 100644 index 0000000..073aef2 --- /dev/null +++ b/components/marked/index.js @@ -0,0 +1 @@ +export default './lib/marked' diff --git a/components/marked/lib/marked.js b/components/marked/lib/marked.js new file mode 100644 index 0000000..538c495 --- /dev/null +++ b/components/marked/lib/marked.js @@ -0,0 +1,1573 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/markedjs/marked + */ + +;(function(root) { +'use strict'; + +/** + * Block-Level Grammar + */ + +var block = { + newline: /^\n+/, + code: /^( {4}[^\n]+\n*)+/, + fences: noop, + hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/, + heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/, + nptable: noop, + blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/, + list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: '^ {0,3}(?:' // optional indentation + + '<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) + + '|comment[^\\n]*(\\n+|$)' // (2) + + '|<\\?[\\s\\S]*?\\?>\\n*' // (3) + + '|\\n*' // (4) + + '|\\n*' // (5) + + '|)[\\s\\S]*?(?:\\n{2,}|$)' // (6) + + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag + + '|(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag + + ')', + def: /^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/, + table: noop, + lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, + paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/, + text: /^[^\n]+/ +}; + +block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/; +block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/; +block.def = edit(block.def) + .replace('label', block._label) + .replace('title', block._title) + .getRegex(); + +block.bullet = /(?:[*+-]|\d+\.)/; +block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; +block.item = edit(block.item, 'gm') + .replace(/bull/g, block.bullet) + .getRegex(); + +block.list = edit(block.list) + .replace(/bull/g, block.bullet) + .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))') + .replace('def', '\\n+(?=' + block.def.source + ')') + .getRegex(); + +block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + + '|track|ul'; +block._comment = //; +block.html = edit(block.html, 'i') + .replace('comment', block._comment) + .replace('tag', block._tag) + .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/) + .getRegex(); + +block.paragraph = edit(block.paragraph) + .replace('hr', block.hr) + .replace('heading', block.heading) + .replace('lheading', block.lheading) + .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks + .getRegex(); + +block.blockquote = edit(block.blockquote) + .replace('paragraph', block.paragraph) + .getRegex(); + +/** + * Normal Block Grammar + */ + +block.normal = merge({}, block); + +/** + * GFM Block Grammar + */ + +block.gfm = merge({}, block.normal, { + fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/, + paragraph: /^/, + heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/ +}); + +block.gfm.paragraph = edit(block.paragraph) + .replace('(?!', '(?!' + + block.gfm.fences.source.replace('\\1', '\\2') + '|' + + block.list.source.replace('\\1', '\\3') + '|') + .getRegex(); + +/** + * GFM + Tables Block Grammar + */ + +block.tables = merge({}, block.gfm, { + nptable: /^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/, + table: /^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/ +}); + +/** + * Pedantic grammar + */ + +block.pedantic = merge({}, block.normal, { + html: edit( + '^ *(?:comment *(?:\\n|\\s*$)' + + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag + + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))') + .replace('comment', block._comment) + .replace(/tag/g, '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b') + .getRegex(), + def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/ +}); + +/** + * Block Lexer + */ + +function Lexer(options) { + this.tokens = []; + this.tokens.links = Object.create(null); + this.options = options || marked.defaults; + this.rules = block.normal; + + if (this.options.pedantic) { + this.rules = block.pedantic; + } else if (this.options.gfm) { + if (this.options.tables) { + this.rules = block.tables; + } else { + this.rules = block.gfm; + } + } +} + +/** + * Expose Block Rules + */ + +Lexer.rules = block; + +/** + * Static Lex Method + */ + +Lexer.lex = function(src, options) { + var lexer = new Lexer(options); + return lexer.lex(src); +}; + +/** + * Preprocessing + */ + +Lexer.prototype.lex = function(src) { + src = src + .replace(/\r\n|\r/g, '\n') + .replace(/\t/g, ' ') + .replace(/\u00a0/g, ' ') + .replace(/\u2424/g, '\n'); + + return this.token(src, true); +}; + +/** + * Lexing + */ + +Lexer.prototype.token = function(src, top) { + src = src.replace(/^ +$/gm, ''); + var next, + loose, + cap, + bull, + b, + item, + listStart, + listItems, + t, + space, + i, + tag, + l, + isordered, + istask, + ischecked; + + while (src) { + // newline + if (cap = this.rules.newline.exec(src)) { + src = src.substring(cap[0].length); + if (cap[0].length > 1) { + this.tokens.push({ + type: 'space' + }); + } + } + + // code + if (cap = this.rules.code.exec(src)) { + src = src.substring(cap[0].length); + cap = cap[0].replace(/^ {4}/gm, ''); + this.tokens.push({ + type: 'code', + text: !this.options.pedantic + ? rtrim(cap, '\n') + : cap + }); + continue; + } + + // fences (gfm) + if (cap = this.rules.fences.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'code', + lang: cap[2], + text: cap[3] || '' + }); + continue; + } + + // heading + if (cap = this.rules.heading.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'heading', + depth: cap[1].length, + text: cap[2] + }); + continue; + } + + // table no leading pipe (gfm) + if (top && (cap = this.rules.nptable.exec(src))) { + item = { + type: 'table', + header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] + }; + + if (item.header.length === item.align.length) { + src = src.substring(cap[0].length); + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = splitCells(item.cells[i], item.header.length); + } + + this.tokens.push(item); + + continue; + } + } + + // hr + if (cap = this.rules.hr.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'hr' + }); + continue; + } + + // blockquote + if (cap = this.rules.blockquote.exec(src)) { + src = src.substring(cap[0].length); + + this.tokens.push({ + type: 'blockquote_start' + }); + + cap = cap[0].replace(/^ *> ?/gm, ''); + + // Pass `top` to keep the current + // "toplevel" state. This is exactly + // how markdown.pl works. + this.token(cap, top); + + this.tokens.push({ + type: 'blockquote_end' + }); + + continue; + } + + // list + if (cap = this.rules.list.exec(src)) { + src = src.substring(cap[0].length); + bull = cap[2]; + isordered = bull.length > 1; + + listStart = { + type: 'list_start', + ordered: isordered, + start: isordered ? +bull : '', + loose: false + }; + + this.tokens.push(listStart); + + // Get each top-level item. + cap = cap[0].match(this.rules.item); + + listItems = []; + next = false; + l = cap.length; + i = 0; + + for (; i < l; i++) { + item = cap[i]; + + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) +/, ''); + + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { + space -= item.length; + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (this.options.smartLists && i !== l - 1) { + b = block.bullet.exec(cap[i + 1])[0]; + if (bull !== b && !(bull.length > 1 && b.length > 1)) { + src = cap.slice(i + 1).join('\n') + src; + i = l - 1; + } + } + + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item.charAt(item.length - 1) === '\n'; + if (!loose) loose = next; + } + + if (loose) { + listStart.loose = true; + } + + // Check for task list items + istask = /^\[[ xX]\] /.test(item); + ischecked = undefined; + if (istask) { + ischecked = item[1] !== ' '; + item = item.replace(/^\[[ xX]\] +/, ''); + } + + t = { + type: 'list_item_start', + task: istask, + checked: ischecked, + loose: loose + }; + + listItems.push(t); + this.tokens.push(t); + + // Recurse. + this.token(item, false); + + this.tokens.push({ + type: 'list_item_end' + }); + } + + if (listStart.loose) { + l = listItems.length; + i = 0; + for (; i < l; i++) { + listItems[i].loose = true; + } + } + + this.tokens.push({ + type: 'list_end' + }); + + continue; + } + + // html + if (cap = this.rules.html.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: this.options.sanitize + ? 'paragraph' + : 'html', + pre: !this.options.sanitizer + && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), + text: cap[0] + }); + continue; + } + + // def + if (top && (cap = this.rules.def.exec(src))) { + src = src.substring(cap[0].length); + if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); + tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + if (!this.tokens.links[tag]) { + this.tokens.links[tag] = { + href: cap[2], + title: cap[3] + }; + } + continue; + } + + // table (gfm) + if (top && (cap = this.rules.table.exec(src))) { + item = { + type: 'table', + header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') : [] + }; + + if (item.header.length === item.align.length) { + src = src.substring(cap[0].length); + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = splitCells( + item.cells[i].replace(/^ *\| *| *\| *$/g, ''), + item.header.length); + } + + this.tokens.push(item); + + continue; + } + } + + // lheading + if (cap = this.rules.lheading.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'heading', + depth: cap[2] === '=' ? 1 : 2, + text: cap[1] + }); + continue; + } + + // top-level paragraph + if (top && (cap = this.rules.paragraph.exec(src))) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'paragraph', + text: cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1] + }); + continue; + } + + // text + if (cap = this.rules.text.exec(src)) { + // Top-level should never reach here. + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'text', + text: cap[0] + }); + continue; + } + + if (src) { + throw new Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return this.tokens; +}; + +/** + * Inline-Level Grammar + */ + +var inline = { + escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/, + autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/, + url: noop, + tag: '^comment' + + '|^' // self-closing tag + + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag + + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. + + '|^' // declaration, e.g. + + '|^', // CDATA section + link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/, + reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/, + nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/, + strong: /^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/, + em: /^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/, + code: /^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/, + br: /^( {2,}|\\)\n(?!\s*$)/, + del: noop, + text: /^[\s\S]+?(?=[\\?@\[\]\\^_`{|}~])/g; + +inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/; +inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/; +inline.autolink = edit(inline.autolink) + .replace('scheme', inline._scheme) + .replace('email', inline._email) + .getRegex(); + +inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/; + +inline.tag = edit(inline.tag) + .replace('comment', block._comment) + .replace('attribute', inline._attribute) + .getRegex(); + +inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/; +inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/; +inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/; + +inline.link = edit(inline.link) + .replace('label', inline._label) + .replace('href', inline._href) + .replace('title', inline._title) + .getRegex(); + +inline.reflink = edit(inline.reflink) + .replace('label', inline._label) + .getRegex(); + +/** + * Normal Inline Grammar + */ + +inline.normal = merge({}, inline); + +/** + * Pedantic Inline Grammar + */ + +inline.pedantic = merge({}, inline.normal, { + strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, + link: edit(/^!?\[(label)\]\((.*?)\)/) + .replace('label', inline._label) + .getRegex(), + reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/) + .replace('label', inline._label) + .getRegex() +}); + +/** + * GFM Inline Grammar + */ + +inline.gfm = merge({}, inline.normal, { + escape: edit(inline.escape).replace('])', '~|])').getRegex(), + url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/) + .replace('email', inline._email) + .getRegex(), + _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/, + del: /^~+(?=\S)([\s\S]*?\S)~+/, + text: edit(inline.text) + .replace(']|', '~]|') + .replace('|', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|') + .getRegex() +}); + +/** + * GFM + Line Breaks Inline Grammar + */ + +inline.breaks = merge({}, inline.gfm, { + br: edit(inline.br).replace('{2,}', '*').getRegex(), + text: edit(inline.gfm.text).replace('{2,}', '*').getRegex() +}); + +/** + * Inline Lexer & Compiler + */ + +function InlineLexer(links, options) { + this.options = options || marked.defaults; + this.links = links; + this.rules = inline.normal; + this.renderer = this.options.renderer || new Renderer(); + this.renderer.options = this.options; + + if (!this.links) { + throw new Error('Tokens array requires a `links` property.'); + } + + if (this.options.pedantic) { + this.rules = inline.pedantic; + } else if (this.options.gfm) { + if (this.options.breaks) { + this.rules = inline.breaks; + } else { + this.rules = inline.gfm; + } + } +} + +/** + * Expose Inline Rules + */ + +InlineLexer.rules = inline; + +/** + * Static Lexing/Compiling Method + */ + +InlineLexer.output = function(src, links, options) { + var inline = new InlineLexer(links, options); + return inline.output(src); +}; + +/** + * Lexing/Compiling + */ + +InlineLexer.prototype.output = function(src) { + var out = '', + link, + text, + href, + title, + cap, + prevCapZero; + + while (src) { + // escape + if (cap = this.rules.escape.exec(src)) { + src = src.substring(cap[0].length); + out += cap[1]; + continue; + } + + // autolink + if (cap = this.rules.autolink.exec(src)) { + src = src.substring(cap[0].length); + if (cap[2] === '@') { + text = escape(this.mangle(cap[1])); + href = 'mailto:' + text; + } else { + text = escape(cap[1]); + href = text; + } + out += this.renderer.link(href, null, text); + continue; + } + + // url (gfm) + if (!this.inLink && (cap = this.rules.url.exec(src))) { + do { + prevCapZero = cap[0]; + cap[0] = this.rules._backpedal.exec(cap[0])[0]; + } while (prevCapZero !== cap[0]); + src = src.substring(cap[0].length); + if (cap[2] === '@') { + text = escape(cap[0]); + href = 'mailto:' + text; + } else { + text = escape(cap[0]); + if (cap[1] === 'www.') { + href = 'http://' + text; + } else { + href = text; + } + } + out += this.renderer.link(href, null, text); + continue; + } + + // tag + if (cap = this.rules.tag.exec(src)) { + if (!this.inLink && /^/i.test(cap[0])) { + this.inLink = false; + } + src = src.substring(cap[0].length); + out += this.options.sanitize + ? this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape(cap[0]) + : cap[0] + continue; + } + + // link + if (cap = this.rules.link.exec(src)) { + src = src.substring(cap[0].length); + this.inLink = true; + href = cap[2]; + if (this.options.pedantic) { + link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + + if (link) { + href = link[1]; + title = link[3]; + } else { + title = ''; + } + } else { + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); + out += this.outputLink(cap, { + href: InlineLexer.escapes(href), + title: InlineLexer.escapes(title) + }); + this.inLink = false; + continue; + } + + // reflink, nolink + if ((cap = this.rules.reflink.exec(src)) + || (cap = this.rules.nolink.exec(src))) { + src = src.substring(cap[0].length); + link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = this.links[link.toLowerCase()]; + if (!link || !link.href) { + out += cap[0].charAt(0); + src = cap[0].substring(1) + src; + continue; + } + this.inLink = true; + out += this.outputLink(cap, link); + this.inLink = false; + continue; + } + + // strong + if (cap = this.rules.strong.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.strong(this.output(cap[4] || cap[3] || cap[2] || cap[1])); + continue; + } + + // em + if (cap = this.rules.em.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.em(this.output(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1])); + continue; + } + + // code + if (cap = this.rules.code.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.codespan(escape(cap[2].trim(), true)); + continue; + } + + // br + if (cap = this.rules.br.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.br(); + continue; + } + + // del (gfm) + if (cap = this.rules.del.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.del(this.output(cap[1])); + continue; + } + + // text + if (cap = this.rules.text.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.text(escape(this.smartypants(cap[0]))); + continue; + } + + if (src) { + throw new Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return out; +}; + +InlineLexer.escapes = function(text) { + return text ? text.replace(InlineLexer.rules._escapes, '$1') : text; +} + +/** + * Compile Link + */ + +InlineLexer.prototype.outputLink = function(cap, link) { + var href = link.href, + title = link.title ? escape(link.title) : null; + + return cap[0].charAt(0) !== '!' + ? this.renderer.link(href, title, this.output(cap[1])) + : this.renderer.image(href, title, escape(cap[1])); +}; + +/** + * Smartypants Transformations + */ + +InlineLexer.prototype.smartypants = function(text) { + if (!this.options.smartypants) return text; + return text + // em-dashes + .replace(/---/g, '\u2014') + // en-dashes + .replace(/--/g, '\u2013') + // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') + // closing singles & apostrophes + .replace(/'/g, '\u2019') + // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') + // closing doubles + .replace(/"/g, '\u201d') + // ellipses + .replace(/\.{3}/g, '\u2026'); +}; + +/** + * Mangle Links + */ + +InlineLexer.prototype.mangle = function(text) { + if (!this.options.mangle) return text; + var out = '', + l = text.length, + i = 0, + ch; + + for (; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; +}; + +/** + * Renderer + */ + +function Renderer(options) { + this.options = options || marked.defaults; +} + +Renderer.prototype.code = function(code, lang, escaped) { + if (this.options.highlight) { + var out = this.options.highlight(code, lang); + if (out != null && out !== code) { + escaped = true; + code = out; + } + } + + if (!lang) { + return '
'
+      + (escaped ? code : escape(code, true))
+      + '
'; + } + + return '
'
+    + (escaped ? code : escape(code, true))
+    + '
\n'; +}; + +Renderer.prototype.blockquote = function(quote) { + return '
\n' + quote + '
\n'; +}; + +Renderer.prototype.html = function(html) { + return html; +}; + +Renderer.prototype.heading = function(text, level, raw) { + if (this.options.headerIds) { + return '' + + text + + '\n'; + } + // ignore IDs + return '' + text + '\n'; +}; + +Renderer.prototype.hr = function() { + return this.options.xhtml ? '
\n' : '
\n'; +}; + +Renderer.prototype.list = function(body, ordered, start) { + var type = ordered ? 'ol' : 'ul', + startatt = (ordered && start !== 1) ? (' start="' + start + '"') : ''; + return '<' + type + startatt + '>\n' + body + '\n'; +}; + +Renderer.prototype.listitem = function(text) { + return '
  • ' + text + '
  • \n'; +}; + +Renderer.prototype.checkbox = function(checked) { + return ' '; +} + +Renderer.prototype.paragraph = function(text) { + return '

    ' + text + '

    \n'; +}; + +Renderer.prototype.table = function(header, body) { + if (body) body = '' + body + ''; + + return '\n' + + '\n' + + header + + '\n' + + body + + '
    \n'; +}; + +Renderer.prototype.tablerow = function(content) { + return '\n' + content + '\n'; +}; + +Renderer.prototype.tablecell = function(content, flags) { + var type = flags.header ? 'th' : 'td'; + var tag = flags.align + ? '<' + type + ' align="' + flags.align + '">' + : '<' + type + '>'; + return tag + content + '\n'; +}; + +// span level renderer +Renderer.prototype.strong = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.em = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.codespan = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.br = function() { + return this.options.xhtml ? '
    ' : '
    '; +}; + +Renderer.prototype.del = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.link = function(href, title, text) { + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)) + .replace(/[^\w:]/g, '') + .toLowerCase(); + } catch (e) { + return text; + } + if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) { + return text; + } + } + if (this.options.baseUrl && !originIndependentUrl.test(href)) { + href = resolveUrl(this.options.baseUrl, href); + } + try { + href = encodeURI(href).replace(/%25/g, '%'); + } catch (e) { + return text; + } + var out = '
    '; + return out; +}; + +Renderer.prototype.image = function(href, title, text) { + if (this.options.baseUrl && !originIndependentUrl.test(href)) { + href = resolveUrl(this.options.baseUrl, href); + } + var out = '' + text + '' : '>'; + return out; +}; + +Renderer.prototype.text = function(text) { + return text; +}; + +/** + * TextRenderer + * returns only the textual part of the token + */ + +function TextRenderer() {} + +// no need for block level renderers + +TextRenderer.prototype.strong = +TextRenderer.prototype.em = +TextRenderer.prototype.codespan = +TextRenderer.prototype.del = +TextRenderer.prototype.text = function (text) { + return text; +} + +TextRenderer.prototype.link = +TextRenderer.prototype.image = function(href, title, text) { + return '' + text; +} + +TextRenderer.prototype.br = function() { + return ''; +} + +/** + * Parsing & Compiling + */ + +function Parser(options) { + this.tokens = []; + this.token = null; + this.options = options || marked.defaults; + this.options.renderer = this.options.renderer || new Renderer(); + this.renderer = this.options.renderer; + this.renderer.options = this.options; +} + +/** + * Static Parse Method + */ + +Parser.parse = function(src, options) { + var parser = new Parser(options); + return parser.parse(src); +}; + +/** + * Parse Loop + */ + +Parser.prototype.parse = function(src) { + this.inline = new InlineLexer(src.links, this.options); + // use an InlineLexer with a TextRenderer to extract pure text + this.inlineText = new InlineLexer( + src.links, + merge({}, this.options, {renderer: new TextRenderer()}) + ); + this.tokens = src.reverse(); + + var out = ''; + while (this.next()) { + out += this.tok(); + } + + return out; +}; + +/** + * Next Token + */ + +Parser.prototype.next = function() { + return this.token = this.tokens.pop(); +}; + +/** + * Preview Next Token + */ + +Parser.prototype.peek = function() { + return this.tokens[this.tokens.length - 1] || 0; +}; + +/** + * Parse Text Tokens + */ + +Parser.prototype.parseText = function() { + var body = this.token.text; + + while (this.peek().type === 'text') { + body += '\n' + this.next().text; + } + + return this.inline.output(body); +}; + +/** + * Parse Current Token + */ + +Parser.prototype.tok = function() { + switch (this.token.type) { + case 'space': { + return ''; + } + case 'hr': { + return this.renderer.hr(); + } + case 'heading': { + return this.renderer.heading( + this.inline.output(this.token.text), + this.token.depth, + unescape(this.inlineText.output(this.token.text))); + } + case 'code': { + return this.renderer.code(this.token.text, + this.token.lang, + this.token.escaped); + } + case 'table': { + var header = '', + body = '', + i, + row, + cell, + j; + + // header + cell = ''; + for (i = 0; i < this.token.header.length; i++) { + cell += this.renderer.tablecell( + this.inline.output(this.token.header[i]), + { header: true, align: this.token.align[i] } + ); + } + header += this.renderer.tablerow(cell); + + for (i = 0; i < this.token.cells.length; i++) { + row = this.token.cells[i]; + + cell = ''; + for (j = 0; j < row.length; j++) { + cell += this.renderer.tablecell( + this.inline.output(row[j]), + { header: false, align: this.token.align[j] } + ); + } + + body += this.renderer.tablerow(cell); + } + return this.renderer.table(header, body); + } + case 'blockquote_start': { + body = ''; + + while (this.next().type !== 'blockquote_end') { + body += this.tok(); + } + + return this.renderer.blockquote(body); + } + case 'list_start': { + body = ''; + var ordered = this.token.ordered, + start = this.token.start; + + while (this.next().type !== 'list_end') { + body += this.tok(); + } + + return this.renderer.list(body, ordered, start); + } + case 'list_item_start': { + body = ''; + var loose = this.token.loose; + + if (this.token.task) { + body += this.renderer.checkbox(this.token.checked); + } + + while (this.next().type !== 'list_item_end') { + body += !loose && this.token.type === 'text' + ? this.parseText() + : this.tok(); + } + + return this.renderer.listitem(body); + } + case 'html': { + // TODO parse inline content if parameter markdown=1 + return this.renderer.html(this.token.text); + } + case 'paragraph': { + return this.renderer.paragraph(this.inline.output(this.token.text)); + } + case 'text': { + return this.renderer.paragraph(this.parseText()); + } + } +}; + +/** + * Helpers + */ + +function escape(html, encode) { + return html + .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + +function unescape(html) { + // explicitly match decimal, hex, and named HTML entities + return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) { + n = n.toLowerCase(); + if (n === 'colon') return ':'; + if (n.charAt(0) === '#') { + return n.charAt(1) === 'x' + ? String.fromCharCode(parseInt(n.substring(2), 16)) + : String.fromCharCode(+n.substring(1)); + } + return ''; + }); +} + +function edit(regex, opt) { + regex = regex.source || regex; + opt = opt || ''; + return { + replace: function(name, val) { + val = val.source || val; + val = val.replace(/(^|[^\[])\^/g, '$1'); + regex = regex.replace(name, val); + return this; + }, + getRegex: function() { + return new RegExp(regex, opt); + } + }; +} + +function resolveUrl(base, href) { + if (!baseUrls[' ' + base]) { + // we can ignore everything in base after the last slash of its path component, + // but we might need to add _that_ + // https://tools.ietf.org/html/rfc3986#section-3 + if (/^[^:]+:\/*[^/]*$/.test(base)) { + baseUrls[' ' + base] = base + '/'; + } else { + baseUrls[' ' + base] = rtrim(base, '/', true); + } + } + base = baseUrls[' ' + base]; + + if (href.slice(0, 2) === '//') { + return base.replace(/:[\s\S]*/, ':') + href; + } else if (href.charAt(0) === '/') { + return base.replace(/(:\/*[^/]*)[\s\S]*/, '$1') + href; + } else { + return base + href; + } +} +var baseUrls = {}; +var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i; + +function noop() {} +noop.exec = noop; + +function merge(obj) { + var i = 1, + target, + key; + + for (; i < arguments.length; i++) { + target = arguments[i]; + for (key in target) { + if (Object.prototype.hasOwnProperty.call(target, key)) { + obj[key] = target[key]; + } + } + } + + return obj; +} + +function splitCells(tableRow, count) { + // ensure that every cell-delimiting pipe has a space + // before it to distinguish it from an escaped pipe + var row = tableRow.replace(/\|/g, function (match, offset, str) { + var escaped = false, + curr = offset; + while (--curr >= 0 && str[curr] === '\\') escaped = !escaped; + if (escaped) { + // odd number of slashes means | is escaped + // so we leave it alone + return '|'; + } else { + // add space before unescaped | + return ' |'; + } + }), + cells = row.split(/ \|/), + i = 0; + + if (cells.length > count) { + cells.splice(count); + } else { + while (cells.length < count) cells.push(''); + } + + for (; i < cells.length; i++) { + // leading or trailing whitespace is ignored per the gfm spec + cells[i] = cells[i].trim().replace(/\\\|/g, '|'); + } + return cells; +} + +// Remove trailing 'c's. Equivalent to str.replace(/c*$/, ''). +// /c*$/ is vulnerable to REDOS. +// invert: Remove suffix of non-c chars instead. Default falsey. +function rtrim(str, c, invert) { + if (str.length === 0) { + return ''; + } + + // Length of suffix matching the invert condition. + var suffLen = 0; + + // Step left until we fail to match the invert condition. + while (suffLen < str.length) { + var currChar = str.charAt(str.length - suffLen - 1); + if (currChar === c && !invert) { + suffLen++; + } else if (currChar !== c && invert) { + suffLen++; + } else { + break; + } + } + + return str.substr(0, str.length - suffLen); +} + +/** + * Marked + */ + +function marked(src, opt, callback) { + // throw error in case of non string input + if (typeof src === 'undefined' || src === null) { + throw new Error('marked(): input parameter is undefined or null'); + } + if (typeof src !== 'string') { + throw new Error('marked(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected'); + } + + if (callback || typeof opt === 'function') { + if (!callback) { + callback = opt; + opt = null; + } + + opt = merge({}, marked.defaults, opt || {}); + + var highlight = opt.highlight, + tokens, + pending, + i = 0; + + try { + tokens = Lexer.lex(src, opt) + } catch (e) { + return callback(e); + } + + pending = tokens.length; + + var done = function(err) { + if (err) { + opt.highlight = highlight; + return callback(err); + } + + var out; + + try { + out = Parser.parse(tokens, opt); + } catch (e) { + err = e; + } + + opt.highlight = highlight; + + return err + ? callback(err) + : callback(null, out); + }; + + if (!highlight || highlight.length < 3) { + return done(); + } + + delete opt.highlight; + + if (!pending) return done(); + + for (; i < tokens.length; i++) { + (function(token) { + if (token.type !== 'code') { + return --pending || done(); + } + return highlight(token.text, token.lang, function(err, code) { + if (err) return done(err); + if (code == null || code === token.text) { + return --pending || done(); + } + token.text = code; + token.escaped = true; + --pending || done(); + }); + })(tokens[i]); + } + + return; + } + try { + if (opt) opt = merge({}, marked.defaults, opt); + return Parser.parse(Lexer.lex(src, opt), opt); + } catch (e) { + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; + if ((opt || marked.defaults).silent) { + return '

    An error occurred:

    '
    +        + escape(e.message + '', true)
    +        + '
    '; + } + throw e; + } +} + +/** + * Options + */ + +marked.options = +marked.setOptions = function(opt) { + merge(marked.defaults, opt); + return marked; +}; + +marked.getDefaults = function () { + return { + baseUrl: null, + breaks: false, + gfm: true, + headerIds: true, + headerPrefix: '', + highlight: null, + langPrefix: 'language-', + mangle: true, + pedantic: false, + renderer: new Renderer(), + sanitize: false, + sanitizer: null, + silent: false, + smartLists: false, + smartypants: false, + tables: true, + xhtml: false + }; +} + +marked.defaults = marked.getDefaults(); + +/** + * Expose + */ + +marked.Parser = Parser; +marked.parser = Parser.parse; + +marked.Renderer = Renderer; +marked.TextRenderer = TextRenderer; + +marked.Lexer = Lexer; +marked.lexer = Lexer.lex; + +marked.InlineLexer = InlineLexer; +marked.inlineLexer = InlineLexer.output; + +marked.parse = marked; + +if (typeof module !== 'undefined' && typeof exports === 'object') { + module.exports = marked; +} else if (typeof define === 'function' && define.amd) { + define(function() { return marked; }); +} else { + root.marked = marked; +} +})(this || (typeof window !== 'undefined' ? window : global)); diff --git a/components/page-foot/page-foot.vue b/components/page-foot/page-foot.vue new file mode 100644 index 0000000..23cbd2d --- /dev/null +++ b/components/page-foot/page-foot.vue @@ -0,0 +1,38 @@ + + + + diff --git a/components/page-head/page-head.vue b/components/page-head/page-head.vue new file mode 100644 index 0000000..4fc0508 --- /dev/null +++ b/components/page-head/page-head.vue @@ -0,0 +1,16 @@ + + diff --git a/components/product.vue b/components/product.vue new file mode 100644 index 0000000..10f2c77 --- /dev/null +++ b/components/product.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/components/tab-nvue/mediaList.vue b/components/tab-nvue/mediaList.vue new file mode 100644 index 0000000..e0b8b81 --- /dev/null +++ b/components/tab-nvue/mediaList.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/components/u-charts/u-charts.js b/components/u-charts/u-charts.js new file mode 100644 index 0000000..dde031f --- /dev/null +++ b/components/u-charts/u-charts.js @@ -0,0 +1,5046 @@ +/* + * uCharts v1.8.5.20190815 + * uni-app平台高性能跨全端图表,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360) + * Copyright (c) 2019 QIUN秋云 https://www.ucharts.cn All rights reserved. + * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) + * + * uCharts官方网站 + * https://www.uCharts.cn + * + * 开源地址: + * https://gitee.com/uCharts/uCharts + * + * uni-app插件市场地址: + * http://ext.dcloud.net.cn/plugin?id=271 + * + */ + +'use strict'; + +var config = { + yAxisWidth: 15, + yAxisSplit: 5, + xAxisHeight: 15, + xAxisLineHeight: 15, + legendHeight: 15, + yAxisTitleWidth: 15, + padding: [10, 10, 10, 10], + pixelRatio: 1, + rotate: false, + columePadding: 3, + fontSize: 13, + //dataPointShape: ['diamond', 'circle', 'triangle', 'rect'], + dataPointShape: ['circle', 'circle', 'circle', 'circle'], + colors: ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d'], + pieChartLinePadding: 15, + pieChartTextPadding: 5, + xAxisTextPadding: 3, + titleColor: '#333333', + titleFontSize: 20, + subtitleColor: '#999999', + subtitleFontSize: 15, + toolTipPadding: 3, + toolTipBackground: '#000000', + toolTipOpacity: 0.7, + toolTipLineHeight: 20, + radarGridCount: 3, + radarLabelTextMargin: 15, + gaugeLabelTextMargin: 15 +}; + +let assign; +if (Object.assign) { + assign = Object.assign; +} else { + // 使用polyfill + assign = function(target, varArgs) { + if (target == null) { + throw new TypeError('Cannot convert undefined or null to object'); + } + var to = Object(target); + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + if (nextSource != null) { + for (var nextKey in nextSource) { + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + } +} + +var util = { + toFixed: function toFixed(num, limit) { + limit = limit || 2; + if (this.isFloat(num)) { + num = num.toFixed(limit); + } + return num; + }, + isFloat: function isFloat(num) { + return num % 1 !== 0; + }, + approximatelyEqual: function approximatelyEqual(num1, num2) { + return Math.abs(num1 - num2) < 1e-10; + }, + isSameSign: function isSameSign(num1, num2) { + return Math.abs(num1) === num1 && Math.abs(num2) === num2 || Math.abs(num1) !== num1 && Math.abs(num2) !== num2; + }, + isSameXCoordinateArea: function isSameXCoordinateArea(p1, p2) { + return this.isSameSign(p1.x, p2.x); + }, + isCollision: function isCollision(obj1, obj2) { + obj1.end = {}; + obj1.end.x = obj1.start.x + obj1.width; + obj1.end.y = obj1.start.y - obj1.height; + obj2.end = {}; + obj2.end.x = obj2.start.x + obj2.width; + obj2.end.y = obj2.start.y - obj2.height; + var flag = obj2.start.x > obj1.end.x || obj2.end.x < obj1.start.x || obj2.end.y > obj1.start.y || obj2.start.y < obj1.end.y; + return !flag; + } +}; + +//兼容H5点击事件 +function getH5Offset(e) { + e.mp = { + changedTouches: [] + }; + e.mp.changedTouches.push({ + x: e.offsetX, + y: e.offsetY + }); + return e; +} + +// hex 转 rgba +function hexToRgb(hexValue, opc) { + var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + var hex = hexValue.replace(rgx, function(m, r, g, b) { + return r + r + g + g + b + b; + }); + var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + var r = parseInt(rgb[1], 16); + var g = parseInt(rgb[2], 16); + var b = parseInt(rgb[3], 16); + return 'rgba(' + r + ',' + g + ',' + b + ',' + opc + ')'; +} + +function findRange(num, type, limit) { + if (isNaN(num)) { + throw new Error('[uCharts] unvalid series data!'); + } + limit = limit || 10; + type = type ? type : 'upper'; + var multiple = 1; + while (limit < 1) { + limit *= 10; + multiple *= 10; + } + if (type === 'upper') { + num = Math.ceil(num * multiple); + } else { + num = Math.floor(num * multiple); + } + while (num % limit !== 0) { + if (type === 'upper') { + num++; + } else { + num--; + } + } + return num / multiple; +} + +function calCandleMA(dayArr, nameArr, colorArr, kdata) { + let seriesTemp = []; + for (let k = 0; k < dayArr.length; k++) { + let seriesItem = { + data: [], + name: nameArr[k], + color: colorArr[k] + }; + for (let i = 0, len = kdata.length; i < len; i++) { + if (i < dayArr[k]) { + seriesItem.data.push(null); + continue; + } + let sum = 0; + for (let j = 0; j < dayArr[k]; j++) { + sum += kdata[i - j][1]; + } + seriesItem.data.push(+(sum / dayArr[k]).toFixed(3)); + } + seriesTemp.push(seriesItem); + } + return seriesTemp; +} + +function calValidDistance(distance, chartData, config, opts) { + var dataChartAreaWidth = opts.width - opts.area[1] - opts.area[3]; + var dataChartWidth = chartData.eachSpacing * (opts.chartData.xAxisData.xAxisPoints.length-1); + var validDistance = distance; + if (distance >= 0) { + validDistance = 0; + } else if (Math.abs(distance) >= dataChartWidth - dataChartAreaWidth) { + validDistance = dataChartAreaWidth - dataChartWidth; + } + return validDistance; +} + +function isInAngleRange(angle, startAngle, endAngle) { + function adjust(angle) { + while (angle < 0) { + angle += 2 * Math.PI; + } + while (angle > 2 * Math.PI) { + angle -= 2 * Math.PI; + } + return angle; + } + angle = adjust(angle); + startAngle = adjust(startAngle); + endAngle = adjust(endAngle); + if (startAngle > endAngle) { + endAngle += 2 * Math.PI; + if (angle < startAngle) { + angle += 2 * Math.PI; + } + } + return angle >= startAngle && angle <= endAngle; +} + +function calRotateTranslate(x, y, h) { + var xv = x; + var yv = h - y; + var transX = xv + (h - yv - xv) / Math.sqrt(2); + transX *= -1; + var transY = (h - yv) * (Math.sqrt(2) - 1) - (h - yv - xv) / Math.sqrt(2); + return { + transX: transX, + transY: transY + }; +} + +function createCurveControlPoints(points, i) { + + function isNotMiddlePoint(points, i) { + if (points[i - 1] && points[i + 1]) { + return points[i].y >= Math.max(points[i - 1].y, points[i + 1].y) || points[i].y <= Math.min(points[i - 1].y, + points[ + i + 1].y); + } else { + return false; + } + } + var a = 0.2; + var b = 0.2; + var pAx = null; + var pAy = null; + var pBx = null; + var pBy = null; + if (i < 1) { + pAx = points[0].x + (points[1].x - points[0].x) * a; + pAy = points[0].y + (points[1].y - points[0].y) * a; + } else { + pAx = points[i].x + (points[i + 1].x - points[i - 1].x) * a; + pAy = points[i].y + (points[i + 1].y - points[i - 1].y) * a; + } + + if (i > points.length - 3) { + var last = points.length - 1; + pBx = points[last].x - (points[last].x - points[last - 1].x) * b; + pBy = points[last].y - (points[last].y - points[last - 1].y) * b; + } else { + pBx = points[i + 1].x - (points[i + 2].x - points[i].x) * b; + pBy = points[i + 1].y - (points[i + 2].y - points[i].y) * b; + } + if (isNotMiddlePoint(points, i + 1)) { + pBy = points[i + 1].y; + } + if (isNotMiddlePoint(points, i)) { + pAy = points[i].y; + } + return { + ctrA: { + x: pAx, + y: pAy + }, + ctrB: { + x: pBx, + y: pBy + } + }; +} + +function convertCoordinateOrigin(x, y, center) { + return { + x: center.x + x, + y: center.y - y + }; +} + +function avoidCollision(obj, target) { + if (target) { + // is collision test + while (util.isCollision(obj, target)) { + if (obj.start.x > 0) { + obj.start.y--; + } else if (obj.start.x < 0) { + obj.start.y++; + } else { + if (obj.start.y > 0) { + obj.start.y++; + } else { + obj.start.y--; + } + } + } + } + return obj; +} + +function fillSeries(series, opts, config) { + var index = 0; + return series.map(function(item) { + if (!item.color) { + item.color = config.colors[index]; + index = (index + 1) % config.colors.length; + } + if (!item.type) { + item.type = opts.type; + } + if (typeof item.show == "undefined") { + item.show = true; + } + if (!item.type) { + item.type = opts.type; + } + if (!item.pointShape) { + item.pointShape = "circle"; + } + if (!item.legendShape) { + switch (item.type) { + case 'line': + item.legendShape = "line"; + break; + case 'column': + item.legendShape = "rect"; + break; + case 'area': + item.legendShape = "triangle"; + break; + default: + item.legendShape = "circle"; + } + } + return item; + }); +} + +function getDataRange(minData, maxData) { + var limit = 0; + var range = maxData - minData; + if (range >= 10000) { + limit = 1000; + } else if (range >= 1000) { + limit = 100; + } else if (range >= 100) { + limit = 10; + } else if (range >= 10) { + limit = 5; + } else if (range >= 1) { + limit = 1; + } else if (range >= 0.1) { + limit = 0.1; + } else if (range >= 0.01) { + limit = 0.01; + } else if (range >= 0.001) { + limit = 0.001; + } else if (range >= 0.0001) { + limit = 0.0001; + } else if (range >= 0.00001) { + limit = 0.00001; + } else { + limit = 0.000001; + } + return { + minRange: findRange(minData, 'lower', limit), + maxRange: findRange(maxData, 'upper', limit) + }; +} + +function measureText(text) { + var fontSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : config.fontSize; + text = String(text); + var text = text.split(''); + var width = 0; + for (let i = 0; i < text.length; i++) { + let item = text[i]; + if (/[a-zA-Z]/.test(item)) { + width += 7; + } else if (/[0-9]/.test(item)) { + width += 5.5; + } else if (/\./.test(item)) { + width += 2.7; + } else if (/-/.test(item)) { + width += 3.25; + } else if (/[\u4e00-\u9fa5]/.test(item)) { + width += 10; + } else if (/\(|\)/.test(item)) { + width += 3.73; + } else if (/\s/.test(item)) { + width += 2.5; + } else if (/%/.test(item)) { + width += 8; + } else { + width += 10; + } + } + return width * fontSize / 10; +} + +function dataCombine(series) { + return series.reduce(function(a, b) { + return (a.data ? a.data : a).concat(b.data); + }, []); +} + +function dataCombineStack(series, len) { + var sum = new Array(len); + for (var j = 0; j < sum.length; j++) { + sum[j] = 0; + } + for (var i = 0; i < series.length; i++) { + for (var j = 0; j < sum.length; j++) { + sum[j] += series[i].data[j]; + } + } + return series.reduce(function(a, b) { + return (a.data ? a.data : a).concat(b.data).concat(sum); + }, []); +} + +function getTouches(touches, opts, e) { + let x, y; + if (touches.clientX) { + if (opts.rotate) { + y = opts.height - touches.clientX * opts.pixelRatio; + x = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pixelRatio / 2) * (opts.pixelRatio - 1)) * + opts.pixelRatio; + } else { + x = touches.clientX * opts.pixelRatio; + y = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pixelRatio / 2) * (opts.pixelRatio - 1)) * + opts.pixelRatio; + } + } else { + if (opts.rotate) { + y = opts.height - touches.x * opts.pixelRatio; + x = touches.y * opts.pixelRatio; + } else { + x = touches.x * opts.pixelRatio; + y = touches.y * opts.pixelRatio; + } + } + return { + x: x, + y: y + } +} + +function getSeriesDataItem(series, index) { + var data = []; + for (let i = 0; i < series.length; i++) { + let item = series[i]; + if (item.data[index] !== null && typeof item.data[index] !== 'undefined' && item.show) { + let seriesItem = {}; + seriesItem.color = item.color; + seriesItem.type = item.type; + seriesItem.style = item.style; + seriesItem.pointShape = item.pointShape; + seriesItem.disableLegend = item.disableLegend; + seriesItem.name = item.name; + seriesItem.show = item.show; + seriesItem.data = item.format ? item.format(item.data[index]) : item.data[index]; + data.push(seriesItem); + } + } + return data; +} + +function getMaxTextListLength(list) { + var lengthList = list.map(function(item) { + return measureText(item); + }); + return Math.max.apply(null, lengthList); +} + +function getRadarCoordinateSeries(length) { + var eachAngle = 2 * Math.PI / length; + var CoordinateSeries = []; + for (var i = 0; i < length; i++) { + CoordinateSeries.push(eachAngle * i); + } + + return CoordinateSeries.map(function(item) { + return -1 * item + Math.PI / 2; + }); +} + +function getToolTipData(seriesData, calPoints, index, categories) { + var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + + var textList = seriesData.map(function(item) { + return { + text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data, + color: item.color + }; + }); + var validCalPoints = []; + var offset = { + x: 0, + y: 0 + }; + for (let i = 0; i < calPoints.length; i++) { + let points = calPoints[i]; + if (typeof points[index] !== 'undefined' && points[index] !== null) { + validCalPoints.push(points[index]); + } + } + for (let i = 0; i < validCalPoints.length; i++) { + let item = validCalPoints[i]; + offset.x = Math.round(item.x); + offset.y += item.y; + } + offset.y /= validCalPoints.length; + return { + textList: textList, + offset: offset + }; +} + +function getMixToolTipData(seriesData, calPoints, index, categories) { + var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + var textList = seriesData.map(function(item) { + return { + text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data, + color: item.color, + disableLegend: item.disableLegend ? true : false + }; + }); + textList = textList.filter(function(item) { + if (item.disableLegend !== true) { + return item; + } + }); + var validCalPoints = []; + var offset = { + x: 0, + y: 0 + }; + for (let i = 0; i < calPoints.length; i++) { + let points = calPoints[i]; + if (typeof points[index] !== 'undefined' && points[index] !== null) { + validCalPoints.push(points[index]); + } + } + for (let i = 0; i < validCalPoints.length; i++) { + let item = validCalPoints[i]; + offset.x = Math.round(item.x); + offset.y += item.y; + } + offset.y /= validCalPoints.length; + return { + textList: textList, + offset: offset + }; +} + +function getCandleToolTipData(series, seriesData, calPoints, index, categories, extra) { + var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {}; + let upColor = extra.color.upFill; + let downColor = extra.color.downFill; + //颜色顺序为开盘,收盘,最低,最高 + let color = [upColor, upColor, downColor, upColor]; + var textList = []; + let text0 = { + text: categories[index], + color: null + }; + textList.push(text0); + seriesData.map(function(item) { + if (index == 0 && item.data[1] - item.data[0] < 0) { + color[1] = downColor; + } else { + if (item.data[0] < series[index - 1][1]) { + color[0] = downColor; + } + if (item.data[1] < item.data[0]) { + color[1] = downColor; + } + if (item.data[2] > series[index - 1][1]) { + color[2] = upColor; + } + if (item.data[3] < series[index - 1][1]) { + color[3] = downColor; + } + } + let text1 = { + text: '开盘:' + item.data[0], + color: color[0] + }; + let text2 = { + text: '收盘:' + item.data[1], + color: color[1] + }; + let text3 = { + text: '最低:' + item.data[2], + color: color[2] + }; + let text4 = { + text: '最高:' + item.data[3], + color: color[3] + }; + textList.push(text1, text2, text3, text4); + }); + var validCalPoints = []; + var offset = { + x: 0, + y: 0 + }; + for (let i = 0; i < calPoints.length; i++) { + let points = calPoints[i]; + if (typeof points[index] !== 'undefined' && points[index] !== null) { + validCalPoints.push(points[index]); + } + } + offset.x = Math.round(validCalPoints[0][0].x); + return { + textList: textList, + offset: offset + }; +} + +function filterSeries(series) { + let tempSeries = []; + for (let i = 0; i < series.length; i++) { + if (series[i].show == true) { + tempSeries.push(series[i]) + } + } + return tempSeries; +} + +function findCurrentIndex(currentPoints, xAxisPoints, opts, config) { + var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0; + var currentIndex = -1; + var spacing = 0; + if((opts.type=='line' || opts.type=='area') && opts.xAxis.boundaryGap=='justify'){ + spacing = opts.chartData.eachSpacing/2; + } + if (isInExactChartArea(currentPoints, opts, config)) { + xAxisPoints.forEach(function(item, index) { + if (currentPoints.x + offset + spacing > item) { + currentIndex = index; + } + }); + } + return currentIndex; +} + +function findLegendIndex(currentPoints, legendData, opts) { + let currentIndex = -1; + if (isInExactLegendArea(currentPoints, legendData.area)) { + let points = legendData.points; + let index = -1; + for (let i = 0, len = points.length; i < len; i++) { + let item = points[i]; + for (let j = 0; j < item.length; j++) { + index += 1; + let area = item[j]['area']; + if (currentPoints.x > area[0] && currentPoints.x < area[2] && currentPoints.y > area[1] && currentPoints.y < area[3]) { + currentIndex = index; + break; + } + } + } + return currentIndex; + } + return currentIndex; +} + +function isInExactLegendArea(currentPoints, area) { + return currentPoints.x > area.start.x && currentPoints.x < area.end.x && currentPoints.y > area.start.y && + currentPoints.y < area.end.y; +} + +function isInExactChartArea(currentPoints, opts, config) { + return currentPoints.x < opts.width - opts.area[1] + 10 && currentPoints.x > opts.area[3] -10 && currentPoints.y > opts.area[0] && currentPoints.y < opts.height - opts.area[2]; +} + +function findRadarChartCurrentIndex(currentPoints, radarData, count) { + var eachAngleArea = 2 * Math.PI / count; + var currentIndex = -1; + if (isInExactPieChartArea(currentPoints, radarData.center, radarData.radius)) { + var fixAngle = function fixAngle(angle) { + if (angle < 0) { + angle += 2 * Math.PI; + } + if (angle > 2 * Math.PI) { + angle -= 2 * Math.PI; + } + return angle; + }; + + var angle = Math.atan2(radarData.center.y - currentPoints.y, currentPoints.x - radarData.center.x); + angle = -1 * angle; + if (angle < 0) { + angle += 2 * Math.PI; + } + + var angleList = radarData.angleList.map(function(item) { + item = fixAngle(-1 * item); + + return item; + }); + + angleList.forEach(function(item, index) { + var rangeStart = fixAngle(item - eachAngleArea / 2); + var rangeEnd = fixAngle(item + eachAngleArea / 2); + if (rangeEnd < rangeStart) { + rangeEnd += 2 * Math.PI; + } + if (angle >= rangeStart && angle <= rangeEnd || angle + 2 * Math.PI >= rangeStart && angle + 2 * Math.PI <= + rangeEnd) { + currentIndex = index; + } + }); + } + + return currentIndex; +} + +function findFunnelChartCurrentIndex(currentPoints, funnelData) { + var currentIndex = -1; + for (var i = 0, len = funnelData.series.length; i < len; i++) { + var item = funnelData.series[i]; + if (currentPoints.x > item.funnelArea[0] && currentPoints.x < item.funnelArea[2] && currentPoints.y > item.funnelArea[1] && currentPoints.y < item.funnelArea[3]) { + currentIndex = i; + break; + } + } + return currentIndex; +} + +function findWordChartCurrentIndex(currentPoints, wordData) { + var currentIndex = -1; + for (var i = 0, len = wordData.length; i < len; i++) { + var item = wordData[i]; + if (currentPoints.x > item.area[0] && currentPoints.x < item.area[2] && currentPoints.y > item.area[1] && currentPoints.y < item.area[3]) { + currentIndex = i; + break; + } + } + return currentIndex; +} + +function findMapChartCurrentIndex(currentPoints, opts) { + var currentIndex = -1; + var cData=opts.chartData.mapData; + var data=opts.series; + var tmp=pointToCoordinate(currentPoints.y, currentPoints.x,cData.bounds,cData.scale,cData.xoffset,cData.yoffset); + var poi=[tmp.x, tmp.y]; + for (var i = 0, len = data.length; i < len; i++) { + var item = data[i].geometry.coordinates; + if(isPoiWithinPoly(poi,item)){ + currentIndex = i; + break; + } + } + return currentIndex; +} + +function findPieChartCurrentIndex(currentPoints, pieData) { + var currentIndex = -1; + if (isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) { + var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x); + angle = -angle; + for (var i = 0, len = pieData.series.length; i < len; i++) { + var item = pieData.series[i]; + if (isInAngleRange(angle, item._start_, item._start_ + item._proportion_ * 2 * Math.PI)) { + currentIndex = i; + break; + } + } + } + + return currentIndex; +} + +function isInExactPieChartArea(currentPoints, center, radius) { + return Math.pow(currentPoints.x - center.x, 2) + Math.pow(currentPoints.y - center.y, 2) <= Math.pow(radius, 2); +} + +function splitPoints(points) { + var newPoints = []; + var items = []; + points.forEach(function(item, index) { + if (item !== null) { + items.push(item); + } else { + if (items.length) { + newPoints.push(items); + } + items = []; + } + }); + if (items.length) { + newPoints.push(items); + } + + return newPoints; +} + +function calLegendData(series, opts, config, chartData) { + let legendData = { + area: { + start: { + x: 0, + y: 0 + }, + end: { + x: 0, + y: 0 + }, + width: 0, + height: 0, + wholeWidth: 0, + wholeHeight: 0 + }, + points: [], + widthArr: [], + heightArr: [] + }; + if (opts.legend.show === false) { + chartData.legendData = legendData; + return legendData; + } + + let padding = opts.legend.padding; + let margin = opts.legend.margin; + let fontSize = opts.legend.fontSize; + let shapeWidth = 15 * opts.pixelRatio; + let shapeRight = 5 * opts.pixelRatio; + let lineHeight = Math.max(opts.legend.lineHeight * opts.pixelRatio, fontSize); + if (opts.legend.position == 'top' || opts.legend.position == 'bottom') { + let legendList = []; + let widthCount = 0; + let widthCountArr = []; + let currentRow = []; + for (let i = 0; i < series.length; i++) { + let item = series[i]; + let itemWidth = shapeWidth + shapeRight + measureText(item.name || 'undefined', fontSize) + opts.legend.itemGap; + if (widthCount + itemWidth > opts.width - opts.padding[1] - opts.padding[3]) { + legendList.push(currentRow); + widthCountArr.push(widthCount - opts.legend.itemGap); + widthCount = itemWidth; + currentRow = [item]; + } else { + widthCount += itemWidth; + currentRow.push(item); + } + } + if (currentRow.length) { + legendList.push(currentRow); + widthCountArr.push(widthCount - opts.legend.itemGap); + legendData.widthArr = widthCountArr; + let legendWidth = Math.max.apply(null, widthCountArr); + switch (opts.legend.float) { + case 'left': + legendData.area.start.x = opts.padding[3]; + legendData.area.end.x = opts.padding[3] + 2 * padding; + break; + case 'right': + legendData.area.start.x = opts.width - opts.padding[1] - legendWidth - 2 * padding; + legendData.area.end.x = opts.width - opts.padding[1]; + break; + default: + legendData.area.start.x = (opts.width - legendWidth) / 2 - padding; + legendData.area.end.x = (opts.width + legendWidth) / 2 + padding; + } + legendData.area.width = legendWidth + 2 * padding; + legendData.area.wholeWidth = legendWidth + 2 * padding; + legendData.area.height = legendList.length * lineHeight + 2 * padding; + legendData.area.wholeHeight = legendList.length * lineHeight + 2 * padding + 2 * margin; + legendData.points = legendList; + } + } else { + let len = series.length; + let maxHeight = opts.height - opts.padding[0] - opts.padding[2] - 2 * margin - 2 * padding; + let maxLength = Math.min(Math.floor(maxHeight / lineHeight), len); + legendData.area.height = maxLength * lineHeight + padding * 2; + legendData.area.wholeHeight = maxLength * lineHeight + padding * 2; + switch (opts.legend.float) { + case 'top': + legendData.area.start.y = opts.padding[0] + margin; + legendData.area.end.y = opts.padding[0] + margin + legendData.area.height; + break; + case 'bottom': + legendData.area.start.y = opts.height - opts.padding[2] - margin - legendData.area.height; + legendData.area.end.y = opts.height - opts.padding[2] - margin; + break; + default: + legendData.area.start.y = (opts.height - legendData.area.height) / 2; + legendData.area.end.y = (opts.height + legendData.area.height) / 2; + } + let lineNum = len % maxLength === 0 ? len / maxLength : Math.floor((len / maxLength) + 1); + let currentRow = []; + for (let i = 0; i < lineNum; i++) { + let temp = series.slice(i * maxLength, i * maxLength + maxLength); + currentRow.push(temp); + } + + legendData.points = currentRow; + + if (currentRow.length) { + for (let i = 0; i < currentRow.length; i++) { + let item = currentRow[i]; + let maxWidth = 0; + for (let j = 0; j < item.length; j++) { + let itemWidth = shapeWidth + shapeRight + measureText(item[j].name || 'undefined', fontSize) + opts.legend.itemGap; + if (itemWidth > maxWidth) { + maxWidth = itemWidth; + } + } + legendData.widthArr.push(maxWidth); + legendData.heightArr.push(item.length * lineHeight + padding * 2); + } + let legendWidth = 0 + for (let i = 0; i < legendData.widthArr.length; i++) { + legendWidth += legendData.widthArr[i]; + } + legendData.area.width = legendWidth - opts.legend.itemGap + 2 * padding; + legendData.area.wholeWidth = legendData.area.width + padding; + } + } + + switch (opts.legend.position) { + case 'top': + legendData.area.start.y = opts.padding[0] + margin; + legendData.area.end.y = opts.padding[0] + margin + legendData.area.height; + break; + case 'bottom': + legendData.area.start.y = opts.height - opts.padding[2] - legendData.area.height - margin; + legendData.area.end.y = opts.height - opts.padding[2] - margin; + break; + case 'left': + legendData.area.start.x = opts.padding[3]; + legendData.area.end.x = opts.padding[3] + legendData.area.width; + break; + case 'right': + legendData.area.start.x = opts.width - opts.padding[1] - legendData.area.width; + legendData.area.end.x = opts.width - opts.padding[1]; + break; + } + chartData.legendData = legendData; + return legendData; +} + +function calCategoriesData(categories, opts, config, eachSpacing) { + var result = { + angle: 0, + xAxisHeight: config.xAxisHeight + }; + var categoriesTextLenth = categories.map(function(item) { + return measureText(item); + }); + var maxTextLength = Math.max.apply(this, categoriesTextLenth); + + if (opts.xAxis.rotateLabel == true && maxTextLength + 2 * config.xAxisTextPadding > eachSpacing) { + result.angle = 45 * Math.PI / 180; + result.xAxisHeight = 2 * config.xAxisTextPadding + maxTextLength * Math.sin(result.angle); + } + return result; +} + +function getRadarDataPoints(angleList, center, radius, series, opts) { + var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1; + + var radarOption = opts.extra.radar || {}; + radarOption.max = radarOption.max || 0; + var maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series))); + + var data = []; + for (let i = 0; i < series.length; i++) { + let each = series[i]; + let listItem = {}; + listItem.color = each.color; + listItem.data = []; + each.data.forEach(function(item, index) { + let tmp = {}; + tmp.angle = angleList[index]; + + tmp.proportion = item / maxData; + tmp.position = convertCoordinateOrigin(radius * tmp.proportion * process * Math.cos(tmp.angle), radius * tmp.proportion * + process * Math.sin(tmp.angle), center); + listItem.data.push(tmp); + }); + + data.push(listItem); + } + + return data; +} + +function getPieDataPoints(series, radius) { + var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + + var count = 0; + var _start_ = 0; + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item.data = item.data === null ? 0 : item.data; + count += item.data; + } + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item.data = item.data === null ? 0 : item.data; + if (count === 0) { + item._proportion_ = 1 / series.length * process; + } else { + item._proportion_ = item.data / count * process; + } + item._radius_ = radius; + } + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item._start_ = _start_; + _start_ += 2 * item._proportion_ * Math.PI; + } + + return series; +} + +function getFunnelDataPoints(series, radius) { + var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + series = series.sort(function(a,b){return parseInt(b.data)-parseInt(a.data);}); + for (let i = 0; i < series.length; i++) { + series[i].radius = series[i].data/series[0].data*radius*process; + series[i]._proportion_ = series[i].data/series[0].data; + } + return series.reverse(); +} + +function getRoseDataPoints(series, type, minRadius, radius) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var count = 0; + var _start_ = 0; + + var dataArr = []; + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item.data = item.data === null ? 0 : item.data; + count += item.data; + dataArr.push(item.data); + } + + var minData = Math.min.apply(null, dataArr); + var maxData = Math.max.apply(null, dataArr); + var radiusLength = radius - minRadius; + + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item.data = item.data === null ? 0 : item.data; + if (count === 0 || type == 'area') { + item._proportion_ = item.data / count * process; + item._rose_proportion_ = 1 / series.length * process; + } else { + item._proportion_ = item.data / count * process; + item._rose_proportion_ = item.data / count * process; + } + item._radius_ = minRadius + radiusLength * ((item.data - minData) / (maxData - minData)); + } + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item._start_ = _start_; + _start_ += 2 * item._rose_proportion_ * Math.PI; + } + + return series; +} + +function getArcbarDataPoints(series, arcbarOption) { + var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + if (process == 1) { + process = 0.999999; + } + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item.data = item.data === null ? 0 : item.data; + let totalAngle; + if (arcbarOption.type == 'default') { + if (arcbarOption.endAngle < arcbarOption.startAngle) { + totalAngle = 2 + arcbarOption.endAngle - arcbarOption.startAngle; + } else{ + totalAngle = arcbarOption.startAngle - arcbarOption.endAngle; + } + } else { + totalAngle = 2; + } + item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle; + if (item._proportion_ >= 2) { + item._proportion_ = item._proportion_ % 2; + } + } + return series; +} + +function getGaugeAxisPoints(categories, startAngle, endAngle) { + let totalAngle = startAngle - endAngle + 1; + let tempStartAngle = startAngle; + for (let i = 0; i < categories.length; i++) { + categories[i].value = categories[i].value === null ? 0 : categories[i].value; + categories[i]._startAngle_ = tempStartAngle; + categories[i]._endAngle_ = totalAngle * categories[i].value + startAngle; + if (categories[i]._endAngle_ >= 2) { + categories[i]._endAngle_ = categories[i]._endAngle_ % 2; + } + tempStartAngle = categories[i]._endAngle_; + } + return categories; +} + +function getGaugeDataPoints(series, categories, gaugeOption) { + let process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1; + for (let i = 0; i < series.length; i++) { + let item = series[i]; + item.data = item.data === null ? 0 : item.data; + if (gaugeOption.pointer.color == 'auto') { + for (let i = 0; i < categories.length; i++) { + if (item.data <= categories[i].value) { + item.color = categories[i].color; + break; + } + } + } else { + item.color = gaugeOption.pointer.color; + } + let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1; + item._endAngle_ = totalAngle * item.data + gaugeOption.startAngle; + item._oldAngle_ = gaugeOption.oldAngle; + if (gaugeOption.oldAngle < gaugeOption.endAngle) { + item._oldAngle_ += 2; + } + if (item.data >= gaugeOption.oldData) { + item._proportion_ = (item._endAngle_ - item._oldAngle_) * process + gaugeOption.oldAngle; + } else { + item._proportion_ = item._oldAngle_ - (item._oldAngle_ - item._endAngle_) * process; + } + if (item._proportion_ >= 2) { + item._proportion_ = item._proportion_ % 2; + } + } + return series; +} + +function getPieTextMaxLength(series) { + series = getPieDataPoints(series); + let maxLength = 0; + for (let i = 0; i < series.length; i++) { + let item = series[i]; + let text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%'; + maxLength = Math.max(maxLength, measureText(text)); + } + + return maxLength; +} + +function fixColumeData(points, eachSpacing, columnLen, index, config, opts) { + return points.map(function(item) { + if (item === null) { + return null; + } + item.width = Math.ceil((eachSpacing - 2 * config.columePadding) / columnLen); + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } + if (item.width <= 0) { + item.width = 1; + } + item.x += (index + 0.5 - columnLen / 2) * item.width; + return item; + }); +} + +function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) { + return points.map(function(item) { + if (item === null) { + return null; + } + item.width = Math.ceil((eachSpacing - 2 * config.columePadding) / 2); + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } + + if (index > 0) { + item.width -= 2 * border; + } + return item; + }); +} + +function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts, series) { + + return points.map(function(item, indexn) { + + if (item === null) { + return null; + } + item.width = Math.ceil((eachSpacing - 2 * config.columePadding) / 2); + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } + return item; + }); +} + +function getXAxisPoints(categories, opts, config) { + var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth; + var spacingValid = opts.width - opts.area[1] - opts.area[3]; + var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length; + if((opts.type=='line' || opts.type=='area') && dataCount>1 && opts.xAxis.boundaryGap=='justify'){ + dataCount -=1; + } + var eachSpacing = spacingValid / dataCount; + + var xAxisPoints = []; + var startX = opts.area[3]; + var endX = opts.width - opts.area[1]; + categories.forEach(function(item, index) { + xAxisPoints.push(startX + index * eachSpacing); + }); + if(opts.xAxis.boundaryGap !=='justify'){ + if (opts.enableScroll === true) { + xAxisPoints.push(startX + categories.length * eachSpacing); + } else { + xAxisPoints.push(endX); + } + } + return { + xAxisPoints: xAxisPoints, + startX: startX, + endX: endX, + eachSpacing: eachSpacing + }; +} + +function getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) { + var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1; + var points = []; + var validHeight = opts.height - opts.area[0] - opts.area[2]; + data.forEach(function(item, index) { + if (item === null) { + points.push(null); + } else { + var cPoints = []; + item.forEach(function(items, indexs) { + var point = {}; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + var value = items.value || items; + var height = validHeight * (value - minRange) / (maxRange - minRange); + height *= process; + point.y = opts.height - Math.round(height) - opts.area[2]; + cPoints.push(point); + }); + points.push(cPoints); + } + }); + + return points; +} + +function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) { + var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1; + var boundaryGap='center'; + if (opts.type == 'line'||opts.type == 'area'){ + boundaryGap=opts.xAxis.boundaryGap; + } + var points = []; + var validHeight = opts.height - opts.area[0] - opts.area[2]; + data.forEach(function(item, index) { + if (item === null) { + points.push(null); + } else { + var point = {}; + point.color = item.color; + point.x = xAxisPoints[index]; + if(boundaryGap=='center'){ + point.x += Math.round(eachSpacing / 2); + } + var value = item; + if (typeof item === 'object' && item !== null) { + value = item.value + } + var height = validHeight * (value - minRange) / (maxRange - minRange); + height *= process; + point.y = opts.height - Math.round(height) - opts.area[2]; + points.push(point); + } + }); + + return points; +} + +function getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, stackSeries) { + var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1; + var points = []; + var validHeight = opts.height - opts.area[0] - opts.area[2]; + + data.forEach(function(item, index) { + if (item === null) { + points.push(null); + } else { + var point = {}; + point.color = item.color; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + + if (seriesIndex > 0) { + var value = 0; + for (let i = 0; i <= seriesIndex; i++) { + value += stackSeries[i].data[index]; + } + var value0 = value - item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + var height0 = validHeight * (value0 - minRange) / (maxRange - minRange); + } else { + var value = item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + var height0 = 0; + } + var heightc = height0; + height *= process; + heightc *= process; + point.y = opts.height - Math.round(height) - opts.area[2]; + point.y0 = opts.height - Math.round(heightc) - opts.area[2]; + points.push(point); + } + }); + + return points; +} + +function getYAxisTextList(series, opts, config, stack) { + var data; + if (stack == 'stack') { + data = dataCombineStack(series, opts.categories.length); + } else { + data = dataCombine(series); + } + var sorted = []; + // remove null from data + data = data.filter(function(item) { + //return item !== null; + if (typeof item === 'object' && item !== null) { + if (Array.isArray(item)) { + return item !== null; + } else { + return item.value !== null; + } + } else { + return item !== null; + } + }); + data.map(function(item) { + if (typeof item === 'object') { + if (Array.isArray(item)) { + item.map(function(subitem) { + sorted.push(subitem); + }) + } else { + sorted.push(item.value); + } + } else { + sorted.push(item); + } + }) + var minData = 0; + var maxData = 0; + if (sorted.length > 0) { + minData = Math.min.apply(this, sorted); + maxData = Math.max.apply(this, sorted); + } + if (typeof opts.yAxis.min === 'number') { + minData = Math.min(opts.yAxis.min, minData); + } + if (typeof opts.yAxis.max === 'number') { + maxData = Math.max(opts.yAxis.max, maxData); + } + + if (minData === maxData) { + var rangeSpan = maxData || 10; + maxData += rangeSpan; + } + + var dataRange = getDataRange(minData, maxData); + var minRange = dataRange.minRange; + var maxRange = dataRange.maxRange; + + var range = []; + var eachRange = (maxRange - minRange) / config.yAxisSplit; + + for (var i = 0; i <= config.yAxisSplit; i++) { + range.push(minRange + eachRange * i); + } + return range.reverse(); +} + +function calYAxisData(series, opts, config) { + //堆叠图重算Y轴 + var columnstyle = assign({}, { + type: "" + }, opts.extra.column); + var ranges = getYAxisTextList(series, opts, config, columnstyle.type); + var yAxisWidth = config.yAxisWidth; + var yAxisFontSize = opts.yAxis.fontSize || config.fontSize; + var rangesFormat = ranges.map(function(item) { + item = util.toFixed(item, 6); + item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item; + yAxisWidth = Math.max(yAxisWidth, measureText(item, yAxisFontSize) + 5); + return item; + }); + if (opts.yAxis.disabled === true) { + yAxisWidth = 0; + } + + return { + rangesFormat: rangesFormat, + ranges: ranges, + yAxisWidth: yAxisWidth + }; +} + +function calTooltipYAxisData(point, series, opts, config, eachSpacing) { + var ranges = getYAxisTextList(series, opts, config); + var spacingValid = opts.height - opts.area[0] - opts.area[2]; + let maxVal = ranges[0]; + let minVal = ranges[ranges.length - 1]; + let minAxis = opts.padding[3]; + let maxAxis = opts.padding[1] + spacingValid; + let item = maxVal - (maxVal - minVal) * (point - minAxis) / (maxAxis - minAxis); + item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item; + return item; +} + +function calMarkLineData(minRange, maxRange, points, opts) { + let spacingValid = opts.height - opts.area[0] - opts.area[2]; + for (let i = 0; i < points.length; i++) { + let height = spacingValid * (points[i].value - minRange) / (maxRange - minRange); + points[i].y = opts.height - Math.round(height) - opts.area[2]; + } + return points; +} + +function contextRotate(context, opts) { + if (opts.rotateLock !== true) { + context.translate(opts.height, 0); + context.rotate(90 * Math.PI / 180); + } else if (opts._rotate_ !== true) { + context.translate(opts.height, 0); + context.rotate(90 * Math.PI / 180); + opts._rotate_ = true; + } +} + +function drawPointShape(points, color, shape, context, opts) { + context.beginPath(); + context.setStrokeStyle("#ffffff"); + context.setLineWidth(1 * opts.pixelRatio); + context.setFillStyle(color); + if (shape === 'diamond') { + points.forEach(function(item, index) { + if (item !== null) { + context.moveTo(item.x, item.y - 4.5); + context.lineTo(item.x - 4.5, item.y); + context.lineTo(item.x, item.y + 4.5); + context.lineTo(item.x + 4.5, item.y); + context.lineTo(item.x, item.y - 4.5); + } + }); + } else if (shape === 'circle') { + points.forEach(function(item, index) { + if (item !== null) { + context.moveTo(item.x + 3.5 * opts.pixelRatio, item.y); + context.arc(item.x, item.y, 4 * opts.pixelRatio, 0, 2 * Math.PI, false); + } + }); + } else if (shape === 'rect') { + points.forEach(function(item, index) { + if (item !== null) { + context.moveTo(item.x - 3.5, item.y - 3.5); + context.rect(item.x - 3.5, item.y - 3.5, 7, 7); + } + }); + } else if (shape === 'triangle') { + points.forEach(function(item, index) { + if (item !== null) { + context.moveTo(item.x, item.y - 4.5); + context.lineTo(item.x - 4.5, item.y + 4.5); + context.lineTo(item.x + 4.5, item.y + 4.5); + context.lineTo(item.x, item.y - 4.5); + } + }); + } + context.closePath(); + context.fill(); + context.stroke(); +} + +function drawRingTitle(opts, config, context, center) { + var titlefontSize = opts.title.fontSize || config.titleFontSize; + var subtitlefontSize = opts.subtitle.fontSize || config.subtitleFontSize; + var title = opts.title.name || ''; + var subtitle = opts.subtitle.name || ''; + var titleFontColor = opts.title.color || config.titleColor; + var subtitleFontColor = opts.subtitle.color || config.subtitleColor; + var titleHeight = title ? titlefontSize : 0; + var subtitleHeight = subtitle ? subtitlefontSize : 0; + var margin = 5; + + if (subtitle) { + var textWidth = measureText(subtitle, subtitlefontSize); + var startX = center.x - textWidth / 2 + (opts.subtitle.offsetX || 0); + var startY = center.y + subtitlefontSize / 2 + (opts.subtitle.offsetY || 0); + if (title) { + startY += (titleHeight + margin) / 2; + } + context.beginPath(); + context.setFontSize(subtitlefontSize); + context.setFillStyle(subtitleFontColor); + context.fillText(subtitle, startX, startY); + context.closePath(); + context.stroke(); + } + if (title) { + var _textWidth = measureText(title, titlefontSize); + var _startX = center.x - _textWidth / 2 + (opts.title.offsetX || 0); + var _startY = center.y + titlefontSize / 2 + (opts.title.offsetY || 0); + if (subtitle) { + _startY -= (subtitleHeight + margin) / 2; + } + context.beginPath(); + context.setFontSize(titlefontSize); + context.setFillStyle(titleFontColor); + context.fillText(title, _startX, _startY); + context.closePath(); + context.stroke(); + } +} + +function drawPointText(points, series, config, context) { + // 绘制数据文案 + var data = series.data; + points.forEach(function(item, index) { + if (item !== null) { + //var formatVal = series.format ? series.format(data[index]) : data[index]; + context.beginPath(); + context.setFontSize(series.textSize || config.fontSize); + context.setFillStyle(series.textColor || '#666666'); + var value = data[index] + if (typeof data[index] === 'object' && data[index] !== null) { + value = data[index].value + } + var formatVal = series.format ? series.format(value) : value; + context.fillText(String(formatVal), item.x - measureText(formatVal, series.textSize || config.fontSize) / 2, item.y - + 2); + context.closePath(); + context.stroke(); + } + }); + +} + +function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) { + radius -= gaugeOption.width / 2 + config.gaugeLabelTextMargin; + + let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1; + let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber; + let totalNumber = gaugeOption.endNumber - gaugeOption.startNumber; + let splitNumber = totalNumber / gaugeOption.splitLine.splitNumber; + let nowAngle = gaugeOption.startAngle; + let nowNumber = gaugeOption.startNumber; + for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) { + var pos = { + x: radius * Math.cos(nowAngle * Math.PI), + y: radius * Math.sin(nowAngle * Math.PI) + }; + var labelText = gaugeOption.labelFormat ? gaugeOption.labelFormat(nowNumber) : nowNumber; + pos.x += centerPosition.x - measureText(labelText) / 2; + pos.y += centerPosition.y; + var startX = pos.x; + var startY = pos.y; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(gaugeOption.labelColor || '#666666'); + context.fillText(labelText, startX, startY + config.fontSize / 2); + context.closePath(); + context.stroke(); + + nowAngle += splitAngle; + if (nowAngle >= 2) { + nowAngle = nowAngle % 2; + } + nowNumber += splitNumber; + } + +} + +function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) { + var radarOption = opts.extra.radar || {}; + radius += config.radarLabelTextMargin; + + angleList.forEach(function(angle, index) { + var pos = { + x: radius * Math.cos(angle), + y: radius * Math.sin(angle) + }; + var posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition); + var startX = posRelativeCanvas.x; + var startY = posRelativeCanvas.y; + if (util.approximatelyEqual(pos.x, 0)) { + startX -= measureText(opts.categories[index] || '') / 2; + } else if (pos.x < 0) { + startX -= measureText(opts.categories[index] || ''); + } + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(radarOption.labelColor || '#666666'); + context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2); + context.closePath(); + context.stroke(); + }); + +} + +function drawPieText(series, opts, config, context, radius, center) { + var lineRadius = config.pieChartLinePadding; + var textObjectCollection = []; + var lastTextObject = null; + + var seriesConvert = series.map(function(item) { + var text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_.toFixed(4) * 100) +'%'; + if(item._rose_proportion_) item._proportion_=item._rose_proportion_; + var arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._proportion_ / 2); + var color = item.color; + var radius = item._radius_; + return { + arc: arc, + text: text, + color: color, + radius: radius, + textColor: item.textColor, + textSize: item.textSize, + }; + }); + for (let i = 0; i < seriesConvert.length; i++) { + let item = seriesConvert[i]; + // line end + let orginX1 = Math.cos(item.arc) * (item.radius + lineRadius); + let orginY1 = Math.sin(item.arc) * (item.radius + lineRadius); + + // line start + let orginX2 = Math.cos(item.arc) * item.radius; + let orginY2 = Math.sin(item.arc) * item.radius; + + // text start + let orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding; + let orginY3 = orginY1; + let textWidth = measureText(item.text); + let startY = orginY3; + + if (lastTextObject && util.isSameXCoordinateArea(lastTextObject.start, { + x: orginX3 + })) { + if (orginX3 > 0) { + startY = Math.min(orginY3, lastTextObject.start.y); + } else if (orginX1 < 0) { + startY = Math.max(orginY3, lastTextObject.start.y); + } else { + if (orginY3 > 0) { + startY = Math.max(orginY3, lastTextObject.start.y); + } else { + startY = Math.min(orginY3, lastTextObject.start.y); + } + } + } + if (orginX3 < 0) { + orginX3 -= textWidth; + } + + let textObject = { + lineStart: { + x: orginX2, + y: orginY2 + }, + lineEnd: { + x: orginX1, + y: orginY1 + }, + start: { + x: orginX3, + y: startY + }, + width: textWidth, + height: config.fontSize, + text: item.text, + color: item.color, + textColor: item.textColor, + textSize: item.textSize + }; + lastTextObject = avoidCollision(textObject, lastTextObject); + textObjectCollection.push(lastTextObject); + } + + for (let i = 0; i < textObjectCollection.length; i++) { + let item = textObjectCollection[i]; + let lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center); + let lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center); + let textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center); + context.setLineWidth(1 * opts.pixelRatio); + context.setFontSize(config.fontSize); + context.beginPath(); + context.setStrokeStyle(item.color); + context.setFillStyle(item.color); + context.moveTo(lineStartPoistion.x, lineStartPoistion.y); + let curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x; + let textStartX = item.start.x < 0 ? textPosition.x - 5 : textPosition.x + 5; + context.quadraticCurveTo(lineEndPoistion.x, lineEndPoistion.y, curveStartX, textPosition.y); + context.moveTo(lineStartPoistion.x, lineStartPoistion.y); + context.stroke(); + context.closePath(); + context.beginPath(); + context.moveTo(textPosition.x + item.width, textPosition.y); + context.arc(curveStartX, textPosition.y, 2, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + context.beginPath(); + context.setFontSize(item.textSize || config.fontSize); + context.setFillStyle(item.textColor || '#666666'); + context.fillText(item.text, textStartX, textPosition.y + 3); + context.closePath(); + context.stroke(); + context.closePath(); + } +} + +function drawToolTipSplitLine(offsetX, opts, config, context) { + var toolTipOption = opts.extra.tooltip || {}; + toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType; + toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength; + var startY = opts.area[0]; + var endY = opts.height - opts.area[2]; + + if (toolTipOption.gridType == 'dash') { + context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]); + } + context.setStrokeStyle(toolTipOption.gridColor || '#cccccc'); + context.setLineWidth(1 * opts.pixelRatio); + context.beginPath(); + context.moveTo(offsetX, startY); + context.lineTo(offsetX, endY); + context.stroke(); + context.setLineDash([]); + + if (toolTipOption.xAxisLabel) { + let labelText = opts.categories[opts.tooltip.index]; + context.setFontSize(config.fontSize); + let textWidth = measureText(labelText, config.fontSize); + + let textX = offsetX - 0.5 * textWidth; + let textY = endY; + context.beginPath(); + context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity || config.toolTipOpacity)); + context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground); + context.setLineWidth(1 * opts.pixelRatio); + context.rect(textX - config.toolTipPadding, textY, textWidth + 2 * config.toolTipPadding, config.fontSize + 2 * config.toolTipPadding); + context.closePath(); + context.stroke(); + context.fill(); + + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(toolTipOption.labelFontColor || config.fontColor); + context.fillText(String(labelText), textX, textY + config.toolTipPadding + config.fontSize); + context.closePath(); + context.stroke(); + } +} + +function drawMarkLine(minRange, maxRange, opts, config, context) { + let markLineOption = assign({}, { + type: 'solid', + dashLength: 4, + data: [] + }, opts.extra.markLine); + let startX = opts.area[3]; + let endX = opts.width - opts.padding[1]; + let points = calMarkLineData(minRange, maxRange, markLineOption.data, opts); + + for (let i = 0; i < points.length; i++) { + let item = assign({}, { + lineColor: '#DE4A42', + showLabel: false, + labelFontColor: '#666666', + labelBgColor: '#DFE8FF', + labelBgOpacity: 0.8, + yAxisIndex: 0 + }, points[i]); + + if (markLineOption.type == 'dash') { + context.setLineDash([markLineOption.dashLength, markLineOption.dashLength]); + } + context.setStrokeStyle(item.lineColor); + context.setLineWidth(1 * opts.pixelRatio); + context.beginPath(); + context.moveTo(startX, item.y); + context.lineTo(endX, item.y); + context.stroke(); + context.setLineDash([]); + if (item.showLabel) { + let labelText = opts.yAxis.format ? opts.yAxis.format(Number(item.value)) : item.value; + context.setFontSize(config.fontSize); + let textWidth = measureText(labelText, config.fontSize); + let bgStartX = opts.padding[3] + config.yAxisTitleWidth - config.toolTipPadding; + let bgEndX = Math.max(opts.area[3], textWidth + config.toolTipPadding * 2); + let bgWidth = bgEndX - bgStartX; + + let textX = bgStartX + (bgWidth - textWidth) / 2; + let textY = item.y; + context.setFillStyle(hexToRgb(item.labelBgColor, item.labelBgOpacity)); + context.setStrokeStyle(item.labelBgColor); + context.setLineWidth(1 * opts.pixelRatio); + context.beginPath(); + context.rect(bgStartX, textY - 0.5 * config.fontSize - config.toolTipPadding, bgWidth, config.fontSize + 2 * config.toolTipPadding); + context.closePath(); + context.stroke(); + context.fill(); + + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(item.labelFontColor); + context.fillText(String(labelText), textX, textY + 0.5 * config.fontSize); + context.stroke(); + } + } +} + +function drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints) { + var toolTipOption = assign({}, { + gridType: 'solid', + dashLength: 4 + }, opts.extra.tooltip); + + var startX = opts.area[3]; + var endX = opts.width - opts.padding[1]; + + if (toolTipOption.gridType == 'dash') { + context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]); + } + context.setStrokeStyle(toolTipOption.gridColor || '#cccccc'); + context.setLineWidth(1 * opts.pixelRatio); + context.beginPath(); + context.moveTo(startX, opts.tooltip.offset.y); + context.lineTo(endX, opts.tooltip.offset.y); + context.stroke(); + context.setLineDash([]); + + if (toolTipOption.yAxisLabel) { + let labelText = calTooltipYAxisData(opts.tooltip.offset.y, opts.series, opts, config, eachSpacing); + context.setFontSize(config.fontSize); + let textWidth = measureText(labelText, config.fontSize); + let bgStartX = opts.padding[3] + config.yAxisTitleWidth - config.toolTipPadding; + let bgEndX = Math.max(opts.area[3], textWidth + config.toolTipPadding * 2); + let bgWidth = bgEndX - bgStartX; + + let textX = bgStartX + (bgWidth - textWidth) / 2; + let textY = opts.tooltip.offset.y; + context.beginPath(); + context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity || config.toolTipOpacity)); + context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground); + context.setLineWidth(1 * opts.pixelRatio); + context.rect(bgStartX, textY - 0.5 * config.fontSize - config.toolTipPadding, bgWidth, config.fontSize + 2 * config.toolTipPadding); + context.closePath(); + context.stroke(); + context.fill(); + + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(toolTipOption.labelFontColor || config.fontColor); + context.fillText(labelText, textX, textY + 0.5 * config.fontSize); + context.closePath(); + context.stroke(); + } +} + +function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) { + var toolTipOption = assign({}, { + activeBgColor: '#000000', + activeBgOpacity: 0.08 + }, opts.extra.tooltip); + var startY = opts.area[0]; + var endY = opts.height - opts.area[2]; + context.beginPath(); + context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity)); + context.rect(offsetX - eachSpacing / 2, startY, eachSpacing, endY - startY); + context.closePath(); + context.fill(); +} + +function drawToolTip(textList, offset, opts, config, context, eachSpacing, xAxisPoints) { + var toolTipOption = assign({}, { + bgColor: '#000000', + bgOpacity: 0.7, + fontColor: '#FFFFFF' + }, opts.extra.tooltip); + var legendWidth = 4 * opts.pixelRatio; + var legendMarginRight = 5 * opts.pixelRatio; + var arrowWidth = 8 * opts.pixelRatio; + var isOverRightBorder = false; + if (opts.type == 'line' || opts.type == 'area' || opts.type == 'candle' || opts.type == 'mix') { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + + offset = assign({ + x: 0, + y: 0 + }, offset); + offset.y -= 8 * opts.pixelRatio; + var textWidth = textList.map(function(item) { + return measureText(item.text, config.fontSize); + }); + var toolTipWidth = legendWidth + legendMarginRight + 4 * config.toolTipPadding + Math.max.apply(null, textWidth); + var toolTipHeight = 2 * config.toolTipPadding + textList.length * config.toolTipLineHeight; + + // if beyond the right border + if (offset.x - Math.abs(opts._scrollDistance_) + arrowWidth + toolTipWidth > opts.width) { + isOverRightBorder = true; + } + if (toolTipHeight + offset.y > opts.height) { + offset.y = opts.height - toolTipHeight; + } + // draw background rect + context.beginPath(); + context.setFillStyle(hexToRgb(toolTipOption.bgColor || config.toolTipBackground, toolTipOption.bgOpacity || config.toolTipOpacity)); + if (isOverRightBorder) { + context.moveTo(offset.x, offset.y + 10 * opts.pixelRatio); + context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pixelRatio - 5 * opts.pixelRatio); + context.lineTo(offset.x - arrowWidth, offset.y); + context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y); + context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y + toolTipHeight); + context.lineTo(offset.x - arrowWidth, offset.y + toolTipHeight); + context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pixelRatio + 5 * opts.pixelRatio); + context.lineTo(offset.x, offset.y + 10 * opts.pixelRatio); + } else { + context.moveTo(offset.x, offset.y + 10 * opts.pixelRatio); + context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pixelRatio - 5 * opts.pixelRatio); + context.lineTo(offset.x + arrowWidth, offset.y); + context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y); + context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y + toolTipHeight); + context.lineTo(offset.x + arrowWidth, offset.y + toolTipHeight); + context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pixelRatio + 5 * opts.pixelRatio); + context.lineTo(offset.x, offset.y + 10 * opts.pixelRatio); + } + + context.closePath(); + context.fill(); + + // draw legend + textList.forEach(function(item, index) { + if (item.color !== null) { + context.beginPath(); + context.setFillStyle(item.color); + var startX = offset.x + arrowWidth + 2 * config.toolTipPadding; + var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + + config.toolTipPadding + 1; + if (isOverRightBorder) { + startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding; + } + context.fillRect(startX, startY, legendWidth, config.fontSize); + context.closePath(); + } + }); + + // draw text list + + textList.forEach(function(item, index) { + var startX = offset.x + arrowWidth + 2 * config.toolTipPadding + legendWidth + legendMarginRight; + if (isOverRightBorder) { + startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding + +legendWidth + legendMarginRight; + } + var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + + config.toolTipPadding; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(toolTipOption.fontColor); + context.fillText(item.text, startX, startY + config.fontSize); + context.closePath(); + context.stroke(); + }); +} + +function drawYAxisTitle(title, opts, config, context) { + var startX = config.xAxisHeight + (opts.height - config.xAxisHeight - measureText(title)) / 2; + context.save(); + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.yAxis.titleFontColor || '#333333'); + context.translate(0, opts.height); + context.rotate(-90 * Math.PI / 180); + context.fillText(title, startX, opts.padding[3] + 0.5 * config.fontSize); + context.closePath(); + context.stroke(); + context.restore(); +} + +function drawColumnDataPoints(series, opts, config, context) { + let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + let ranges = [].concat(opts.chartData.yAxisData.ranges); + let xAxisData = opts.chartData.xAxisData, + xAxisPoints = xAxisData.xAxisPoints, + eachSpacing = xAxisData.eachSpacing; + let columnOption = assign({}, { + type: 'group', + width: eachSpacing / 2, + meter: { + border: 4, + fillColor: '#FFFFFF' + } + }, opts.extra.column); + let minRange = ranges.pop(); + let maxRange = ranges.shift(); + let calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing); + } + + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + switch (columnOption.type) { + case 'group': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + var tooltipPoints = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series, process); + calPoints.push(tooltipPoints); + points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); + points.forEach(function(item, index) { + if (item !== null) { + context.beginPath(); + context.setStrokeStyle(item.color || eachSeries.color); + context.setLineWidth(1) + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2; + var height = opts.height - item.y - opts.area[2]; + context.moveTo(startX-1, item.y); + context.lineTo(startX+item.width-2,item.y); + context.lineTo(startX+item.width-2,opts.height - opts.area[2]); + context.lineTo(startX,opts.height - opts.area[2]); + context.lineTo(startX,item.y); + //context.rect(startX, item.y, item.width, height); + context.closePath(); + context.stroke(); + context.fill(); + } + }); + break; + case 'stack': + // 绘制堆叠数据图 + var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, + seriesIndex, + series, process); + calPoints.push(points); + points = fixColumeStackData(points, eachSpacing, series.length, seriesIndex, config, opts, series); + + points.forEach(function(item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - opts.area[2]; + var height0 = opts.height - item.y0 - opts.area[2]; + if (seriesIndex > 0) { + height -= height0; + } + context.moveTo(startX, item.y); + context.fillRect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + break; + case 'meter': + // 绘制温度计数据图 + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + points = fixColumeMeterData(points, eachSpacing, series.length, seriesIndex, config, opts, columnOption.meter + .border); + if (seriesIndex == 0) { + points.forEach(function(item, index) { + if (item !== null) { + //画背景颜色 + context.beginPath(); + context.setFillStyle(columnOption.meter.fillColor); + var startX = item.x - item.width / 2; + var height = opts.height - item.y - opts.area[2]; + context.moveTo(startX, item.y); + context.fillRect(startX, item.y, item.width, height); + context.closePath(); + context.fill(); + //画边框线 + if (columnOption.meter.border > 0) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(columnOption.meter.border * opts.pixelRatio); + context.moveTo(startX + columnOption.meter.border * 0.5, item.y + height); + context.lineTo(startX + columnOption.meter.border * 0.5, item.y + columnOption.meter.border * 0.5); + context.lineTo(startX + item.width - columnOption.meter.border * 0.5, item.y + columnOption.meter.border * 0.5); + context.lineTo(startX + item.width - columnOption.meter.border * 0.5, item.y + height); + context.stroke(); + } + } + }); + } else { + points.forEach(function(item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2; + var height = opts.height - item.y - opts.area[2]; + context.moveTo(startX, item.y); + context.fillRect(startX, item.y, item.width, height); + context.closePath(); + context.fill(); + } + }); + } + break; + } + }); + + if (opts.dataLabel !== false && process === 1) { + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + switch (columnOption.type) { + case 'group': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); + + drawPointText(points, eachSeries, config, context); + break; + case 'stack': + var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, + seriesIndex, + series, process); + drawPointText(points, eachSeries, config, context); + break; + case 'meter': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + break; + } + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing, + minRange: minRange, + maxRange: maxRange + }; +} + +function drawCandleDataPoints(series, seriesMA, opts, config, context) { + var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1; + var candleOption = assign({}, { + color: {}, + average: {} + }, opts.extra.candle); + candleOption.color = assign({}, { + upLine: '#f04864', + upFill: '#f04864', + downLine: '#2fc25b', + downFill: '#2fc25b' + }, candleOption.color); + candleOption.average = assign({}, { + show: false, + name: [], + day: [], + color: config.colors + }, candleOption.average); + opts.extra.candle = candleOption; + + let ranges = [].concat(opts.chartData.yAxisData.ranges); + let xAxisData = opts.chartData.xAxisData, + xAxisPoints = xAxisData.xAxisPoints, + eachSpacing = xAxisData.eachSpacing; + + let minRange = ranges.pop(); + let maxRange = ranges.shift(); + let calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + //画均线 + if (candleOption.average.show) { + seriesMA.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + //calPoints.push(points); + var splitPointList = splitPoints(points); + + splitPointList.forEach(function(points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(1); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + points.forEach(function(item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, + item.x, item + .y); + } + }); + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + }); + } + //画K线 + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + var splitPointList = splitPoints(points); + splitPointList = splitPointList[0]; + + splitPointList.forEach(function(points, index) { + context.beginPath(); + //如果上涨 + if (data[index][1] - data[index][0] > 0) { + context.setStrokeStyle(candleOption.color.upLine); + context.setFillStyle(candleOption.color.upFill); + context.setLineWidth(1 * opts.pixelRatio); + context.moveTo(points[3].x, points[3].y); //顶点 + context.lineTo(points[1].x, points[1].y); //收盘中间点 + context.lineTo(points[1].x - eachSpacing / 4, points[1].y); //收盘左侧点 + context.lineTo(points[0].x - eachSpacing / 4, points[0].y); //开盘左侧点 + context.lineTo(points[0].x, points[0].y); //开盘中间点 + context.lineTo(points[2].x, points[2].y); //底点 + context.lineTo(points[0].x, points[0].y); //开盘中间点 + context.lineTo(points[0].x + eachSpacing / 4, points[0].y); //开盘右侧点 + context.lineTo(points[1].x + eachSpacing / 4, points[1].y); //收盘右侧点 + context.lineTo(points[1].x, points[1].y); //收盘中间点 + context.moveTo(points[3].x, points[3].y); //顶点 + } else { + context.setStrokeStyle(candleOption.color.downLine); + context.setFillStyle(candleOption.color.downFill); + context.setLineWidth(1 * opts.pixelRatio); + context.moveTo(points[3].x, points[3].y); //顶点 + context.lineTo(points[0].x, points[0].y); //开盘中间点 + context.lineTo(points[0].x - eachSpacing / 4, points[0].y); //开盘左侧点 + context.lineTo(points[1].x - eachSpacing / 4, points[1].y); //收盘左侧点 + context.lineTo(points[1].x, points[1].y); //收盘中间点 + context.lineTo(points[2].x, points[2].y); //底点 + context.lineTo(points[1].x, points[1].y); //收盘中间点 + context.lineTo(points[1].x + eachSpacing / 4, points[1].y); //收盘右侧点 + context.lineTo(points[0].x + eachSpacing / 4, points[0].y); //开盘右侧点 + context.lineTo(points[0].x, points[0].y); //开盘中间点 + context.moveTo(points[3].x, points[3].y); //顶点 + } + context.closePath(); + context.fill(); + context.stroke(); + }); + }); + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing, + minRange: minRange, + maxRange: maxRange + }; +} + +function drawAreaDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var areaOption = assign({},{ + type: 'straight', + opacity: 0.2, + addLine: false, + width: 2 + },opts.extra.area); + + let ranges = [].concat(opts.chartData.yAxisData.ranges); + let xAxisData = opts.chartData.xAxisData, + xAxisPoints = xAxisData.xAxisPoints, + eachSpacing = xAxisData.eachSpacing; + + let minRange = ranges.pop(); + let maxRange = ranges.shift(); + let endY = opts.height - opts.area[2]; + let calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + series.forEach(function(eachSeries, seriesIndex) { + let data = eachSeries.data; + let points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + + let splitPointList = splitPoints(points); + + for (let i = 0; i < splitPointList.length; i++) { + let points = splitPointList[i]; + // 绘制区域数 + context.beginPath(); + context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity)); + context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity)); + context.setLineWidth(areaOption.width * opts.pixelRatio); + if (points.length > 1) { + let firstPoint = points[0]; + let lastPoint = points[points.length - 1]; + + context.moveTo(firstPoint.x, firstPoint.y); + if (areaOption.type === 'curve') { + points.forEach(function(item, index) { + if (index > 0) { + let ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y,item.x, item.y); + } + }); + } else { + points.forEach(function(item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + + context.lineTo(lastPoint.x, endY); + context.lineTo(firstPoint.x, endY); + context.lineTo(firstPoint.x, firstPoint.y); + } else { + let item = points[0]; + context.moveTo(item.x - eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, endY); + context.lineTo(item.x - eachSpacing / 2, endY); + context.moveTo(item.x - eachSpacing / 2, item.y); + } + context.closePath(); + context.fill(); + + //画连线 + if (areaOption.addLine) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(areaOption.width * opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (areaOption.type === 'curve') { + points.forEach(function(item, index) { + if (index > 0) { + let ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y,item.x,item.y); + } + }); + } else { + points.forEach(function(item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + } + } + + //画点 + if (opts.dataPointShape !== false) { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context, opts); + } + + }); + + if (opts.dataLabel !== false && process === 1) { + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing, + minRange: minRange, + maxRange: maxRange + }; +} + +function drawLineDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var lineOption = opts.extra.line || { + type: 'straight', + width: 2 + }; + lineOption.type = lineOption.type ? lineOption.type : 'straight'; + lineOption.width = lineOption.width ? lineOption.width : 2; + + let ranges = [].concat(opts.chartData.yAxisData.ranges); + let xAxisData = opts.chartData.xAxisData, + xAxisPoints = xAxisData.xAxisPoints, + eachSpacing = xAxisData.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + var splitPointList = splitPoints(points); + + splitPointList.forEach(function(points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(lineOption.width * opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (lineOption.type === 'curve') { + points.forEach(function(item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, + item.x, item + .y); + } + }); + } else { + points.forEach(function(item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + + if (opts.dataPointShape !== false) { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context, opts); + } + }); + + if (opts.dataLabel !== false && process === 1) { + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing, + minRange: minRange, + maxRange: maxRange + }; +} + +function drawMixDataPoints(series, opts, config, context) { + let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + let ranges = [].concat(opts.chartData.yAxisData.ranges); + let xAxisData = opts.chartData.xAxisData, + xAxisPoints = xAxisData.xAxisPoints, + eachSpacing = xAxisData.eachSpacing; + + let minRange = ranges.pop(); + let maxRange = ranges.shift(); + let endY = opts.height - opts.area[2]; + let calPoints = []; + + var columnIndex = 0; + var columnLength = 0; + series.forEach(function(eachSeries, seriesIndex) { + if (eachSeries.type == 'column') { + columnLength += 1; + } + }); + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + + // 绘制柱状数据图 + if (eachSeries.type == 'column') { + points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts); + points.forEach(function(item, index) { + if (item !== null) { + context.beginPath(); + context.setStrokeStyle(item.color || eachSeries.color); + context.setLineWidth(1) + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2; + var height = opts.height - item.y - opts.area[2]; + context.moveTo(startX, item.y); + context.moveTo(startX-1, item.y); + context.lineTo(startX+item.width-2,item.y); + context.lineTo(startX+item.width-2,opts.height - opts.area[2]); + context.lineTo(startX,opts.height - opts.area[2]); + context.lineTo(startX,item.y); + //context.rect(startX, item.y, item.width, height); + context.closePath(); + context.stroke(); + context.fill(); + context.closePath(); + context.fill(); + } + }); + columnIndex += 1; + } + + //绘制区域图数据 + + if (eachSeries.type == 'area') { + let splitPointList = splitPoints(points); + for (let i = 0; i < splitPointList.length; i++) { + let points = splitPointList[i]; + // 绘制区域数据 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setFillStyle(hexToRgb(eachSeries.color, 0.2)); + context.setLineWidth(2 * opts.pixelRatio); + if (points.length > 1) { + var firstPoint = points[0]; + let lastPoint = points[points.length - 1]; + context.moveTo(firstPoint.x, firstPoint.y); + if (eachSeries.style === 'curve') { + points.forEach(function(item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function(item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.lineTo(lastPoint.x, endY); + context.lineTo(firstPoint.x, endY); + context.lineTo(firstPoint.x, firstPoint.y); + } else { + let item = points[0]; + context.moveTo(item.x - eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, endY); + context.lineTo(item.x - eachSpacing / 2, endY); + context.moveTo(item.x - eachSpacing / 2, item.y); + } + context.closePath(); + context.fill(); + } + } + + // 绘制折线数据图 + if (eachSeries.type == 'line') { + var splitPointList = splitPoints(points); + splitPointList.forEach(function(points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2 * opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (eachSeries.style == 'curve') { + points.forEach(function(item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, + item.x, + item.y); + } + }); + } else { + points.forEach(function(item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + } + + // 绘制点数据图 + if (eachSeries.type == 'point') { + points.forEach(function(pointsa, index) { + if (pointsa) { + context.beginPath(); + context.setFillStyle(eachSeries.color); + context.setStrokeStyle('#FFFFFF'); + context.setLineWidth(1 * opts.pixelRatio); + context.moveTo(pointsa.x + 3.5 * opts.pixelRatio, pointsa.y); + context.arc(pointsa.x, pointsa.y, 4 * opts.pixelRatio, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + context.stroke(); + } + }); + } + + if (eachSeries.addPoint == true && eachSeries.type !== 'column') { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context, opts); + } + }); + if (opts.dataLabel !== false && process === 1) { + var columnIndex = 0; + series.forEach(function(eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + if (eachSeries.type !== 'column') { + drawPointText(points, eachSeries, config, context); + } else { + points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts); + drawPointText(points, eachSeries, config, context); + columnIndex += 1; + } + + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing, + minRange: minRange, + maxRange: maxRange + }; +} + +function drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints) { + var toolTipOption = opts.extra.tooltip || {}; + if (toolTipOption.horizentalLine && opts.tooltip && process === 1 && (opts.type == 'line' || opts.type == 'area' || opts.type == 'column' || opts.type == 'candle' || opts.type == 'mix')) { + drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints) + } + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTip(opts.tooltip.textList, opts.tooltip.offset, opts, config, context, eachSpacing, xAxisPoints); + } + context.restore(); + +} + +function drawXAxis(categories, opts, config, context) { + + let xAxisData = opts.chartData.xAxisData, + xAxisPoints = xAxisData.xAxisPoints, + startX = xAxisData.startX, + endX = xAxisData.endX, + eachSpacing = xAxisData.eachSpacing; + var boundaryGap='center'; + if (opts.type == 'line'||opts.type == 'area'){ + boundaryGap=opts.xAxis.boundaryGap; + } + var startY = opts.height - opts.area[2]; + var endY = opts.area[0]; + + //绘制滚动条 + if (opts.enableScroll && opts.xAxis.scrollShow) { + var scrollY = opts.height - opts.area[2] + config.xAxisHeight; + var scrollScreenWidth = endX - startX; + var scrollTotalWidth = eachSpacing * (xAxisPoints.length - 1); + var scrollWidth = scrollScreenWidth * scrollScreenWidth / scrollTotalWidth; + var scrollLeft = 0; + if (opts._scrollDistance_) { + scrollLeft = -opts._scrollDistance_ * (scrollScreenWidth) / scrollTotalWidth; + } + context.beginPath(); + context.setLineCap('round'); + context.setLineWidth(6 * opts.pixelRatio); + context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF"); + context.moveTo(startX, scrollY); + context.lineTo(endX, scrollY); + context.stroke(); + context.closePath(); + context.beginPath(); + context.setLineCap('round'); + context.setLineWidth(6 * opts.pixelRatio); + context.setStrokeStyle(opts.xAxis.scrollColor || "#A6A6A6"); + context.moveTo(startX + scrollLeft, scrollY); + context.lineTo(startX + scrollLeft + scrollWidth, scrollY); + context.stroke(); + context.closePath(); + context.setLineCap('butt'); + } + + context.save(); + + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) { + context.translate(opts._scrollDistance_, 0); + } + + + if (opts.xAxis.disableGrid !== true) { + context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc"); + context.setLineCap('butt'); + context.setLineWidth(1 * opts.pixelRatio); + if (opts.xAxis.gridType == 'dash') { + context.setLineDash([opts.xAxis.dashLength, opts.xAxis.dashLength]); + } + if (opts.xAxis.type === 'calibration') { + xAxisPoints.forEach(function(item, index) { + if (index > 0) { + context.beginPath(); + context.moveTo(item - eachSpacing / 2, startY); + context.lineTo(item - eachSpacing / 2, startY + 4 * opts.pixelRatio); + context.closePath(); + context.stroke(); + } + }); + } else { + opts.xAxis.gridEval = opts.xAxis.gridEval || 1; + xAxisPoints.forEach(function(item, index) { + if (index % opts.xAxis.gridEval == 0) { + context.beginPath(); + context.moveTo(item, startY); + context.lineTo(item, endY); + context.stroke(); + } + }); + } + context.setLineDash([]); + } + + + //不绘制X轴 + if (opts.xAxis.disabled !== true) { + // 对X轴列表做抽稀处理 + let validWidth = opts.width - opts.padding[1] - opts.padding[3] - config.yAxisWidth - config.yAxisTitleWidth; + //默认全部显示X轴标签 + let maxXAxisListLength = categories.length; + //如果设置了X轴单屏数量 + if (opts.xAxis.labelCount) { + //如果设置X轴密度 + if (opts.xAxis.itemCount) { + maxXAxisListLength = Math.ceil(categories.length / opts.xAxis.itemCount * opts.xAxis.labelCount); + } else { + maxXAxisListLength = opts.xAxis.labelCount; + } + maxXAxisListLength -= 1; + } + + let ratio = Math.ceil(categories.length / maxXAxisListLength); + + let newCategories = []; + let cgLength = categories.length; + for (let i = 0; i < cgLength; i++) { + if (i % ratio !== 0) { + newCategories.push(""); + } else { + newCategories.push(categories[i]); + } + } + newCategories[cgLength - 1] = categories[cgLength - 1]; + + var xAxisFontSize = opts.xAxis.fontSize || config.fontSize; + if (config._xAxisTextAngle_ === 0) { + newCategories.forEach(function(item, index) { + var offset = - measureText(item, xAxisFontSize) / 2; + if(boundaryGap == 'center'){ + offset+=eachSpacing / 2; + } + context.beginPath(); + context.setFontSize(xAxisFontSize); + context.setFillStyle(opts.xAxis.fontColor || '#666666'); + context.fillText(item, xAxisPoints[index] + offset, startY + xAxisFontSize + (config.xAxisHeight - xAxisFontSize) / 2); + context.closePath(); + context.stroke(); + }); + + } else { + newCategories.forEach(function(item, index) { + context.save(); + context.beginPath(); + context.setFontSize(xAxisFontSize); + context.setFillStyle(opts.xAxis.fontColor || '#666666'); + var textWidth = measureText(item); + var offset = - textWidth; + if(boundaryGap == 'center'){ + offset+=eachSpacing / 2; + } + var _calRotateTranslate = calRotateTranslate(xAxisPoints[index] + eachSpacing / 2, startY + xAxisFontSize / 2 + 5, opts.height), + transX = _calRotateTranslate.transX, + transY = _calRotateTranslate.transY; + + context.rotate(-1 * config._xAxisTextAngle_); + context.translate(transX, transY); + context.fillText(item, xAxisPoints[index] + offset, startY + xAxisFontSize + 5); + context.closePath(); + context.stroke(); + context.restore(); + }); + } + } + context.restore(); + +} + +function drawYAxisGrid(categories, opts, config, context) { + if (opts.yAxis.disableGrid === true) { + return; + } + let spacingValid = opts.height - opts.area[0] - opts.area[2]; + let eachSpacing = spacingValid / config.yAxisSplit; + let startX = opts.area[3]; + let xAxisPoints = opts.chartData.xAxisData.xAxisPoints, + xAxiseachSpacing = opts.chartData.xAxisData.eachSpacing; + let TotalWidth = xAxiseachSpacing * (xAxisPoints.length - 1); + let endX = startX + TotalWidth; + + let points = []; + for (let i = 0; i < config.yAxisSplit + 1; i++) { + points.push(opts.height - opts.area[2] - eachSpacing * i); + } + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.yAxis.gridType == 'dash') { + context.setLineDash([opts.yAxis.dashLength, opts.yAxis.dashLength]); + } + context.setStrokeStyle(opts.yAxis.gridColor || "#cccccc"); + context.setLineWidth(1 * opts.pixelRatio); + points.forEach(function(item, index) { + context.beginPath(); + context.moveTo(startX, item); + context.lineTo(endX, item); + context.stroke(); + }); + context.setLineDash([]); + + context.restore(); +} + +function drawYAxis(series, opts, config, context) { + if (opts.yAxis.disabled === true) { + return; + } + let rangesFormat = opts.chartData.yAxisData.rangesFormat; + var spacingValid = opts.height - opts.area[0] - opts.area[2]; + var eachSpacing = Math.floor(spacingValid / config.yAxisSplit); + var startX = opts.area[3]; + var endX = opts.width - opts.area[1]; + var endY = opts.height - opts.area[2]; + var fillEndY = endY + config.xAxisHeight; + if (opts.xAxis.scrollShow) { + fillEndY -= 3 * opts.pixelRatio; + } + // set YAxis background + context.beginPath(); + context.setFillStyle(opts.background || '#ffffff'); + if (opts._scrollDistance_ < 0) { + context.fillRect(0, 0, startX, fillEndY); + } + if(opts.enableScroll == true){ + context.fillRect(endX, 0, opts.width, fillEndY); + } + context.closePath(); + context.stroke(); + + var points = []; + for (var i = 0; i <= config.yAxisSplit; i++) { + points.push(opts.area[0] + eachSpacing * i); + } + + var yAxisFontSize = opts.yAxis.fontSize || config.fontSize; + rangesFormat.forEach(function(item, index) { + var pos = points[index] ? points[index] : endY; + context.beginPath(); + context.setFontSize(yAxisFontSize); + context.setFillStyle(opts.yAxis.fontColor || '#666666'); + context.fillText(String(item), opts.area[3] - config.yAxisWidth, pos + yAxisFontSize / 2); + context.closePath(); + context.stroke(); + }); + + if (opts.yAxis.title) { + drawYAxisTitle(opts.yAxis.title, opts, config, context); + } +} + +function drawLegend(series, opts, config, context, chartData) { + if (opts.legend.show === false) { + return; + } + let legendData = chartData.legendData; + let legendList = legendData.points; + let legendArea = legendData.area; + let padding = opts.legend.padding; + let fontSize = opts.legend.fontSize; + let shapeWidth = 15 * opts.pixelRatio; + let shapeRight = 5 * opts.pixelRatio; + let itemGap = opts.legend.itemGap; + let lineHeight = Math.max(opts.legend.lineHeight * opts.pixelRatio, fontSize); + + //画背景及边框 + context.beginPath(); + context.setLineWidth(opts.legend.borderWidth); + context.setStrokeStyle(opts.legend.borderColor); + context.setFillStyle(opts.legend.backgroundColor); + context.moveTo(legendArea.start.x, legendArea.start.y); + context.rect(legendArea.start.x, legendArea.start.y, legendArea.width, legendArea.height); + context.closePath(); + context.fill(); + context.stroke(); + + legendList.forEach(function(itemList, listIndex) { + let width = 0; + let height = 0; + width = legendData.widthArr[listIndex]; + height = legendData.heightArr[listIndex]; + let startX = 0; + let startY = 0; + if (opts.legend.position == 'top' || opts.legend.position == 'bottom') { + startX = legendArea.start.x + (legendArea.width - width) / 2; + startY = legendArea.start.y + padding + listIndex * lineHeight; + } else { + if (listIndex == 0) { + width = 0; + } else { + width = legendData.widthArr[listIndex - 1]; + } + startX = legendArea.start.x + padding + width; + startY = legendArea.start.y + padding + (legendArea.height - height) / 2; + } + + context.setFontSize(config.fontSize); + for (let i = 0; i < itemList.length; i++) { + let item = itemList[i]; + item.area = [0, 0, 0, 0]; + item.area[0] = startX; + item.area[1] = startY; + item.area[3] = startY + lineHeight; + context.beginPath(); + context.setLineWidth(1 * opts.pixelRatio); + context.setStrokeStyle(item.show ? item.color : opts.legend.hiddenColor); + context.setFillStyle(item.show ? item.color : opts.legend.hiddenColor); + switch (item.legendShape) { + case 'line': + context.moveTo(startX, startY + 0.5 * lineHeight - 2 * opts.pixelRatio); + context.fillRect(startX, startY + 0.5 * lineHeight - 2 * opts.pixelRatio, 15 * opts.pixelRatio, 4 * opts.pixelRatio); + break; + case 'triangle': + context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight - 5 * opts.pixelRatio); + context.lineTo(startX + 2.5 * opts.pixelRatio, startY + 0.5 * lineHeight + 5 * opts.pixelRatio); + context.lineTo(startX + 12.5 * opts.pixelRatio, startY + 0.5 * lineHeight + 5 * opts.pixelRatio); + context.lineTo(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight - 5 * opts.pixelRatio); + break; + case 'diamond': + context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight - 5 * opts.pixelRatio); + context.lineTo(startX + 2.5 * opts.pixelRatio, startY + 0.5 * lineHeight); + context.lineTo(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight + 5 * opts.pixelRatio); + context.lineTo(startX + 12.5 * opts.pixelRatio, startY + 0.5 * lineHeight); + context.lineTo(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight - 5 * opts.pixelRatio); + break; + case 'circle': + context.moveTo(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight); + context.arc(startX + 7.5 * opts.pixelRatio, startY + 0.5 * lineHeight, 5 * opts.pixelRatio, 0, 2 * Math.PI); + break; + case 'rect': + context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pixelRatio); + context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pixelRatio, 15 * opts.pixelRatio, 10 * opts.pixelRatio); + break; + default: + context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pixelRatio); + context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pixelRatio, 15 * opts.pixelRatio, 10 * opts.pixelRatio); + } + context.closePath(); + context.fill(); + context.stroke(); + + startX += shapeWidth + shapeRight; + let fontTrans = 0.5 * lineHeight + 0.5 * fontSize - 2; + context.beginPath(); + context.setFontSize(fontSize); + context.setFillStyle(item.show ? opts.legend.fontColor : opts.legend.hiddenColor); + context.fillText(item.name, startX, startY + fontTrans); + context.closePath(); + context.stroke(); + if (opts.legend.position == 'top' || opts.legend.position == 'bottom') { + startX += measureText(item.name, fontSize) + itemGap; + item.area[2] = startX; + } else { + item.area[2] = startX + measureText(item.name, fontSize) + itemGap;; + startX -= shapeWidth + shapeRight; + startY += lineHeight; + } + } + }); +} + +function drawPieDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var pieOption = assign({}, { + activeOpacity: 0.5, + activeRadius: 10 * opts.pixelRatio, + offsetAngle: 0, + labelWidth: 15 * opts.pixelRatio, + ringWidth: 0, + border:false, + borderWidth:2, + borderColor:'#FFFFFF' + }, opts.extra.pie); + var centerPosition = { + x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2, + y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2 + }; + if (config.pieChartLinePadding == 0) { + config.pieChartLinePadding = pieOption.activeRadius; + } + + var radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding); + + series = getPieDataPoints(series, radius, process); + + var activeRadius = pieOption.activeRadius; + + series = series.map(function(eachSeries) { + eachSeries._start_ += (pieOption.offsetAngle) * Math.PI / 180; + return eachSeries; + }); + series.forEach(function(eachSeries, seriesIndex) { + if (opts.tooltip) { + if (opts.tooltip.index == seriesIndex) { + context.beginPath(); + context.setFillStyle(hexToRgb(eachSeries.color, opts.extra.pie.activeOpacity || 0.5)); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_ + activeRadius, eachSeries._start_, + eachSeries._start_ + 2 * + eachSeries._proportion_ * Math.PI); + context.closePath(); + context.fill(); + } + } + context.beginPath(); + context.setLineWidth(pieOption.borderWidth * opts.pixelRatio); + context.lineJoin = "round"; + context.setStrokeStyle(pieOption.borderColor); + context.setFillStyle(eachSeries.color); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI); + context.closePath(); + context.fill(); + if (pieOption.border == true) { + context.stroke(); + } + }); + + if (opts.type === 'ring') { + var innerPieWidth = radius * 0.6; + if (typeof opts.extra.pie.ringWidth === 'number' && opts.extra.pie.ringWidth > 0) { + innerPieWidth = Math.max(0, radius - opts.extra.pie.ringWidth); + } + context.beginPath(); + context.setFillStyle(opts.background || '#ffffff'); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, innerPieWidth, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + } + + if (opts.dataLabel !== false && process === 1) { + var valid = false; + for (var i = 0, len = series.length; i < len; i++) { + if (series[i].data > 0) { + valid = true; + break; + } + } + + if (valid) { + drawPieText(series, opts, config, context, radius, centerPosition); + } + } + + if (process === 1 && opts.type === 'ring') { + drawRingTitle(opts, config, context, centerPosition); + } + + return { + center: centerPosition, + radius: radius, + series: series + }; +} + +function drawRoseDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var roseOption = assign({}, { + type: 'area', + activeOpacity: 0.5, + activeRadius: 10 * opts.pixelRatio, + offsetAngle: 0, + labelWidth: 15 * opts.pixelRatio, + border:false, + borderWidth:2, + borderColor:'#FFFFFF' + }, opts.extra.rose); + if (config.pieChartLinePadding == 0) { + config.pieChartLinePadding = roseOption.activeRadius; + } + var centerPosition = { + x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2, + y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2 + }; + var radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding); + var minRadius = roseOption.minRadius || radius * 0.5; + + series = getRoseDataPoints(series, roseOption.type, minRadius, radius, process); + + var activeRadius = roseOption.activeRadius; + + series = series.map(function(eachSeries) { + eachSeries._start_ += (roseOption.offsetAngle || 0) * Math.PI / 180; + return eachSeries; + }); + + series.forEach(function(eachSeries, seriesIndex) { + if (opts.tooltip) { + if (opts.tooltip.index == seriesIndex) { + context.beginPath(); + context.setFillStyle(hexToRgb(eachSeries.color, roseOption.activeOpacity || 0.5)); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, activeRadius + eachSeries._radius_, eachSeries._start_, + eachSeries._start_ + 2 * eachSeries._rose_proportion_ * Math.PI); + context.closePath(); + context.fill(); + } + } + context.beginPath(); + context.setLineWidth(roseOption.borderWidth * opts.pixelRatio); + context.lineJoin = "round"; + context.setStrokeStyle(roseOption.borderColor); + context.setFillStyle(eachSeries.color); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * + eachSeries._rose_proportion_ * Math.PI); + context.closePath(); + context.fill(); + if (roseOption.border == true) { + context.stroke(); + } + }); + + if (opts.dataLabel !== false && process === 1) { + var valid = false; + for (var i = 0, len = series.length; i < len; i++) { + if (series[i].data > 0) { + valid = true; + break; + } + } + + if (valid) { + drawPieText(series, opts, config, context, radius, centerPosition); + } + } + + return { + center: centerPosition, + radius: radius, + series: series + }; +} + +function drawArcbarDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var arcbarOption = assign({}, { + startAngle: 0.75, + endAngle: 0.25, + type: 'default', + width: 12 * opts.pixelRatio + }, opts.extra.arcbar); + + series = getArcbarDataPoints(series, arcbarOption, process); + var centerPosition = { + x: opts.width / 2, + y: opts.height / 2 + }; + var radius = Math.min(centerPosition.x, centerPosition.y); + radius -= 5 * opts.pixelRatio; + radius -= arcbarOption.width / 2; + + //背景颜色 + context.setLineWidth(arcbarOption.width); + context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9'); + context.setLineCap('round'); + context.beginPath(); + if (arcbarOption.type == 'default') { + context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * + Math.PI, false); + } else { + context.arc(centerPosition.x, centerPosition.y, radius, 0, 2 * Math.PI, false); + } + context.stroke(); + + for (let i = 0; i < series.length; i++) { + let eachSeries = series[i]; + context.setLineWidth(arcbarOption.width); + context.setStrokeStyle(eachSeries.color); + context.setLineCap('round'); + context.beginPath(); + context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ * + Math.PI, false); + context.stroke(); + } + + drawRingTitle(opts, config, context, centerPosition); + + return { + center: centerPosition, + radius: radius, + series: series + }; +} + +function drawGaugeDataPoints(categories, series, opts, config, context) { + var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1; + var gaugeOption = assign({}, { + startAngle: 0.75, + endAngle: 0.25, + width: 15, + splitLine: { + fixRadius: 0, + splitNumber: 10, + width: 15, + color: '#FFFFFF', + childNumber: 5, + childWidth: 5 + }, + pointer: { + width: 15, + color: 'auto' + } + }, opts.extra.gauge); + + if (gaugeOption.oldAngle == undefined) { + gaugeOption.oldAngle = gaugeOption.startAngle; + } + if (gaugeOption.oldData == undefined) { + gaugeOption.oldData = 0; + } + categories = getGaugeAxisPoints(categories, gaugeOption.startAngle, gaugeOption.endAngle); + + var centerPosition = { + x: opts.width / 2, + y: opts.height / 2 + }; + var radius = Math.min(centerPosition.x, centerPosition.y); + radius -= 5 * opts.pixelRatio; + radius -= gaugeOption.width / 2; + var innerRadius = radius - gaugeOption.width; + + //画背景 + context.setLineWidth(gaugeOption.width); + context.setLineCap('butt'); + for (let i = 0; i < categories.length; i++) { + let eachCategories = categories[i]; + context.beginPath(); + context.setStrokeStyle(eachCategories.color); + context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_ * Math.PI, eachCategories._endAngle_ * + Math.PI, false); + context.stroke(); + } + context.save(); + + //画刻度线 + let totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1; + let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber; + let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber; + let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius; + let endX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width; + let childendX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.childWidth; + + context.translate(centerPosition.x, centerPosition.y); + context.rotate((gaugeOption.startAngle - 1) * Math.PI); + + for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) { + context.beginPath(); + context.setStrokeStyle(gaugeOption.splitLine.color); + context.setLineWidth(2 * opts.pixelRatio); + context.moveTo(startX, 0); + context.lineTo(endX, 0); + context.stroke(); + context.rotate(splitAngle * Math.PI); + } + context.restore(); + + context.save(); + context.translate(centerPosition.x, centerPosition.y); + context.rotate((gaugeOption.startAngle - 1) * Math.PI); + + for (let i = 0; i < gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1; i++) { + context.beginPath(); + context.setStrokeStyle(gaugeOption.splitLine.color); + context.setLineWidth(1 * opts.pixelRatio); + context.moveTo(startX, 0); + context.lineTo(childendX, 0); + context.stroke(); + context.rotate(childAngle * Math.PI); + } + context.restore(); + + //画指针 + series = getGaugeDataPoints(series, categories, gaugeOption, process); + + for (let i = 0; i < series.length; i++) { + let eachSeries = series[i]; + context.save(); + context.translate(centerPosition.x, centerPosition.y); + context.rotate((eachSeries._proportion_ - 1) * Math.PI); + context.beginPath(); + context.setFillStyle(eachSeries.color); + context.moveTo(gaugeOption.pointer.width, 0); + context.lineTo(0, -gaugeOption.pointer.width / 2); + context.lineTo(-innerRadius, 0); + context.lineTo(0, gaugeOption.pointer.width / 2); + context.lineTo(gaugeOption.pointer.width, 0); + context.closePath(); + context.fill(); + context.beginPath(); + context.setFillStyle('#FFFFFF'); + context.arc(0, 0, gaugeOption.pointer.width / 6, 0, 2 * Math.PI, false); + context.fill(); + context.restore(); + } + + if (opts.dataLabel !== false) { + drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context); + } + + drawRingTitle(opts, config, context, centerPosition); + + if (process === 1 && opts.type === 'gauge') { + opts.extra.gauge.oldAngle = series[0]._proportion_; + opts.extra.gauge.oldData = series[0].data; + } + return { + center: centerPosition, + radius: radius, + innerRadius: innerRadius, + categories: categories, + totalAngle: totalAngle + }; +} + +function drawRadarDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var radarOption = assign({},{ + gridColor: '#cccccc', + labelColor: '#666666', + opacity: 0.2 + },opts.extra.radar); + + var coordinateAngle = getRadarCoordinateSeries(opts.categories.length); + + var centerPosition = { + x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2, + y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2 + }; + + var radius = Math.min(centerPosition.x - (getMaxTextListLength(opts.categories) + config.radarLabelTextMargin), + centerPosition.y - config.radarLabelTextMargin); + //TODO逻辑不对 + radius -= opts.padding[1]; + + // draw grid + context.beginPath(); + context.setLineWidth(1 * opts.pixelRatio); + context.setStrokeStyle(radarOption.gridColor); + coordinateAngle.forEach(function(angle) { + var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition); + context.moveTo(centerPosition.x, centerPosition.y); + context.lineTo(pos.x, pos.y); + }); + context.stroke(); + context.closePath(); + // draw split line grid + + var _loop = function _loop(i) { + var startPos = {}; + context.beginPath(); + context.setLineWidth(1 * opts.pixelRatio); + context.setStrokeStyle(radarOption.gridColor); + coordinateAngle.forEach(function(angle, index) { + var pos = convertCoordinateOrigin(radius / config.radarGridCount * i * Math.cos(angle), radius / config.radarGridCount * + i * Math.sin(angle), centerPosition); + if (index === 0) { + startPos = pos; + context.moveTo(pos.x, pos.y); + } else { + context.lineTo(pos.x, pos.y); + } + }); + context.lineTo(startPos.x, startPos.y); + context.stroke(); + context.closePath(); + }; + + for (var i = 1; i <= config.radarGridCount; i++) { + _loop(i); + } + + var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process); + + radarDataPoints.forEach(function(eachSeries, seriesIndex) { + // 绘制区域数据 + context.beginPath(); + context.setFillStyle(hexToRgb(eachSeries.color, radarOption.opacity)); + eachSeries.data.forEach(function(item, index) { + if (index === 0) { + context.moveTo(item.position.x, item.position.y); + } else { + context.lineTo(item.position.x, item.position.y); + } + }); + context.closePath(); + context.fill(); + + if (opts.dataPointShape !== false) { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + var points = eachSeries.data.map(function(item) { + return item.position; + }); + drawPointShape(points, eachSeries.color, shape, context, opts); + } + }); + // draw label text + drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context); + + return { + center: centerPosition, + radius: radius, + angleList: coordinateAngle + }; +} + +function normalInt(min, max, iter) { + iter = iter==0?1:iter; + var arr = []; + for (var i = 0; i < iter; i++) { + arr[i] = Math.random(); + }; + return Math.floor(arr.reduce(function(i,j){return i+j})/iter*(max-min))+min; +}; + +function collisionNew(area,points,width,height){ + var isIn=false; + for(let i=0;ipoints[i].area[2]||area[1]>points[i].area[3]||area[2]width || area[3]>height){ + isIn=true; + break; + }else{ + isIn=false; + } + }else{ + isIn=true; + break; + } + } + } + return isIn; +}; + +function getBoundingBox(data) { + var bounds = {}, coords; + bounds.xMin = 180; + bounds.xMax = 0; + bounds.yMin = 90; + bounds.yMax = 0 + for (var i = 0; i < data.length; i++) { + var coorda = data[i].geometry.coordinates + for (var k = 0; k < coorda.length; k++) { + coords = coorda[k]; + if (coords.length == 1) { + coords = coords[0] + } + for (var j = 0; j < coords.length; j++) { + var longitude = coords[j][0]; + var latitude = coords[j][1]; + var point = { + x: longitude, + y: latitude + } + bounds.xMin = bounds.xMin < point.x ? bounds.xMin : point.x; + bounds.xMax = bounds.xMax > point.x ? bounds.xMax : point.x; + bounds.yMin = bounds.yMin < point.y ? bounds.yMin : point.y; + bounds.yMax = bounds.yMax > point.y ? bounds.yMax : point.y; + } + } + } + return bounds; +} + +function coordinateToPoint(latitude, longitude,bounds,scale,xoffset,yoffset) { + return { + x: (longitude - bounds.xMin) * scale+xoffset, + y: (bounds.yMax - latitude) * scale+yoffset + }; +} + +function pointToCoordinate(pointY, pointX,bounds,scale,xoffset,yoffset) { + return { + x: (pointX-xoffset)/scale+bounds.xMin, + y: bounds.yMax - (pointY-yoffset)/scale + }; +} + +function isRayIntersectsSegment(poi,s_poi,e_poi){ + if (s_poi[1]==e_poi[1]){return false;} + if (s_poi[1]>poi[1] && e_poi[1]>poi[1]){return false;} + if (s_poi[1]poi[1]){return false;} + if (e_poi[1]==poi[1] && s_poi[1]>poi[1]){return false;} + if (s_poi[0]0.7) { + return true; + }else {return false}; + }; + for (let i = 0; i < points.length; i++) { + let text = points[i].name; + let tHeight = points[i].textSize; + let tWidth = measureText(text,tHeight); + let isSpin = Spin(); + let x,y,area,areav; + let breaknum=0; + while(true) { + breaknum++; + let isCollision; + if (isSpin) { + x = normalInt(-opts.width/2, opts.width/2,5) - tWidth/2; + y = normalInt(-opts.height/2, opts.height/2,5)+tHeight/2; + area=[y-5-tWidth+opts.width/2,(-x-5+opts.height/2),y+5+opts.width/2,(-x+tHeight+5+opts.height/2)]; + areav=[opts.width-(opts.width/2-opts.height/2)-(-x+tHeight+5+opts.height/2)-5,(opts.height/2-opts.width/2)+(y-5-tWidth+opts.width/2)-5,opts.width-(opts.width/2-opts.height/2)-(-x+tHeight+5+opts.height/2)+tHeight,(opts.height/2-opts.width/2)+(y-5-tWidth+opts.width/2)+tWidth+5]; + isCollision = collisionNew(areav,points,opts.height,opts.width); + }else{ + x = normalInt(-opts.width/2, opts.width/2,5) - tWidth/2; + y = normalInt(-opts.height/2, opts.height/2,5)+tHeight/2; + area=[x-5+opts.width/2,y-5-tHeight+opts.height/2,x+tWidth+5+opts.width/2,y+5+opts.height/2]; + isCollision = collisionNew(area,points,opts.width,opts.height); + } + if (!isCollision) break; + if (breaknum==1000){ + area=[-1000,-1000,-1000,-1000]; + break; + } + }; + if (isSpin) { + points[i].area=areav; + points[i].areav=area; + }else{ + points[i].area=area; + } + points[i].rotate=isSpin; + }; + break; + } + return points; +} + + +function drawWordCloudDataPoints(series, opts, config, context) { + let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + let wordOption = assign({},{ + type: 'normal', + autoColors: true + },opts.extra.word); + + context.beginPath(); + context.setFillStyle(opts.background||'#FFFFFF'); + context.rect(0,0,opts.width,opts.height); + context.fill(); + context.save(); + let points = opts.chartData.wordCloudData; + context.translate(opts.width/2,opts.height/2); + + for(let i=0;i0){ + if (opts.tooltip) { + if (opts.tooltip.index == i) { + context.strokeText(text,(points[i].areav[0]+5-opts.width/2)*process-tWidth*(1-process)/2,(points[i].areav[1]+5+tHeight-opts.height/2)*process); + }else{ + context.fillText(text,(points[i].areav[0]+5-opts.width/2)*process-tWidth*(1-process)/2,(points[i].areav[1]+5+tHeight-opts.height/2)*process); + } + }else{ + context.fillText(text,(points[i].areav[0]+5-opts.width/2)*process-tWidth*(1-process)/2,(points[i].areav[1]+5+tHeight-opts.height/2)*process); + } + } + }else{ + if(points[i].area[0]>0){ + if (opts.tooltip) { + if (opts.tooltip.index == i) { + context.strokeText(text,(points[i].area[0]+5-opts.width/2)*process-tWidth*(1-process)/2,(points[i].area[1]+5+tHeight-opts.height/2)*process); + }else{ + context.fillText(text,(points[i].area[0]+5-opts.width/2)*process-tWidth*(1-process)/2,(points[i].area[1]+5+tHeight-opts.height/2)*process); + } + }else{ + context.fillText(text,(points[i].area[0]+5-opts.width/2)*process-tWidth*(1-process)/2,(points[i].area[1]+5+tHeight-opts.height/2)*process); + } + + } + } + + context.stroke(); + context.restore(); + } + context.restore(); +} + +function drawFunnelDataPoints(series, opts, config, context) { + let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + let funnelOption = assign({},{ + activeWidth:10, + activeOpacity:0.3, + border:false, + borderWidth:2, + borderColor:'#FFFFFF', + fillOpacity:1, + labelAlign:'right' + },opts.extra.funnel); + let eachSpacing = (opts.height - opts.area[0] - opts.area[2])/series.length; + let centerPosition = { + x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2, + y: opts.height-opts.area[2] + }; + let activeWidth = funnelOption.activeWidth; + let radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - activeWidth, (opts.height - opts.area[0] - opts.area[2]) / 2 - activeWidth); + series = getFunnelDataPoints(series, radius, process); + context.save(); + context.translate(centerPosition.x,centerPosition.y); + for(let i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {}; + this.opts = assign({}, this.opts, data); + this.opts.updateData = true; + let scrollPosition = data.scrollPosition || 'current'; + switch (scrollPosition) { + case 'current': + this.opts._scrollDistance_ = this.scrollOption.currentOffset; + break; + case 'left': + this.opts._scrollDistance_ = 0; + this.scrollOption = { + currentOffset: 0, + startTouchX: 0, + distance: 0, + lastMoveTime: 0 + }; + break; + case 'right': + let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config), + yAxisWidth = _calYAxisData.yAxisWidth; + this.config.yAxisWidth = yAxisWidth; + let offsetLeft = 0; + let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config), + xAxisPoints = _getXAxisPoints0.xAxisPoints, + startX = _getXAxisPoints0.startX, + endX = _getXAxisPoints0.endX, + eachSpacing = _getXAxisPoints0.eachSpacing; + let totalWidth = eachSpacing * (xAxisPoints.length - 1); + let screenWidth = endX - startX; + offsetLeft = screenWidth - totalWidth; + this.scrollOption = { + currentOffset: offsetLeft, + startTouchX: offsetLeft, + distance: 0, + lastMoveTime: 0 + }; + this.opts._scrollDistance_ = offsetLeft; + break; + } + drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); +}; + +Charts.prototype.zoom = function() { + var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount; + if (this.opts.enableScroll !== true) { + console.log('请启用滚动条后使用!') + return; + } + //当前屏幕中间点 + let centerPoint = Math.round(Math.abs(this.scrollOption.currentOffset) / this.opts.chartData.eachSpacing) + Math.round( + this.opts.xAxis.itemCount / 2); + this.opts.animation = false; + this.opts.xAxis.itemCount = val.itemCount; + //重新计算x轴偏移距离 + let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config), + yAxisWidth = _calYAxisData.yAxisWidth; + this.config.yAxisWidth = yAxisWidth; + let offsetLeft = 0; + let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config), + xAxisPoints = _getXAxisPoints0.xAxisPoints, + startX = _getXAxisPoints0.startX, + endX = _getXAxisPoints0.endX, + eachSpacing = _getXAxisPoints0.eachSpacing; + let centerLeft = eachSpacing * centerPoint; + let screenWidth = endX - startX; + let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1); + offsetLeft = screenWidth / 2 - centerLeft; + if (offsetLeft > 0) { + offsetLeft = 0; + } + if (offsetLeft < MaxLeft) { + offsetLeft = MaxLeft; + } + this.scrollOption = { + currentOffset: offsetLeft, + startTouchX: offsetLeft, + distance: 0, + lastMoveTime: 0 + }; + this.opts._scrollDistance_ = offsetLeft; + drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); +}; + +Charts.prototype.stopAnimation = function() { + this.animationInstance && this.animationInstance.stop(); +}; + +Charts.prototype.addEventListener = function(type, listener) { + this.event.addEventListener(type, listener); +}; + +Charts.prototype.getCurrentDataIndex = function(e) { + var touches = null; + if (e.changedTouches) { + touches = e.changedTouches[0]; + } else { + touches = e.mp.changedTouches[0]; + } + if (touches) { + let _touches$ = getTouches(touches, this.opts, e); + if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose') { + return findPieChartCurrentIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts.chartData.pieData); + } else if (this.opts.type === 'radar') { + return findRadarChartCurrentIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts.chartData.radarData, this.opts.categories.length); + } else if (this.opts.type === 'funnel') { + return findFunnelChartCurrentIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts.chartData.funnelData); + } else if (this.opts.type === 'map') { + return findMapChartCurrentIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts); + }else if (this.opts.type === 'word') { + return findWordChartCurrentIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts.chartData.wordCloudData); + } else { + return findCurrentIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts.chartData.xAxisPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset)); + } + } + return -1; +}; + +Charts.prototype.getLegendDataIndex = function(e) { + var touches = null; + if (e.changedTouches) { + touches = e.changedTouches[0]; + } else { + touches = e.mp.changedTouches[0]; + } + if (touches) { + let _touches$ = getTouches(touches, this.opts, e); + return findLegendIndex({ + x: _touches$.x, + y: _touches$.y + }, this.opts.chartData.legendData); + } + return -1; +}; + +Charts.prototype.touchLegend = function(e) { + var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var touches = null; + if (e.changedTouches) { + touches = e.changedTouches[0]; + } else { + touches = e.mp.changedTouches[0]; + } + if (touches) { + var _touches$ = getTouches(touches, this.opts, e); + var index = this.getLegendDataIndex(e); + if (index >= 0) { + this.opts.series[index].show = !this.opts.series[index].show; + this.opts.animation = option.animation ? true : false; + drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); + } + } + +}; + +Charts.prototype.showToolTip = function(e) { + var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var touches = null; + if (e.changedTouches) { + touches = e.changedTouches[0]; + } else { + touches = e.mp.changedTouches[0]; + } + if (!touches) { + console.log("touchError"); + } + var _touches$ = getTouches(touches, this.opts, e); + var currentOffset = this.scrollOption.currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'column') { + var index = this.getCurrentDataIndex(e); + if (index > -1) { + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var _getToolTipData = getToolTipData(seriesData, this.opts.chartData.calPoints, index, this.opts.categories,option), + textList = _getToolTipData.textList, + offset = _getToolTipData.offset; + offset.y = _touches$.y; + opts.tooltip = { + textList: textList, + offset: offset, + option: option, + index: index + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } + if (this.opts.type === 'mix') { + var index = this.getCurrentDataIndex(e); + if (index > -1) { + var currentOffset = this.scrollOption.currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var _getMixToolTipData = getMixToolTipData(seriesData, this.opts.chartData.calPoints, index, this.opts.categories,option), + textList = _getMixToolTipData.textList, + offset = _getMixToolTipData.offset; + offset.y = _touches$.y; + opts.tooltip = { + textList: textList, + offset: offset, + option: option, + index: index + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } + if (this.opts.type === 'candle') { + var index = this.getCurrentDataIndex(e); + if (index > -1) { + var currentOffset = this.scrollOption.currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var _getToolTipData = getCandleToolTipData(this.opts.series[0].data, seriesData, this.opts.chartData.calPoints, + index, this.opts.categories, this.opts.extra.candle, option), + textList = _getToolTipData.textList, + offset = _getToolTipData.offset; + offset.y = _touches$.y; + opts.tooltip = { + textList: textList, + offset: offset, + option: option, + index: index + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } + if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose'||this.opts.type === 'funnel' ) { + var index = this.getCurrentDataIndex(e); + if (index > -1) { + var currentOffset = this.scrollOption.currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + var seriesData = this.opts._series_[index]; + var textList = [{ + text: option.format ? option.format(seriesData) : seriesData.name + ': ' + seriesData.data, + color: seriesData.color + }]; + var offset = { + x: _touches$.x, + y: _touches$.y + }; + opts.tooltip = { + textList: textList, + offset: offset, + option: option, + index: index + }; + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } + if (this.opts.type === 'map'||this.opts.type === 'word') { + var index = this.getCurrentDataIndex(e); + if (index > -1) { + var currentOffset = this.scrollOption.currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + var seriesData = this.opts._series_[index]; + var textList = [{ + text: option.format ? option.format(seriesData) : seriesData.properties.name , + color: seriesData.color + }]; + var offset = { + x: _touches$.x, + y: _touches$.y + }; + opts.tooltip = { + textList: textList, + offset: offset, + option: option, + index: index + }; + } + opts.updateData = false; + drawCharts.call(this, opts.type, opts, this.config, this.context); + } + if (this.opts.type === 'radar') { + var index = this.getCurrentDataIndex(e); + if (index > -1) { + var currentOffset = this.scrollOption.currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var textList = seriesData.map(function(item) { + return { + text: option.format ? option.format(item) : item.name + ': ' + item.data, + color: item.color + }; + }); + var offset = { + x: _touches$.x, + y: _touches$.y + }; + opts.tooltip = { + textList: textList, + offset: offset, + option: option, + index: index + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } +}; + +Charts.prototype.translate = function(distance) { + this.scrollOption = { + currentOffset: distance, + startTouchX: distance, + distance: 0, + lastMoveTime: 0 + }; + let opts = assign({}, this.opts, { + _scrollDistance_: distance, + animation: false + }); + drawCharts.call(this, this.opts.type, opts, this.config, this.context); +}; + +Charts.prototype.scrollStart = function(e) { + var touches = null; + if (e.changedTouches) { + touches = e.changedTouches[0]; + } else { + touches = e.mp.changedTouches[0]; + } + var _touches$ = getTouches(touches, this.opts, e); + if (touches && this.opts.enableScroll === true) { + this.scrollOption.startTouchX = _touches$.x; + } +}; + +Charts.prototype.scroll = function(e) { + if (this.scrollOption.lastMoveTime === 0) { + this.scrollOption.lastMoveTime = Date.now(); + } + let Limit = this.opts.extra.touchMoveLimit || 20; + let currMoveTime = Date.now(); + let duration = currMoveTime - this.scrollOption.lastMoveTime; + if (duration < Math.floor(1000 / Limit)) return; + this.scrollOption.lastMoveTime = currMoveTime; + var touches = null; + if (e.changedTouches) { + touches = e.changedTouches[0]; + } else { + touches = e.mp.changedTouches[0]; + } + if (touches && this.opts.enableScroll === true) { + var _touches$ = getTouches(touches, this.opts, e); + var _distance; + _distance = _touches$.x - this.scrollOption.startTouchX; + var currentOffset = this.scrollOption.currentOffset; + var validDistance = calValidDistance(currentOffset + _distance, this.opts.chartData, this.config, this.opts); + this.scrollOption.distance = _distance = validDistance - currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset + _distance, + animation: false + }); + drawCharts.call(this, opts.type, opts, this.config, this.context); + return currentOffset + _distance; + } +}; + +Charts.prototype.scrollEnd = function(e) { + if (this.opts.enableScroll === true) { + var _scrollOption = this.scrollOption, + currentOffset = _scrollOption.currentOffset, + distance = _scrollOption.distance; + this.scrollOption.currentOffset = currentOffset + distance; + this.scrollOption.distance = 0; + } +}; +if (typeof module === "object" && typeof module.exports === "object") { + module.exports = Charts; + //export default Charts;//建议使用nodejs的module导出方式,如报错请使用export方式导出 +} diff --git a/components/u-link/u-link.vue b/components/u-link/u-link.vue new file mode 100644 index 0000000..33f1e4f --- /dev/null +++ b/components/u-link/u-link.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/docs/AppConfigVersionPlan.md b/docs/AppConfigVersionPlan.md new file mode 100644 index 0000000..99a87eb --- /dev/null +++ b/docs/AppConfigVersionPlan.md @@ -0,0 +1,95 @@ +# 小程序接口与 WebView 版本一致性方案 + +## 目标 +- 小程序获取接口地址与 WebView 地址。 +- 判断版本一致性与可用性。 +- 不可用时提示用户退出小程序重新打开。 + +## 总体思路 +采用“配置中心 + 启动校验 + 缓存兜底 + 失效提示”的方案: +1. 小程序启动时请求配置中心接口获取最新配置。 +2. 校验小程序版本、API版本、WebView版本一致性。 +3. 校验失败则提示退出重启;通过则写入缓存并使用配置。 +4. 配置接口不可用时使用缓存,缓存失效则提示退出重启。 + +## 配置中心接口 +- 方法: `GET` +- 路径: `/api/open/app/config` + +### 返回示例 +```json +{ + "app": { + "minVersion": "1.2.0", + "latestVersion": "1.3.5", + "forceUpdate": true + }, + "api": { + "baseUrl": "https://api.xxx.com", + "version": "2026-03-16", + "minClientVersion": "1.2.0" + }, + "webview": { + "baseUrl": "https://m.xxx.com", + "version": "2026-03-16", + "minClientVersion": "1.2.0" + }, + "ttlSeconds": 3600, + "disabled": false, + "disableReason": "" +} +``` + +### 字段说明 +- `app.minVersion`: 最低可用小程序版本。 +- `app.latestVersion`: 最新版本号。 +- `app.forceUpdate`: 是否强制更新。 +- `api.baseUrl`: API 入口地址。 +- `api.version`: API 版本号(用于一致性校验)。 +- `api.minClientVersion`: API 允许的最小客户端版本。 +- `webview.baseUrl`: WebView 入口地址。 +- `webview.version`: WebView 版本号(用于一致性校验)。 +- `webview.minClientVersion`: WebView 允许的最小客户端版本。 +- `ttlSeconds`: 配置缓存有效期(秒)。 +- `disabled`: 服务下线开关。 +- `disableReason`: 下线原因。 + +## 小程序启动校验流程 +1. 小程序 `App.onLaunch` 请求 `/api/open/app/config`。 +2. 校验顺序: + - `disabled == true` → 提示“服务暂不可用,请退出小程序重新打开”。 + - `当前版本 < app.minVersion` → 提示强更并阻断。 + - `api.version != webview.version` → 提示“版本不一致,请退出小程序重新打开”。 + - `当前版本 < api.minClientVersion` 或 `当前版本 < webview.minClientVersion` → 提示强更。 +3. 校验通过: + - 缓存配置(本地 `storage`)。 + - 全局设置 API baseUrl 与 WebView baseUrl。 + +## 缓存与兜底策略 +- 配置接口失败: + - 如果本地缓存存在且未过期 → 使用缓存。 + - 若缓存过期或不存在 → 提示“配置获取失败,请退出小程序重新打开”。 + +## 提示文案建议 +- 版本不一致: + - “当前版本不一致,请退出小程序并重新打开以获取最新配置。” +- 服务不可用: + - “服务暂不可用,请退出小程序重新打开。” +- 配置获取失败: + - “配置获取失败,请退出小程序重新打开。” + +## WebView 入口处理 +- WebView URL 必须由配置中心下发,避免在客户端写死。 +- 进入 WebView 前再次校验缓存是否过期;过期则重新拉取。 + +## 前端需要完成的部分 +1. 在 `App.onLaunch` 拉取 `/api/open/app/config`,并写入本地缓存。 +2. 实现版本校验逻辑(`app.minVersion`、`api.version`、`webview.version`、`minClientVersion`)。 +3. 校验失败时弹窗提示,并引导退出小程序重新打开。 +4. 缓存过期或接口失败时,优先使用缓存;无缓存则提示退出。 +5. WebView 入口统一从配置下发的 `webview.baseUrl` 拼接跳转。 +6. 请求 API 时统一使用配置下发的 `api.baseUrl`。 + +## 可选扩展 +- 灰度策略:按用户或设备下发不同配置。 +- 公告字段:返回 `notice` 用于维护提示。 diff --git a/docs/Task1.md b/docs/Task1.md new file mode 100644 index 0000000..1a36318 --- /dev/null +++ b/docs/Task1.md @@ -0,0 +1,404 @@ +# UniApp + H5混合开发微信小程序 技术实施方案(UniApp端) +你希望通过UniApp开发微信小程序,以web-view嵌套H5承载核心业务展示,同时由UniApp原生层负责登录、退出、支付等核心能力,以下是UniApp端的详细技术实施方案,明确需要开发的核心模块、功能和关键逻辑。 + +## 一、整体架构与职责边界 +### 核心分工 +| 模块/能力 | UniApp(小程序端)负责 | H5端负责 | +|----------------|---------------------------------------------|--------------------------------| +| 用户身份 | 微信登录、token管理、用户信息存储、退出登录逻辑 | 接收并使用用户信息,触发退出登录指令 | +| 支付 | 调起微信支付、支付结果处理、支付状态同步 | 发起支付请求、展示支付结果 | +| 页面容器 | 提供tabBar框架、web-view容器、页面跳转控制 | 承载table栏、业务内容展示、内部页面跳转 | +| 通信 | 接收H5消息、主动向H5推送数据、处理通信异常 | 向UniApp发送指令、接收UniApp数据、展示状态反馈 | + +## 二、UniApp端核心开发内容 +### 1. 项目基础配置 +#### (1)全局配置(pages.json) +配置tabBar、页面路由、web-view权限等核心配置: +```json +{ + "pages": [ + // 登录页 + "pages/login/login", + // tabBar主页面(嵌套web-view) + "pages/index/index", + // 其他tabBar页面(如需) + "pages/my/my" + ], + "tabBar": { + "color": "#666666", + "selectedColor": "#007AFF", + "backgroundColor": "#ffffff", + "borderStyle": "black", + "list": [ + { + "pagePath": "pages/index/index", + "text": "首页", + "iconPath": "static/tabbar/home.png", + "selectedIconPath": "static/tabbar/home-active.png" + }, + { + "pagePath": "pages/my/my", + "text": "我的", + "iconPath": "static/tabbar/my.png", + "selectedIconPath": "static/tabbar/my-active.png" + } + ] + }, + "permission": { + "scope.userLocation": { + "desc": "你的位置信息将用于小程序定位" + } + }, + "webview": { + "webviewParameter": { + "allowUniversalAccessFromFileURLs": true, + "allowFileAccess": true + } + } +} +``` + +#### (2)微信小程序配置(manifest.json) +开启微信小程序相关权限,配置AppID等: +```json +{ + "mp-weixin": { + "appid": "你的微信小程序AppID", + "setting": { + "urlCheck": false, // 允许访问非域名白名单的H5(开发阶段,正式需配置白名单) + "es6": true, + "postcss": true + }, + "usingComponents": true, + "permission": { + "scope.userInfo": { + "desc": "获取你的用户信息用于登录" + } + } + } +} +``` + +### 2. 核心页面开发 +#### (1)登录页(pages/login/login.vue) +负责微信授权登录、获取用户信息、token存储: +```vue + + + + + +``` + +#### (2)tabBar首页(pages/index/index.vue) +核心容器页,嵌套web-view、处理与H5的通信: +```vue + + + + + +``` + +#### (3)“我的”页面(pages/my/my.vue) +可选,如需原生展示用户信息、退出按钮等: +```vue + + + + + +``` + +### 3. 全局工具类(可选) +封装通信、登录校验等通用方法,便于复用: +```js +// common/utils.js +/** + * 向H5发送消息 + * @param {String} webViewId web-view的ID + * @param {Object} msg 消息内容 + */ +export const sendMsgToH5 = (webViewId, msg) => { + const webViewCtx = uni.createWebViewContext(webViewId); + webViewCtx.postMessage({ data: msg }); +}; + +/** + * 校验登录态 + * @returns {Boolean} 是否已登录 + */ +export const checkLogin = () => { + const token = uni.getStorageSync('wx_token'); + if (!token) { + uni.redirectTo({ url: '/pages/login/login' }); + return false; + } + return true; +}; +``` + +### 4. 关键注意事项 +1. **域名白名单配置**:微信小程序后台需配置H5域名、后端接口域名的白名单,否则无法访问; +2. **通信格式统一**:UniApp与H5的通信消息需约定固定格式(如`{type: 'xxx', data: 'xxx'}`),避免解析异常; +3. **支付权限**:确保小程序已开通微信支付权限,后端支付接口需正确对接微信支付商户平台; +4. **登录态同步**:H5页面刷新时,需重新从UniApp获取登录态(可通过URL参数或postMessage); +5. **兼容性**:web-view组件在微信小程序中部分JS API有限制,需避免在H5中调用小程序专属API(如支付、登录)。 + +## 总结 +UniApp端核心开发内容可归纳为3个关键点: +1. **基础层**:配置tabBar、页面路由、微信小程序权限,搭建整体框架; +2. **核心能力层**:开发登录页实现微信授权登录,在web-view容器页处理与H5的通信,封装支付、退出登录等核心逻辑; +3. **保障层**:统一通信格式、配置域名白名单、处理登录态同步,确保混合开发模式稳定运行。 diff --git a/docs/Task2.md b/docs/Task2.md new file mode 100644 index 0000000..043a29d --- /dev/null +++ b/docs/Task2.md @@ -0,0 +1,18 @@ +在 @App.vue里,链接一些工具, 类似 +``` +import Request from "@/common/request"; + +const request = new Request(); +export default { + Tool:{ + Request: request, + }, +} +``` + +这样之后在其他页面,只需要调用 +``` +const app = getApp() +app.Tool.Request.get(...) +``` +是不是就可以用了?你看一下可行性,可以的话把目前的 Rquest这样试试一下,再加一个 接口地址的静态变量工具,避免接口地址在代码里分散管理,需要做集中管理。 diff --git a/docs/Task3.md b/docs/Task3.md new file mode 100644 index 0000000..57cf2c2 --- /dev/null +++ b/docs/Task3.md @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + +
    + + + + + + + + +个人中心 - 领航专升本志愿通 + + + + + + + + + + +
    +
    +

    个人中心

    +
    +settings +notifications +
    +
    +
    +
    +
    +
    +
    +verified +
    +
    +
    +

    领航学子

    +
    +普通用户 + +stars + 未激活会员 + +
    +
    + +
    +
    + +
    +
    +
    +

    12

    +

    志愿数量

    +
    +
    +
    +

    342

    +

    全省排名

    +
    +
    +
    +

    85%

    +

    录取概率

    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/docs/WeChatMiniLogin.md b/docs/WeChatMiniLogin.md new file mode 100644 index 0000000..7764bb5 --- /dev/null +++ b/docs/WeChatMiniLogin.md @@ -0,0 +1,109 @@ +# 微信小程序登录接口文档 + +## 概述 +- 接口用于微信小程序登录,前端通过 `code` 换取 `openid/session_key`,后端自动创建或更新 `t_user` 与 `t_platform_user`。 +- 成功后返回用户ID与平台用户ID,供前端后续业务使用。 + +## 基础信息 +- 方法: `POST` +- 路径: `/api/open/wechat/mini/login` +- Content-Type: `application/json` + +## 请求头 +- `Content-Type: application/json` +- `Authorization`: 不需要(已加入登录白名单) +- 安全校验(当 `security.enable: true` 时必须): + - `X-App-Timestamp`: 毫秒时间戳 + - `X-App-Sign`: MD5(`timestamp` + `secret_key`) + +## 请求参数 +| 字段 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| code | string | 是 | 微信登录 `wx.login` 返回的 `code` | +| phoneCode | string | 否 | 快速手机号登录返回的 `phoneCode`(优先使用) | +| encryptedData | string | 否 | `getPhoneNumber` 返回的加密数据 | +| iv | string | 否 | `getPhoneNumber` 返回的解密向量 | +| nickname | string | 否 | 用户昵称 | +| avatarUrl | string | 否 | 用户头像URL | +| phone | string | 否 | 手机号(不传或空字符串将写入为 NULL) | +| gender | int | 否 | 性别:0-未知,1-男,2-女 | +| platformExtra | object | 否 | 平台扩展字段(如城市、语言等) | + +### 请求示例 +```json +{ + "code": "wx_login_code", + "phoneCode": "8064f569d035bf3a9b4c7fc223bbbc589bf442c0557e0ae51039031d883668f5", + "encryptedData": "EZyKBdrHgQoAjgMDPNGXRGOjsPrB8LHcupwFCztA3IBNvbdkrSsk6iU6FqQsrn5TfpMJeTzHJ2l7lg6e+EBqqDXVgVEgQxkTWlxBS6mwUN4NgRI2FanA0wPFAWMZGmn7jKgEJhu8xKGSihcI111Y/mq+3T6gDzjZvkz32MhngL5/wBEjDQbBdBXfvY6FveyV7CinM0j17wE7pbjNIFrExw==", + "iv": "DMzzMUAx5ke1S8nFItBHSg==", + "nickname": "张三", + "avatarUrl": "https://example.com/avatar.png", + "phone": "13800000000", + "gender": 1, + "platformExtra": { + "city": "Shenzhen", + "language": "zh_CN" + } +} +``` + +## 响应参数 +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| userId | int64 | 用户ID(t_user.id) | +| platformUserId | int64 | 平台用户ID(t_platform_user.id) | +| openid | string | 微信 openid | +| unionid | string | 微信 unionid(可能为空) | +| sessionKey | string | 微信 session_key | +| phone | string | 手机号(如成功获取) | +| token | string | 登录令牌(用于鉴权) | +| isNewPlatform | bool | 是否新创建平台用户 | +| isNewUser | bool | 是否新创建用户 | + +### 成功响应示例 +```json +{ + "code": 200, + "message": "success", + "data": { + "userId": 10001, + "platformUserId": 20001, + "openid": "oL1oU5gS6Q...", + "unionid": "o6_bmasdasds...", + "sessionKey": "HKq6lZzG2u...", + "phone": "13800000000", + "token": "c6f7f1e4-5a3b-4f4e-9d0b-6b3f7b8c5e3a", + "isNewPlatform": false, + "isNewUser": false + } +} +``` + +## 错误响应示例 +```json +{ + "code": 400, + "message": "微信接口错误: 40163 code been used", + "data": null +} +``` + +## 业务说明 +- 首次登录时会创建 `t_user` 与 `t_platform_user`。 +- 之后登录会更新 `platform_session_key`、`last_login_time`,并按需更新 `nickname/avatarUrl/gender/phone`。 +- `phoneCode` 优先于 `encryptedData+iv` 用于获取手机号;两者都不提供时不更新手机号。 +- 返回 `token` 可直接用于鉴权(`Authorization: Bearer `)。 +- 若 `wechat.mini_program.app_id/app_secret` 未配置,将返回错误。 + +## 配置说明 +配置文件中新增: +```yaml +wechat: + mini_program: + app_id: "wx_your_app_id" + app_secret: "wx_your_app_secret" +``` + +## 相关配置与限制 +- 若启用安全校验(`security.enable: true`),该接口仍需携带签名头。 +- 默认未做登录态发放(如需 JWT/Token,可在接口层扩展)。 diff --git a/docs/login_page.md b/docs/login_page.md new file mode 100644 index 0000000..0883ebf --- /dev/null +++ b/docs/login_page.md @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    +polymer +
    +
    +

    品牌小程序

    +

    连接精彩生活,发现无限可能

    +
    +
    +
    + + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + +用户服务协议 + + + + +
    +
    + +

    用户服务协议

    +
    +
    + + +
    +
    +
    + +
    +
    +
    +

    一、前言

    +
    +
    +

    + 欢迎您使用我们的服务。本协议是用户(以下简称“您”)与公司之间关于使用产品及服务(以下简称“本服务”)所订立的权利义务规范。 +

    +

    + 在注册或使用本服务前,请您务必审慎阅读并充分理解本协议各条款内容,特别是免除或者限制责任的条款、法律适用和争议解决条款。当您按照注册页面提示填写信息、阅读并同意本协议且完成全部注册程序后,即表示您已充分阅读、理解并接受本协议的全部内容。 +

    +
    +
    + +
    +
    +
    +

    二、服务内容

    +
    +
    +

    + 1. 本公司向用户提供包括但不限于信息存储空间、搜索、社区交流、电子商务等技术服务。具体服务内容以届时实际提供的功能为准。 +

    +

    + 2. 用户理解并同意,本公司有权根据业务发展需要,随时对服务内容进行变更、中止或终止,而无需提前通知用户,但法律法规另有规定的除外。 +

    +
    +

    + 注意:部分增值服务可能涉及收费,我们将会在相应页面进行明确提示,用户可根据需求自主选择。 +

    +
    +
    +
    + +
    +
    +
    +

    三、用户行为规范

    +
    +
    +
    +security +
    +

    账号安全

    +

    用户应当妥善保管账号及密码,对其账号下发生的一切活动承担法律责任。不得将账号转让、出借、出租或售卖给他人。

    +
    +
    +
    +gavel +
    +

    合法使用

    +

    用户在使用本服务时,必须遵守法律法规,不得利用本服务制作、复制、发布、传播违法违规信息或从事非法活动。

    +
    +
    +
    +copyright +
    +

    知识产权

    +

    用户在平台上发布的原创内容,其著作权归用户本人所有,但用户授权本公司在全球范围内拥有免费的、永久的、不可撤销的非独占使用许可。

    +
    +
    +
    +
    + +
    +
    +
    +

    四、免责声明

    +
    +
    +
      +
    • +info +鉴于网络服务的特殊性,用户同意本公司有权随时变更、中断或终止部分或全部的网络服务。 +
    • +
    • +info +本公司不保证网络服务一定能满足用户的要求,也不保证网络服务不会中断。 +
    • +
    • +info +对于因不可抗力或本公司不能控制的原因造成的网络服务中断或其他缺陷,本公司不承担任何责任,但将尽力减少因此而给用户造成的损失和影响。 +
    • +
    +
    +
    +
    + +
    +

    更新日期:2023年10月24日

    +

    生效日期:2023年10月24日

    +
    + + +
    +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + +
    + +
    +

    个人信息保护政策

    +

    + 我们非常重视您的个人信息保护。本指引将详细说明我们如何收集、使用、共享及保护您的信息,请您务必仔细阅读并理解。 +

    +
    + +
    + +
    +
    +data_usage +

    一、我们如何收集信息

    +
    +

    为了向您提供基本服务,我们需要收集以下必要信息:

    +
    +
    +check_circle +
    +

    账号基础信息

    +

    手机号码、头像、昵称等用于身份验证的信息。

    +
    +
    +
    +check_circle +
    +

    设备及网络信息

    +

    IP地址、设备型号、操作系统版本、唯一设备标识符。

    +
    +
    +
    +check_circle +
    +

    位置及日志信息

    +

    在使用特定功能时,经您授权收集的地理位置信息。

    +
    +
    +
    +
    + +
    +
    +analytics +

    二、我们如何使用信息

    +
    +
      +
    • +01. +

      服务提供:利用收集的信息实现软件的基本功能与核心服务。

      +
    • +
    • +02. +

      安全保障:用于身份验证、客户服务、安全防范及诈骗监测。

      +
    • +
    • +03. +

      产品改进:通过数据分析优化产品体验,开发新的功能模块。

      +
    • +
    +
    + +
    +
    +share +

    三、我们如何共享信息

    +
    +

    + 我们不会向第三方转让您的个人信息,除非获得您的明确同意或法律法规另有规定。在以下情形中,我们可能会共享信息: +

    +
    +第三方SDK集成 +关联公司业务合规 +法律程序要求 +
    +
    + +
    +
    +shield +

    四、我们如何保护您的信息

    +
    +
    +

    + 我们采用行业领先的安全技术(如SSL加密传输、匿名化处理)来保护您的信息不被泄露、毁损或丢失。 +

    +

    + 我们建立了专门的管理制度、流程和组织以保障信息的安全。严格限制访问信息的人员范围,并要求他们履行保密义务。 +

    +
    +
    + +
    +
    + + + +
    +
    +
    + +
    +

    最近更新日期:2023年10月27日

    +

    © 2023 隐私保护中心 版权所有

    +
    +
    + \ No newline at end of file diff --git a/docs/user_password_login.md b/docs/user_password_login.md new file mode 100644 index 0000000..8c49235 --- /dev/null +++ b/docs/user_password_login.md @@ -0,0 +1,70 @@ +# 手机号+密码登录接口文档 + +## 概述 +用于移动端/前端通过手机号和密码登录,成功后返回 `token` 与用户信息,后续请求携带 `Authorization: Bearer `。 + +## 基础信息 +- 方法: `POST` +- 路径: `/api/open/user/login` +- Content-Type: `application/json` + +## 请求头 +- `Content-Type: application/json` +- `Authorization`: 不需要(已加入登录白名单) +- 安全校验(当 `security.enable: true` 时必须): + - `X-App-Timestamp`: 毫秒时间戳 + - `X-App-Sign`: MD5(`timestamp` + `secret_key`) + +## 请求参数 +| 字段 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| phone | string | 是 | 手机号 | +| password | string | 是 | 密码 | + +### 请求示例 +```json +{ + "phone": "13800000000", + "password": "your_password" +} +``` + +## 响应参数 +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| token | string | 登录令牌 | +| user | object | 登录用户信息(基础字段) | + +### 成功响应示例 +```json +{ + "code": 200, + "message": "success", + "data": { + "token": "c6f7f1e4-5a3b-4f4e-9d0b-6b3f7b8c5e3a", + "user": { + "id": "10001", + "username": "13800000000", + "realname": "张三", + "avatar": "https://oss-xxx/avatar.png", + "phone": "13800000000", + "email": "", + "token": "c6f7f1e4-5a3b-4f4e-9d0b-6b3f7b8c5e3a" + } + } +} +``` + +## 错误响应示例 +```json +{ + "code": 401, + "message": "手机号或密码错误", + "data": null +} +``` + +## 备注 +- 需要在 `t_user` 中预先设置 `password` 与 `salt`。 +- 密码加密方式与系统一致:`common.Encrypt(phone, rawPassword, salt)`。 +- token 默认 24 小时过期(Redis)。 diff --git a/docs/user_profile.md b/docs/user_profile.md new file mode 100644 index 0000000..4882919 --- /dev/null +++ b/docs/user_profile.md @@ -0,0 +1,76 @@ +# 登录后获取用户信息接口文档 + +## 概述 +登录成功后,前端携带 `token` 调用该接口获取用户基础信息与平台扩展信息(头像、昵称、性别、地区等)。 + +## 基础信息 +- 方法: `GET` +- 路径: `/api/user/profile` +- Content-Type: `application/json` + +## 请求头 +- `Authorization: Bearer ` + +## 请求参数(Query) +| 字段 | 类型 | 必填 | 说明 | +| --- | --- | --- | --- | +| platformType | int | 否 | 平台类型,默认 `1`(微信小程序) | + +### 请求示例 +``` +GET /api/user/profile?platformType=1 +Authorization: Bearer +``` + +## 响应参数 +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| userId | int64 | 用户ID(t_user.id) | +| username | string | 用户名 | +| nickname | string | 昵称 | +| avatarUrl | string | 头像URL | +| phone | string | 手机号 | +| gender | int | 性别:0-未知,1-男,2-女 | +| region | string | 地区(优先 `platform_extra.region`,否则拼接国家/省/市) | +| platformType | int | 平台类型 | +| platformOpenid | string | 平台 openid | +| platformUnionid | string | 平台 unionid | +| platformExtra | object | 平台扩展字段(原样返回) | + +### 成功响应示例 +```json +{ + "code": 200, + "message": "success", + "data": { + "userId": 10001, + "username": "wx_20260315121500_ab12cd34", + "nickname": "张三", + "avatarUrl": "https://oss-xxx/avatar.png", + "phone": "13800000000", + "gender": 1, + "region": "中国 广东 深圳", + "platformType": 1, + "platformOpenid": "oL1oU5gS6Q...", + "platformUnionid": "o6_bmasdasds...", + "platformExtra": { + "country": "中国", + "province": "广东", + "city": "深圳" + } + } +} +``` + +## 错误响应示例 +```json +{ + "code": 401, + "message": "未登录", + "data": null +} +``` + +## 备注 +- 需要先登录并获取 `token`。 +- `platformExtra` 为空时,`region` 可能为空。 diff --git a/h5/home.html b/h5/home.html new file mode 100644 index 0000000..ec8675f --- /dev/null +++ b/h5/home.html @@ -0,0 +1,10 @@ + + + + + +
    + 这里是h5的Home页面 +
    + + \ No newline at end of file diff --git a/h5/index.html b/h5/index.html new file mode 100644 index 0000000..5095b45 --- /dev/null +++ b/h5/index.html @@ -0,0 +1,10 @@ + + + + + +
    + 这里是h5的首页 +
    + + \ No newline at end of file diff --git a/h5/my.html b/h5/my.html new file mode 100644 index 0000000..0db962d --- /dev/null +++ b/h5/my.html @@ -0,0 +1,180 @@ + + + + + + 我的 + + + +
    +

    H5 我的

    +
    +
    收到的文本
    + +
    +
    +
    用户信息
    + +
    +
    + + +
    +
    该页面通过 postMessage 与 uni-app web-view 通信
    +
    + + + + diff --git a/h5/python_test/auto_submit.py b/h5/python_test/auto_submit.py new file mode 100644 index 0000000..ff7ab9a --- /dev/null +++ b/h5/python_test/auto_submit.py @@ -0,0 +1,47 @@ +from playwright.sync_api import sync_playwright + +URL = "https://psy5mp.xinliyun.cn/" +ID_CARD = "410323200512060159" +PASSWORD = "000000" + +LOGIN_ID_INPUT = "#van-field-1-input" +LOGIN_PWD_INPUT = "#van-field-2-input" +LOGIN_BTN = "#app > div > form > div.form-act > button" + +PAPER_ENTRY = "#app > div > div.layout-content > div.van-cell.van-cell--center.van-cell--clickable > div" +PAPER_START = "#app > div > div.paper-desc > div.paper-act.van-safe-area-bottom > button" + +FIRST_OPTION = "#app > div > div.paper-quiz-wrapper > div.paper-detail > div.van-radio-group > div > div:nth-child(1)" + + +def main() -> None: + with sync_playwright() as p: + browser = p.chromium.launch(headless=False) + page = browser.new_page() + + page.goto(URL, wait_until="domcontentloaded") + + # 登录 + page.fill(LOGIN_ID_INPUT, ID_CARD) + page.fill(LOGIN_PWD_INPUT, PASSWORD) + page.click(LOGIN_BTN) + + # 进入待测量表列表 + page.wait_for_selector(PAPER_ENTRY) + page.click(PAPER_ENTRY) + + # 进入测评介绍页并开始 + page.wait_for_selector(PAPER_START) + page.click(PAPER_START) + + # 连续选择第一个选项 90 次 + for _ in range(90): + page.wait_for_selector(FIRST_OPTION) + page.click(FIRST_OPTION) + + page.wait_for_timeout(1000) + browser.close() + + +if __name__ == "__main__": + main() diff --git a/h5/python_test/test.md b/h5/python_test/test.md new file mode 100644 index 0000000..a626ace --- /dev/null +++ b/h5/python_test/test.md @@ -0,0 +1,59 @@ +# 使用 Python 实现浏览器自动化提交表单 + +下面示例使用 Playwright(同步 API)自动完成登录、进入测评、并连续点击选项 90 次。 + +## 环境准备 +```bash +python -m pip install playwright +playwright install +``` + +## 示例脚本 +```python +from playwright.sync_api import sync_playwright + +URL = "https://psy5mp.xinliyun.cn/" +ID_CARD = "410323200512060159" +PASSWORD = "000000" + +LOGIN_ID_INPUT = "#van-field-1-input" +LOGIN_PWD_INPUT = "#van-field-2-input" +LOGIN_BTN = "#app > div > form > div.form-act > button" + +PAPER_ENTRY = "#app > div > div.layout-content > div.van-cell.van-cell--center.van-cell--clickable > div" +PAPER_START = "#app > div > div.paper-desc > div.paper-act.van-safe-area-bottom > button" + +FIRST_OPTION = "#app > div > div.paper-quiz-wrapper > div.paper-detail > div.van-radio-group > div > div:nth-child(1)" + +with sync_playwright() as p: + browser = p.chromium.launch(headless=False) + page = browser.new_page() + + page.goto(URL, wait_until="domcontentloaded") + + # 登录 + page.fill(LOGIN_ID_INPUT, ID_CARD) + page.fill(LOGIN_PWD_INPUT, PASSWORD) + page.click(LOGIN_BTN) + + # 进入待测量表列表 + page.wait_for_selector(PAPER_ENTRY) + page.click(PAPER_ENTRY) + + # 进入测评介绍页并开始 + page.wait_for_selector(PAPER_START) + page.click(PAPER_START) + + # 连续选择第一个选项 90 次 + for _ in range(90): + page.wait_for_selector(FIRST_OPTION) + page.click(FIRST_OPTION) + + page.wait_for_timeout(1000) + browser.close() +``` + +## 备注 +- 如果页面切换很慢,可在关键步骤之间增加 `page.wait_for_timeout(500)`。 +- 如果元素选择器变动,优先在浏览器开发者工具中更新选择器。 +- 如需无头模式,将 `headless=False` 改为 `True`。 diff --git a/h5/test.html b/h5/test.html new file mode 100644 index 0000000..e58d14a --- /dev/null +++ b/h5/test.html @@ -0,0 +1,200 @@ + + + + + + +个人中心 - 领航专升本志愿通 + + + + + + + + + + +
    +
    +

    个人中心

    +
    +settings +notifications +
    +
    +
    +
    +
    +
    +
    +verified +
    +
    +
    +

    领航学子

    +
    +普通用户 + +stars + 未激活会员 + +
    +
    + +
    +
    + +
    +
    +
    +

    12

    +

    志愿数量

    +
    +
    +
    +

    342

    +

    全省排名

    +
    +
    +
    +

    85%

    +

    录取概率

    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/hybrid/html/issue-17581.html b/hybrid/html/issue-17581.html new file mode 100644 index 0000000..b235ffc --- /dev/null +++ b/hybrid/html/issue-17581.html @@ -0,0 +1,55 @@ + + + + + + 点击显示小点 + + + + + + + + diff --git a/hybrid/html/local.html b/hybrid/html/local.html new file mode 100644 index 0000000..75e563e --- /dev/null +++ b/hybrid/html/local.html @@ -0,0 +1,88 @@ + + + + + + 本地网页 + + + +

    web-view 组件加载本地 html 示例,仅在 App 环境下生效。点击下列按钮,跳转至其它页面。

    +
    + + + + + +
    +

    网页向应用发送消息。注意:小程序端应用会在此页面后退时接收到消息。

    +
    + +
    + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..208afd9 --- /dev/null +++ b/index.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + +
    + + + diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..96c1fce --- /dev/null +++ b/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + testTimeout: 20000, + reporters: [ + 'default' + ], + watchPathIgnorePatterns: ['/node_modules/', '/dist/', '/.git/'], + moduleFileExtensions: ['js', 'json'], + rootDir: __dirname, + testMatch: ["/pages/**/*test.[jt]s?(x)"], + testPathIgnorePatterns: ['/node_modules/'] +} diff --git a/main.js b/main.js new file mode 100644 index 0000000..ff49fde --- /dev/null +++ b/main.js @@ -0,0 +1,44 @@ +import App from './App' +import store from './store' + +// #ifndef VUE3 +import Vue from 'vue' +Vue.config.productionTip = false +Vue.prototype.$store = store +Vue.prototype.$adpid = "1111111111" +Vue.prototype.$backgroundAudioData = { + playing: false, + playTime: 0, + formatedPlayTime: '00:00:00' +} +App.mpType = 'app' +const app = new Vue({ + store, + ...App +}) +app.$mount() +// #endif + +// #ifdef VUE3 +import { + createSSRApp +} from 'vue' +import * as Pinia from 'pinia'; +import Vuex from "vuex"; +export function createApp() { + const app = createSSRApp(App) + app.use(store) + app.use(Pinia.createPinia()); + app.config.globalProperties.$adpid = "1111111111" + app.config.globalProperties.$backgroundAudioData = { + playing: false, + playTime: 0, + formatedPlayTime: '00:00:00' + } + return { + app, + Vuex, // 如果 nvue 使用 vuex 的各种map工具方法时,必须 return Vuex + Pinia // 此处必须将 Pinia 返回 + } +} +// #endif diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..99cc33c --- /dev/null +++ b/manifest.json @@ -0,0 +1,191 @@ +{ + "name" : "uniapp-demo-new", + "appid" : "", + "description" : "应用描述", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + "app-plus" : { + "usingComponents" : true, + "nvueCompiler" : "uni-app", + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "nvueLaunchMode" : "fast", + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : { + "OAuth" : {}, + "Payment" : {}, + "Push" : {}, + "Share" : {}, + "Speech" : {}, + "VideoPlayer" : {} + }, + "distribute" : { + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios" : { + "UIBackgroundModes" : [ "audio" ], + "urlschemewhitelist" : [ "baidumap", "iosamap" ] + }, + "sdkConfigs" : { + "speech" : { + "ifly" : {} + } + }, + "orientation" : [ "portrait-primary" ] + }, + "uniStatistics" : { + "enable" : true + } + }, + "quickapp" : {}, + "quickapp-native" : { + "icon" : "/static/logo.png", + "package" : "com.example.demo", + "features" : [ + { + "name" : "system.clipboard" + } + ] + }, + "quickapp-webview" : { + "icon" : "/static/logo.png", + "package" : "com.example.demo", + "minPlatformVersion" : 1070, + "versionName" : "1.0.0", + "versionCode" : 100 + }, + "mp-weixin" : { + "appid" : "wxb9cf28f42ffa35e5", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true, + "permission" : { + "scope.userLocation" : { + "desc" : "演示定位能力" + } + }, + "uniStatistics" : { + "enable" : true + } + }, + "mp-alipay" : { + "usingComponents" : true, + "uniStatistics" : { + "enable" : true + } + }, + "mp-baidu" : { + "usingComponents" : true, + "uniStatistics" : { + "enable" : true + }, + "dynamicLib" : { + "editorLib" : { + "provider" : "swan-editor" + } + } + }, + "mp-toutiao" : { + "usingComponents" : true, + "uniStatistics" : { + "enable" : true + } + }, + "mp-jd" : { + "usingComponents" : true, + "uniStatistics" : { + "enable" : true + } + }, + "h5" : { + "template" : "template.h5.html", + "router" : { + "mode" : "history", + "base" : "" + }, + "sdkConfigs" : { + "maps" : { + "qqmap" : { + "key" : "TKUBZ-D24AF-GJ4JY-JDVM2-IBYKK-KEBCU" + } + } + }, + "async" : { + "timeout" : 20000 + }, + "uniStatistics" : { + "enable" : true + } + }, + "vueVersion" : "3", + "mp-kuaishou" : { + "uniStatistics" : { + "enable" : true + } + }, + "mp-lark" : { + "uniStatistics" : { + "enable" : true + } + }, + "mp-qq" : { + "uniStatistics" : { + "enable" : true + } + }, + "quickapp-webview-huawei" : { + "uniStatistics" : { + "enable" : true + } + }, + "quickapp-webview-union" : { + "uniStatistics" : { + "enable" : true + } + }, + "uniStatistics" : { + "version" : "2", + "enable" : true + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7cb4d31 --- /dev/null +++ b/package.json @@ -0,0 +1,133 @@ +{ + "id": "hello-uniapp", + "name": "hello-uniapp", + "displayName": "hello-uniapp 示例工程", + "version": "3.4.9", + "description": "uni-app 框架示例,一套代码,同时发行到iOS、Android、H5、小程序等多个平台,请使用手机扫码快速体验 uni-app 的强大功能", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": "https://github.com/dcloudio/hello-uniapp.git", + "keywords": [ + "hello-uniapp", + "uni-app", + "uni-ui", + "示例工程" +], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/dcloudio/hello-uniapp/issues" + }, + "homepage": "https://github.com/dcloudio/hello-uniapp#readme", + "dependencies": {}, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "uniapp-template-project", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "√", + "aliyun": "√", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "√", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "√", + "kuaishou": "√", + "jd": "√", + "harmony": "√", + "qq": "√", + "lark": "√" + }, + "quickapp": { + "huawei": "-", + "union": "-" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + }, + "uni-app": { + "scripts": { + "mp-dingtalk": { + "title": "钉钉小程序", + "env": { + "UNI_PLATFORM": "mp-alipay" + }, + "define": { + "MP-DINGTALK": true + } + }, + "hello-uniapp-demo": { + "title": "hello-uniapp 演示网站", + "env": { + "UNI_PLATFORM": "h5" + }, + "define": { + "H5-DEMO": true + } + } + } + }, + "engines": { + "HBuilderX": "^3.1.0", + "uni-app": "^4.03", + "uni-app-x": "" + } +} \ No newline at end of file diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..ee709d1 --- /dev/null +++ b/pages.json @@ -0,0 +1,1198 @@ +{ + "leftWindow": { + "path": "windows/left-window.vue", + "style": { + "width": "350px" + } + }, + "topWindow": { + "path": "windows/top-window.vue", + "style": { + "height": "60px" + } + }, + "pages": [ + // pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页" + } + }, + { + "path": "pages/my/my", + "style": { + "navigationBarTitleText": "个人中心" + } + }, + { + "path": "pages/wv-test/wv-test", + "style": { + "navigationBarTitleText": "WV测试" + } + }, + { + "path": "pages/login/login", + "style": { + "navigationBarTitleText": "登录" + } + }, + { + "path": "pages/protocol/service", + "style": { + "navigationBarTitleText": "用户服务协议" + } + }, + { + "path": "pages/protocol/privacy", + "style": { + "navigationBarTitleText": "隐私保护指引" + } + }, + { + "path": "pages/military/home/home", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/course/course", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/plan/plan", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/profile/profile", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/topic-map/topic-map", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/plan-detail/plan-detail", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/course-detail/course-detail", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/military/teacher-detail/teacher-detail", + "style": { + "navigationStyle": "custom" + } + }, + // #ifdef H5 || APP-PLUS + { + "path": "pages/about/about", + "style": { + "navigationBarTitleText": "关于" + } + }, + // #endif + { + "path": "platforms/app-plus/feedback/feedback", + "style": { + "navigationBarTitleText": "问题反馈" + } + } + // #ifdef H5 + , { + "path": "pages/error/404", + "style": { + "navigationBarTitleText": "Not Found" + } + } + // #endif + // #ifdef APP-PLUS + ,{ + "path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup", + "style": { + "app-plus": { + "animationDuration": 200, + "animationType": "fade-in", + "background": "transparent", + "backgroundColorTop": "transparent", + "popGesture": "none", + "scrollIndicator": false, + "titleNView": false + }, + "disableScroll": true + } + } + // #endif + +], + "subPackages": [{ + "root": "pages/API", + "pages": [{ + "path": "login/login", + "style": { + "navigationBarTitleText": "授权登录" + } + }, + // #ifdef APP-PLUS + { + "path": "subnvue/subnvue", + "style": { + "navigationBarTitleText": "原生子窗体", + "app-plus": { + "subNVues": [{ + "id": "drawer", + "path": "subnvue/subnvue/drawer", + "type": "popup", + "style": { + "width": "50%" + } + }, { + "id": "popup", + "path": "subnvue/subnvue/popup", + "type": "popup", + "style": { + "margin": "auto", + "width": "80%", + "height": "600rpx" + } + }, { + "id": "video_mask", + "path": "subnvue/subnvue/video-mask", + "style": { + "position": "absolute", + "bottom": "30px", + "left": "0", + "width": "230px", + "height": "110px", + "background": "transparent" + } + }] + } + } + }, + // #endif + { + "path": "get-user-info/get-user-info", + "style": { + "navigationBarTitleText": "获取用户信息" + } + }, + { + "path": "request-payment/request-payment", + "style": { + "navigationBarTitleText": "发起支付" + } + }, + { + "path": "share/share", + "style": { + "navigationBarTitleText": "分享" + } + }, + { + "path": "set-navigation-bar-title/set-navigation-bar-title", + "style": { + "navigationBarTitleText": "设置界面标题" + } + }, + { + "path": "show-loading/show-loading", + "style": { + "navigationBarTitleText": "加载提示框" + } + }, + { + "path": "navigator/navigator", + "style": { + "navigationBarTitleText": "页面跳转" + } + }, + { + "path": "navigator/new-page/new-vue-page-1", + "style": { + "navigationBarTitleText": "新VUE页面1" + } + }, + { + "path": "navigator/new-page/new-vue-page-2", + "style": { + "navigationBarTitleText": "新VUE页面2" + } + }, + // #ifndef VUE3 + { + "path": "navigator/new-page/new-nvue-page-1", + "style": { + "navigationBarTitleText": "新NVUE页面1" + } + }, + { + "path": "navigator/new-page/new-nvue-page-2", + "style": { + "navigationBarTitleText": "新NVUE页面2" + } + }, + // #endif + { + "path": "pull-down-refresh/pull-down-refresh", + "style": { + "navigationBarTitleText": "下拉刷新", + "enablePullDownRefresh": true + } + }, + { + "path": "animation/animation", + "style": { + "navigationBarTitleText": "创建动画" + } + }, + { + "path": "get-node-info/get-node-info", + "style": { + "navigationBarTitleText": "节点信息" + } + }, + { + "path": "intersection-observer/intersection-observer", + "style": { + "navigationBarTitleText": "节点布局相交状态" + } + }, + { + "path": "canvas/canvas", + "style": { + "navigationBarTitleText": "创建绘画" + } + }, + { + "path": "action-sheet/action-sheet", + "style": { + "navigationBarTitleText": "操作菜单" + } + }, + { + "path": "modal/modal", + "style": { + "navigationBarTitleText": "模态弹窗" + } + }, + { + "path": "toast/toast", + "style": { + "navigationBarTitleText": "消息提示框" + } + }, + { + "path": "get-network-type/get-network-type", + "style": { + "navigationBarTitleText": "获取设备网络状态" + } + }, + { + "path": "get-system-info/get-system-info", + "style": { + "navigationBarTitleText": "获取设备系统信息" + } + }, + { + "path": "add-phone-contact/add-phone-contact", + "style": { + "navigationBarTitleText": "添加手机联系人" + } + }, + { + "path": "on-accelerometer-change/on-accelerometer-change", + "style": { + "navigationBarTitleText": "监听加速度计数据" + } + }, + { + "path": "on-compass-change/on-compass-change", + "style": { + "navigationBarTitleText": "监听罗盘数据" + } + }, + { + "path": "make-phone-call/make-phone-call", + "style": { + "navigationBarTitleText": "打电话" + } + }, + { + "path": "scan-code/scan-code", + "style": { + "navigationBarTitleText": "扫码" + } + }, + { + "path": "clipboard/clipboard", + "style": { + "navigationBarTitleText": "剪贴板" + } + }, + { + "path": "request/request", + "style": { + "navigationBarTitleText": "网络请求" + } + }, + { + "path": "upload-file/upload-file", + "style": { + "navigationBarTitleText": "上传文件" + } + }, + { + "path": "download-file/download-file", + "style": { + "navigationBarTitleText": "下载文件" + } + }, + { + "path": "image/image", + "style": { + "navigationBarTitleText": "图片" + } + }, + { + "path": "voice/voice", + "style": { + "navigationBarTitleText": "录音" + } + }, + { + "path": "inner-audio/inner-audio", + "style": { + "navigationBarTitleText": "音频" + } + }, + { + "path": "background-audio/background-audio", + "style": { + "navigationBarTitleText": "背景音频" + } + }, + { + "path": "video/video", + "style": { + "navigationBarTitleText": "视频" + } + }, + { + "path": "file/file", + "style": { + "navigationBarTitleText": "文件" + } + }, + // #ifndef MP-QQ || MP-TOUTIAO + { + "path": "map/map", + "style": { + "navigationBarTitleText": "map" + } + }, + // #endif + // #ifdef APP-PLUS + { + "path": "map-search/map-search", + "style": { + "navigationBarTitleText": "map search" + } + }, + // #endif + { + "path": "get-location/get-location", + "style": { + "navigationBarTitleText": "获取位置" + } + }, + { + "path": "open-location/open-location", + "style": { + "navigationBarTitleText": "查看位置" + } + }, + // #ifndef MP-TOUTIAO + { + "path": "choose-location/choose-location", + "style": { + "navigationBarTitleText": "使用地图选择位置" + } + }, + // #endif + { + "path": "storage/storage", + "style": { + "navigationBarTitleText": "数据存储" + } + }, + { + "path": "sqlite/sqlite", + "style": { + "navigationBarTitleText": "SQLite" + } + }, + // #ifdef APP-PLUS || MP-WEIXIN + { + "path": "rewarded-video-ad/rewarded-video-ad", + "style": { + "navigationBarTitleText": "激励视频广告" + } + }, + // #endif + // #ifdef APP-PLUS + { + "path": "full-screen-video-ad/full-screen-video-ad", + "style": { + "navigationBarTitleText": "全屏视频广告" + } + }, + // #endif + // #ifndef H5 + { + "path": "brightness/brightness", + "style": { + "navigationBarTitleText": "屏幕亮度" + } + }, + // #endif + // #ifndef H5 || MP-ALIPAY + { + "path": "save-media/save-media", + "style": { + "navigationBarTitleText": "保存媒体到本地" + } + }, + // #endif + // #ifdef APP-PLUS || MP-WEIXIN || MP-QQ || MP-JD + { + "path": "bluetooth/bluetooth", + "style": { + "navigationBarTitleText": "蓝牙" + } + }, + { + "path": "soter/soter", + "style": { + "navigationBarTitleText": "生物认证" + } + }, + // #endif + // #ifdef APP-PLUS || MP-WEIXIN + { + "path": "ibeacon/ibeacon", + "style": { + "navigationBarTitleText": "iBeacon" + } + }, + // #endif + { + "path": "vibrate/vibrate", + "style": { + "navigationBarTitleText": "震动" + } + }, + // #ifndef MP-ALIPAY + { + "path": "websocket-socketTask/websocket-socketTask", + "style": { + "navigationBarTitleText": "websocket-socketTask" + } + }, + // #endif + { + "path": "websocket-global/websocket-global", + "style": { + "navigationBarTitleText": "websocket-global" + } + } + ] + }, + { + "root": "pages/extUI", + "pages": [{ + "path": "forms/forms", + "style": { + "navigationBarTitleText": "Form 表单" + } + }, + { + "path": "group/group", + "style": { + "navigationBarTitleText": "Group 分组" + } + }, + { + "path": "badge/badge", + "style": { + "navigationBarTitleText": "Badge 数字角标" + } + }, + { + "path": "breadcrumb/breadcrumb", + "style": { + "navigationBarTitleText": "Breadcrumb 面包屑" + } + }, + { + "path": "countdown/countdown", + "style": { + "navigationBarTitleText": "Countdown 倒计时" + } + }, + { + "path": "drawer/drawer", + "style": { + "navigationBarTitleText": "Drawer 抽屉" + } + }, + { + "path": "icons/icons", + "style": { + "navigationBarTitleText": "Icons 图标" + } + }, + { + "path": "load-more/load-more", + "style": { + "navigationBarTitleText": "LoadMore 加载更多" + } + }, + { + "path": "nav-bar/nav-bar", + "style": { + "navigationBarTitleText": "NavBar 导航栏", + "navigationStyle": "custom", + "enablePullDownRefresh": true, + "app-plus": { + "titleNView": false, + "bounce": "none", + "pullToRefresh": { + "style": "circle", + "offset": "70px" + } + } + } + }, + { + "path": "number-box/number-box", + "style": { + "navigationBarTitleText": "NumberBox 数字输入框" + } + }, + { + "path": "popup/popup", + "style": { + "navigationBarTitleText": "Popup 弹出层", + "app-plus": { + "softinputMode": "adjustResize" + } + } + }, + { + "path": "segmented-control/segmented-control", + "style": { + "navigationBarTitleText": "SegmentedControl 分段器" + } + }, + { + "path": "tag/tag", + "style": { + "navigationBarTitleText": "Tag 标签" + } + }, + { + "path": "list/list", + "style": { + "navigationBarTitleText": "List 列表" + } + }, + { + "path": "card/card", + "style": { + "navigationBarTitleText": "Card 卡片" + } + }, + { + "path": "collapse/collapse", + "style": { + "navigationBarTitleText": "Collapse 折叠面板" + } + }, + { + "path": "pagination/pagination", + "style": { + "navigationBarTitleText": "Pagination 分页器" + } + }, + { + "path": "swiper-dot/swiper-dot", + "style": { + "navigationBarTitleText": "SwiperDot 轮播图指示点", + "mp-baidu": { + "disableSwipeBack": true + } + } + }, + { + "path": "grid/grid", + "style": { + "navigationBarTitleText": "Grid 宫格" + } + }, + { + "path": "rate/rate", + "style": { + "navigationBarTitleText": "Rate 评分" + } + }, + { + "path": "steps/steps", + "style": { + "navigationBarTitleText": "Steps 步骤条" + } + }, + { + "path": "notice-bar/notice-bar", + "style": { + "navigationBarTitleText": "NoticeBar 通告栏" + } + }, + { + "path": "swipe-action/swipe-action", + "style": { + "navigationBarTitleText": "SwipeAction 滑动操作", + "app-plus": { + "bounce": "none" + } + } + }, + { + "path": "search-bar/search-bar", + "style": { + "navigationBarTitleText": "SearchBar 搜索栏" + } + }, + { + "path": "calendar/calendar", + "style": { + "navigationBarTitleText": "Calendar 日历" + } + }, + { + "path": "indexed-list/indexed-list", + "style": { + "navigationBarTitleText": "IndexedList 索引列表", + "mp-weixin": { + "disableScroll": true + }, + "app-plus": { + "bounce": "none" + }, + "mp-alipay": { + "allowsBounceVertical": "NO" + }, + "mp-baidu": { + "disableScroll": true + } + } + }, + { + "path": "fab/fab", + "style": { + "navigationBarTitleText": "Fab 悬浮按钮" + } + }, + { + "path": "fav/fav", + "style": { + "navigationBarTitleText": "Fav 收藏按钮" + } + }, + { + "path": "goods-nav/goods-nav", + "style": { + "navigationBarTitleText": "GoodsNav 商品导航" + } + }, + { + "path": "section/section", + "style": { + "navigationBarTitleText": "Section 标题栏" + } + }, + { + "path": "transition/transition", + "style": { + "navigationBarTitleText": "Transition 过渡动画" + } + }, + { + "path": "title/title", + "style": { + "navigationBarTitleText": "Title 章节标题" + } + }, + { + "path": "tooltip/tooltip", + "style": { + "navigationBarTitleText": "Tooltip 文字提示" + } + }, + { + "path": "link/link", + "style": { + "navigationBarTitleText": "Link 链接" + } + }, + { + "path": "combox/combox", + "style": { + "navigationBarTitleText": "Combox 组合框" + } + }, + { + "path": "list/chat", + "style": {} + }, + { + "path": "table/table", + "style": { + "navigationBarTitleText": "", + "enablePullDownRefresh": false + } + }, + { + "path": "dateformat/dateformat", + "style": { + "navigationBarTitleText": "Dateformat 日期格式化", + "enablePullDownRefresh": false + } + }, + { + "path": "data-checkbox/data-checkbox", + "style": { + "navigationBarTitleText": "DataCheckbox 单选复选框", + "enablePullDownRefresh": false + } + }, + { + "path": "easyinput/easyinput", + "style": { + "navigationBarTitleText": "Easyinput 增强输入框", + "enablePullDownRefresh": false + } + }, + { + "path": "data-picker/data-picker", + "style": { + "navigationBarTitleText": "DataPicker 级联选择", + "enablePullDownRefresh": false + } + }, + { + "path": "data-select/data-select", + "style": { + "navigationBarTitleText": "DataSelect 下拉框", + "enablePullDownRefresh": false + } + }, + { + "path": "datetime-picker/datetime-picker", + "style": { + "navigationBarTitleText": "DatetimePicker 日期时间", + "enablePullDownRefresh": false + } + }, + { + "path": "row/row", + "style": { + "navigationBarTitleText": "Layout 布局", + "enablePullDownRefresh": false + } + }, + { + "path": "file-picker/file-picker", + "style": { + "navigationBarTitleText": "FilePicker 文件选择上传", + "enablePullDownRefresh": false + } + }, + { + "path": "space/space", + "style": { + "navigationBarTitleText": "间距", + "enablePullDownRefresh": false + } + }, + { + "path": "font/font", + "style": { + "navigationBarTitleText": "字体", + "enablePullDownRefresh": false + } + }, + { + "path": "color/color", + "style": { + "navigationBarTitleText": "颜色", + "enablePullDownRefresh": false + } + }, + { + "path": "radius/radius", + "style": { + "navigationBarTitleText": "圆角", + "enablePullDownRefresh": false + } + }, + { + "path": "button/button", + "style": { + "navigationBarTitleText": "", + "enablePullDownRefresh": false + } + } + ] + }, + { + "root": "pages/template", + "pages": [ + // #ifndef VUE3 + { + "path": "ucharts/ucharts", + "style": { + "navigationBarTitleText": "uCharts 图表" + } + }, + // #endif + { + "path": "nav-default/nav-default", + "style": { + "navigationBarTitleText": "默认导航栏" + } + }, + { + "path": "component-communication/component-communication", + "style": { + "navigationBarTitleText": "组件通讯" + } + }, + // #ifdef APP-PLUS || H5 || MP-ALIPAY + { + "path": "nav-transparent/nav-transparent", + "style": { + "navigationBarTitleText": "透明渐变导航栏", + "transparentTitle": "auto" + } + }, + // #endif + // #ifdef APP-PLUS || H5 + { + "path": "nav-button/nav-button", + "style": { + "navigationBarTitleText": "导航栏带自定义按钮", + "app-plus": { + "titleNView": { + "buttons": [{ + "type": "share" + }, + { + "type": "favorite" + } + ] + } + } + } + }, + // #endif + // #ifdef APP-PLUS || H5 || MP-ALIPAY + { + "path": "nav-image/nav-image", + "style": { + "navigationBarBackgroundColor": "#FFFFFF", + "navigationBarTextStyle": "black", + "titleImage": "https://web-assets.dcloud.net.cn/unidoc/zh/logo1@2x.png" + } + }, + // #endif + // #ifdef APP-PLUS || H5 + { + "path": "nav-city-dropdown/nav-city-dropdown", + "style": { + "navigationBarTitleText": "导航栏带城市选择", + "app-plus": { + "titleNView": { + "buttons": [{ + "text": "北京市", + "fontSize": "14", + "select": true, + "width": "auto" + }] + } + } + } + }, + { + "path": "nav-dot/nav-dot", + "style": { + "navigationBarTitleText": "导航栏带红点和角标", + "app-plus": { + "titleNView": { + "buttons": [{ + "text": "消息", + "fontSize": "14", + "redDot": true + }, + { + "text": "关注", + "fontSize": "14", + "badgeText": "12" + } + ] + } + } + } + }, + { + "path": "nav-search-input/nav-search-input", + "style": { + "navigationBarTitleText": "导航栏带搜索框", + "app-plus": { + "titleNView": { + "type": "transparent", + "titleColor": "#fff", + "backgroundColor": "#007AFF", + "buttons": [{ + "fontSrc": "/static/uni.ttf", + "text": "\ue537", + "width": "40px", + "fontSize": "28px", + "color": "#fff", + "background": "rgba(0,0,0,0)" + }], + "searchInput": { + "backgroundColor": "#fff", + "borderRadius": "6px", + "placeholder": "请输入地址 如:大钟寺", + "disabled": true + } + } + } + } + }, + { + "path": "nav-search-input/detail/detail", + "style": { + "navigationBarTitleText": "搜索", + "app-plus": { + "titleNView": { + "titleColor": "#fff", + "backgroundColor": "#007AFF", + "buttons": [{ + "fontSrc": "/static/uni.ttf", + "text": "\ue537", + "width": "auto", + "fontSize": "28px", + "color": "#fff" + }], + "searchInput": { + "backgroundColor": "#fff", + "borderRadius": "6px", + "placeholder": "请输入地址 如:大钟寺", + "autoFocus": true + } + } + } + } + }, + // #endif + { + "path": "list2detail-list/list2detail-list", + "style": { + "navigationBarTitleText": "列表到详情示例", + "enablePullDownRefresh": true + } + }, + { + "path": "list2detail-detail/list2detail-detail", + "style": { + "navigationBarTitleText": "详情", + "app-plus": { + "titleNView": { + "type": "transparent", + "buttons": [{ + "type": "share" + }] + } + }, + "h5": { + "titleNView": { + "type": "transparent", + "buttons": [] + } + } + } + }, + { + "path": "tabbar/tabbar", + "style": { + "navigationBarTitleText": "可拖动顶部选项卡" + } + }, + { + "path": "tabbar/detail/detail", + "style": { + "navigationBarTitleText": "详情页面" + } + }, + // #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-QQ + { + "path": "swiper-vertical/swiper-vertical", + "style": { + "navigationBarTitleText": "上下滑动切换视频", + "app-plus": { + "titleNView": false + } + } + }, + { + "path": "swiper-list/swiper-list", + "style": { + "navigationBarTitleText": "swiper-list" + } + }, + // #endif + // #ifdef APP-PLUS + { + "path": "swiper-list-nvue/swiper-list-nvue", + "style": { + "navigationBarTitleText": "swiper-list" + } + }, + // #endif + { + "path": "scheme/scheme", + "style": { + "navigationBarTitleText": "打开外部应用" + } + }, + // #ifdef APP-PLUS || MP-WEIXIN || MP-QQ || H5 + // #ifndef VUE3 + { + "path": "vant-button/vant-button", + "style": { + "navigationBarTitleText": "微信自定义组件示例", + "usingComponents": { + "van-button": "/wxcomponents/vant/button/index" + } + } + }, + // #endif + // #endif + // #ifdef APP || H5 + { + "path" : "renderjs/renderjs", + "style" : + { + "navigationBarTitleText" : "renderjs" + } + }, + // #endif + { + "path": "global/global", + "style": { + "navigationBarTitleText": "GlobalData和vuex" + } + }, + // #ifdef VUE3 + { + "path" : "pinia/pinia", + "style" : + { + "navigationBarTitleText" : "pinia" + } + }, + // #endif + // #ifdef APP + { + "path" : "vuex-nvue/vuex-nvue", + "style" : + { + "navigationBarTitleText" : "vuex-nvue" + } + }, + // #endif + { + "path" : "vuex-vue/vuex-vue", + "style" : + { + "navigationBarTitleText" : "vuex-vue" + } + }, + { + "path" : "crypto-api/crypto-api", + "style" : + { + "navigationBarTitleText" : "crypto" + } + } + ] + } + ], + "globalStyle": { + "pageOrientation": "portrait", + "navigationBarTitleText": "Hello uniapp", + "navigationBarTextStyle": "white", + "navigationBarBackgroundColor": "#007AFF", + "backgroundColor": "#F8F8F8", + "backgroundColorTop": "#F4F5F6", + "backgroundColorBottom": "#F4F5F6", + "mp-360": { + "navigationStyle": "custom" + }, + "h5": { + "maxWidth": 1190, + "navigationBarTextStyle": "black", + "navigationBarBackgroundColor": "#F1F1F1" + } + }, + "tabBar": { + "color": "#8F98A6", + "selectedColor": "#FF8A33", + "borderStyle": "white", + "backgroundColor": "#FFFFFF", + "list": [{ + "pagePath": "pages/index/index", + "iconPath": "static/icons/icons8-home.png", + "selectedIconPath": "static/icons/icons8-home-active.png", + "text": "首页" + }, + { + "pagePath": "pages/my/my", + "iconPath": "static/icons/icons8-woman.png", + "selectedIconPath": "static/icons/icons8-woman-active.png", + "text": "个人中心" + } + // ,{ + // "pagePath": "pages/wv-test/wv-test", + // "iconPath": "static/icons/icons8-notepad.png", + // "selectedIconPath": "static/icons/icons8-notepad-active.png", + // "text": "WV测试" + // } + ] + } +} diff --git a/pages/API/action-sheet/action-sheet.vue b/pages/API/action-sheet/action-sheet.vue new file mode 100644 index 0000000..9e44c1f --- /dev/null +++ b/pages/API/action-sheet/action-sheet.vue @@ -0,0 +1,60 @@ + + diff --git a/pages/API/add-phone-contact/add-phone-contact.vue b/pages/API/add-phone-contact/add-phone-contact.vue new file mode 100644 index 0000000..8c1d70c --- /dev/null +++ b/pages/API/add-phone-contact/add-phone-contact.vue @@ -0,0 +1,102 @@ + + + + diff --git a/pages/API/animation/animation.vue b/pages/API/animation/animation.vue new file mode 100644 index 0000000..3b8c9a5 --- /dev/null +++ b/pages/API/animation/animation.vue @@ -0,0 +1,125 @@ + + + + diff --git a/pages/API/background-audio/background-audio.vue b/pages/API/background-audio/background-audio.vue new file mode 100644 index 0000000..7f7688d --- /dev/null +++ b/pages/API/background-audio/background-audio.vue @@ -0,0 +1,163 @@ + + + + diff --git a/pages/API/bluetooth/bluetooth.vue b/pages/API/bluetooth/bluetooth.vue new file mode 100644 index 0000000..20144e1 --- /dev/null +++ b/pages/API/bluetooth/bluetooth.vue @@ -0,0 +1,723 @@ + + + + diff --git a/pages/API/brightness/brightness.vue b/pages/API/brightness/brightness.vue new file mode 100644 index 0000000..9646dd1 --- /dev/null +++ b/pages/API/brightness/brightness.vue @@ -0,0 +1,86 @@ + + + + diff --git a/pages/API/canvas/canvas.vue b/pages/API/canvas/canvas.vue new file mode 100644 index 0000000..a1aaa40 --- /dev/null +++ b/pages/API/canvas/canvas.vue @@ -0,0 +1,366 @@ + + + + diff --git a/pages/API/choose-location/choose-location.vue b/pages/API/choose-location/choose-location.vue new file mode 100644 index 0000000..2c03223 --- /dev/null +++ b/pages/API/choose-location/choose-location.vue @@ -0,0 +1,62 @@ + + + + diff --git a/pages/API/clipboard/clipboard.vue b/pages/API/clipboard/clipboard.vue new file mode 100644 index 0000000..596d086 --- /dev/null +++ b/pages/API/clipboard/clipboard.vue @@ -0,0 +1,91 @@ + + + + + + diff --git a/pages/API/download-file/download-file.test.js b/pages/API/download-file/download-file.test.js new file mode 100644 index 0000000..b845adc --- /dev/null +++ b/pages/API/download-file/download-file.test.js @@ -0,0 +1,27 @@ +const platformInfo = process.env.uniTestPlatformInfo.toLocaleLowerCase() +describe('pages/API/download-file/download-file.vue', () => { + let page; + const versions = ['12.4', '13.7', '15.5', '17.4', '17.5_深色主题', '18.1']; + const [platform, version] = platformInfo.split(' '); + if (platform === 'ios_simulator' && versions.includes(version)) { + it('skip', async () => { + expect(1).toBe(1); + }); + return; + } + beforeAll(async () => { + page = await program.reLaunch('/pages/API/download-file/download-file') + await page.waitFor('view') + }); + it('check download url', async () => { + expect.assertions(2); + await page.callMethod('downloadImage') + const waitTime = process.env.uniTestPlatformInfo.includes('firefox') ? 5000:2000 + const start = Date.now(); + await page.waitFor(async () => { + return await page.data('jest_result') === true || (Date.now() - start > waitTime) + }) + expect(await page.data('jest_result')).toBeTruthy(); + expect(await page.data('imageSrc')).toBeTruthy(); + }); +}); diff --git a/pages/API/download-file/download-file.vue b/pages/API/download-file/download-file.vue new file mode 100644 index 0000000..7e3b898 --- /dev/null +++ b/pages/API/download-file/download-file.vue @@ -0,0 +1,67 @@ + + + + diff --git a/pages/API/file/file.vue b/pages/API/file/file.vue new file mode 100644 index 0000000..f75702f --- /dev/null +++ b/pages/API/file/file.vue @@ -0,0 +1,129 @@ + + + + diff --git a/pages/API/full-screen-video-ad/full-screen-video-ad.vue b/pages/API/full-screen-video-ad/full-screen-video-ad.vue new file mode 100644 index 0000000..cd14d18 --- /dev/null +++ b/pages/API/full-screen-video-ad/full-screen-video-ad.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/pages/API/get-location/get-location.vue b/pages/API/get-location/get-location.vue new file mode 100644 index 0000000..a152770 --- /dev/null +++ b/pages/API/get-location/get-location.vue @@ -0,0 +1,200 @@ + + + + diff --git a/pages/API/get-network-type/get-network-type.vue b/pages/API/get-network-type/get-network-type.vue new file mode 100644 index 0000000..ae3c1f4 --- /dev/null +++ b/pages/API/get-network-type/get-network-type.vue @@ -0,0 +1,88 @@ + + + + diff --git a/pages/API/get-node-info/get-node-info.test.js b/pages/API/get-node-info/get-node-info.test.js new file mode 100644 index 0000000..0e67174 --- /dev/null +++ b/pages/API/get-node-info/get-node-info.test.js @@ -0,0 +1,32 @@ +describe('测试 css 变量', () => { + let page + const isApp = process.env.UNI_PLATFORM.includes('app'); + beforeAll(async () => { + // 重新reLaunch至首页,并获取首页page对象(其中 program 是uni-automator自动注入的全局对象) + page = await program.reLaunch('/pages/API/get-node-info/get-node-info') + await page.waitFor(1000) + }) + + it('css var', async () => { + + if (isApp) { + const element1 = await page.$('.box1') + const size = await element1.size() + expect(size.height > 0).toBe(true) + + const element2 = await page.$('.box2') + const size2 = await element2.size() + expect(size2.height === 0).toBe(true) + + const element3 = await page.$('.box3') + const size3 = await element3.size() + expect(size3.height === 0).toBe(true) + + const element4 = await page.$('.box4') + const size4 = await element4.size() + expect(size4.height > size.height).toBe(true) + } else { + expect(1).toBe(1) + } + }) +}); diff --git a/pages/API/get-node-info/get-node-info.vue b/pages/API/get-node-info/get-node-info.vue new file mode 100644 index 0000000..977e473 --- /dev/null +++ b/pages/API/get-node-info/get-node-info.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/pages/API/get-system-info/get-system-info.vue b/pages/API/get-system-info/get-system-info.vue new file mode 100644 index 0000000..37bfe44 --- /dev/null +++ b/pages/API/get-system-info/get-system-info.vue @@ -0,0 +1,148 @@ + + + + diff --git a/pages/API/get-user-info/get-user-info.vue b/pages/API/get-user-info/get-user-info.vue new file mode 100644 index 0000000..4284841 --- /dev/null +++ b/pages/API/get-user-info/get-user-info.vue @@ -0,0 +1,165 @@ + + + + diff --git a/pages/API/ibeacon/ibeacon.vue b/pages/API/ibeacon/ibeacon.vue new file mode 100644 index 0000000..dafe0d4 --- /dev/null +++ b/pages/API/ibeacon/ibeacon.vue @@ -0,0 +1,300 @@ + + + + diff --git a/pages/API/image/image.vue b/pages/API/image/image.vue new file mode 100644 index 0000000..0078f2d --- /dev/null +++ b/pages/API/image/image.vue @@ -0,0 +1,239 @@ + + + + diff --git a/pages/API/inner-audio/inner-audio.vue b/pages/API/inner-audio/inner-audio.vue new file mode 100644 index 0000000..da278c6 --- /dev/null +++ b/pages/API/inner-audio/inner-audio.vue @@ -0,0 +1,124 @@ + + + diff --git a/pages/API/intersection-observer/intersection-observer.vue b/pages/API/intersection-observer/intersection-observer.vue new file mode 100644 index 0000000..3515a2a --- /dev/null +++ b/pages/API/intersection-observer/intersection-observer.vue @@ -0,0 +1,69 @@ + + + diff --git a/pages/API/login/login.vue b/pages/API/login/login.vue new file mode 100644 index 0000000..e636147 --- /dev/null +++ b/pages/API/login/login.vue @@ -0,0 +1,325 @@ + + + + diff --git a/pages/API/make-phone-call/make-phone-call.vue b/pages/API/make-phone-call/make-phone-call.vue new file mode 100644 index 0000000..210a26b --- /dev/null +++ b/pages/API/make-phone-call/make-phone-call.vue @@ -0,0 +1,50 @@ + + + + diff --git a/pages/API/map-search/map-search.nvue b/pages/API/map-search/map-search.nvue new file mode 100644 index 0000000..48ed0f7 --- /dev/null +++ b/pages/API/map-search/map-search.nvue @@ -0,0 +1,102 @@ + + + + + diff --git a/pages/API/map/map.nvue b/pages/API/map/map.nvue new file mode 100644 index 0000000..cdfec95 --- /dev/null +++ b/pages/API/map/map.nvue @@ -0,0 +1,447 @@ + + + + + diff --git a/pages/API/modal/modal.vue b/pages/API/modal/modal.vue new file mode 100644 index 0000000..c442459 --- /dev/null +++ b/pages/API/modal/modal.vue @@ -0,0 +1,40 @@ + + \ No newline at end of file diff --git a/pages/API/navigator/navigator.vue b/pages/API/navigator/navigator.vue new file mode 100644 index 0000000..e4ea911 --- /dev/null +++ b/pages/API/navigator/navigator.vue @@ -0,0 +1,106 @@ + + diff --git a/pages/API/navigator/new-page/new-nvue-page-1.nvue b/pages/API/navigator/new-page/new-nvue-page-1.nvue new file mode 100644 index 0000000..96a8b56 --- /dev/null +++ b/pages/API/navigator/new-page/new-nvue-page-1.nvue @@ -0,0 +1,83 @@ + + + diff --git a/pages/API/navigator/new-page/new-nvue-page-2.nvue b/pages/API/navigator/new-page/new-nvue-page-2.nvue new file mode 100644 index 0000000..642ca71 --- /dev/null +++ b/pages/API/navigator/new-page/new-nvue-page-2.nvue @@ -0,0 +1,69 @@ + + + diff --git a/pages/API/navigator/new-page/new-vue-page-1.vue b/pages/API/navigator/new-page/new-vue-page-1.vue new file mode 100644 index 0000000..e77beb2 --- /dev/null +++ b/pages/API/navigator/new-page/new-vue-page-1.vue @@ -0,0 +1,108 @@ + + + diff --git a/pages/API/navigator/new-page/new-vue-page-2.vue b/pages/API/navigator/new-page/new-vue-page-2.vue new file mode 100644 index 0000000..ff6efe5 --- /dev/null +++ b/pages/API/navigator/new-page/new-vue-page-2.vue @@ -0,0 +1,84 @@ + + + diff --git a/pages/API/on-accelerometer-change/on-accelerometer-change.vue b/pages/API/on-accelerometer-change/on-accelerometer-change.vue new file mode 100644 index 0000000..2f57f3b --- /dev/null +++ b/pages/API/on-accelerometer-change/on-accelerometer-change.vue @@ -0,0 +1,62 @@ + + diff --git a/pages/API/rewarded-video-ad/rewarded-video-ad.vue b/pages/API/rewarded-video-ad/rewarded-video-ad.vue new file mode 100644 index 0000000..029c857 --- /dev/null +++ b/pages/API/rewarded-video-ad/rewarded-video-ad.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/pages/API/save-media/save-media.vue b/pages/API/save-media/save-media.vue new file mode 100644 index 0000000..2c4ac11 --- /dev/null +++ b/pages/API/save-media/save-media.vue @@ -0,0 +1,158 @@ + + + + diff --git a/pages/API/scan-code/scan-code.vue b/pages/API/scan-code/scan-code.vue new file mode 100644 index 0000000..b5ed860 --- /dev/null +++ b/pages/API/scan-code/scan-code.vue @@ -0,0 +1,76 @@ + + + + diff --git a/pages/API/set-navigation-bar-title/set-navigation-bar-title.test.js b/pages/API/set-navigation-bar-title/set-navigation-bar-title.test.js new file mode 100644 index 0000000..771ce59 --- /dev/null +++ b/pages/API/set-navigation-bar-title/set-navigation-bar-title.test.js @@ -0,0 +1,14 @@ +describe('pages/API/set-navigation-bar-title/set-navigation-bar-title.vue', () => { + let page + beforeAll(async () => { + // 重新reLaunch至首页,并获取首页page对象(其中 program 是uni-automator自动注入的全局对象) + page = await program.reLaunch('/pages/API/set-navigation-bar-title/set-navigation-bar-title') + const waitTime = process.env.UNI_PLATFORM === "mp-weixin" ? 10000 : 5000 + await page.waitFor(waitTime) + page = await program.currentPage() + }) + it('set-navigation-bar-title 组件标题', async () => { + let view = await page.$('.common-page-head-title') + expect(await view.text()).toBe('nav-default') + }) +}) diff --git a/pages/API/set-navigation-bar-title/set-navigation-bar-title.vue b/pages/API/set-navigation-bar-title/set-navigation-bar-title.vue new file mode 100644 index 0000000..19080d7 --- /dev/null +++ b/pages/API/set-navigation-bar-title/set-navigation-bar-title.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/pages/API/share/share.vue b/pages/API/share/share.vue new file mode 100644 index 0000000..90e8701 --- /dev/null +++ b/pages/API/share/share.vue @@ -0,0 +1,293 @@ + + + + + diff --git a/platforms/app-plus/orientation/orientation.vue b/platforms/app-plus/orientation/orientation.vue new file mode 100644 index 0000000..085d736 --- /dev/null +++ b/platforms/app-plus/orientation/orientation.vue @@ -0,0 +1,64 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-easyinput/package.json b/uni_modules/uni-easyinput/package.json new file mode 100644 index 0000000..90ab0ea --- /dev/null +++ b/uni_modules/uni-easyinput/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-easyinput", + "displayName": "uni-easyinput 增强输入框", + "version": "1.1.19", + "description": "Easyinput 组件是对原生input组件的增强", + "keywords": [ + "uni-ui", + "uniui", + "input", + "uni-easyinput", + "输入框" +], + "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", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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-easyinput/readme.md b/uni_modules/uni-easyinput/readme.md new file mode 100644 index 0000000..41c6db3 --- /dev/null +++ b/uni_modules/uni-easyinput/readme.md @@ -0,0 +1,11 @@ + + +### Easyinput 增强输入框 +> **组件名:uni-easyinput** +> 代码块: `uEasyinput` + + +easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的,easyinput 内置了边框,图标等,同时包含 input 所有功能 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-easyinput) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-fab/changelog.md b/uni_modules/uni-fab/changelog.md new file mode 100644 index 0000000..71b228f --- /dev/null +++ b/uni_modules/uni-fab/changelog.md @@ -0,0 +1,25 @@ +## 1.2.6(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.2.5(2023-03-29) +- 新增 pattern.icon 属性,可自定义图标 +## 1.2.4(2022-09-07) +小程序端由于 style 使用了对象导致报错,[详情](https://ask.dcloud.net.cn/question/152790?item_id=211778&rf=false) +## 1.2.3(2022-09-05) +- 修复 nvue 环境下,具有 tabBar 时,fab 组件下部位置无法正常获取 --window-bottom 的bug,详见:[https://ask.dcloud.net.cn/question/110638?notification_id=826310](https://ask.dcloud.net.cn/question/110638?notification_id=826310) +## 1.2.2(2021-12-29) +- 更新 组件依赖 +## 1.2.1(2021-11-19) +- 修复 阴影颜色不正确的bug +## 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-fab](https://uniapp.dcloud.io/component/uniui/uni-fab) +## 1.1.1(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-02-05) +- 调整为uni_modules目录规范 +- 优化 按钮背景色调整 +- 优化 兼容pc端 diff --git a/uni_modules/uni-fab/components/uni-fab/uni-fab.vue b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue new file mode 100644 index 0000000..0cc2ef3 --- /dev/null +++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue @@ -0,0 +1,491 @@ + + + + + diff --git a/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak new file mode 100644 index 0000000..196d1af --- /dev/null +++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak @@ -0,0 +1,379 @@ + + + + + diff --git a/uni_modules/uni-fab/package.json b/uni_modules/uni-fab/package.json new file mode 100644 index 0000000..1990345 --- /dev/null +++ b/uni_modules/uni-fab/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-fab", + "displayName": "uni-fab 悬浮按钮", + "version": "1.2.6", + "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。", + "keywords": [ + "uni-ui", + "uniui", + "按钮", + "悬浮按钮", + "fab" +], + "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","uni-icons"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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" + } + } + } + } +} diff --git a/uni_modules/uni-fab/readme.md b/uni_modules/uni-fab/readme.md new file mode 100644 index 0000000..1a06319 --- /dev/null +++ b/uni_modules/uni-fab/readme.md @@ -0,0 +1,9 @@ +## Fab 悬浮按钮 +> **组件名:uni-fab** +> 代码块: `uFab` + + +点击可展开一个图形按钮菜单 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fab) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-fav/changelog.md b/uni_modules/uni-fav/changelog.md new file mode 100644 index 0000000..092c30c --- /dev/null +++ b/uni_modules/uni-fav/changelog.md @@ -0,0 +1,19 @@ +## 1.2.1(2022-05-30) +- 新增 stat 属性 ,是否开启uni统计功能 +## 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-fav](https://uniapp.dcloud.io/component/uniui/uni-fav) +## 1.1.1(2021-08-24) +- 新增 支持国际化 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.6(2021-05-12) +- 新增 组件示例地址 +## 1.0.5(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.4(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.0.3(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.0.2(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/en.json b/uni_modules/uni-fav/components/uni-fav/i18n/en.json new file mode 100644 index 0000000..b288cb0 --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/en.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "collect", + "uni-fav.collected": "collected" +} diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/index.js b/uni_modules/uni-fav/components/uni-fav/i18n/index.js new file mode 100644 index 0000000..fa8f0f3 --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json new file mode 100644 index 0000000..41ccefb --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "收藏", + "uni-fav.collected": "已收藏" +} diff --git a/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json new file mode 100644 index 0000000..41ccefb --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-fav.collect": "收藏", + "uni-fav.collected": "已收藏" +} diff --git a/uni_modules/uni-fav/components/uni-fav/uni-fav.vue b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue new file mode 100644 index 0000000..8e391c2 --- /dev/null +++ b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/uni_modules/uni-fav/package.json b/uni_modules/uni-fav/package.json new file mode 100644 index 0000000..81fb73d --- /dev/null +++ b/uni_modules/uni-fav/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-fav", + "displayName": "uni-fav 收藏按钮", + "version": "1.2.1", + "description": " Fav 收藏组件,可自定义颜色、大小。", + "keywords": [ + "fav", + "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": [ + "uni-scss", + "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" + } + } + } + } +} diff --git a/uni_modules/uni-fav/readme.md b/uni_modules/uni-fav/readme.md new file mode 100644 index 0000000..00c5425 --- /dev/null +++ b/uni_modules/uni-fav/readme.md @@ -0,0 +1,10 @@ + + +## Fav 收藏按钮 +> **组件名:uni-fav** +> 代码块: `uFav` + +用于收藏功能,可点击切换选中、不选中的状态。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fav) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-file-picker/changelog.md b/uni_modules/uni-file-picker/changelog.md new file mode 100644 index 0000000..00a76cc --- /dev/null +++ b/uni_modules/uni-file-picker/changelog.md @@ -0,0 +1,81 @@ +## 1.0.11(2024-07-19) +- 修复 vue3 使用value报错的bug +## 1.0.10(2024-07-09) +- 优化 vue3兼容性 +## 1.0.9(2024-07-09) +- 修复 value 属性不兼容vue3的bug +## 1.0.8(2024-03-20) +- 补充 删除文件时返回文件下标 +## 1.0.7(2024-02-21) +- 新增 微信小程序选择视频时改用chooseMedia,并返回视频缩略图 +## 1.0.6(2024-01-06) +- 新增 微信小程序不再调用chooseImage,而是调用chooseMedia +## 1.0.5(2024-01-03) +- 新增 上传文件至云存储携带本地文件名称 +## 1.0.4(2023-03-29) +- 修复 手动上传删除一个文件后不能再上传的bug +## 1.0.3(2022-12-19) +- 新增 sourceType 属性, 可以自定义图片和视频选择的来源 +## 1.0.2(2022-07-04) +- 修复 在uni-forms下样式不生效的bug +## 1.0.1(2021-11-23) +- 修复 参数为对象的情况下,url在某些情况显示错误的bug +## 1.0.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-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker) +## 0.2.16(2021-11-08) +- 修复 传入空对象 ,显示错误的Bug +## 0.2.15(2021-08-30) +- 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug +## 0.2.14(2021-08-23) +- 新增 参数中返回 fileID 字段 +## 0.2.13(2021-08-23) +- 修复 腾讯云传入fileID 不能回显的bug +- 修复 选择图片后,不能放大的问题 +## 0.2.12(2021-08-17) +- 修复 由于 0.2.11 版本引起的不能回显图片的Bug +## 0.2.11(2021-08-16) +- 新增 clearFiles(index) 方法,可以手动删除指定文件 +- 修复 v-model 值设为 null 报错的Bug +## 0.2.10(2021-08-13) +- 修复 return-type="object" 时,无法删除文件的Bug +## 0.2.9(2021-08-03) +- 修复 auto-upload 属性失效的Bug +## 0.2.8(2021-07-31) +- 修复 fileExtname属性不指定值报错的Bug +## 0.2.7(2021-07-31) +- 修复 在某种场景下图片不回显的Bug +## 0.2.6(2021-07-30) +- 修复 return-type为object下,返回值不正确的Bug +## 0.2.5(2021-07-30) +- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题 +## 0.2.3(2021-07-28) +- 优化 调整示例代码 +## 0.2.2(2021-07-27) +- 修复 vue3 下赋值错误的Bug +- 优化 h5平台下上传文件导致页面卡死的问题 +## 0.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.1.1(2021-07-02) +- 修复 sourceType 缺少默认值导致 ios 无法选择文件 +## 0.1.0(2021-06-30) +- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改 +## 0.0.11(2021-06-30) +- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题 +## 0.0.10(2021-06-29) +- 优化 文件上传后进度条消失时机 +## 0.0.9(2021-06-29) +- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug +## 0.0.8(2021-06-15) +- 修复 删除文件时无法触发 v-model 的Bug +## 0.0.7(2021-05-12) +- 新增 组件示例地址 +## 0.0.6(2021-04-09) +- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug +## 0.0.5(2021-04-09) +- 优化 更新组件示例 +## 0.0.4(2021-04-09) +- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔 +## 0.0.3(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js new file mode 100644 index 0000000..c4ff85d --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js @@ -0,0 +1,287 @@ +'use strict'; + +const ERR_MSG_OK = 'chooseAndUploadFile:ok'; +const ERR_MSG_FAIL = 'chooseAndUploadFile:fail'; + +function chooseImage(opts) { + const { + count, + sizeType = ['original', 'compressed'], + sourceType, + extension + } = opts + return new Promise((resolve, reject) => { + // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口 + // #ifdef MP-WEIXIN + uni.chooseMedia({ + count, + sizeType, + sourceType, + mediaType: ['image'], + extension, + success(res) { + res.tempFiles.forEach(item => { + item.path = item.tempFilePath; + }) + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }) + // #endif + // #ifndef MP-WEIXIN + uni.chooseImage({ + count, + sizeType, + sourceType, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }); + // #endif + + }); +} + +function chooseVideo(opts) { + const { + count, + camera, + compressed, + maxDuration, + sourceType, + extension + } = opts; + return new Promise((resolve, reject) => { + // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口 + // #ifdef MP-WEIXIN + uni.chooseMedia({ + count, + compressed, + maxDuration, + sourceType, + extension, + mediaType: ['video'], + success(res) { + const { + tempFiles, + } = res; + resolve(normalizeChooseAndUploadFileRes({ + errMsg: 'chooseVideo:ok', + tempFiles: tempFiles.map(item => { + return { + name: item.name || '', + path: item.tempFilePath, + thumbTempFilePath: item.thumbTempFilePath, + size:item.size, + type: (res.tempFile && res.tempFile.type) || '', + width:item.width, + height:item.height, + duration:item.duration, + fileType: 'video', + cloudPath: '', + } + }), + }, 'video')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }) + // #endif + // #ifndef MP-WEIXIN + uni.chooseVideo({ + camera, + compressed, + maxDuration, + sourceType, + extension, + success(res) { + const { + tempFilePath, + duration, + size, + height, + width + } = res; + resolve(normalizeChooseAndUploadFileRes({ + errMsg: 'chooseVideo:ok', + tempFilePaths: [tempFilePath], + tempFiles: [{ + name: (res.tempFile && res.tempFile.name) || '', + path: tempFilePath, + size, + type: (res.tempFile && res.tempFile.type) || '', + width, + height, + duration, + fileType: 'video', + cloudPath: '', + }, ], + }, 'video')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }); + // #endif + }); +} + +function chooseAll(opts) { + const { + count, + extension + } = opts; + return new Promise((resolve, reject) => { + let chooseFile = uni.chooseFile; + if (typeof wx !== 'undefined' && + typeof wx.chooseMessageFile === 'function') { + chooseFile = wx.chooseMessageFile; + } + if (typeof chooseFile !== 'function') { + return reject({ + errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。', + }); + } + chooseFile({ + type: 'all', + count, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res)); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function normalizeChooseAndUploadFileRes(res, fileType) { + res.tempFiles.forEach((item, index) => { + if (!item.name) { + item.name = item.path.substring(item.path.lastIndexOf('/') + 1); + } + if (fileType) { + item.fileType = fileType; + } + item.cloudPath = + Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.')); + }); + if (!res.tempFilePaths) { + res.tempFilePaths = res.tempFiles.map((file) => file.path); + } + return res; +} + +function uploadCloudFiles(files, max = 5, onUploadProgress) { + files = JSON.parse(JSON.stringify(files)) + const len = files.length + let count = 0 + let self = this + return new Promise(resolve => { + while (count < max) { + next() + } + + function next() { + let cur = count++ + if (cur >= len) { + !files.find(item => !item.url && !item.errMsg) && resolve(files) + return + } + const fileItem = files[cur] + const index = self.files.findIndex(v => v.uuid === fileItem.uuid) + fileItem.url = '' + delete fileItem.errMsg + + uniCloud + .uploadFile({ + filePath: fileItem.path, + cloudPath: fileItem.cloudPath, + fileType: fileItem.fileType, + onUploadProgress: res => { + res.index = index + onUploadProgress && onUploadProgress(res) + } + }) + .then(res => { + fileItem.url = res.fileID + fileItem.index = index + if (cur < len) { + next() + } + }) + .catch(res => { + fileItem.errMsg = res.errMsg || res.message + fileItem.index = index + if (cur < len) { + next() + } + }) + } + }) +} + + + + + +function uploadFiles(choosePromise, { + onChooseFile, + onUploadProgress +}) { + return choosePromise + .then((res) => { + if (onChooseFile) { + const customChooseRes = onChooseFile(res); + if (typeof customChooseRes !== 'undefined') { + return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ? + res : chooseRes); + } + } + return res; + }) + .then((res) => { + if (res === false) { + return { + errMsg: ERR_MSG_OK, + tempFilePaths: [], + tempFiles: [], + }; + } + return res + }) +} + +function chooseAndUploadFile(opts = { + type: 'all' +}) { + if (opts.type === 'image') { + return uploadFiles(chooseImage(opts), opts); + } else if (opts.type === 'video') { + return uploadFiles(chooseVideo(opts), opts); + } + return uploadFiles(chooseAll(opts), opts); +} + +export { + chooseAndUploadFile, + uploadCloudFiles +}; diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue new file mode 100644 index 0000000..95eaf30 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue @@ -0,0 +1,668 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue new file mode 100644 index 0000000..ab15bad --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue @@ -0,0 +1,325 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue new file mode 100644 index 0000000..0c1abe8 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue @@ -0,0 +1,292 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/utils.js b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js new file mode 100644 index 0000000..b1911e0 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js @@ -0,0 +1,110 @@ +/** + * 获取文件名和后缀 + * @param {String} name + */ +export const get_file_ext = (name) => { + const last_len = name.lastIndexOf('.') + const len = name.length + return { + name: name.substring(0, last_len), + ext: name.substring(last_len + 1, len) + } +} + +/** + * 获取扩展名 + * @param {Array} fileExtname + */ +export const get_extname = (fileExtname) => { + if (!Array.isArray(fileExtname)) { + let extname = fileExtname.replace(/(\[|\])/g, '') + return extname.split(',') + } else { + return fileExtname + } + return [] +} + +/** + * 获取文件和检测是否可选 + */ +export const get_files_and_is_max = (res, _extname) => { + let filePaths = [] + let files = [] + if(!_extname || _extname.length === 0){ + return { + filePaths, + files + } + } + res.tempFiles.forEach(v => { + let fileFullName = get_file_ext(v.name) + const extname = fileFullName.ext.toLowerCase() + if (_extname.indexOf(extname) !== -1) { + files.push(v) + filePaths.push(v.path) + } + }) + if (files.length !== res.tempFiles.length) { + uni.showToast({ + title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`, + icon: 'none', + duration: 5000 + }) + } + + return { + filePaths, + files + } +} + + +/** + * 获取图片信息 + * @param {Object} filepath + */ +export const get_file_info = (filepath) => { + return new Promise((resolve, reject) => { + uni.getImageInfo({ + src: filepath, + success(res) { + resolve(res) + }, + fail(err) { + reject(err) + } + }) + }) +} +/** + * 获取封装数据 + */ +export const get_file_data = async (files, type = 'image') => { + // 最终需要上传数据库的数据 + let fileFullName = get_file_ext(files.name) + const extname = fileFullName.ext.toLowerCase() + let filedata = { + name: files.name, + uuid: files.uuid, + extname: extname || '', + cloudPath: files.cloudPath, + fileType: files.fileType, + thumbTempFilePath: files.thumbTempFilePath, + url: files.path || files.path, + size: files.size, //单位是字节 + image: {}, + path: files.path, + video: {} + } + if (type === 'image') { + const imageinfo = await get_file_info(files.path) + delete filedata.video + filedata.image.width = imageinfo.width + filedata.image.height = imageinfo.height + filedata.image.location = imageinfo.path + } else { + delete filedata.image + } + return filedata +} diff --git a/uni_modules/uni-file-picker/package.json b/uni_modules/uni-file-picker/package.json new file mode 100644 index 0000000..b365074 --- /dev/null +++ b/uni_modules/uni-file-picker/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-file-picker", + "displayName": "uni-file-picker 文件选择上传", + "version": "1.0.11", + "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间", + "keywords": [ + "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", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "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" + } + } + } + } +} diff --git a/uni_modules/uni-file-picker/readme.md b/uni_modules/uni-file-picker/readme.md new file mode 100644 index 0000000..781aea7 --- /dev/null +++ b/uni_modules/uni-file-picker/readme.md @@ -0,0 +1,11 @@ + +## FilePicker 文件选择上传 + +> **组件名:uni-file-picker** +> 代码块: `uFilePicker` + + +文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-forms/changelog.md b/uni_modules/uni-forms/changelog.md new file mode 100644 index 0000000..7af452c --- /dev/null +++ b/uni_modules/uni-forms/changelog.md @@ -0,0 +1,100 @@ +## 1.4.13(2024-10-08) +- 修复 校验规则在抖音开发者工具上不生效的bug,详见:[https://ask.dcloud.net.cn/question/191933](https://ask.dcloud.net.cn/question/191933) +## 1.4.12 (2024-9-21) +- 修复 form上次修改的问题 +## 1.4.11 (2024-9-14) +- 修复 binddata的兼容性问题 +## 1.4.10(2023-11-03) +- 优化 labelWidth 描述错误 +## 1.4.9(2023-02-10) +- 修复 required 参数无法动态绑定 +## 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) +- 修复 label 插槽不生效的bug +## 1.3.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-forms](https://uniapp.dcloud.io/component/uniui/uni-forms) +## 1.2.7(2021-08-13) +- 修复 没有添加校验规则的字段依然报错的Bug +## 1.2.6(2021-08-11) +- 修复 重置表单错误信息无法清除的问题 +## 1.2.5(2021-08-11) +- 优化 组件文档 +## 1.2.4(2021-08-11) +- 修复 表单验证只生效一次的问题 +## 1.2.3(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.2.2(2021-07-26) +- 修复 vue2 下条件编译导致destroyed生命周期失效的Bug +- 修复 1.2.1 引起的示例在小程序平台报错的Bug +## 1.2.1(2021-07-22) +- 修复 动态校验表单,默认值为空的情况下校验失效的Bug +- 修复 不指定name属性时,运行报错的Bug +- 优化 label默认宽度从65调整至70,使required为true且四字时不换行 +- 优化 组件示例,新增动态校验示例代码 +- 优化 组件文档,使用方式更清晰 +## 1.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.2(2021-06-25) +- 修复 pattern 属性在微信小程序平台无效的问题 +## 1.1.1(2021-06-22) +- 修复 validate-trigger属性为submit且err-show-type属性为toast时不能弹出的Bug +## 1.1.0(2021-06-22) +- 修复 只写setRules方法而导致校验不生效的Bug +- 修复 由上个办法引发的错误提示文字错位的Bug +## 1.0.48(2021-06-21) +- 修复 不设置 label 属性 ,无法设置label插槽的问题 +## 1.0.47(2021-06-21) +- 修复 不设置label属性,label-width属性不生效的bug +- 修复 setRules 方法与rules属性冲突的问题 +## 1.0.46(2021-06-04) +- 修复 动态删减数据导致报错的问题 +## 1.0.45(2021-06-04) +- 新增 modelValue 属性 ,value 即将废弃 +## 1.0.44(2021-06-02) +- 新增 uni-forms-item 可以设置单独的 rules +- 新增 validate 事件增加 keepitem 参数,可以选择那些字段不过滤 +- 优化 submit 事件重命名为 validate +## 1.0.43(2021-05-12) +- 新增 组件示例地址 +## 1.0.42(2021-04-30) +- 修复 自定义检验器失效的问题 +## 1.0.41(2021-03-05) +- 更新 校验器 +- 修复 表单规则设置类型为 number 的情况下,值为0校验失败的Bug +## 1.0.40(2021-03-04) +- 修复 动态显示uni-forms-item的情况下,submit 方法获取值错误的Bug +## 1.0.39(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 校验器传入 int 等类型 ,返回String类型的Bug 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 new file mode 100644 index 0000000..6af50aa --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue @@ -0,0 +1,632 @@ + + + + + diff --git a/uni_modules/uni-forms/components/uni-forms/uni-forms.vue b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue new file mode 100644 index 0000000..64dde2a --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue @@ -0,0 +1,404 @@ + + + + + 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 0000000..31d57f4 --- /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/components/uni-forms/validate.js b/uni_modules/uni-forms/components/uni-forms/validate.js new file mode 100644 index 0000000..c29ef7f --- /dev/null +++ b/uni_modules/uni-forms/components/uni-forms/validate.js @@ -0,0 +1,486 @@ +var pattern = { + email: /^\S+?@\S+?\.\S+?$/, + idcard: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/, + url: new RegExp( + "^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$", + 'i') +}; + +const FORMAT_MAPPING = { + "int": 'integer', + "bool": 'boolean', + "double": 'number', + "long": 'number', + "password": 'string' + // "fileurls": 'array' +} + +function formatMessage(args, resources = '') { + var defaultMessage = ['label'] + defaultMessage.forEach((item) => { + if (args[item] === undefined) { + args[item] = '' + } + }) + + let str = resources + for (let key in args) { + let reg = new RegExp('{' + key + '}') + str = str.replace(reg, args[key]) + } + return str +} + +function isEmptyValue(value, type) { + if (value === undefined || value === null) { + return true; + } + + if (typeof value === 'string' && !value) { + return true; + } + + if (Array.isArray(value) && !value.length) { + return true; + } + + if (type === 'object' && !Object.keys(value).length) { + return true; + } + + return false; +} + +const types = { + integer(value) { + return types.number(value) && parseInt(value, 10) === value; + }, + string(value) { + return typeof value === 'string'; + }, + number(value) { + if (isNaN(value)) { + return false; + } + return typeof value === 'number'; + }, + "boolean": function(value) { + return typeof value === 'boolean'; + }, + "float": function(value) { + return types.number(value) && !types.integer(value); + }, + array(value) { + return Array.isArray(value); + }, + object(value) { + return typeof value === 'object' && !types.array(value); + }, + date(value) { + return value instanceof Date; + }, + timestamp(value) { + if (!this.integer(value) || Math.abs(value).toString().length > 16) { + return false + } + return true; + }, + file(value) { + return typeof value.url === 'string'; + }, + email(value) { + return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255; + }, + url(value) { + return typeof value === 'string' && !!value.match(pattern.url); + }, + pattern(reg, value) { + try { + return new RegExp(reg).test(value); + } catch (e) { + return false; + } + }, + method(value) { + return typeof value === 'function'; + }, + idcard(value) { + return typeof value === 'string' && !!value.match(pattern.idcard); + }, + 'url-https'(value) { + return this.url(value) && value.startsWith('https://'); + }, + 'url-scheme'(value) { + return value.startsWith('://'); + }, + 'url-web'(value) { + return false; + } +} + +class RuleValidator { + + constructor(message) { + this._message = message + } + + async validateRule(fieldKey, fieldValue, value, data, allData) { + var result = null + + let rules = fieldValue.rules + + let hasRequired = rules.findIndex((item) => { + return item.required + }) + if (hasRequired < 0) { + if (value === null || value === undefined) { + return result + } + if (typeof value === 'string' && !value.length) { + return result + } + } + + var message = this._message + + if (rules === undefined) { + return message['default'] + } + + for (var i = 0; i < rules.length; i++) { + let rule = rules[i] + let vt = this._getValidateType(rule) + + Object.assign(rule, { + label: fieldValue.label || `["${fieldKey}"]` + }) + + if (RuleValidatorHelper[vt]) { + result = RuleValidatorHelper[vt](rule, value, message) + if (result != null) { + break + } + } + + if (rule.validateExpr) { + let now = Date.now() + let resultExpr = rule.validateExpr(value, allData, now) + if (resultExpr === false) { + result = this._getMessage(rule, rule.errorMessage || this._message['default']) + break + } + } + + if (rule.validateFunction) { + result = await this.validateFunction(rule, value, data, allData, vt) + if (result !== null) { + break + } + } + } + + if (result !== null) { + result = message.TAG + result + } + + return result + } + + async validateFunction(rule, value, data, allData, vt) { + let result = null + try { + let callbackMessage = null + const res = await rule.validateFunction(rule, value, allData || data, (message) => { + callbackMessage = message + }) + if (callbackMessage || (typeof res === 'string' && res) || res === false) { + result = this._getMessage(rule, callbackMessage || res, vt) + } + } catch (e) { + result = this._getMessage(rule, e.message, vt) + } + return result + } + + _getMessage(rule, message, vt) { + return formatMessage(rule, message || rule.errorMessage || this._message[vt] || message['default']) + } + + _getValidateType(rule) { + var result = '' + if (rule.required) { + result = 'required' + } else if (rule.format) { + result = 'format' + } else if (rule.arrayType) { + result = 'arrayTypeFormat' + } else if (rule.range) { + result = 'range' + } else if (rule.maximum !== undefined || rule.minimum !== undefined) { + result = 'rangeNumber' + } else if (rule.maxLength !== undefined || rule.minLength !== undefined) { + result = 'rangeLength' + } else if (rule.pattern) { + result = 'pattern' + } else if (rule.validateFunction) { + result = 'validateFunction' + } + return result + } +} + +const RuleValidatorHelper = { + required(rule, value, message) { + if (rule.required && isEmptyValue(value, rule.format || typeof value)) { + return formatMessage(rule, rule.errorMessage || message.required); + } + + return null + }, + + range(rule, value, message) { + const { + range, + errorMessage + } = rule; + + let list = new Array(range.length); + for (let i = 0; i < range.length; i++) { + const item = range[i]; + if (types.object(item) && item.value !== undefined) { + list[i] = item.value; + } else { + list[i] = item; + } + } + + let result = false + if (Array.isArray(value)) { + result = (new Set(value.concat(list)).size === list.length); + } else { + if (list.indexOf(value) > -1) { + result = true; + } + } + + if (!result) { + return formatMessage(rule, errorMessage || message['enum']); + } + + return null + }, + + rangeNumber(rule, value, message) { + if (!types.number(value)) { + return formatMessage(rule, rule.errorMessage || message.pattern.mismatch); + } + + let { + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum + } = rule; + let min = exclusiveMinimum ? value <= minimum : value < minimum; + let max = exclusiveMaximum ? value >= maximum : value > maximum; + + if (minimum !== undefined && min) { + return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMinimum ? + 'exclusiveMinimum' : 'minimum' + ]) + } else if (maximum !== undefined && max) { + return formatMessage(rule, rule.errorMessage || message['number'][exclusiveMaximum ? + 'exclusiveMaximum' : 'maximum' + ]) + } else if (minimum !== undefined && maximum !== undefined && (min || max)) { + return formatMessage(rule, rule.errorMessage || message['number'].range) + } + + return null + }, + + rangeLength(rule, value, message) { + if (!types.string(value) && !types.array(value)) { + return formatMessage(rule, rule.errorMessage || message.pattern.mismatch); + } + + let min = rule.minLength; + let max = rule.maxLength; + let val = value.length; + + if (min !== undefined && val < min) { + return formatMessage(rule, rule.errorMessage || message['length'].minLength) + } else if (max !== undefined && val > max) { + return formatMessage(rule, rule.errorMessage || message['length'].maxLength) + } else if (min !== undefined && max !== undefined && (val < min || val > max)) { + return formatMessage(rule, rule.errorMessage || message['length'].range) + } + + return null + }, + + pattern(rule, value, message) { + if (!types['pattern'](rule.pattern, value)) { + return formatMessage(rule, rule.errorMessage || message.pattern.mismatch); + } + + return null + }, + + format(rule, value, message) { + var customTypes = Object.keys(types); + var format = FORMAT_MAPPING[rule.format] ? FORMAT_MAPPING[rule.format] : (rule.format || rule.arrayType); + + if (customTypes.indexOf(format) > -1) { + if (!types[format](value)) { + return formatMessage(rule, rule.errorMessage || message.typeError); + } + } + + return null + }, + + arrayTypeFormat(rule, value, message) { + if (!Array.isArray(value)) { + return formatMessage(rule, rule.errorMessage || message.typeError); + } + + for (let i = 0; i < value.length; i++) { + const element = value[i]; + let formatResult = this.format(rule, element, message) + if (formatResult !== null) { + return formatResult + } + } + + return null + } +} + +class SchemaValidator extends RuleValidator { + + constructor(schema, options) { + super(SchemaValidator.message); + + this._schema = schema + this._options = options || null + } + + updateSchema(schema) { + this._schema = schema + } + + async validate(data, allData) { + let result = this._checkFieldInSchema(data) + if (!result) { + result = await this.invokeValidate(data, false, allData) + } + return result.length ? result[0] : null + } + + async validateAll(data, allData) { + let result = this._checkFieldInSchema(data) + if (!result) { + result = await this.invokeValidate(data, true, allData) + } + return result + } + + async validateUpdate(data, allData) { + let result = this._checkFieldInSchema(data) + if (!result) { + result = await this.invokeValidateUpdate(data, false, allData) + } + return result.length ? result[0] : null + } + + async invokeValidate(data, all, allData) { + let result = [] + let schema = this._schema + for (let key in schema) { + let value = schema[key] + let errorMessage = await this.validateRule(key, value, data[key], data, allData) + if (errorMessage != null) { + result.push({ + key, + errorMessage + }) + if (!all) break + } + } + return result + } + + async invokeValidateUpdate(data, all, allData) { + let result = [] + for (let key in data) { + let errorMessage = await this.validateRule(key, this._schema[key], data[key], data, allData) + if (errorMessage != null) { + result.push({ + key, + errorMessage + }) + if (!all) break + } + } + return result + } + + _checkFieldInSchema(data) { + var keys = Object.keys(data) + var keys2 = Object.keys(this._schema) + if (new Set(keys.concat(keys2)).size === keys2.length) { + return '' + } + + var noExistFields = keys.filter((key) => { + return keys2.indexOf(key) < 0; + }) + var errorMessage = formatMessage({ + field: JSON.stringify(noExistFields) + }, SchemaValidator.message.TAG + SchemaValidator.message['defaultInvalid']) + return [{ + key: 'invalid', + errorMessage + }] + } +} + +function Message() { + return { + TAG: "", + default: '验证错误', + defaultInvalid: '提交的字段{field}在数据库中并不存在', + validateFunction: '验证无效', + required: '{label}必填', + 'enum': '{label}超出范围', + timestamp: '{label}格式无效', + whitespace: '{label}不能为空', + typeError: '{label}类型无效', + date: { + format: '{label}日期{value}格式无效', + parse: '{label}日期无法解析,{value}无效', + invalid: '{label}日期{value}无效' + }, + length: { + minLength: '{label}长度不能少于{minLength}', + maxLength: '{label}长度不能超过{maxLength}', + range: '{label}必须介于{minLength}和{maxLength}之间' + }, + number: { + minimum: '{label}不能小于{minimum}', + maximum: '{label}不能大于{maximum}', + exclusiveMinimum: '{label}不能小于等于{minimum}', + exclusiveMaximum: '{label}不能大于等于{maximum}', + range: '{label}必须介于{minimum}and{maximum}之间' + }, + pattern: { + mismatch: '{label}格式不匹配' + } + }; +} + + +SchemaValidator.message = new Message(); + +export default SchemaValidator diff --git a/uni_modules/uni-forms/package.json b/uni_modules/uni-forms/package.json new file mode 100644 index 0000000..42204d9 --- /dev/null +++ b/uni_modules/uni-forms/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-forms", + "displayName": "uni-forms 表单", + "version": "1.4.13", + "description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据", + "keywords": [ + "uni-ui", + "表单", + "校验", + "表单校验", + "表单验证" +], + "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", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-forms/readme.md b/uni_modules/uni-forms/readme.md new file mode 100644 index 0000000..5334701 --- /dev/null +++ b/uni_modules/uni-forms/readme.md @@ -0,0 +1,23 @@ + + +## Forms 表单 + +> **组件名:uni-forms** +> 代码块: `uForms`、`uni-forms-item` +> 关联组件:`uni-forms-item`、`uni-easyinput`、`uni-data-checkbox`、`uni-group`。 + + +uni-app的内置组件已经有了 `
    `组件,用于提交表单内容。 + +然而几乎每个表单都需要做表单验证,为了方便做表单验证,减少重复开发,`uni ui` 又基于 ``组件封装了 ``组件,内置了表单验证功能。 + +`` 提供了 `rules`属性来描述校验规则、``子组件来包裹具体的表单项,以及给原生或三方组件提供了 `binddata()` 来设置表单值。 + +每个要校验的表单项,不管input还是checkbox,都必须放在``组件中,且一个``组件只能放置一个表单项。 + +``组件内部预留了显示error message的区域,默认是在表单项的底部。 + +另外,``组件下面的各个表单项,可以通过``包裹为不同的分组。同一``下的不同表单项目将聚拢在一起,同其他group保持垂直间距。``仅影响视觉效果。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-forms) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-goods-nav/changelog.md b/uni_modules/uni-goods-nav/changelog.md new file mode 100644 index 0000000..c06a778 --- /dev/null +++ b/uni_modules/uni-goods-nav/changelog.md @@ -0,0 +1,18 @@ +## 1.2.1(2022-05-30) +- 新增 stat属性,是否开启uni统计功能 +## 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-goods-nav](https://uniapp.dcloud.io/component/uniui/uni-goods-nav) +## 1.1.1(2021-08-24) +- 新增 支持国际化 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.5(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json new file mode 100644 index 0000000..94f1868 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/en.json @@ -0,0 +1,6 @@ +{ + "uni-goods-nav.options.shop": "shop", + "uni-goods-nav.options.cart": "cart", + "uni-goods-nav.buttonGroup.addToCart": "add to cart", + "uni-goods-nav.buttonGroup.buyNow": "buy now" +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js new file mode 100644 index 0000000..d2afd08 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json new file mode 100644 index 0000000..84243b0 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hans.json @@ -0,0 +1,6 @@ +{ + "uni-goods-nav.options.shop": "店铺", + "uni-goods-nav.options.cart": "购物车", + "uni-goods-nav.buttonGroup.addToCart": "加入购物车", + "uni-goods-nav.buttonGroup.buyNow": "立即购买" +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json new file mode 100644 index 0000000..bfd405e --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/i18n/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "uni-goods-nav.options.shop": "店鋪", + "uni-goods-nav.options.cart": "購物車", + "uni-goods-nav.buttonGroup.addToCart": "加入購物車", + "uni-goods-nav.buttonGroup.buyNow": "立即購買" +} diff --git a/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue b/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue new file mode 100644 index 0000000..e7f28b6 --- /dev/null +++ b/uni_modules/uni-goods-nav/components/uni-goods-nav/uni-goods-nav.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/uni_modules/uni-goods-nav/package.json b/uni_modules/uni-goods-nav/package.json new file mode 100644 index 0000000..a68509b --- /dev/null +++ b/uni_modules/uni-goods-nav/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-goods-nav", + "displayName": "uni-goods-nav 商品导航", + "version": "1.2.1", + "description": "商品导航组件主要用于电商类应用底部导航,可自定义加入购物车,购买等操作", + "keywords": [ + "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": [ + "uni-scss", + "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" + } + } + } + } +} diff --git a/uni_modules/uni-goods-nav/readme.md b/uni_modules/uni-goods-nav/readme.md new file mode 100644 index 0000000..67a7482 --- /dev/null +++ b/uni_modules/uni-goods-nav/readme.md @@ -0,0 +1,10 @@ + + +## GoodsNav 商品导航 +> **组件名:uni-goods-nav** +> 代码块: `uGoodsNav` + +商品加入购物车,立即购买等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-goods-nav) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-grid/changelog.md b/uni_modules/uni-grid/changelog.md new file mode 100644 index 0000000..184941d --- /dev/null +++ b/uni_modules/uni-grid/changelog.md @@ -0,0 +1,13 @@ +## 1.4.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-grid](https://uniapp.dcloud.io/component/uniui/uni-grid) +## 1.3.2(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.3.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.3.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.2.4(2021-05-12) +- 新增 组件示例地址 +## 1.2.3(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue b/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue new file mode 100644 index 0000000..ab86a04 --- /dev/null +++ b/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/uni_modules/uni-grid/components/uni-grid/uni-grid.vue b/uni_modules/uni-grid/components/uni-grid/uni-grid.vue new file mode 100644 index 0000000..71edf41 --- /dev/null +++ b/uni_modules/uni-grid/components/uni-grid/uni-grid.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/uni_modules/uni-grid/package.json b/uni_modules/uni-grid/package.json new file mode 100644 index 0000000..c68c952 --- /dev/null +++ b/uni_modules/uni-grid/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-grid", + "displayName": "uni-grid 宫格", + "version": "1.4.0", + "description": "Grid 宫格组件,提供移动端常见的宫格布局,如九宫格。", + "keywords": [ + "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": ["uni-scss","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" + } + } + } + } +} diff --git a/uni_modules/uni-grid/readme.md b/uni_modules/uni-grid/readme.md new file mode 100644 index 0000000..c0bd3b9 --- /dev/null +++ b/uni_modules/uni-grid/readme.md @@ -0,0 +1,11 @@ + + +## Grid 宫格 +> **组件名:uni-grid** +> 代码块: `uGrid` + + +宫格组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-grid) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-group/changelog.md b/uni_modules/uni-group/changelog.md new file mode 100644 index 0000000..5b27e3a --- /dev/null +++ b/uni_modules/uni-group/changelog.md @@ -0,0 +1,16 @@ +## 1.2.2(2022-05-30) +- 新增 stat属性,是否开启uni统计功能 +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 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-group](https://uniapp.dcloud.io/component/uniui/uni-group) +## 1.1.7(2021-11-08) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +- 优化 组件文档 +## 1.0.3(2021-05-12) +- 新增 组件示例地址 +## 1.0.2(2021-02-05) +- 调整为uni_modules目录规范 +- 优化 兼容 nvue 页面 diff --git a/uni_modules/uni-group/components/uni-group/uni-group.vue b/uni_modules/uni-group/components/uni-group/uni-group.vue new file mode 100644 index 0000000..40494e9 --- /dev/null +++ b/uni_modules/uni-group/components/uni-group/uni-group.vue @@ -0,0 +1,134 @@ + + + + diff --git a/uni_modules/uni-group/package.json b/uni_modules/uni-group/package.json new file mode 100644 index 0000000..779b3ae --- /dev/null +++ b/uni_modules/uni-group/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-group", + "displayName": "uni-group 分组", + "version": "1.2.2", + "description": "分组组件可用于将组件用于分组,添加间隔,以产生明显的区块", + "keywords": [ + "uni-ui", + "uniui", + "group", + "分组", + "" +], + "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-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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-group/readme.md b/uni_modules/uni-group/readme.md new file mode 100644 index 0000000..16dac9e --- /dev/null +++ b/uni_modules/uni-group/readme.md @@ -0,0 +1,9 @@ + +## Group 分组 +> **组件名:uni-group** +> 代码块: `uGroup` + +分组组件可用于将组件分组,添加间隔,以产生明显的区块。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-group) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-icons/changelog.md b/uni_modules/uni-icons/changelog.md new file mode 100644 index 0000000..347ebf6 --- /dev/null +++ b/uni_modules/uni-icons/changelog.md @@ -0,0 +1,42 @@ +## 2.0.10(2024-06-07) +- 优化 uni-app x 中,size 属性的类型 +## 2.0.9(2024-01-12) +fix: 修复图标大小默认值错误的问题 +## 2.0.8(2023-12-14) +- 修复 项目未使用 ts 情况下,打包报错的bug +## 2.0.7(2023-12-14) +- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug +## 2.0.6(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.5(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.4(2023-12-06) +- 优化 uni-app x 下示例项目图标排序 +## 2.0.3(2023-12-06) +- 修复 nvue下引入组件报错的bug +## 2.0.2(2023-12-05) +-优化 size 属性支持单位 +## 2.0.1(2023-12-05) +- 新增 uni-app x 支持定义图标 +## 1.3.5(2022-01-24) +- 优化 size 属性可以传入不带单位的字符串数值 +## 1.3.4(2022-01-24) +- 优化 size 支持其他单位 +## 1.3.3(2022-01-17) +- 修复 nvue 有些图标不显示的bug,兼容老版本图标 +## 1.3.2(2021-12-01) +- 优化 示例可复制图标名称 +## 1.3.1(2021-11-23) +- 优化 兼容旧组件 type 值 +## 1.3.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-icons](https://uniapp.dcloud.io/component/uniui/uni-icons) +## 1.1.7(2021-11-08) +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.5(2021-05-12) +- 新增 组件示例地址 +## 1.1.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-icons/components/uni-icons/icons.js b/uni_modules/uni-icons/components/uni-icons/icons.js new file mode 100644 index 0000000..6425718 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/icons.js @@ -0,0 +1,1169 @@ +export default { + "id": "2852637", + "name": "uniui图标库", + "font_family": "uniicons", + "css_prefix_text": "uniui-", + "description": "", + "glyphs": [ + { + "icon_id": "25027049", + "name": "yanse", + "font_class": "color", + "unicode": "e6cf", + "unicode_decimal": 59087 + }, + { + "icon_id": "25027048", + "name": "wallet", + "font_class": "wallet", + "unicode": "e6b1", + "unicode_decimal": 59057 + }, + { + "icon_id": "25015720", + "name": "settings-filled", + "font_class": "settings-filled", + "unicode": "e6ce", + "unicode_decimal": 59086 + }, + { + "icon_id": "25015434", + "name": "shimingrenzheng-filled", + "font_class": "auth-filled", + "unicode": "e6cc", + "unicode_decimal": 59084 + }, + { + "icon_id": "24934246", + "name": "shop-filled", + "font_class": "shop-filled", + "unicode": "e6cd", + "unicode_decimal": 59085 + }, + { + "icon_id": "24934159", + "name": "staff-filled-01", + "font_class": "staff-filled", + "unicode": "e6cb", + "unicode_decimal": 59083 + }, + { + "icon_id": "24932461", + "name": "VIP-filled", + "font_class": "vip-filled", + "unicode": "e6c6", + "unicode_decimal": 59078 + }, + { + "icon_id": "24932462", + "name": "plus_circle_fill", + "font_class": "plus-filled", + "unicode": "e6c7", + "unicode_decimal": 59079 + }, + { + "icon_id": "24932463", + "name": "folder_add-filled", + "font_class": "folder-add-filled", + "unicode": "e6c8", + "unicode_decimal": 59080 + }, + { + "icon_id": "24932464", + "name": "yanse-filled", + "font_class": "color-filled", + "unicode": "e6c9", + "unicode_decimal": 59081 + }, + { + "icon_id": "24932465", + "name": "tune-filled", + "font_class": "tune-filled", + "unicode": "e6ca", + "unicode_decimal": 59082 + }, + { + "icon_id": "24932455", + "name": "a-rilidaka-filled", + "font_class": "calendar-filled", + "unicode": "e6c0", + "unicode_decimal": 59072 + }, + { + "icon_id": "24932456", + "name": "notification-filled", + "font_class": "notification-filled", + "unicode": "e6c1", + "unicode_decimal": 59073 + }, + { + "icon_id": "24932457", + "name": "wallet-filled", + "font_class": "wallet-filled", + "unicode": "e6c2", + "unicode_decimal": 59074 + }, + { + "icon_id": "24932458", + "name": "paihangbang-filled", + "font_class": "medal-filled", + "unicode": "e6c3", + "unicode_decimal": 59075 + }, + { + "icon_id": "24932459", + "name": "gift-filled", + "font_class": "gift-filled", + "unicode": "e6c4", + "unicode_decimal": 59076 + }, + { + "icon_id": "24932460", + "name": "fire-filled", + "font_class": "fire-filled", + "unicode": "e6c5", + "unicode_decimal": 59077 + }, + { + "icon_id": "24928001", + "name": "refreshempty", + "font_class": "refreshempty", + "unicode": "e6bf", + "unicode_decimal": 59071 + }, + { + "icon_id": "24926853", + "name": "location-ellipse", + "font_class": "location-filled", + "unicode": "e6af", + "unicode_decimal": 59055 + }, + { + "icon_id": "24926735", + "name": "person-filled", + "font_class": "person-filled", + "unicode": "e69d", + "unicode_decimal": 59037 + }, + { + "icon_id": "24926703", + "name": "personadd-filled", + "font_class": "personadd-filled", + "unicode": "e698", + "unicode_decimal": 59032 + }, + { + "icon_id": "24923351", + "name": "back", + "font_class": "back", + "unicode": "e6b9", + "unicode_decimal": 59065 + }, + { + "icon_id": "24923352", + "name": "forward", + "font_class": "forward", + "unicode": "e6ba", + "unicode_decimal": 59066 + }, + { + "icon_id": "24923353", + "name": "arrowthinright", + "font_class": "arrow-right", + "unicode": "e6bb", + "unicode_decimal": 59067 + }, + { + "icon_id": "24923353", + "name": "arrowthinright", + "font_class": "arrowthinright", + "unicode": "e6bb", + "unicode_decimal": 59067 + }, + { + "icon_id": "24923354", + "name": "arrowthinleft", + "font_class": "arrow-left", + "unicode": "e6bc", + "unicode_decimal": 59068 + }, + { + "icon_id": "24923354", + "name": "arrowthinleft", + "font_class": "arrowthinleft", + "unicode": "e6bc", + "unicode_decimal": 59068 + }, + { + "icon_id": "24923355", + "name": "arrowthinup", + "font_class": "arrow-up", + "unicode": "e6bd", + "unicode_decimal": 59069 + }, + { + "icon_id": "24923355", + "name": "arrowthinup", + "font_class": "arrowthinup", + "unicode": "e6bd", + "unicode_decimal": 59069 + }, + { + "icon_id": "24923356", + "name": "arrowthindown", + "font_class": "arrow-down", + "unicode": "e6be", + "unicode_decimal": 59070 + },{ + "icon_id": "24923356", + "name": "arrowthindown", + "font_class": "arrowthindown", + "unicode": "e6be", + "unicode_decimal": 59070 + }, + { + "icon_id": "24923349", + "name": "arrowdown", + "font_class": "bottom", + "unicode": "e6b8", + "unicode_decimal": 59064 + },{ + "icon_id": "24923349", + "name": "arrowdown", + "font_class": "arrowdown", + "unicode": "e6b8", + "unicode_decimal": 59064 + }, + { + "icon_id": "24923346", + "name": "arrowright", + "font_class": "right", + "unicode": "e6b5", + "unicode_decimal": 59061 + }, + { + "icon_id": "24923346", + "name": "arrowright", + "font_class": "arrowright", + "unicode": "e6b5", + "unicode_decimal": 59061 + }, + { + "icon_id": "24923347", + "name": "arrowup", + "font_class": "top", + "unicode": "e6b6", + "unicode_decimal": 59062 + }, + { + "icon_id": "24923347", + "name": "arrowup", + "font_class": "arrowup", + "unicode": "e6b6", + "unicode_decimal": 59062 + }, + { + "icon_id": "24923348", + "name": "arrowleft", + "font_class": "left", + "unicode": "e6b7", + "unicode_decimal": 59063 + }, + { + "icon_id": "24923348", + "name": "arrowleft", + "font_class": "arrowleft", + "unicode": "e6b7", + "unicode_decimal": 59063 + }, + { + "icon_id": "24923334", + "name": "eye", + "font_class": "eye", + "unicode": "e651", + "unicode_decimal": 58961 + }, + { + "icon_id": "24923335", + "name": "eye-filled", + "font_class": "eye-filled", + "unicode": "e66a", + "unicode_decimal": 58986 + }, + { + "icon_id": "24923336", + "name": "eye-slash", + "font_class": "eye-slash", + "unicode": "e6b3", + "unicode_decimal": 59059 + }, + { + "icon_id": "24923337", + "name": "eye-slash-filled", + "font_class": "eye-slash-filled", + "unicode": "e6b4", + "unicode_decimal": 59060 + }, + { + "icon_id": "24923305", + "name": "info-filled", + "font_class": "info-filled", + "unicode": "e649", + "unicode_decimal": 58953 + }, + { + "icon_id": "24923299", + "name": "reload-01", + "font_class": "reload", + "unicode": "e6b2", + "unicode_decimal": 59058 + }, + { + "icon_id": "24923195", + "name": "mic_slash_fill", + "font_class": "micoff-filled", + "unicode": "e6b0", + "unicode_decimal": 59056 + }, + { + "icon_id": "24923165", + "name": "map-pin-ellipse", + "font_class": "map-pin-ellipse", + "unicode": "e6ac", + "unicode_decimal": 59052 + }, + { + "icon_id": "24923166", + "name": "map-pin", + "font_class": "map-pin", + "unicode": "e6ad", + "unicode_decimal": 59053 + }, + { + "icon_id": "24923167", + "name": "location", + "font_class": "location", + "unicode": "e6ae", + "unicode_decimal": 59054 + }, + { + "icon_id": "24923064", + "name": "starhalf", + "font_class": "starhalf", + "unicode": "e683", + "unicode_decimal": 59011 + }, + { + "icon_id": "24923065", + "name": "star", + "font_class": "star", + "unicode": "e688", + "unicode_decimal": 59016 + }, + { + "icon_id": "24923066", + "name": "star-filled", + "font_class": "star-filled", + "unicode": "e68f", + "unicode_decimal": 59023 + }, + { + "icon_id": "24899646", + "name": "a-rilidaka", + "font_class": "calendar", + "unicode": "e6a0", + "unicode_decimal": 59040 + }, + { + "icon_id": "24899647", + "name": "fire", + "font_class": "fire", + "unicode": "e6a1", + "unicode_decimal": 59041 + }, + { + "icon_id": "24899648", + "name": "paihangbang", + "font_class": "medal", + "unicode": "e6a2", + "unicode_decimal": 59042 + }, + { + "icon_id": "24899649", + "name": "font", + "font_class": "font", + "unicode": "e6a3", + "unicode_decimal": 59043 + }, + { + "icon_id": "24899650", + "name": "gift", + "font_class": "gift", + "unicode": "e6a4", + "unicode_decimal": 59044 + }, + { + "icon_id": "24899651", + "name": "link", + "font_class": "link", + "unicode": "e6a5", + "unicode_decimal": 59045 + }, + { + "icon_id": "24899652", + "name": "notification", + "font_class": "notification", + "unicode": "e6a6", + "unicode_decimal": 59046 + }, + { + "icon_id": "24899653", + "name": "staff", + "font_class": "staff", + "unicode": "e6a7", + "unicode_decimal": 59047 + }, + { + "icon_id": "24899654", + "name": "VIP", + "font_class": "vip", + "unicode": "e6a8", + "unicode_decimal": 59048 + }, + { + "icon_id": "24899655", + "name": "folder_add", + "font_class": "folder-add", + "unicode": "e6a9", + "unicode_decimal": 59049 + }, + { + "icon_id": "24899656", + "name": "tune", + "font_class": "tune", + "unicode": "e6aa", + "unicode_decimal": 59050 + }, + { + "icon_id": "24899657", + "name": "shimingrenzheng", + "font_class": "auth", + "unicode": "e6ab", + "unicode_decimal": 59051 + }, + { + "icon_id": "24899565", + "name": "person", + "font_class": "person", + "unicode": "e699", + "unicode_decimal": 59033 + }, + { + "icon_id": "24899566", + "name": "email-filled", + "font_class": "email-filled", + "unicode": "e69a", + "unicode_decimal": 59034 + }, + { + "icon_id": "24899567", + "name": "phone-filled", + "font_class": "phone-filled", + "unicode": "e69b", + "unicode_decimal": 59035 + }, + { + "icon_id": "24899568", + "name": "phone", + "font_class": "phone", + "unicode": "e69c", + "unicode_decimal": 59036 + }, + { + "icon_id": "24899570", + "name": "email", + "font_class": "email", + "unicode": "e69e", + "unicode_decimal": 59038 + }, + { + "icon_id": "24899571", + "name": "personadd", + "font_class": "personadd", + "unicode": "e69f", + "unicode_decimal": 59039 + }, + { + "icon_id": "24899558", + "name": "chatboxes-filled", + "font_class": "chatboxes-filled", + "unicode": "e692", + "unicode_decimal": 59026 + }, + { + "icon_id": "24899559", + "name": "contact", + "font_class": "contact", + "unicode": "e693", + "unicode_decimal": 59027 + }, + { + "icon_id": "24899560", + "name": "chatbubble-filled", + "font_class": "chatbubble-filled", + "unicode": "e694", + "unicode_decimal": 59028 + }, + { + "icon_id": "24899561", + "name": "contact-filled", + "font_class": "contact-filled", + "unicode": "e695", + "unicode_decimal": 59029 + }, + { + "icon_id": "24899562", + "name": "chatboxes", + "font_class": "chatboxes", + "unicode": "e696", + "unicode_decimal": 59030 + }, + { + "icon_id": "24899563", + "name": "chatbubble", + "font_class": "chatbubble", + "unicode": "e697", + "unicode_decimal": 59031 + }, + { + "icon_id": "24881290", + "name": "upload-filled", + "font_class": "upload-filled", + "unicode": "e68e", + "unicode_decimal": 59022 + }, + { + "icon_id": "24881292", + "name": "upload", + "font_class": "upload", + "unicode": "e690", + "unicode_decimal": 59024 + }, + { + "icon_id": "24881293", + "name": "weixin", + "font_class": "weixin", + "unicode": "e691", + "unicode_decimal": 59025 + }, + { + "icon_id": "24881274", + "name": "compose", + "font_class": "compose", + "unicode": "e67f", + "unicode_decimal": 59007 + }, + { + "icon_id": "24881275", + "name": "qq", + "font_class": "qq", + "unicode": "e680", + "unicode_decimal": 59008 + }, + { + "icon_id": "24881276", + "name": "download-filled", + "font_class": "download-filled", + "unicode": "e681", + "unicode_decimal": 59009 + }, + { + "icon_id": "24881277", + "name": "pengyouquan", + "font_class": "pyq", + "unicode": "e682", + "unicode_decimal": 59010 + }, + { + "icon_id": "24881279", + "name": "sound", + "font_class": "sound", + "unicode": "e684", + "unicode_decimal": 59012 + }, + { + "icon_id": "24881280", + "name": "trash-filled", + "font_class": "trash-filled", + "unicode": "e685", + "unicode_decimal": 59013 + }, + { + "icon_id": "24881281", + "name": "sound-filled", + "font_class": "sound-filled", + "unicode": "e686", + "unicode_decimal": 59014 + }, + { + "icon_id": "24881282", + "name": "trash", + "font_class": "trash", + "unicode": "e687", + "unicode_decimal": 59015 + }, + { + "icon_id": "24881284", + "name": "videocam-filled", + "font_class": "videocam-filled", + "unicode": "e689", + "unicode_decimal": 59017 + }, + { + "icon_id": "24881285", + "name": "spinner-cycle", + "font_class": "spinner-cycle", + "unicode": "e68a", + "unicode_decimal": 59018 + }, + { + "icon_id": "24881286", + "name": "weibo", + "font_class": "weibo", + "unicode": "e68b", + "unicode_decimal": 59019 + }, + { + "icon_id": "24881288", + "name": "videocam", + "font_class": "videocam", + "unicode": "e68c", + "unicode_decimal": 59020 + }, + { + "icon_id": "24881289", + "name": "download", + "font_class": "download", + "unicode": "e68d", + "unicode_decimal": 59021 + }, + { + "icon_id": "24879601", + "name": "help", + "font_class": "help", + "unicode": "e679", + "unicode_decimal": 59001 + }, + { + "icon_id": "24879602", + "name": "navigate-filled", + "font_class": "navigate-filled", + "unicode": "e67a", + "unicode_decimal": 59002 + }, + { + "icon_id": "24879603", + "name": "plusempty", + "font_class": "plusempty", + "unicode": "e67b", + "unicode_decimal": 59003 + }, + { + "icon_id": "24879604", + "name": "smallcircle", + "font_class": "smallcircle", + "unicode": "e67c", + "unicode_decimal": 59004 + }, + { + "icon_id": "24879605", + "name": "minus-filled", + "font_class": "minus-filled", + "unicode": "e67d", + "unicode_decimal": 59005 + }, + { + "icon_id": "24879606", + "name": "micoff", + "font_class": "micoff", + "unicode": "e67e", + "unicode_decimal": 59006 + }, + { + "icon_id": "24879588", + "name": "closeempty", + "font_class": "closeempty", + "unicode": "e66c", + "unicode_decimal": 58988 + }, + { + "icon_id": "24879589", + "name": "clear", + "font_class": "clear", + "unicode": "e66d", + "unicode_decimal": 58989 + }, + { + "icon_id": "24879590", + "name": "navigate", + "font_class": "navigate", + "unicode": "e66e", + "unicode_decimal": 58990 + }, + { + "icon_id": "24879591", + "name": "minus", + "font_class": "minus", + "unicode": "e66f", + "unicode_decimal": 58991 + }, + { + "icon_id": "24879592", + "name": "image", + "font_class": "image", + "unicode": "e670", + "unicode_decimal": 58992 + }, + { + "icon_id": "24879593", + "name": "mic", + "font_class": "mic", + "unicode": "e671", + "unicode_decimal": 58993 + }, + { + "icon_id": "24879594", + "name": "paperplane", + "font_class": "paperplane", + "unicode": "e672", + "unicode_decimal": 58994 + }, + { + "icon_id": "24879595", + "name": "close", + "font_class": "close", + "unicode": "e673", + "unicode_decimal": 58995 + }, + { + "icon_id": "24879596", + "name": "help-filled", + "font_class": "help-filled", + "unicode": "e674", + "unicode_decimal": 58996 + }, + { + "icon_id": "24879597", + "name": "plus-filled", + "font_class": "paperplane-filled", + "unicode": "e675", + "unicode_decimal": 58997 + }, + { + "icon_id": "24879598", + "name": "plus", + "font_class": "plus", + "unicode": "e676", + "unicode_decimal": 58998 + }, + { + "icon_id": "24879599", + "name": "mic-filled", + "font_class": "mic-filled", + "unicode": "e677", + "unicode_decimal": 58999 + }, + { + "icon_id": "24879600", + "name": "image-filled", + "font_class": "image-filled", + "unicode": "e678", + "unicode_decimal": 59000 + }, + { + "icon_id": "24855900", + "name": "locked-filled", + "font_class": "locked-filled", + "unicode": "e668", + "unicode_decimal": 58984 + }, + { + "icon_id": "24855901", + "name": "info", + "font_class": "info", + "unicode": "e669", + "unicode_decimal": 58985 + }, + { + "icon_id": "24855903", + "name": "locked", + "font_class": "locked", + "unicode": "e66b", + "unicode_decimal": 58987 + }, + { + "icon_id": "24855884", + "name": "camera-filled", + "font_class": "camera-filled", + "unicode": "e658", + "unicode_decimal": 58968 + }, + { + "icon_id": "24855885", + "name": "chat-filled", + "font_class": "chat-filled", + "unicode": "e659", + "unicode_decimal": 58969 + }, + { + "icon_id": "24855886", + "name": "camera", + "font_class": "camera", + "unicode": "e65a", + "unicode_decimal": 58970 + }, + { + "icon_id": "24855887", + "name": "circle", + "font_class": "circle", + "unicode": "e65b", + "unicode_decimal": 58971 + }, + { + "icon_id": "24855888", + "name": "checkmarkempty", + "font_class": "checkmarkempty", + "unicode": "e65c", + "unicode_decimal": 58972 + }, + { + "icon_id": "24855889", + "name": "chat", + "font_class": "chat", + "unicode": "e65d", + "unicode_decimal": 58973 + }, + { + "icon_id": "24855890", + "name": "circle-filled", + "font_class": "circle-filled", + "unicode": "e65e", + "unicode_decimal": 58974 + }, + { + "icon_id": "24855891", + "name": "flag", + "font_class": "flag", + "unicode": "e65f", + "unicode_decimal": 58975 + }, + { + "icon_id": "24855892", + "name": "flag-filled", + "font_class": "flag-filled", + "unicode": "e660", + "unicode_decimal": 58976 + }, + { + "icon_id": "24855893", + "name": "gear-filled", + "font_class": "gear-filled", + "unicode": "e661", + "unicode_decimal": 58977 + }, + { + "icon_id": "24855894", + "name": "home", + "font_class": "home", + "unicode": "e662", + "unicode_decimal": 58978 + }, + { + "icon_id": "24855895", + "name": "home-filled", + "font_class": "home-filled", + "unicode": "e663", + "unicode_decimal": 58979 + }, + { + "icon_id": "24855896", + "name": "gear", + "font_class": "gear", + "unicode": "e664", + "unicode_decimal": 58980 + }, + { + "icon_id": "24855897", + "name": "smallcircle-filled", + "font_class": "smallcircle-filled", + "unicode": "e665", + "unicode_decimal": 58981 + }, + { + "icon_id": "24855898", + "name": "map-filled", + "font_class": "map-filled", + "unicode": "e666", + "unicode_decimal": 58982 + }, + { + "icon_id": "24855899", + "name": "map", + "font_class": "map", + "unicode": "e667", + "unicode_decimal": 58983 + }, + { + "icon_id": "24855825", + "name": "refresh-filled", + "font_class": "refresh-filled", + "unicode": "e656", + "unicode_decimal": 58966 + }, + { + "icon_id": "24855826", + "name": "refresh", + "font_class": "refresh", + "unicode": "e657", + "unicode_decimal": 58967 + }, + { + "icon_id": "24855808", + "name": "cloud-upload", + "font_class": "cloud-upload", + "unicode": "e645", + "unicode_decimal": 58949 + }, + { + "icon_id": "24855809", + "name": "cloud-download-filled", + "font_class": "cloud-download-filled", + "unicode": "e646", + "unicode_decimal": 58950 + }, + { + "icon_id": "24855810", + "name": "cloud-download", + "font_class": "cloud-download", + "unicode": "e647", + "unicode_decimal": 58951 + }, + { + "icon_id": "24855811", + "name": "cloud-upload-filled", + "font_class": "cloud-upload-filled", + "unicode": "e648", + "unicode_decimal": 58952 + }, + { + "icon_id": "24855813", + "name": "redo", + "font_class": "redo", + "unicode": "e64a", + "unicode_decimal": 58954 + }, + { + "icon_id": "24855814", + "name": "images-filled", + "font_class": "images-filled", + "unicode": "e64b", + "unicode_decimal": 58955 + }, + { + "icon_id": "24855815", + "name": "undo-filled", + "font_class": "undo-filled", + "unicode": "e64c", + "unicode_decimal": 58956 + }, + { + "icon_id": "24855816", + "name": "more", + "font_class": "more", + "unicode": "e64d", + "unicode_decimal": 58957 + }, + { + "icon_id": "24855817", + "name": "more-filled", + "font_class": "more-filled", + "unicode": "e64e", + "unicode_decimal": 58958 + }, + { + "icon_id": "24855818", + "name": "undo", + "font_class": "undo", + "unicode": "e64f", + "unicode_decimal": 58959 + }, + { + "icon_id": "24855819", + "name": "images", + "font_class": "images", + "unicode": "e650", + "unicode_decimal": 58960 + }, + { + "icon_id": "24855821", + "name": "paperclip", + "font_class": "paperclip", + "unicode": "e652", + "unicode_decimal": 58962 + }, + { + "icon_id": "24855822", + "name": "settings", + "font_class": "settings", + "unicode": "e653", + "unicode_decimal": 58963 + }, + { + "icon_id": "24855823", + "name": "search", + "font_class": "search", + "unicode": "e654", + "unicode_decimal": 58964 + }, + { + "icon_id": "24855824", + "name": "redo-filled", + "font_class": "redo-filled", + "unicode": "e655", + "unicode_decimal": 58965 + }, + { + "icon_id": "24841702", + "name": "list", + "font_class": "list", + "unicode": "e644", + "unicode_decimal": 58948 + }, + { + "icon_id": "24841489", + "name": "mail-open-filled", + "font_class": "mail-open-filled", + "unicode": "e63a", + "unicode_decimal": 58938 + }, + { + "icon_id": "24841491", + "name": "hand-thumbsdown-filled", + "font_class": "hand-down-filled", + "unicode": "e63c", + "unicode_decimal": 58940 + }, + { + "icon_id": "24841492", + "name": "hand-thumbsdown", + "font_class": "hand-down", + "unicode": "e63d", + "unicode_decimal": 58941 + }, + { + "icon_id": "24841493", + "name": "hand-thumbsup-filled", + "font_class": "hand-up-filled", + "unicode": "e63e", + "unicode_decimal": 58942 + }, + { + "icon_id": "24841494", + "name": "hand-thumbsup", + "font_class": "hand-up", + "unicode": "e63f", + "unicode_decimal": 58943 + }, + { + "icon_id": "24841496", + "name": "heart-filled", + "font_class": "heart-filled", + "unicode": "e641", + "unicode_decimal": 58945 + }, + { + "icon_id": "24841498", + "name": "mail-open", + "font_class": "mail-open", + "unicode": "e643", + "unicode_decimal": 58947 + }, + { + "icon_id": "24841488", + "name": "heart", + "font_class": "heart", + "unicode": "e639", + "unicode_decimal": 58937 + }, + { + "icon_id": "24839963", + "name": "loop", + "font_class": "loop", + "unicode": "e633", + "unicode_decimal": 58931 + }, + { + "icon_id": "24839866", + "name": "pulldown", + "font_class": "pulldown", + "unicode": "e632", + "unicode_decimal": 58930 + }, + { + "icon_id": "24813798", + "name": "scan", + "font_class": "scan", + "unicode": "e62a", + "unicode_decimal": 58922 + }, + { + "icon_id": "24813786", + "name": "bars", + "font_class": "bars", + "unicode": "e627", + "unicode_decimal": 58919 + }, + { + "icon_id": "24813788", + "name": "cart-filled", + "font_class": "cart-filled", + "unicode": "e629", + "unicode_decimal": 58921 + }, + { + "icon_id": "24813790", + "name": "checkbox", + "font_class": "checkbox", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "24813791", + "name": "checkbox-filled", + "font_class": "checkbox-filled", + "unicode": "e62c", + "unicode_decimal": 58924 + }, + { + "icon_id": "24813794", + "name": "shop", + "font_class": "shop", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "icon_id": "24813795", + "name": "headphones", + "font_class": "headphones", + "unicode": "e630", + "unicode_decimal": 58928 + }, + { + "icon_id": "24813796", + "name": "cart", + "font_class": "cart", + "unicode": "e631", + "unicode_decimal": 58929 + } + ] +} diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue new file mode 100644 index 0000000..ce307c1 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue @@ -0,0 +1,91 @@ + + + + + diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue new file mode 100644 index 0000000..9634a9c --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/uni_modules/uni-icons/components/uni-icons/uni.ttf b/uni_modules/uni-icons/components/uni-icons/uni.ttf new file mode 100644 index 0000000..60a1968 Binary files /dev/null and b/uni_modules/uni-icons/components/uni-icons/uni.ttf differ diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.css b/uni_modules/uni-icons/components/uni-icons/uniicons.css new file mode 100644 index 0000000..3911463 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons.css @@ -0,0 +1,664 @@ + +.uniui-cart-filled:before { + content: "\e6d0"; +} + +.uniui-gift-filled:before { + content: "\e6c4"; +} + +.uniui-color:before { + content: "\e6cf"; +} + +.uniui-wallet:before { + content: "\e6b1"; +} + +.uniui-settings-filled:before { + content: "\e6ce"; +} + +.uniui-auth-filled:before { + content: "\e6cc"; +} + +.uniui-shop-filled:before { + content: "\e6cd"; +} + +.uniui-staff-filled:before { + content: "\e6cb"; +} + +.uniui-vip-filled:before { + content: "\e6c6"; +} + +.uniui-plus-filled:before { + content: "\e6c7"; +} + +.uniui-folder-add-filled:before { + content: "\e6c8"; +} + +.uniui-color-filled:before { + content: "\e6c9"; +} + +.uniui-tune-filled:before { + content: "\e6ca"; +} + +.uniui-calendar-filled:before { + content: "\e6c0"; +} + +.uniui-notification-filled:before { + content: "\e6c1"; +} + +.uniui-wallet-filled:before { + content: "\e6c2"; +} + +.uniui-medal-filled:before { + content: "\e6c3"; +} + +.uniui-fire-filled:before { + content: "\e6c5"; +} + +.uniui-refreshempty:before { + content: "\e6bf"; +} + +.uniui-location-filled:before { + content: "\e6af"; +} + +.uniui-person-filled:before { + content: "\e69d"; +} + +.uniui-personadd-filled:before { + content: "\e698"; +} + +.uniui-arrowthinleft:before { + content: "\e6d2"; +} + +.uniui-arrowthinup:before { + content: "\e6d3"; +} + +.uniui-arrowthindown:before { + content: "\e6d4"; +} + +.uniui-back:before { + content: "\e6b9"; +} + +.uniui-forward:before { + content: "\e6ba"; +} + +.uniui-arrow-right:before { + content: "\e6bb"; +} + +.uniui-arrow-left:before { + content: "\e6bc"; +} + +.uniui-arrow-up:before { + content: "\e6bd"; +} + +.uniui-arrow-down:before { + content: "\e6be"; +} + +.uniui-arrowthinright:before { + content: "\e6d1"; +} + +.uniui-down:before { + content: "\e6b8"; +} + +.uniui-bottom:before { + content: "\e6b8"; +} + +.uniui-arrowright:before { + content: "\e6d5"; +} + +.uniui-right:before { + content: "\e6b5"; +} + +.uniui-up:before { + content: "\e6b6"; +} + +.uniui-top:before { + content: "\e6b6"; +} + +.uniui-left:before { + content: "\e6b7"; +} + +.uniui-arrowup:before { + content: "\e6d6"; +} + +.uniui-eye:before { + content: "\e651"; +} + +.uniui-eye-filled:before { + content: "\e66a"; +} + +.uniui-eye-slash:before { + content: "\e6b3"; +} + +.uniui-eye-slash-filled:before { + content: "\e6b4"; +} + +.uniui-info-filled:before { + content: "\e649"; +} + +.uniui-reload:before { + content: "\e6b2"; +} + +.uniui-micoff-filled:before { + content: "\e6b0"; +} + +.uniui-map-pin-ellipse:before { + content: "\e6ac"; +} + +.uniui-map-pin:before { + content: "\e6ad"; +} + +.uniui-location:before { + content: "\e6ae"; +} + +.uniui-starhalf:before { + content: "\e683"; +} + +.uniui-star:before { + content: "\e688"; +} + +.uniui-star-filled:before { + content: "\e68f"; +} + +.uniui-calendar:before { + content: "\e6a0"; +} + +.uniui-fire:before { + content: "\e6a1"; +} + +.uniui-medal:before { + content: "\e6a2"; +} + +.uniui-font:before { + content: "\e6a3"; +} + +.uniui-gift:before { + content: "\e6a4"; +} + +.uniui-link:before { + content: "\e6a5"; +} + +.uniui-notification:before { + content: "\e6a6"; +} + +.uniui-staff:before { + content: "\e6a7"; +} + +.uniui-vip:before { + content: "\e6a8"; +} + +.uniui-folder-add:before { + content: "\e6a9"; +} + +.uniui-tune:before { + content: "\e6aa"; +} + +.uniui-auth:before { + content: "\e6ab"; +} + +.uniui-person:before { + content: "\e699"; +} + +.uniui-email-filled:before { + content: "\e69a"; +} + +.uniui-phone-filled:before { + content: "\e69b"; +} + +.uniui-phone:before { + content: "\e69c"; +} + +.uniui-email:before { + content: "\e69e"; +} + +.uniui-personadd:before { + content: "\e69f"; +} + +.uniui-chatboxes-filled:before { + content: "\e692"; +} + +.uniui-contact:before { + content: "\e693"; +} + +.uniui-chatbubble-filled:before { + content: "\e694"; +} + +.uniui-contact-filled:before { + content: "\e695"; +} + +.uniui-chatboxes:before { + content: "\e696"; +} + +.uniui-chatbubble:before { + content: "\e697"; +} + +.uniui-upload-filled:before { + content: "\e68e"; +} + +.uniui-upload:before { + content: "\e690"; +} + +.uniui-weixin:before { + content: "\e691"; +} + +.uniui-compose:before { + content: "\e67f"; +} + +.uniui-qq:before { + content: "\e680"; +} + +.uniui-download-filled:before { + content: "\e681"; +} + +.uniui-pyq:before { + content: "\e682"; +} + +.uniui-sound:before { + content: "\e684"; +} + +.uniui-trash-filled:before { + content: "\e685"; +} + +.uniui-sound-filled:before { + content: "\e686"; +} + +.uniui-trash:before { + content: "\e687"; +} + +.uniui-videocam-filled:before { + content: "\e689"; +} + +.uniui-spinner-cycle:before { + content: "\e68a"; +} + +.uniui-weibo:before { + content: "\e68b"; +} + +.uniui-videocam:before { + content: "\e68c"; +} + +.uniui-download:before { + content: "\e68d"; +} + +.uniui-help:before { + content: "\e679"; +} + +.uniui-navigate-filled:before { + content: "\e67a"; +} + +.uniui-plusempty:before { + content: "\e67b"; +} + +.uniui-smallcircle:before { + content: "\e67c"; +} + +.uniui-minus-filled:before { + content: "\e67d"; +} + +.uniui-micoff:before { + content: "\e67e"; +} + +.uniui-closeempty:before { + content: "\e66c"; +} + +.uniui-clear:before { + content: "\e66d"; +} + +.uniui-navigate:before { + content: "\e66e"; +} + +.uniui-minus:before { + content: "\e66f"; +} + +.uniui-image:before { + content: "\e670"; +} + +.uniui-mic:before { + content: "\e671"; +} + +.uniui-paperplane:before { + content: "\e672"; +} + +.uniui-close:before { + content: "\e673"; +} + +.uniui-help-filled:before { + content: "\e674"; +} + +.uniui-paperplane-filled:before { + content: "\e675"; +} + +.uniui-plus:before { + content: "\e676"; +} + +.uniui-mic-filled:before { + content: "\e677"; +} + +.uniui-image-filled:before { + content: "\e678"; +} + +.uniui-locked-filled:before { + content: "\e668"; +} + +.uniui-info:before { + content: "\e669"; +} + +.uniui-locked:before { + content: "\e66b"; +} + +.uniui-camera-filled:before { + content: "\e658"; +} + +.uniui-chat-filled:before { + content: "\e659"; +} + +.uniui-camera:before { + content: "\e65a"; +} + +.uniui-circle:before { + content: "\e65b"; +} + +.uniui-checkmarkempty:before { + content: "\e65c"; +} + +.uniui-chat:before { + content: "\e65d"; +} + +.uniui-circle-filled:before { + content: "\e65e"; +} + +.uniui-flag:before { + content: "\e65f"; +} + +.uniui-flag-filled:before { + content: "\e660"; +} + +.uniui-gear-filled:before { + content: "\e661"; +} + +.uniui-home:before { + content: "\e662"; +} + +.uniui-home-filled:before { + content: "\e663"; +} + +.uniui-gear:before { + content: "\e664"; +} + +.uniui-smallcircle-filled:before { + content: "\e665"; +} + +.uniui-map-filled:before { + content: "\e666"; +} + +.uniui-map:before { + content: "\e667"; +} + +.uniui-refresh-filled:before { + content: "\e656"; +} + +.uniui-refresh:before { + content: "\e657"; +} + +.uniui-cloud-upload:before { + content: "\e645"; +} + +.uniui-cloud-download-filled:before { + content: "\e646"; +} + +.uniui-cloud-download:before { + content: "\e647"; +} + +.uniui-cloud-upload-filled:before { + content: "\e648"; +} + +.uniui-redo:before { + content: "\e64a"; +} + +.uniui-images-filled:before { + content: "\e64b"; +} + +.uniui-undo-filled:before { + content: "\e64c"; +} + +.uniui-more:before { + content: "\e64d"; +} + +.uniui-more-filled:before { + content: "\e64e"; +} + +.uniui-undo:before { + content: "\e64f"; +} + +.uniui-images:before { + content: "\e650"; +} + +.uniui-paperclip:before { + content: "\e652"; +} + +.uniui-settings:before { + content: "\e653"; +} + +.uniui-search:before { + content: "\e654"; +} + +.uniui-redo-filled:before { + content: "\e655"; +} + +.uniui-list:before { + content: "\e644"; +} + +.uniui-mail-open-filled:before { + content: "\e63a"; +} + +.uniui-hand-down-filled:before { + content: "\e63c"; +} + +.uniui-hand-down:before { + content: "\e63d"; +} + +.uniui-hand-up-filled:before { + content: "\e63e"; +} + +.uniui-hand-up:before { + content: "\e63f"; +} + +.uniui-heart-filled:before { + content: "\e641"; +} + +.uniui-mail-open:before { + content: "\e643"; +} + +.uniui-heart:before { + content: "\e639"; +} + +.uniui-loop:before { + content: "\e633"; +} + +.uniui-pulldown:before { + content: "\e632"; +} + +.uniui-scan:before { + content: "\e62a"; +} + +.uniui-bars:before { + content: "\e627"; +} + +.uniui-checkbox:before { + content: "\e62b"; +} + +.uniui-checkbox-filled:before { + content: "\e62c"; +} + +.uniui-shop:before { + content: "\e62f"; +} + +.uniui-headphones:before { + content: "\e630"; +} + +.uniui-cart:before { + content: "\e631"; +} diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf new file mode 100644 index 0000000..14696d0 Binary files /dev/null and b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf differ diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts new file mode 100644 index 0000000..86318df --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts @@ -0,0 +1,664 @@ + +export type IconsData = { + id : string + name : string + font_family : string + css_prefix_text : string + description : string + glyphs : Array +} + +export type IconsDataItem = { + font_class : string + unicode : string +} + + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] as IconsDataItem[] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js new file mode 100644 index 0000000..49e42cd --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js @@ -0,0 +1,649 @@ + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/uni_modules/uni-icons/package.json b/uni_modules/uni-icons/package.json new file mode 100644 index 0000000..5d6ded5 --- /dev/null +++ b/uni_modules/uni-icons/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-icons", + "displayName": "uni-icons 图标", + "version": "2.0.10", + "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", + "keywords": [ + "uni-ui", + "uniui", + "icon", + "图标" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.2.14" + }, + "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", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "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", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-icons/readme.md b/uni_modules/uni-icons/readme.md new file mode 100644 index 0000000..72096e3 --- /dev/null +++ b/uni_modules/uni-icons/readme.md @@ -0,0 +1,8 @@ +## Icons 图标 +> **组件名:uni-icons** +> 代码块: `uIcons` + +用于展示 icons 图标 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-id/changelog.md b/uni_modules/uni-id/changelog.md new file mode 100644 index 0000000..e43c093 --- /dev/null +++ b/uni_modules/uni-id/changelog.md @@ -0,0 +1,121 @@ +## 3.3.33(2025-01-08) +- 修改文档图片链接 +## 3.3.32(2024-04-26) +- 兼容uni-app-x对客户端uniPlatform的调整(uni-app-x内uniPlatform区分app-android、app-ios) +## 3.3.31(2023-12-13) +- 移除无用文件 +## 3.3.30(2023-12-13) +- 短信、一键登录相关密钥改为非必填 +## 3.3.29(2022-10-20) +- 使用[uni-open-bridge-common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge.html#common)存储用户三方凭证,以便其他服务使用。 +## 3.3.28(2022-07-27) +- 修复 app端微信登录返回的accessToken过期时间(expired)不正确的Bug +## 3.3.27(2022-07-27) +- 短信发送失败、微信登录失败等场景下输出原始错误方便排查错误 +## 3.3.26(2022-07-08) +- 兼容配置放在uni-id下的逻辑,但是仍推荐使用uni-config-center +## 3.3.25(2022-06-30) +- 修复config文件不合法时未抛出具体错误的Bug +## 3.3.24(2022-06-28) +- 修复3.3.12引出的使用多应用配置时报错的Bug +## 3.3.23(2022-06-13) +- 修复上版本引出的部分依赖未找到的Bug +## 3.3.22(2022-06-13) +- 新增 preferedWebPlatform 配置用于解决HBuilderX 3.4.9版本起web端platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-web-platform) +## 3.3.21(2022-05-24) +- 修复createInstance传入clientInfo无效的Bug +## 3.3.20(2022-05-19) +- 调整以下错误码(账号已注册[uni-id-account-exists]、账号不存在[uni-id-account-not-exists]、账号已绑定[uni-id-account-bound]) +## 3.3.19(2022-05-19) +- 修复 addUser 部分情况下会创建出重复账号的Bug +## 3.3.18(2022-05-12) +- 调整绑定、解绑邮箱手机号接口,只要传递code参数就进行验证码校验即使传递的值为undefined +## 3.3.17(2022-05-09) +- register_env内增加os_name字段用于区分注册时的客户端系统类型 +## 3.3.16(2022-05-09) +- 修复 addUser接口添加的用户无法使用密码登录的Bug [详情](https://ask.dcloud.net.cn/question/144670) +## 3.3.15(2022-05-08) +- 修复config文件语法错误时报`this.t is not a function`的Bug 感谢@寒暄 +## 3.3.14(2022-05-08) +- 新增 getWeixinUserInfo接口 用于获取app平台微信登录用户的用户信息 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#get-weixin-user-info) +- 新增 addUser接口 用于手动添加用户 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#add-user) +- 新增 resetPwdBySms接口 用于使用短信验证码重置密码 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#reset-pwd-by-sms) +- 新增 refreshToken接口 用于主动刷新用户token [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#refresh-token) +- 调整 用户注册时记录用户注册环境到 register_env 字段 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#user-table) +- 调整 用户注册时将注册 ip 移至 register_env 内 + +## 3.3.13(2022-03-04) +- createInstance方法支持传递clientInfo [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#create-instance) +- 修复`this.t is not a function`报错 +## 3.3.12(2022-01-15) +- 新增 preferedAppPlatform 配置用于解决uni-app vue2版本vue3版本获取platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-app-platform) +- 修复 checkToken 未返回自定义token内容的Bug +## 3.3.11(2022-01-11) +- 修复用户名密码登录时多个应用出现重复用户名登录报错的Bug +## 3.3.10(2022-01-07) +- 新增 自定义国际化语言支持 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=custom-i8n) +- 修复 一键登录时未校验重复手机号是否已验证的Bug +- 修复 Apple登录时用户邮箱为空时报错的Bug +- 修复 登录接口未传username时错误提示不正确的Bug +## 3.3.9(2021-11-09) +- 去除重复的context.xxx未找到的提示语 +## 3.3.8(2021-10-28) +- 新增 用户账户封禁接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=ban-account) +- 新增 用户账户注销接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=close-account) +- 修复 未传appid时用户重复注册的Bug +## 3.3.7(2021-10-08) +- 移除部分接口的废弃提示 +## 3.3.6(2021-09-08) +- 修复 邀请码可能重复的Bug +## 3.3.5(2021-08-10) +- 修复版本号错误 +## 3.3.4(2021-08-10) +- 微信、QQ、支付宝登录新增type参数用于指定当前是登录还是注册 +## 3.3.3(2021-08-04) +- 修复使用数组形式的配置文件报错的Bug +## 3.3.2(2021-08-03) +- 修复上3.3.0版本引出的createInstance接口传入配置不生效的Bug 感谢[hmh](https://gitee.com/hmh) +## 3.3.1(2021-07-30) +- 修复 将设置用户允许登录的应用列表时传入空数组报错的Bug +## 3.3.0(2021-07-30) +- 新增 不同端应用配置隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-config) +- 新增 不同端用户隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-user) + + 此版本升级需要开发者处理一下用户数据,请参考 [补齐用户dcloud_appid字段](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=makeup-dcloud-appid) +- 新增 QQ登录、注册相关功能 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=qq) +- 调整 不再支持绑定手机、邮箱时不填验证码直接绑定 +## 3.2.1(2021-07-09) +- 撤销3.2.0版本所做的调整 +## 3.2.0(2021-07-09) +- 【重要】支持不同端(管理端、用户端等)用户隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-user) +- 支持不同端(管理端、用户端等)配置文件隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-config) +## 3.1.3(2021-07-08) +- 移除插件内误传的node_modules +## 3.1.2(2021-07-08) +- 修复 微信小程序绑定微信账号时报错的Bug +## 3.1.1(2021-07-01) +- 使用新的错误码规范,兼容旧版 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=errcode) +- 修复微信登录、绑定时未返回用户accessToken的Bug +## 3.1.0(2021-04-19) +- 增加对用户名、邮箱、密码字段的两端去空格 +- 默认忽略用户名、邮箱的大小写 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=case-sensitive) +- 修复 customToken导出async方法报错的Bug +## 3.0.12(2021-04-13) +- 调整bindTokenToDevice默认值为false +## 3.0.11(2021-04-12) +- 修复3.0.7版本引出的多个用户访问时可能出现30201报错的Bug +## 3.0.10(2021-04-08) +- 优化错误提示 +## 3.0.9(2021-04-08) +- bindMobile接口支持通过一键登录的方式绑定 +- 优化错误提示 +## 3.0.8(2021-03-19) +- 修复 3.0.7版本某些情况下生成token报错的Bug +## 3.0.7(2021-03-19) +- 新增 支持uni-config-center,更新uni-id无须再担心配置被覆盖 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=uni-config-center) +- 新增 自定义token内容,可以缓存角色权限之外的更多信息到客户端 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=custom-token) +- 新增 支持传入context获取uni-id实例,防止单实例多并发时全局context混乱 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=create-instance) +## 3.0.6(2021-03-05) +- 新增[uniID.wxBizDataCrypt](https://uniapp.dcloud.io/uniCloud/uni-id?id=%e5%be%ae%e4%bf%a1%e6%95%b0%e6%8d%ae%e8%a7%a3%e5%af%86)方法 +- 优化loginByApple方法,提高接口响应速度 +## 3.0.5(2021-02-03) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-id/package.json b/uni_modules/uni-id/package.json new file mode 100644 index 0000000..d04fe48 --- /dev/null +++ b/uni_modules/uni-id/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-id", + "displayName": "uni-id", + "version": "3.3.33", + "description": "简单、统一、可扩展的用户中心", + "keywords": [ + "uniid", + "uni-id", + "用户管理", + "用户中心", + "短信验证码" +], + "repository": "https://gitee.com/dcloud/uni-id.git", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-function" + }, + "uni_modules": { + "dependencies": ["uni-config-center", "uni-open-bridge-common"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "App": { + "app-vue": "u", + "app-nvue": "u", + "app-harmony": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} diff --git a/uni_modules/uni-id/readme.md b/uni_modules/uni-id/readme.md new file mode 100644 index 0000000..7e9a39a --- /dev/null +++ b/uni_modules/uni-id/readme.md @@ -0,0 +1,33 @@ +**文档已移至[uni-id文档](https://doc.dcloud.net.cn/uniCloud/uni-id/old.html)** + +> 一般uni-id升级大版本时为不兼容更新,从低版本迁移到高版本请参考:[uni-id迁移指南](https://doc.dcloud.net.cn/uniCloud/uni-id/old.html#m1to2) + +## 重要升级说明 + +**uni-id 3.x版本,搭配的uniCloud admin版本需大于1.2.10。** + +### 缓存角色权限 + +自`uni-id 3.0.0`起,支持在token内缓存用户的角色权限,默认开启此功能,各登录接口的needPermission参数不再生效。如需关闭请在config内配置`"removePermissionAndRoleFromToken": true`。 + +为什么要缓存角色权限?要知道云数据库是按照读写次数来收取费用的,并且读写数据库会拖慢接口响应速度。未配置`"removePermissionAndRoleFromToken": true`的情况下,可以在调用checkToken接口时不查询数据库获取用户角色权限。 + +详细checkToken流程如下: + +![](https://web-ext-storage.dcloud.net.cn/ext/uni-id/uni-id-flow.jpg) + +可以看出,旧版token(removePermissionAndRoleFromToken为true时生成的)在checkToken时如需返回权限需要进行两次数据库查询。新版token不需要查库即可返回权限信息。 + +**注意** + +- 由于角色权限缓存在token内,可能会存在权限已经更新但是用户token未过期之前依然是旧版角色权限的情况。可以调短一些token过期时间来减少这种情况的影响。 +- admin角色token内不包含permission,如需自行判断用户是否有某个权限,要注意admin角色需要额外判断一下,写法如下 + ```js + const { + role, + permission + } = await uniID.checkToken(event.uniIdToken) + if(role.includes('admin') || permission.includes('your permission id')) { + // 当前角色拥有'your permission id'对应的权限 + } + ``` \ No newline at end of file diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md new file mode 100644 index 0000000..29f81d8 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js new file mode 100644 index 0000000..ecf631b --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js @@ -0,0 +1 @@ +"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var t=e(require("crypto")),r=e(require("buffer")),n=e(require("stream")),i=e(require("util"));const o={PARAM_ERROR:{errCode:"param-error"},PARAM_REQUIRED:{errCode:"param-required"},USER_NOT_EXIST:{errCode:"user-not-exist"},ROLE_NOT_EXIST:{errCode:"role-not-exist"},PERMISSION_NOT_EXIST:{errCode:"permission-not-exist"},MULTI_USER_MATCHED:{errCode:"multi-user-matched"},USER_INFO_ERROR:{errCode:"user-info-error"},USER_ACCOUNT_CONFLICT:{errCode:"user-account-conflict"},USER_ACCOUNT_CLOSED:{errCode:"user-account-closed"},ACCOUNT_EXISTS:{errCode:"account-exists"},ACCOUNT_NOT_EXISTS:{errCode:"account-not-exists"},ACCOUNT_BOUND:{errCode:"account-bound"},UNBIND_FAILED:{errCode:"unbind-failed"},INVALID_INVITE_CODE:{errCode:"invalid-invite-code"},SET_INVITE_CODE_FAILED:{errCode:"set-invite-code-failed"},GET_THIRD_PARTY_ACCOUNT_FAILED:{errCode:"get-third-party-account-failed"},GET_THIRD_PARTY_USER_INFO_FAILED:{errCode:"get-third-party-user-info-failed"}},s={0:{errCode:0,errMsg:""},10001:{errCode:"account-banned"},10002:o.USER_NOT_EXIST,10003:o.MULTI_USER_MATCHED,10004:o.USER_INFO_ERROR,10005:o.USER_ACCOUNT_CONFLICT,10006:o.USER_ACCOUNT_CLOSED,10102:{errCode:"password-error"},10103:{errCode:"password-error-exceed-limit"},10201:o.ACCOUNT_EXISTS,10202:o.ACCOUNT_NOT_EXISTS,10203:o.INVALID_INVITE_CODE,10301:o.ACCOUNT_EXISTS,10302:o.ACCOUNT_NOT_EXISTS,10401:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10402:o.ACCOUNT_EXISTS,10403:o.ACCOUNT_NOT_EXISTS,10501:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10502:o.ACCOUNT_EXISTS,10503:o.ACCOUNT_NOT_EXISTS,10601:o.ACCOUNT_EXISTS,10602:o.ACCOUNT_NOT_EXISTS,10701:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10702:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10703:o.ACCOUNT_EXISTS,10704:o.ACCOUNT_NOT_EXISTS,10705:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10706:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10801:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10802:o.ACCOUNT_EXISTS,10803:o.ACCOUNT_NOT_EXISTS,20101:o.PARAM_REQUIRED,20102:o.ACCOUNT_EXISTS,30101:o.PARAM_REQUIRED,30201:{errCode:"check-device-feature-failed"},30202:{errCode:"token-not-exist"},30203:{errCode:"token-expired"},30204:{errCode:"check-token-failed"},40201:o.USER_NOT_EXIST,40202:{errCode:"invalid-old-password"},50101:o.PARAM_REQUIRED,50102:o.PARAM_ERROR,50201:o.PARAM_REQUIRED,50203:o.PARAM_ERROR,50202:{errCode:"invalid-verify-code"},50301:{errCode:"send-sms-code-failed"},60101:o.ACCOUNT_BOUND,60201:o.ACCOUNT_BOUND,60301:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60302:o.ACCOUNT_BOUND,60401:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60402:o.ACCOUNT_BOUND,60501:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60502:o.ACCOUNT_BOUND,70101:o.UNBIND_FAILED,70201:o.UNBIND_FAILED,70301:o.UNBIND_FAILED,70401:o.UNBIND_FAILED,70501:o.UNBIND_FAILED,80301:o.USER_NOT_EXIST,80401:o.SET_INVITE_CODE_FAILED,80402:o.SET_INVITE_CODE_FAILED,80501:o.INVALID_INVITE_CODE,80502:o.USER_NOT_EXIST,80503:{errCode:"modify-invite-code-is-not-allowed"},80601:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80602:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80701:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80702:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80801:{errCode:"decrypt-weixin-data-failed"},80802:{errCode:"decrypt-weixin-data-failed"},80803:{errCode:"invalid-weixin-appid"},80804:o.PARAM_REQUIRED,80805:o.PARAM_REQUIRED,80806:o.PARAM_REQUIRED,80901:o.GET_THIRD_PARTY_USER_INFO_FAILED,90001:{errCode:"database-operation-failed"},90002:o.PARAM_REQUIRED,90003:o.PARAM_ERROR,90004:o.USER_NOT_EXIST,90005:o.ROLE_NOT_EXIST,90006:o.PERMISSION_NOT_EXIST};class a extends Error{constructor(e){super(e.message),this.errMsg=e.message||"",Object.defineProperties(this,{message:{get(){return`errCode: ${e.code||""} | errMsg: `+this.errMsg},set(e){this.errMsg=e}}})}}const c=Object.prototype.toString,u=Object.prototype.hasOwnProperty;function d(e,t){return u.call(e,t)}function p(e){return"[object Object]"===c.call(e)}function l(e){return"function"==typeof e}function f(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}function m(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}const h=/_(\w)/g,g=/[A-Z]/g;function y(e){return e.replace(h,(e,t)=>t?t.toUpperCase():"")}function w(e){return e.replace(g,e=>"_"+e.toLowerCase())}function v(e,t){let r,n;switch(t){case"snake2camel":n=y,r=h;break;case"camel2snake":n=w,r=g}for(const i in e)if(d(e,i)&&r.test(i)){const r=n(i);e[r]=e[i],delete e[i],p(e[r])?e[r]=v(e[r],t):Array.isArray(e[r])&&(e[r]=e[r].map(e=>v(e,t)))}return e}function _(e){return v(e,"snake2camel")}function b(e){return v(e,"camel2snake")}function T(e){return function(e,t="-"){e=e||new Date;const r=[];return r.push(e.getFullYear()),r.push(("00"+(e.getMonth()+1)).substr(-2)),r.push(("00"+e.getDate()).substr(-2)),r.join(t)}(e=e||new Date)+" "+function(e,t=":"){e=e||new Date;const r=[];return r.push(("00"+e.getHours()).substr(-2)),r.push(("00"+e.getMinutes()).substr(-2)),r.push(("00"+e.getSeconds()).substr(-2)),r.join(t)}(e)}function E(){"development"===process.env.NODE_ENV&&console.log(...arguments)}function C(e=6){let t="";for(let r=0;r-1?"&":"?"}access_token=${t.accessToken}`}return`${e}${r}`}class G{constructor(e){this.options=Object.assign({baseUrl:"https://api.weixin.qq.com",timeout:5e3},e)}async _requestWxOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};return await H({name:"auth."+e,url:`${this.options.baseUrl}${K(t,r)}`,data:r,options:n,defaultOptions:i})}async code2Session(e){return await this._requestWxOpenapi({name:"code2Session",url:"/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}async getOauthAccessToken(e){const t=await this._requestWxOpenapi({name:"getOauthAccessToken",url:"/sns/oauth2/access_token",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,code:e}});return t.expiresIn&&(t.expired=Date.now()+1e3*t.expiresIn),t}async getUserInfo({accessToken:e,openid:t}={}){const{nickname:r,headimgurl:n}=await this._requestWxOpenapi({name:"getUserInfo",url:"/sns/userinfo",data:{accessToken:e,openid:t,appid:this.options.appId,secret:this.options.secret,scope:"snsapi_userinfo"}});return{nickname:r,avatar:n}}}async function Q({name:e,url:t,data:r,options:n,defaultOptions:i}){let o;n=Object.assign({},i,n,{data:b(Object.assign({},r))});try{o=await uniCloud.httpclient.request(t,n)}catch(t){return function(e,t){throw new a({code:t.code||-2,message:t.message||e+" fail"})}(e,t)}let s=o.data;const c=o.headers["content-type"];if(!Buffer.isBuffer(s)||0!==c.indexOf("text/plain")&&0!==c.indexOf("application/json"))Buffer.isBuffer(s)&&(s={buffer:s,contentType:c});else try{s=JSON.parse(s.toString())}catch(e){s=s.toString()}return _(function(e,t){if(t.ret||t.error){const r=t.ret||t.error||t.errcode||-2,n=t.msg||t.error_description||t.errmsg||e+" fail";throw new a({code:r,message:n})}return delete t.ret,delete t.msg,delete t.error,delete t.error_description,delete t.errcode,delete t.errmsg,{...t,errMsg:e+" ok",errCode:0}}(e,s||{errCode:-2,errMsg:"Request failed"}))}class X{constructor(e){this.options=Object.assign({baseUrl:"https://graph.qq.com",timeout:5e3},e)}async _requestQQOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};var o,s;return await Q({name:"auth."+e,url:(o=this.options.baseUrl,s=t,/^https?:/.test(s)?s:o+s),data:r,options:n,defaultOptions:i})}async getOpenidByToken({accessToken:e}={}){const t=await this._requestQQOpenapi({name:"getOpenidByToken",url:"/oauth2.0/me",data:{accessToken:e,unionid:1,fmt:"json"}});if(t.clientId!==this.options.appId)throw new a({code:"APPID_NOT_MATCH",message:"appid not match"});return{openid:t.openid,unionid:t.unionid}}async code2Session({code:e}={}){return await this._requestQQOpenapi({name:"getOpenidByToken",url:"https://api.q.qq.com/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}}const Y={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};var z={code2Session:{returnValue:{openid:"userId"}}};class W extends class{constructor(e={}){if(!e.appId)throw new Error("appId required");if(!e.privateKey)throw new Error("privateKey required");const t={gateway:"https://openapi.alipay.com/gateway.do",timeout:5e3,charset:"utf-8",version:"1.0",signType:"RSA2",timeOffset:-(new Date).getTimezoneOffset()/60,keyType:"PKCS8"};e.sandbox&&(e.gateway="https://openapi.alipaydev.com/gateway.do"),this.options=Object.assign({},t,e);const r="PKCS8"===this.options.keyType?"PRIVATE KEY":"RSA PRIVATE KEY";this.options.privateKey=this._formatKey(this.options.privateKey,r),this.options.alipayPublicKey&&(this.options.alipayPublicKey=this._formatKey(this.options.alipayPublicKey,"PUBLIC KEY"))}_formatKey(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`}_formatUrl(e,t){let r=e;const n=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token"];for(const e in t)if(n.indexOf(e)>-1){const n=encodeURIComponent(t[e]);r=`${r}${r.includes("?")?"&":"?"}${e}=${n}`,delete t[e]}return{execParams:t,url:r}}_getSign(e,r){const n=r.bizContent||null;delete r.bizContent;const i=Object.assign({method:e,appId:this.options.appId,charset:this.options.charset,version:this.options.version,signType:this.options.signType,timestamp:T((o=this.options.timeOffset,new Date(Date.now()+6e4*((new Date).getTimezoneOffset()+60*(o||0)))))},r);var o;n&&(i.bizContent=JSON.stringify(b(n)));const s=b(i),a=Object.keys(s).sort().map(e=>{let t=s[e];return"[object String]"!==Array.prototype.toString.call(t)&&(t=JSON.stringify(t)),`${e}=${t}`}).join("&"),c=t.createSign(Y[this.options.signType]).update(a,"utf8").sign(this.options.privateKey,"base64");return Object.assign(s,{sign:c})}async _exec(e,t={},r={}){const n=this._getSign(e,t),{url:i,execParams:o}=this._formatUrl(this.options.gateway,n),{status:s,data:a}=await uniCloud.httpclient.request(i,{method:"POST",data:o,dataType:"text",timeout:this.options.timeout});if(200!==s)throw new Error("request fail");const c=JSON.parse(a),u=e.replace(/\./g,"_")+"_response",d=c[u],p=c.error_response;if(d){if(!r.validateSign||this._checkResponseSign(a,u)){if(!d.code||"10000"===d.code){return{errCode:0,errMsg:d.msg||"",..._(d)}}const e=d.sub_code?`${d.sub_code} ${d.sub_msg}`:""+(d.msg||"unkonwn error");throw new Error(e)}throw new Error("check sign error")}if(p)throw new Error(p.sub_msg||p.msg||"request fail");throw new Error("request fail")}_checkResponseSign(e,r){if(!this.options.alipayPublicKey||""===this.options.alipayPublicKey)return console.warn("options.alipayPublicKey is empty"),!0;if(!e)return!1;const n=this._getSignStr(e,r),i=JSON.parse(e).sign,o=t.createVerify(Y[this.options.signType]);return o.update(n,"utf8"),o.verify(this.options.alipayPublicKey,i,"base64")}_getSignStr(e,t){let r=e.trim();const n=e.indexOf(t+'"'),i=e.lastIndexOf('"sign"');return r=r.substr(n+t.length+1),r=r.substr(0,i),r=r.replace(/^[^{]*{/g,"{"),r=r.replace(/\}([^}]*)$/g,"}"),r}}{constructor(e){super(e),this._protocols=z}async code2Session(e){return await this._exec("alipay.system.oauth.token",{grantType:"authorization_code",code:e})}}function J(e){var t=e[0];return t<"0"||t>"7"?"00"+e:e}function Z(e){var t=e.toString(16);return t.length%2?"0"+t:t}function ee(e){if(e<=127)return Z(e);var t=Z(e);return Z(128+t.length/2)+t}function te(e,t){return e(t={exports:{}},t.exports),t.exports}var re=te((function(e,t){var n=r.Buffer;function i(e,t){for(var r in e)t[r]=e[r]}function o(e,t,r){return n(e,t,r)}n.from&&n.alloc&&n.allocUnsafe&&n.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=o),o.prototype=Object.create(n.prototype),i(n,o),o.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return n(e,t,r)},o.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=n(e);return void 0!==t?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}})),ne=(re.Buffer,re.Buffer);function ie(e){if(this.buffer=null,this.writable=!0,this.readable=!0,!e)return this.buffer=ne.alloc(0),this;if("function"==typeof e.pipe)return this.buffer=ne.alloc(0),e.pipe(this),this;if(e.length||"object"==typeof e)return this.buffer=e,this.writable=!1,process.nextTick(function(){this.emit("end",e),this.readable=!1,this.emit("close")}.bind(this)),this;throw new TypeError("Unexpected data type ("+typeof e+")")}i.inherits(ie,n),ie.prototype.write=function(e){this.buffer=ne.concat([this.buffer,ne.from(e)]),this.emit("data",e)},ie.prototype.end=function(e){e&&this.write(e),this.emit("end",e),this.emit("close"),this.writable=!1,this.readable=!1};var oe=ie,se=r.Buffer,ae=r.SlowBuffer,ce=ue;function ue(e,t){if(!se.isBuffer(e)||!se.isBuffer(t))return!1;if(e.length!==t.length)return!1;for(var r=0,n=0;n=128&&--n,n}var we={derToJose:function(e,t){e=ge(e);var r=me(t),n=r+1,i=e.length,o=0;if(48!==e[o++])throw new Error('Could not find expected "seq"');var s=e[o++];if(129===s&&(s=e[o++]),i-o0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var r=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*r;case"weeks":case"week":case"w":return 6048e5*r;case"days":case"day":case"d":return r*mt;case"hours":case"hour":case"hrs":case"hr":case"h":return r*ft;case"minutes":case"minute":case"mins":case"min":case"m":return r*lt;case"seconds":case"second":case"secs":case"sec":case"s":return r*pt;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(e);if("number"===r&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=mt)return gt(e,t,mt,"day");if(t>=ft)return gt(e,t,ft,"hour");if(t>=lt)return gt(e,t,lt,"minute");if(t>=pt)return gt(e,t,pt,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=mt)return Math.round(e/mt)+"d";if(t>=ft)return Math.round(e/ft)+"h";if(t>=lt)return Math.round(e/lt)+"m";if(t>=pt)return Math.round(e/pt)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function gt(e,t,r,n){var i=t>=1.5*r;return Math.round(e/r)+" "+n+(i?"s":"")}var yt=function(e,t){var r=t||Math.floor(Date.now()/1e3);if("string"==typeof e){var n=ht(e);if(void 0===n)return;return Math.floor(r+n/1e3)}return"number"==typeof e?r+e:void 0},wt=te((function(e,t){var r;t=e.exports=Y,r="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},t.SEMVER_SPEC_VERSION="2.0.0";var n=Number.MAX_SAFE_INTEGER||9007199254740991,i=t.re=[],o=t.safeRe=[],s=t.src=[],a=0,c=[["\\s",1],["\\d",256],["[a-zA-Z0-9-]",250]];function u(e){for(var t=0;t)?=?)";var x=a++;s[x]=s[p]+"|x|X|\\*";var I=a++;s[I]=s[d]+"|x|X|\\*";var S=a++;s[S]="[v=\\s]*("+s[I]+")(?:\\.("+s[I]+")(?:\\.("+s[I]+")(?:"+s[y]+")?"+s[_]+"?)?)?";var k=a++;s[k]="[v=\\s]*("+s[x]+")(?:\\.("+s[x]+")(?:\\.("+s[x]+")(?:"+s[w]+")?"+s[_]+"?)?)?";var O=a++;s[O]="^"+s[A]+"\\s*"+s[S]+"$";var P=a++;s[P]="^"+s[A]+"\\s*"+s[k]+"$";var R=a++;s[R]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var j=a++;s[j]="(?:~>?)";var D=a++;s[D]="(\\s*)"+s[j]+"\\s+",i[D]=new RegExp(s[D],"g"),o[D]=new RegExp(u(s[D]),"g");var q=a++;s[q]="^"+s[j]+s[S]+"$";var N=a++;s[N]="^"+s[j]+s[k]+"$";var U=a++;s[U]="(?:\\^)";var L=a++;s[L]="(\\s*)"+s[U]+"\\s+",i[L]=new RegExp(s[L],"g"),o[L]=new RegExp(u(s[L]),"g");var V=a++;s[V]="^"+s[U]+s[S]+"$";var M=a++;s[M]="^"+s[U]+s[k]+"$";var B=a++;s[B]="^"+s[A]+"\\s*("+E+")$|^$";var F=a++;s[F]="^"+s[A]+"\\s*("+T+")$|^$";var $=a++;s[$]="(\\s*)"+s[A]+"\\s*("+E+"|"+s[S]+")",i[$]=new RegExp(s[$],"g"),o[$]=new RegExp(u(s[$]),"g");var H=a++;s[H]="^\\s*("+s[S]+")\\s+-\\s+("+s[S]+")\\s*$";var K=a++;s[K]="^\\s*("+s[k]+")\\s+-\\s+("+s[k]+")\\s*$";var G=a++;s[G]="(<|>)?=?\\s*\\*";for(var Q=0;Q<35;Q++)r(Q,s[Q]),i[Q]||(i[Q]=new RegExp(s[Q]),o[Q]=new RegExp(u(s[Q])));function X(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof Y)return e;if("string"!=typeof e)return null;if(e.length>256)return null;if(!(t.loose?o[C]:o[b]).test(e))return null;try{return new Y(e,t)}catch(e){return null}}function Y(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof Y){if(e.loose===t.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof Y))return new Y(e,t);r("SemVer",e,t),this.options=t,this.loose=!!t.loose;var i=e.trim().match(t.loose?o[C]:o[b]);if(!i)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+i[1],this.minor=+i[2],this.patch=+i[3],this.major>n||this.major<0)throw new TypeError("Invalid major version");if(this.minor>n||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>n||this.patch<0)throw new TypeError("Invalid patch version");i[4]?this.prerelease=i[4].split(".").map((function(e){if(/^[0-9]+$/.test(e)){var t=+e;if(t>=0&&t=0;)"number"==typeof this.prerelease[r]&&(this.prerelease[r]++,r=-2);-1===r&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},t.inc=function(e,t,r,n){"string"==typeof r&&(n=r,r=void 0);try{return new Y(e,r).inc(t,n).version}catch(e){return null}},t.diff=function(e,t){if(te(e,t))return null;var r=X(e),n=X(t),i="";if(r.prerelease.length||n.prerelease.length){i="pre";var o="prerelease"}for(var s in r)if(("major"===s||"minor"===s||"patch"===s)&&r[s]!==n[s])return i+s;return o},t.compareIdentifiers=W;var z=/^[0-9]+$/;function W(e,t){var r=z.test(e),n=z.test(t);return r&&n&&(e=+e,t=+t),e===t?0:r&&!n?-1:n&&!r?1:e0}function ee(e,t,r){return J(e,t,r)<0}function te(e,t,r){return 0===J(e,t,r)}function re(e,t,r){return 0!==J(e,t,r)}function ne(e,t,r){return J(e,t,r)>=0}function ie(e,t,r){return J(e,t,r)<=0}function oe(e,t,r,n){switch(t){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e===r;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e!==r;case"":case"=":case"==":return te(e,r,n);case"!=":return re(e,r,n);case">":return Z(e,r,n);case">=":return ne(e,r,n);case"<":return ee(e,r,n);case"<=":return ie(e,r,n);default:throw new TypeError("Invalid operator: "+t)}}function se(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof se){if(e.loose===!!t.loose)return e;e=e.value}if(!(this instanceof se))return new se(e,t);e=e.trim().split(/\s+/).join(" "),r("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ae?this.value="":this.value=this.operator+this.semver.version,r("comp",this)}t.rcompareIdentifiers=function(e,t){return W(t,e)},t.major=function(e,t){return new Y(e,t).major},t.minor=function(e,t){return new Y(e,t).minor},t.patch=function(e,t){return new Y(e,t).patch},t.compare=J,t.compareLoose=function(e,t){return J(e,t,!0)},t.rcompare=function(e,t,r){return J(t,e,r)},t.sort=function(e,r){return e.sort((function(e,n){return t.compare(e,n,r)}))},t.rsort=function(e,r){return e.sort((function(e,n){return t.rcompare(e,n,r)}))},t.gt=Z,t.lt=ee,t.eq=te,t.neq=re,t.gte=ne,t.lte=ie,t.cmp=oe,t.Comparator=se;var ae={};function ce(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof ce)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new ce(e.raw,t);if(e instanceof se)return new ce(e.value,t);if(!(this instanceof ce))return new ce(e,t);if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e.trim().split(/\s+/).join(" "),this.set=this.raw.split("||").map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError("Invalid SemVer Range: "+this.raw);this.format()}function ue(e){return!e||"x"===e.toLowerCase()||"*"===e}function de(e,t,r,n,i,o,s,a,c,u,d,p,l){return((t=ue(r)?"":ue(n)?">="+r+".0.0":ue(i)?">="+r+"."+n+".0":">="+t)+" "+(a=ue(c)?"":ue(u)?"<"+(+c+1)+".0.0":ue(d)?"<"+c+"."+(+u+1)+".0":p?"<="+c+"."+u+"."+d+"-"+p:"<="+a)).trim()}function pe(e,t,n){for(var i=0;i0){var o=e[i].semver;if(o.major===t.major&&o.minor===t.minor&&o.patch===t.patch)return!0}return!1}return!0}function le(e,t,r){try{t=new ce(t,r)}catch(e){return!1}return t.test(e)}function fe(e,t,r,n){var i,o,s,a,c;switch(e=new Y(e,n),t=new ce(t,n),r){case">":i=Z,o=ie,s=ee,a=">",c=">=";break;case"<":i=ee,o=ne,s=Z,a="<",c="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(le(e,t,n))return!1;for(var u=0;u=0.0.0")),p=p||e,l=l||e,i(e.semver,p.semver,n)?p=e:s(e.semver,l.semver,n)&&(l=e)})),p.operator===a||p.operator===c)return!1;if((!l.operator||l.operator===a)&&o(e,l.semver))return!1;if(l.operator===c&&s(e,l.semver))return!1}return!0}se.prototype.parse=function(e){var t=this.options.loose?o[B]:o[F],r=e.match(t);if(!r)throw new TypeError("Invalid comparator: "+e);this.operator=r[1],"="===this.operator&&(this.operator=""),r[2]?this.semver=new Y(r[2],this.options.loose):this.semver=ae},se.prototype.toString=function(){return this.value},se.prototype.test=function(e){return r("Comparator.test",e,this.options.loose),this.semver===ae||("string"==typeof e&&(e=new Y(e,this.options)),oe(e,this.operator,this.semver,this.options))},se.prototype.intersects=function(e,t){if(!(e instanceof se))throw new TypeError("a Comparator is required");var r;if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),""===this.operator)return r=new ce(e.value,t),le(this.value,r,t);if(""===e.operator)return r=new ce(this.value,t),le(e.semver,r,t);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),i=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),o=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=oe(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),c=oe(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||i||o&&s||a||c},t.Range=ce,ce.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(" ").trim()})).join("||").trim(),this.range},ce.prototype.toString=function(){return this.range},ce.prototype.parseRange=function(e){var t=this.options.loose,n=t?o[K]:o[H];e=e.replace(n,de),r("hyphen replace",e),e=e.replace(o[$],"$1$2$3"),r("comparator trim",e,o[$]),e=(e=e.replace(o[D],"$1~")).replace(o[L],"$1^");var i=t?o[B]:o[F],s=e.split(" ").map((function(e){return function(e,t){return r("comp",e,t),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){r("caret",e,t);var n=t.loose?o[M]:o[V];return e.replace(n,(function(t,n,i,o,s){var a;return r("caret",e,t,n,i,o,s),ue(n)?a="":ue(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":ue(o)?a="0"===n?">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":">="+n+"."+i+".0 <"+(+n+1)+".0.0":s?(r("replaceCaret pr",s),a="0"===n?"0"===i?">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+"-"+s+" <"+(+n+1)+".0.0"):(r("no pr"),a="0"===n?"0"===i?">="+n+"."+i+"."+o+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+" <"+(+n+1)+".0.0"),r("caret return",a),a}))}(e,t)})).join(" ")}(e,t),r("caret",e),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){var n=t.loose?o[N]:o[q];return e.replace(n,(function(t,n,i,o,s){var a;return r("tilde",e,t,n,i,o,s),ue(n)?a="":ue(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":ue(o)?a=">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":s?(r("replaceTilde pr",s),a=">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0"):a=">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0",r("tilde return",a),a}))}(e,t)})).join(" ")}(e,t),r("tildes",e),e=function(e,t){return r("replaceXRanges",e,t),e.split(/\s+/).map((function(e){return function(e,t){e=e.trim();var n=t.loose?o[P]:o[O];return e.replace(n,(function(t,n,i,o,s,a){r("xRange",e,t,n,i,o,s,a);var c=ue(i),u=c||ue(o),d=u||ue(s);return"="===n&&d&&(n=""),c?t=">"===n||"<"===n?"<0.0.0":"*":n&&d?(u&&(o=0),s=0,">"===n?(n=">=",u?(i=+i+1,o=0,s=0):(o=+o+1,s=0)):"<="===n&&(n="<",u?i=+i+1:o=+o+1),t=n+i+"."+o+"."+s):u?t=">="+i+".0.0 <"+(+i+1)+".0.0":d&&(t=">="+i+"."+o+".0 <"+i+"."+(+o+1)+".0"),r("xRange return",t),t}))}(e,t)})).join(" ")}(e,t),r("xrange",e),e=function(e,t){return r("replaceStars",e,t),e.trim().replace(o[G],"")}(e,t),r("stars",e),e}(e,this.options)}),this).join(" ").split(/\s+/);return this.options.loose&&(s=s.filter((function(e){return!!e.match(i)}))),s=s.map((function(e){return new se(e,this.options)}),this)},ce.prototype.intersects=function(e,t){if(!(e instanceof ce))throw new TypeError("a Range is required");return this.set.some((function(r){return r.every((function(r){return e.set.some((function(e){return e.every((function(e){return r.intersects(e,t)}))}))}))}))},t.toComparators=function(e,t){return new ce(e,t).set.map((function(e){return e.map((function(e){return e.value})).join(" ").trim().split(" ")}))},ce.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new Y(e,this.options));for(var t=0;t":0===t.prerelease.length?t.patch++:t.prerelease.push(0),t.raw=t.format();case"":case">=":r&&!Z(r,t)||(r=t);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+e.operator)}}))}if(r&&e.test(r))return r;return null},t.validRange=function(e,t){try{return new ce(e,t).range||"*"}catch(e){return null}},t.ltr=function(e,t,r){return fe(e,t,"<",r)},t.gtr=function(e,t,r){return fe(e,t,">",r)},t.outside=fe,t.prerelease=function(e,t){var r=X(e,t);return r&&r.prerelease.length?r.prerelease:null},t.intersects=function(e,t,r){return e=new ce(e,r),t=new ce(t,r),e.intersects(t)},t.coerce=function(e){if(e instanceof Y)return e;if("string"!=typeof e)return null;var t=e.match(o[R]);if(null==t)return null;return X(t[1]+"."+(t[2]||"0")+"."+(t[3]||"0"))}})),vt=(wt.SEMVER_SPEC_VERSION,wt.re,wt.safeRe,wt.src,wt.parse,wt.valid,wt.clean,wt.SemVer,wt.inc,wt.diff,wt.compareIdentifiers,wt.rcompareIdentifiers,wt.major,wt.minor,wt.patch,wt.compare,wt.compareLoose,wt.rcompare,wt.sort,wt.rsort,wt.gt,wt.lt,wt.eq,wt.neq,wt.gte,wt.lte,wt.cmp,wt.Comparator,wt.Range,wt.toComparators,wt.satisfies,wt.maxSatisfying,wt.minSatisfying,wt.minVersion,wt.validRange,wt.ltr,wt.gtr,wt.outside,wt.prerelease,wt.intersects,wt.coerce,wt.satisfies(process.version,"^6.12.0 || >=8.0.0")),_t=["RS256","RS384","RS512","ES256","ES384","ES512"],bt=["RS256","RS384","RS512"],Tt=["HS256","HS384","HS512"];vt&&(_t.splice(3,0,"PS256","PS384","PS512"),bt.splice(3,0,"PS256","PS384","PS512"));var Et=/^\s+|\s+$/g,Ct=/^[-+]0x[0-9a-f]+$/i,At=/^0b[01]+$/i,xt=/^0o[0-7]+$/i,It=/^(?:0|[1-9]\d*)$/,St=parseInt;function kt(e){return e!=e}function Ot(e,t){return function(e,t){for(var r=-1,n=e?e.length:0,i=Array(n);++r-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991}(e.length)&&!function(e){var t=Ht(e)?qt.call(e):"";return"[object Function]"==t||"[object GeneratorFunction]"==t}(e)}function Ht(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function Kt(e){return!!e&&"object"==typeof e}var Gt=function(e,t,r,n){var i;e=$t(e)?e:(i=e)?Ot(i,function(e){return $t(e)?Vt(e):Mt(e)}(i)):[],r=r&&!n?function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||Kt(e)&&"[object Symbol]"==qt.call(e)}(e))return NaN;if(Ht(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Ht(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Et,"");var r=At.test(e);return r||xt.test(e)?St(e.slice(2),r?2:8):Ct.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(r):0;var o=e.length;return r<0&&(r=Lt(o+r,0)),function(e){return"string"==typeof e||!Ft(e)&&Kt(e)&&"[object String]"==qt.call(e)}(e)?r<=o&&e.indexOf(t,r)>-1:!!o&&function(e,t,r){if(t!=t)return function(e,t,r,n){for(var i=e.length,o=r+(n?1:-1);n?o--:++o-1},Qt=Object.prototype.toString;var Xt=function(e){return!0===e||!1===e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Boolean]"==Qt.call(e)},Yt=/^\s+|\s+$/g,zt=/^[-+]0x[0-9a-f]+$/i,Wt=/^0b[01]+$/i,Jt=/^0o[0-7]+$/i,Zt=parseInt,er=Object.prototype.toString;function tr(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var rr=function(e){return"number"==typeof e&&e==function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==er.call(e)}(e))return NaN;if(tr(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=tr(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Yt,"");var r=Wt.test(e);return r||Jt.test(e)?Zt(e.slice(2),r?2:8):zt.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e)},nr=Object.prototype.toString;var ir=function(e){return"number"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Number]"==nr.call(e)};var or=Function.prototype,sr=Object.prototype,ar=or.toString,cr=sr.hasOwnProperty,ur=ar.call(Object),dr=sr.toString,pr=function(e,t){return function(r){return e(t(r))}}(Object.getPrototypeOf,Object);var lr=function(e){if(!function(e){return!!e&&"object"==typeof e}(e)||"[object Object]"!=dr.call(e)||function(e){var t=!1;if(null!=e&&"function"!=typeof e.toString)try{t=!!(e+"")}catch(e){}return t}(e))return!1;var t=pr(e);if(null===t)return!0;var r=cr.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&ar.call(r)==ur},fr=Object.prototype.toString,mr=Array.isArray;var hr=function(e){return"string"==typeof e||!mr(e)&&function(e){return!!e&&"object"==typeof e}(e)&&"[object String]"==fr.call(e)},gr=/^\s+|\s+$/g,yr=/^[-+]0x[0-9a-f]+$/i,wr=/^0b[01]+$/i,vr=/^0o[0-7]+$/i,_r=parseInt,br=Object.prototype.toString;function Tr(e,t){var r;if("function"!=typeof t)throw new TypeError("Expected a function");return e=function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==br.call(e)}(e))return NaN;if(Er(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Er(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(gr,"");var r=wr.test(e);return r||vr.test(e)?_r(e.slice(2),r?2:8):yr.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e),function(){return--e>0&&(r=t.apply(this,arguments)),e<=1&&(t=void 0),r}}function Er(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var Cr=function(e){return Tr(2,e)},Ar=["RS256","RS384","RS512","ES256","ES384","ES512","HS256","HS384","HS512","none"];vt&&Ar.splice(3,0,"PS256","PS384","PS512");var xr={expiresIn:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"expiresIn" should be a number of seconds or string representing a timespan'},notBefore:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"notBefore" should be a number of seconds or string representing a timespan'},audience:{isValid:function(e){return hr(e)||Array.isArray(e)},message:'"audience" must be a string or array'},algorithm:{isValid:Gt.bind(null,Ar),message:'"algorithm" must be a valid string enum value'},header:{isValid:lr,message:'"header" must be an object'},encoding:{isValid:hr,message:'"encoding" must be a string'},issuer:{isValid:hr,message:'"issuer" must be a string'},subject:{isValid:hr,message:'"subject" must be a string'},jwtid:{isValid:hr,message:'"jwtid" must be a string'},noTimestamp:{isValid:Xt,message:'"noTimestamp" must be a boolean'},keyid:{isValid:hr,message:'"keyid" must be a string'},mutatePayload:{isValid:Xt,message:'"mutatePayload" must be a boolean'}},Ir={iat:{isValid:ir,message:'"iat" should be a number of seconds'},exp:{isValid:ir,message:'"exp" should be a number of seconds'},nbf:{isValid:ir,message:'"nbf" should be a number of seconds'}};function Sr(e,t,r,n){if(!lr(r))throw new Error('Expected "'+n+'" to be a plain object.');Object.keys(r).forEach((function(i){var o=e[i];if(o){if(!o.isValid(r[i]))throw new Error(o.message)}else if(!t)throw new Error('"'+i+'" is not allowed in "'+n+'"')}))}var kr={audience:"aud",issuer:"iss",subject:"sub",jwtid:"jti"},Or=["expiresIn","notBefore","noTimestamp","audience","issuer","subject","jwtid"],Pr=function(e,t,r,n){var i;if("function"!=typeof r||n||(n=r,r={}),r||(r={}),r=Object.assign({},r),i=n||function(e,t){if(e)throw e;return t},r.clockTimestamp&&"number"!=typeof r.clockTimestamp)return i(new st("clockTimestamp must be a number"));if(void 0!==r.nonce&&("string"!=typeof r.nonce||""===r.nonce.trim()))return i(new st("nonce must be a non-empty string"));var o=r.clockTimestamp||Math.floor(Date.now()/1e3);if(!e)return i(new st("jwt must be provided"));if("string"!=typeof e)return i(new st("jwt must be a string"));var s,a=e.split(".");if(3!==a.length)return i(new st("jwt malformed"));try{s=it(e,{complete:!0})}catch(e){return i(e)}if(!s)return i(new st("invalid token"));var c,u=s.header;if("function"==typeof t){if(!n)return i(new st("verify must be called asynchronous if secret or public key is provided as a callback"));c=t}else c=function(e,r){return r(null,t)};return c(u,(function(t,n){if(t)return i(new st("error in secret or public key callback: "+t.message));var c,d=""!==a[2].trim();if(!d&&n)return i(new st("jwt signature is required"));if(d&&!n)return i(new st("secret or public key must be provided"));if(d||r.algorithms||(r.algorithms=["none"]),r.algorithms||(r.algorithms=~n.toString().indexOf("BEGIN CERTIFICATE")||~n.toString().indexOf("BEGIN PUBLIC KEY")?_t:~n.toString().indexOf("BEGIN RSA PUBLIC KEY")?bt:Tt),!~r.algorithms.indexOf(s.header.alg))return i(new st("invalid algorithm"));try{c=nt.verify(e,s.header.alg,n)}catch(e){return i(e)}if(!c)return i(new st("invalid signature"));var p=s.payload;if(void 0!==p.nbf&&!r.ignoreNotBefore){if("number"!=typeof p.nbf)return i(new st("invalid nbf value"));if(p.nbf>o+(r.clockTolerance||0))return i(new ct("jwt not active",new Date(1e3*p.nbf)))}if(void 0!==p.exp&&!r.ignoreExpiration){if("number"!=typeof p.exp)return i(new st("invalid exp value"));if(o>=p.exp+(r.clockTolerance||0))return i(new dt("jwt expired",new Date(1e3*p.exp)))}if(r.audience){var l=Array.isArray(r.audience)?r.audience:[r.audience];if(!(Array.isArray(p.aud)?p.aud:[p.aud]).some((function(e){return l.some((function(t){return t instanceof RegExp?t.test(e):t===e}))})))return i(new st("jwt audience invalid. expected: "+l.join(" or ")))}if(r.issuer&&("string"==typeof r.issuer&&p.iss!==r.issuer||Array.isArray(r.issuer)&&-1===r.issuer.indexOf(p.iss)))return i(new st("jwt issuer invalid. expected: "+r.issuer));if(r.subject&&p.sub!==r.subject)return i(new st("jwt subject invalid. expected: "+r.subject));if(r.jwtid&&p.jti!==r.jwtid)return i(new st("jwt jwtid invalid. expected: "+r.jwtid));if(r.nonce&&p.nonce!==r.nonce)return i(new st("jwt nonce invalid. expected: "+r.nonce));if(r.maxAge){if("number"!=typeof p.iat)return i(new st("iat required when maxAge is specified"));var f=yt(r.maxAge,p.iat);if(void 0===f)return i(new st('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));if(o>=f+(r.clockTolerance||0))return i(new dt("maxAge exceeded",new Date(1e3*f)))}if(!0===r.complete){var m=s.signature;return i(null,{header:u,payload:p,signature:m})}return i(null,p)}))},Rr=function(e,t,r,n){"function"==typeof r?(n=r,r={}):r=r||{};var i="object"==typeof e&&!Buffer.isBuffer(e),o=Object.assign({alg:r.algorithm||"HS256",typ:i?"JWT":void 0,kid:r.keyid},r.header);function s(e){if(n)return n(e);throw e}if(!t&&"none"!==r.algorithm)return s(new Error("secretOrPrivateKey must have a value"));if(void 0===e)return s(new Error("payload is required"));if(i){try{!function(e){Sr(Ir,!0,e,"payload")}(e)}catch(e){return s(e)}r.mutatePayload||(e=Object.assign({},e))}else{var a=Or.filter((function(e){return void 0!==r[e]}));if(a.length>0)return s(new Error("invalid "+a.join(",")+" option for "+typeof e+" payload"))}if(void 0!==e.exp&&void 0!==r.expiresIn)return s(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));if(void 0!==e.nbf&&void 0!==r.notBefore)return s(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));try{!function(e){Sr(xr,!1,e,"options")}(r)}catch(e){return s(e)}var c=e.iat||Math.floor(Date.now()/1e3);if(r.noTimestamp?delete e.iat:i&&(e.iat=c),void 0!==r.notBefore){try{e.nbf=yt(r.notBefore,c)}catch(e){return s(e)}if(void 0===e.nbf)return s(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}if(void 0!==r.expiresIn&&"object"==typeof e){try{e.exp=yt(r.expiresIn,c)}catch(e){return s(e)}if(void 0===e.exp)return s(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}Object.keys(kr).forEach((function(t){var n=kr[t];if(void 0!==r[t]){if(void 0!==e[n])return s(new Error('Bad "options.'+t+'" option. The payload already has an "'+n+'" property.'));e[n]=r[t]}}));var u=r.encoding||"utf8";if("function"!=typeof n)return nt.sign({header:o,payload:e,secret:t,encoding:u});n=n&&Cr(n),nt.createSign({header:o,privateKey:t,payload:e,encoding:u}).once("error",n).once("done",(function(e){n(null,e)}))};let jr=[];class Dr{constructor(e){this.options=Object.assign({baseUrl:"https://appleid.apple.com",timeout:1e4},e)}async _fetch(e,t){const{baseUrl:r}=this.options;return uniCloud.httpclient.request(r+e,t)}async verifyIdentityToken(e){const t=e.split(".")[0],{kid:r}=JSON.parse(Buffer.from(t,"base64").toString());if(!jr.length)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}const n=this.getUsedKey(jr,r);if(!Object.keys(n).length&&!this.fetched)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}let i=null;try{i=Pr(e,function(e,t){var r=Buffer.from(e,"base64"),n=Buffer.from(t,"base64"),i=r.toString("hex"),o=n.toString("hex");i=J(i),o=J(o);var s=i.length/2,a=o.length/2,c=ee(s),u=ee(a),d="30"+ee(s+a+c.length/2+u.length/2+2)+"02"+c+i+"02"+u+o;return"-----BEGIN RSA PUBLIC KEY-----\n"+Buffer.from(d,"hex").toString("base64").match(/.{1,64}/g).join("\n")+"\n-----END RSA PUBLIC KEY-----\n"}(n.n,n.e),{algorithms:n.alg})}catch(e){return{code:10705,msg:e.message}}return{code:0,msg:i}}async getAuthKeys(){const{status:e,data:t}=await this._fetch("/auth/keys",{method:"GET",dataType:"json",timeout:this.options.timeout});if(200!==e)throw new Error("request https://appleid.apple.com/auth/keys fail");return t.keys}getUsedKey(e,t){let r={};for(let n=0;nvoid 0===e))return{code:N,messageValues:{param:this.t("dcloud-appid")}};const r=await P.doc(e).get(),n=r&&r.data&&r.data[0];if(!n)return{code:10002};const i=Object.keys(q).reduce((e,t)=>{const r=t,i=function(e,t){return t.split(".").reduce((e,t)=>e&&e[t],e)}(n,t);return i&&e.push({[r]:i}),e},[]);let o;const s={dcloud_appid:Br.in(t),_id:Br.neq(n._id)},a={dcloud_appid:Br.exists(!1),_id:Br.neq(n._id)};switch(i.length){case 0:return{code:10004};case 1:o=Br.or([Br.and([i[0],s]),Br.and([i[0],a])]);break;default:o=Br.or([Br.and([Br.or(i),s]),Br.and([Br.or(i),a])])}const c=await P.where(o).limit(1).get();return c&&c.data&&c.data[0]?{code:10005}:{code:0}}const $r=uniCloud.database().command;const Hr=uniCloud.database();const Kr=uniCloud.database().command;const Gr=uniCloud.database();const Qr=uniCloud.database();async function Xr(e){if(!e.openid||!e.access_token)throw new Error(this.t("config-param-required",{param:"openid, access_token"}));return function(e,t){const r={0:"",4e3:"缺失参数",4001:"apiKey不存在",4002:"sign校验不通过",4003:"appid不存在",4004:"应用未开通一键登录服务",4005:"应用开通的一键登录服务正在审核中",4006:"服务空间不在白名单中",4100:"账户余额不足",5e3:"获取手机号失败,请稍后重试(或其他未知错误)"};return{...e,msg:r[e.code]?"[getPhoneNumber] 获取手机号: "+r[e.code]:e.errMsg}}(await uniCloud.getPhoneNumber({provider:"univerify",...e}))}const Yr=uniCloud.database();const zr=uniCloud.database();const Wr=uniCloud.database();const Jr=uniCloud.database().command;const Zr=uniCloud.database();const en=uniCloud.database();const tn=uniCloud.database();const rn=uniCloud.database();const nn=uniCloud.database();const on=uniCloud.database();const sn=uniCloud.database();const an={"mobile-code":function(e){return!(!e.service||!e.service.sms)},univerify:function(e){return!(!e.service||!e.service.univerify)},weixin:function(e){return!!(e.oauth&&e.oauth.weixin&&e.oauth.weixin.appsecret)},qq:function(e){return!!(e.oauth&&e.oauth.qq&&e.oauth.qq.appsecret)},apple:function(e){return!!(e.oauth&&e.oauth.apple&&e.oauth.apple.bundleId)},alipay:function(e){return!!(e.oauth&&e.oauth.alipay&&e.oauth.alipay.privateKey)}};const cn=uniCloud.database();var un=Object.freeze({__proto__:null,addUser:async function({username:e,nickname:t,password:r,mobile:n,email:i,role:o=[],authorizedApp:s=[]}={}){const a=O.command,c=[];if(!e&&!n&&!i)throw new Error("username, mobile or email required");let u;if(e&&c.push({username:e}),n&&c.push({mobile:n,mobile_confirmed:1}),i&&c.push({email:i,email_confirmed:1}),s.length>0){u=a.and(a.or(c),a.or({dcloud_appid:a.in(s)},{dcloud_appid:a.exists(!1)}));if((await P.where(u).limit(1).get()).data.length>0)return{code:10201,messageValues:{type:this.t("username")}}}const d={role:o,nickname:t,dcloud_appid:s,register_date:Date.now()};if(e&&(d.username=e),r){const{passwordHash:e,version:t}=this.encryptPwd(r);d.password=e,t&&(d.password_secret_version=t)}return n&&(d.mobile=n,d.mobile_confirmed=1),i&&(d.email=i,d.email_confirmed=1),{code:0,uid:(await P.add(d)).id}},getUserInfo:async function({uid:e,field:t}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};let r;if(t&&t.length){const n={};for(let e=0;evoid 0===e.dcloud_appid||e.dcloud_appid.includes(this.context.APPID));if(0===i.length)return{code:10002};if(i.length>1)return{code:10005};const o=i[0]._id;return this.resetPwd({uid:o,password:r})},setAvatar:async function(e){return await P.doc(e.uid).update({avatar:e.avatar}),{code:0,msg:""}},updatePwd:async function(e){const t=await P.doc(e.uid).get();if(t&&t.data&&t.data.length>0){if(0===this._checkPwd(t.data[0],e.oldPassword).code){const{passwordHash:r,version:n}=this.encryptPwd(e.newPassword),i={password:r,token:[]};n&&(i.password_secret_version=n);return E("upRes",await P.doc(t.data[0]._id).update(i)),{code:0,msg:""}}return{code:40202}}return{code:40201}},updateUser:async function(e){const t=e.uid;if(!t)return{code:N,messageValues:{param:this.t("user-id")}};delete e.uid;const{username:r,email:n}=e,{usernameToLowerCase:i,emailToLowerCase:o}=this._getConfig();let s=r&&r.trim(),a=n&&n.trim();return s&&(i&&(s=s.toLowerCase()),e.username=s),a&&(o&&(a=a.toLowerCase()),e.email=a),E("update -> upRes",await P.doc(t).update(e)),{code:0,msg:""}},banAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:B})},unbanAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},closeAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:F})},openAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},_getAlipayApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.alipay)throw new Error(this.t("config-param-require",{param:e+".alipay"}));return["appid","privateKey"].forEach(r=>{if(!t.oauth.alipay[r])throw new Error(this.t("config-param-require",{param:`${e}.alipay.${r}`}))}),Ur({...t.oauth.alipay})},_getValidInviteCode:async function({inviteCode:e}={}){if(e){return await Mr(e)?{code:0,inviteCode:e}:{code:80401}}return async function(){let e,t=10,r=!1;for(;t>0&&!r;){t--,e=Vr();if(await Mr(e)){r=!0;break}}return r?{code:0,inviteCode:e}:{code:80402}}()},_addUser:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const n=this._getConfig(),i={...e,dcloud_appid:r?[this.context.APPID]:[],register_date:Date.now()},o=(await P.add(i)).id;let s;if(n.removePermissionAndRoleFromToken)s=await this.createToken({uid:o,needPermission:t});else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),s=await this.createToken({uid:o,role:t,permission:r})}const{token:a,tokenExpired:c}=s;return await P.doc(o).update({token:[a]}),{token:a,tokenExpired:c,uid:o,type:"register",userInfo:Object.assign({},i,{token:[a]})}},_loginExec:async function(e,t={}){if(e.status===B)return{code:10001};if(e.status===F)return{code:10006};const r=this._getConfig();let n=e.token||[];"string"==typeof n&&(n=[n]);const i=this._getExpiredToken(n);let o;if(n=n.filter(e=>-1===i.indexOf(e)),r.removePermissionAndRoleFromToken){const r=t.needPermission;o=await this.createToken({uid:e._id,needPermission:r})}else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),o=await this.createToken({uid:e._id,role:t,permission:r})}const{token:s,tokenExpired:a}=o;n.push(s),e.token=n;const c={last_login_date:Date.now(),last_login_ip:this.context.CLIENTIP,token:n,...t.extraData};await P.doc(e._id).update(c);const u=Object.assign({},e,c);return{code:0,msg:"",token:s,uid:u._id,username:u.username,type:"login",userInfo:u,tokenExpired:a}},_registerExec:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const{my_invite_code:n}=e;if(this._getConfig().autoSetInviteCode||n){const t=await this._getValidInviteCode({inviteCode:n});if(t.code)return t;e.my_invite_code=t.inviteCode}const{PLATFORM:i,appId:o,appid:s,APPID:a,uniPlatform:c,appName:u,appVersion:d,appVersionCode:p,channel:l,clientIP:f,CLIENTIP:m,OS:h,osName:g}=this.context;return e.register_env={appid:o||s||a||"",uni_platform:c||i||"",os_name:g||h||"",app_name:u||"",app_version:d||"",app_version_code:p||"",channel:l?l+"":"",client_ip:f||m||""},{code:0,msg:"",...await this._addUser(e,{needPermission:t,autoSetDcloudAppid:r})}},_getWeixinApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.weixin)throw new Error(this.t("config-param-require",{param:e+".weixin"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.weixin[r])throw new Error(this.t("config-param-require",{param:`${e}.weixin.${r}`}))}),qr({...t.oauth.weixin})},_getQQApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.qq)throw new Error(this.t("config-param-require",{param:e+".qq"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.qq[r])throw new Error(this.t("config-param-require",{param:`${e}.qq.${r}`}))}),Nr({...t.oauth.qq})},_getMatchedUser:function(e,t){if(0===e.length)return{code:10002};let r;const n={},i={};for(let r=e.length-1;r>=0;r--){const o=e[r];for(let s=0;s0?{code:10003,messageValues:{target:"用户"}}:{code:0,msg:"",userMatched:r,fieldMatched:s,isFallbackValueMatched:!!s&&i[s]}},_getCurrentAppUser:function(e){const t=this.context.APPID;return e.filter(e=>void 0===e.dcloud_appid||null===e.dcloud_appid||e.dcloud_appid.indexOf(t)>-1||e.dcloud_appid.indexOf(null)>-1)},_checkLoginUserList:function(e){if(e&&1!==e.length)return e[0].status===F?{code:10006}:{code:10005}},setAuthorizedAppLogin:async function({uid:e,dcloudAppidList:t}={}){if("array"!==m(t))return{code:U,messageValues:{param:"dcloudAppidList",reason:this.t("type-array-required",{param:this.t("dcloud-appid-list")})}};if(t&&0!==t.length){const r=await Fr.bind(this)({uid:e,dcloudAppidList:t});if(r.code)return r}return await P.doc(e).update({dcloud_appid:Br.set(t)}),{code:0}},authorizeAppLogin:async function({uid:e,dcloudAppid:t}={}){const r=await Fr.bind(this)({uid:e,dcloudAppidList:[t]});return r.code?r:(await P.doc(e).update({dcloud_appid:Br.push(t)}),{code:0})},forbidAppLogin:async function({uid:e,dcloudAppid:t}={}){return e?(await P.doc(e).update({dcloud_appid:Br.pull(t)}),{code:0}):{code:N,messageValues:{param:this.t("user-id")}}},acceptInvite:async function({uid:e,inviteCode:t}){const r=await P.where({_id:$r.neq(e),inviter_uid:$r.not($r.all([e])),my_invite_code:t}).get();if(1!==r.data.length)return{code:80501,msg:"邀请码无效"};const n=[r.data[0]._id].concat(r.data[0].inviter_uid||[]),i=await P.doc(e).field({my_invite_code:!0,inviter_uid:!0}).get();if(0===i.data.length)return{code:80502};if(i.data[0].inviter_uid&&i.data[0].inviter_uid.length>0)return{code:80503,msg:"邀请码不可修改"};const o=Date.now();return await P.doc(e).update({inviter_uid:n,invite_time:o}),await P.where({inviter_uid:e}).update({inviter_uid:$r.push(n)}),{code:0,msg:""}},getInvitedUser:async function({uid:e,level:t=1,limit:r=20,offset:n=0,needTotal:i=!1}){const o={code:0,msg:"",invitedUser:(await P.where({["inviter_uid."+(t-1)]:e}).field({_id:!0,username:!0,mobile:!0,invite_time:!0}).orderBy("invite_time","desc").skip(n).limit(r).get()).data};if(i){const r=await P.where({["inviter_uid."+(t-1)]:e}).count();o.total=r.total}return o},setUserInviteCode:async function({uid:e,myInviteCode:t}){const r=await this._getValidInviteCode({inviteCode:t});return r.code?r:(await P.doc(e).update({my_invite_code:r.inviteCode}),{code:0,msg:"",myInviteCode:r.inviteCode})},loginByAlipay:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,code:r,myInviteCode:n,role:i,type:o}=e,{openid:s}=await this._getAlipayApi().code2Session(r);if(!s)return{code:10501,messageValues:{account:this.t("alipay-account")}};let a=await P.where({ali_openid:s}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0){if("register"===o)return{code:10502,messageValues:{type:this.t("alipay-account")}};if(1!==a.length)return{code:10005};const e=a[0],r=await this._loginExec(e,{needPermission:t});if(0!==r.code)return r;const{userInfo:n}=r;return{...r,openid:s,mobileConfirmed:1===n.mobile_confirmed,emailConfirmed:1===n.email_confirmed}}{if("login"===o)return{code:10503,messageValues:{type:this.t("alipay-account")}};const e={ali_openid:s};e.my_invite_code=n,e.role=i;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:s,mobileConfirmed:!1,emailConfirmed:!1}}},loginByEmail:async function(e){let{email:t,code:r,password:n,myInviteCode:i,type:o,needPermission:s,role:a}=e||{};if(t=t&&t.trim(),!t)return{code:N,messageValues:{param:"邮箱"}};const{emailToLowerCase:c}=this._getConfig();let u=t;c&&(u=t.toLowerCase());const d=await this.verifyCode({email:u,code:r,type:o||"login"});if(0!==d.code)return d;let p={email:t,email_confirmed:1};const l={field:"email",value:t},f=Hr.command;u!==t&&(p=f.or(p,{email:u,email_confirmed:1}),l.fallbackValue=u);let m=await P.where(p).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10301,messageValues:{type:"邮箱"}};const e=this._getMatchedUser(m,[l]);if(e.code)return e;const{userMatched:t}=e,r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,email:u}}{if("login"===o)return{code:10302,messageValues:{type:"邮箱"}};const e={email:u,email_confirmed:1},t=n&&n.trim();if(t){const{passwordHash:r,version:n}=this.encryptPwd(t);e.password=r,n&&(e.password_secret_version=n)}e.my_invite_code=i,e.role=a;const r=await this._registerExec(e,{needPermission:s});return 0!==r.code?r:{...r,email:u}}},loginBySms:async function({mobile:e,code:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){if(!(e=e&&e.trim()))return{code:N,messageValues:{param:this.t("mobile")}};const c=this._getConfig();if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const u=await this.verifyCode({mobile:e,code:t,type:o||"login"});if(0!==u.code)return u;const d={mobile:e,mobile_confirmed:1};let p=await P.where(d).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0){if("register"===o)return{code:10201,messageValues:{type:this.t("mobile")}};if(1!==p.length)return{code:10005};const t=p[0],r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,mobile:e}}{const t=Date.now();if("login"===o)return{code:10202,messageValues:{type:this.t("mobile")}};const u={mobile:e,mobile_confirmed:1,register_ip:this.context.CLIENTIP,register_date:t},d=r&&r.trim();if(d){const{passwordHash:e,version:t}=this.encryptPwd(d);u.password=e,t&&(u.password_secret_version=t)}if(n){const e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};u.inviter_uid=[e.data[0]._id].concat(e.data[0].inviter_uid||[]),u.invite_time=t}else if(c.forceInviteCode)return{code:10203};u.my_invite_code=i,u.role=a;const p=await this._registerExec(u,{needPermission:s});return 0!==p.code?p:{...p,mobile:e}}},loginByWeixin:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,platform:r,code:n,myInviteCode:i,role:o,type:s}=e,a=r||this.context.PLATFORM,c=function({clientPlatform:e,userAgent:t}={}){switch(e){case"app":case"app-plus":return"app";case"mp-weixin":return"mp";case"h5":case"web":return t.indexOf("MicroMessenger")>-1?"h5":"web";default:throw new Error("Unsupported weixin platform")}}({clientPlatform:a,userAgent:this.context.CLIENTUA}),u="mp-weixin"===a,{openid:d,unionid:p,sessionKey:l,accessToken:f,refreshToken:m,expired:h}=await this._getWeixinApi()[u?"code2Session":"getOauthAccessToken"](n);if(!d)return{code:10401,messageValues:{account:"微信openid"}};const g={dcloudAppid:this.context.APPID,openid:d,platform:"weixin-"+c},y=require("uni-open-bridge-common");let w;u?(w={sessionKey:l},await y.setSessionKey(g,{session_key:l},2592e3)):(w={accessToken:f,refreshToken:m,accessTokenExpired:h},await y.setUserAccessToken(g,{access_token:f,refresh_token:m,access_token_expired:h},2592e3));const v=Gr.command,_=[{wx_openid:{[a]:d}}];p&&_.push({wx_unionid:p});let b=await P.where(v.or(..._)).get();if(b=this._getCurrentAppUser(b.data),b&&b.length>0){if("register"===s)return{code:10402,messageValues:{type:this.t("wechat-account")}};if(1!==b.length)return{code:10005};const e=b[0],r={wx_openid:{[a]:d}};p&&(r.wx_unionid=p);const n=await this._loginExec(e,{needPermission:t,extraData:r});if(0!==n.code)return n;const{userInfo:i}=n;return{...n,openid:d,unionid:p,...w,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===s)return{code:10403,messageValues:{type:this.t("wechat-account")}};const e={wx_openid:{[a]:d},wx_unionid:p};e.my_invite_code=i,e.role=o;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:d,unionid:p,...w,mobileConfirmed:!1,emailConfirmed:!1}}},loginByQQ:async function({code:e,accessToken:t,accessTokenExpired:r,myInviteCode:n,needPermission:i,role:o,type:s}={}){const a=this.context.PLATFORM,c="mp-qq"===a,{openid:u,unionid:d,sessionKey:p}=await this._getQQApi()[c?"code2Session":"getOpenidByToken"]({code:e,accessToken:t});if(!u)return{code:10801,messageValues:{account:"qq openid"}};const l=function({clientPlatform:e}={}){switch(e){case"app":case"app-plus":return"app";case"mp-qq":return"mp";default:throw new Error("Unsupported qq platform")}}({clientPlatform:a}),f={dcloudAppid:this.context.APPID,openid:u,platform:"qq-"+l},m=require("uni-open-bridge-common");let h;c?(h={sessionKey:p},await m.setSessionKey(f,{session_key:p},2592e3)):(h={accessToken:t,accessTokenExpired:r},await m.setUserAccessToken(f,{access_token:t,access_token_expired:r},r?Math.floor((r-Date.now())/1e3):2592e3));const g=Qr.command,y=[{qq_openid:{[a]:u}}];d&&y.push({qq_unionid:d});let w=await P.where(g.or(...y)).get();if(w=this._getCurrentAppUser(w.data),w&&w.length>0){if("register"===s)return{code:10802,messageValues:{type:this.t("qq-account")}};if(1!==w.length)return{code:10005};const e=w[0],t={qq_openid:{[a]:u}};d&&(t.qq_unionid=d);const r=await this._loginExec(e,{needPermission:i,extraData:t});if(0!==r.code)return r;const{userInfo:n}=r;return{...r,openid:u,unionid:d,...h,mobileConfirmed:1===n.mobile_confirmed,emailConfirmed:1===n.email_confirmed}}{if("login"===s)return{code:10803,messageValues:{type:this.t("qq-account")}};const e={qq_openid:{[a]:u},qq_unionid:d};e.my_invite_code=n,e.role=o;const t=await this._registerExec(e);return 0!==t.code?t:{...t,openid:u,unionid:d,...h,mobileConfirmed:!1,emailConfirmed:!1}}},loginByUniverify:async function({openid:e,access_token:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){const c=this._getConfig(),u=c&&c.service&&c.service.univerify;if(!u)throw new Error(this.t("uni-verify-config-required"));if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const d=await Xr.bind(this)({...u,openid:e,access_token:t});if(0!==d.code)return d;const p=String(d.phoneNumber);let l=await P.where({mobile:p,mobile_confirmed:1}).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){if("register"===o)return{code:10601,messageValues:{type:this.t("mobile")}};if(1!==l.length)return{code:10005};const e=l[0],t=await this._loginExec(e,{needPermission:s});return 0!==t.code?t:{...t,mobile:p}}if("login"===o)return{code:10602,messageValues:{type:this.t("mobile")}};const f=Date.now(),m={mobile:p,my_invite_code:i,mobile_confirmed:1,role:a},h=r&&r.trim();if(h){const{passwordHash:e,version:t}=this.encryptPwd(h);m.password=e,t&&(m.password_secret_version=t)}if(n){let e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};e=e.data[0],m.inviter_uid=[e._id].concat(e.inviter_uid||[]),m.invite_time=f}else if(c.forceInviteCode)return{code:10203};m.my_invite_code=i;const g=await this._registerExec(m,{needPermission:s});return 0!==g.code?g:{...g,mobile:p}},loginByApple:async function({nickName:e,fullName:t,identityToken:r,myInviteCode:n,type:i,needPermission:o,role:s}){const a=this._getConfig(),c=a&&a.oauth&&a.oauth.apple,u=c&&c.bundleId;if(!u)throw new Error(this.t("config-param-require",{param:"(app || app-plus).apple.bundleId"}));if(!r)return{code:N,messageValues:{param:"identityToken"}};t=e||(t&&Object.keys(t).length>0?t.familyName+t.givenName:"");const{code:d,msg:p}=await Lr().verifyIdentityToken(r);if(0!==d)return{code:d,msg:p,messageValues:{account:this.t("apple-account")}};const{iss:l,sub:f,aud:m,email:h}=p;if("https://appleid.apple.com"!==l)return{code:10706,messageValues:{account:this.t("apple-account")}};if(!f)return{code:10701,messageValues:{account:this.t("apple-account")}};if(u!==m)return{code:10702,messageValues:{account:this.t("apple-account")}};const g=t||"User-"+(h?h.split("@")[0]:Math.random().toString(32).slice(2));let y=await P.where({apple_openid:f}).get();if(y=this._getCurrentAppUser(y.data),y&&y.length>0){if("register"===i)return{code:10703,messageValues:{type:this.t("apple-account")}};if(1!==y.length)return{code:10005};const e=y[0],t=await this._loginExec(e,{needPermission:o});return 0!==t.code?t:{...t,openid:f}}if("login"===i)return{code:10704,messageValues:{type:this.t("apple-account")}};const w={nickname:g,apple_openid:f,my_invite_code:n,role:s},v=await this._registerExec(w,{needPermission:o});return 0!==v.code?v:{...v,openid:f}},login:async function({username:e,password:t,queryField:r=[],needPermission:n}){const i=Yr.command,o=[];r&&r.length||(r=["username"]),r.length>1&&console.warn(this.t("query-field-warning"));const{usernameToLowerCase:s,emailToLowerCase:a,passwordErrorLimit:c,passwordErrorRetryTime:u}=this._getConfig(),d={email:{email_confirmed:1},mobile:{mobile_confirmed:1}},p={},l=e&&e.trim();if(!l)return{code:N,messageValues:{param:this.t("username")}};s&&(p.username=l.toLowerCase()),a&&(p.email=l.toLowerCase());const f=[];r.forEach(t=>{o.push({[t]:e,...d[t]});const r={field:t,value:e};"username"===t&&p.username!==e?(o.push({[t]:p.username,...d[t]}),r.fallbackValue=p.username):"email"===t&&p.email!==e&&(o.push({[t]:p.email,...d[t]}),r.fallbackValue=p.email),f.push(r)});let m=await P.where(i.or(...o)).get();m=this._getCurrentAppUser(m.data);const h=this.context.CLIENTIP,g=this._getMatchedUser(m,f);if(g.code)return g;const{userMatched:y}=g;let w=y.login_ip_limit||[];w=w.filter(e=>e.last_error_time>Date.now()-1e3*u);let v=w.find(e=>e.ip===h);if(v&&v.error_times>=c)return{code:10103};const _=t&&t.trim();if(!_)return{code:N,messageValues:{param:"密码"}};const b=this._checkPwd(y,_);if(0===b.code){const e=w.indexOf(v);e>-1&&w.splice(e,1);const t={login_ip_limit:w},{passwordHash:r,passwordVersion:i}=b;r&&i&&(t.password=r,t.password_secret_version=i);const o=await this._loginExec(y,{needPermission:n,extraData:t});return o.code,o}return v?(v.error_times++,v.last_error_time=Date.now()):(v={ip:h,error_times:1,last_error_time:Date.now()},w.push(v)),await P.doc(y._id).update({login_ip_limit:w}),{code:10102,msg:"密码错误"}},register:async function(e){const t=[],r=[{name:"username",desc:this.t("username")},{name:"email",desc:this.t("email"),extraCond:{email_confirmed:1}},{name:"mobile",desc:this.t("mobile"),extraCond:{mobile_confirmed:1}}],{usernameToLowerCase:n,emailToLowerCase:i}=this._getConfig();r.forEach(r=>{const o=r.name;let s=e[o]&&e[o].trim();s?(("username"===r.name&&n||"email"===r.name&&i)&&(s=s.toLowerCase()),e[o]=s,t.push({[o]:s,...r.extraCond})):delete e[o]});const{username:o,email:s,mobile:a,myInviteCode:c,needPermission:u,autoSetDcloudAppid:d=!0}=e;if("needPermission"in e&&delete e.needPermission,"autoSetDcloudAppid"in e&&delete e.autoSetDcloudAppid,0===t.length)return{code:20101,messageValues:{param:this.t("user-unique-param")}};const p=zr.command;let l=await P.where(p.or(...t)).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){const t=l[0];if(t.status===F)return{code:10006};for(let n=0;nt[e]===i.extraCond[e])),t[i.name]===e[i.name]&&o)return{code:20102,messageValues:{type:i.desc}}}}const f=e.password&&e.password.trim();if(!f)return{code:N,messageValues:{param:this.t("password")}};const{passwordHash:m,version:h}=this.encryptPwd(f);e.password=m,h&&(e.password_secret_version=h),e.my_invite_code=c,delete e.myInviteCode;const g=await this._registerExec(e,{needPermission:u,autoSetDcloudAppid:d});return 0!==g.code?g:{...g,username:o,email:s,mobile:a}},logout:async function(e){const t=await this.checkToken(e);if(t.code)return t;const r=Wr.command;return await P.doc(t.uid).update({token:r.pull(e)}),{code:0,msg:""}},getRoleByUid:async function({uid:e}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};const t=await P.doc(e).get();return 0===t.data.length?{code:L}:{code:0,msg:"",role:t.data[0].role||[]}},getPermissionByRole:async function({roleID:e}){if(!e)return{code:N,messageValues:{param:"roleID"}};if("admin"===e){return{code:0,msg:"",permission:(await D.limit(1e3).get()).data.map(e=>e.permission_id)}}const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,msg:"",permission:t.data[0].permission||[]}},getPermissionByUid:async function({uid:e}={}){const t=await P.aggregate().match({_id:e}).project({role:!0}).unwind("$role").lookup({from:"uni-id-roles",localField:"role",foreignField:"role_id",as:"roleDetail"}).unwind("$roleDetail").replaceRoot({newRoot:"$roleDetail"}).end(),r=[],n=[];return t.data.forEach(e=>{n.push(e.role_id),r.push(...e.permission)}),{code:0,msg:"",role:n,permission:A(r)}},bindRole:async function({uid:e,roleList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.role=r?t:Jr.push(t),await P.doc(e).update(n),{code:0,msg:""}},bindPermission:async function({roleID:e,permissionList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.permission=r?t:Jr.push(t),await j.where({role_id:e}).update(n),{code:0,msg:""}},unbindRole:async function({uid:e,roleList:t}){return"string"==typeof t&&(t=[t]),await P.doc(e).update({role:Jr.pull(Jr.in(t))}),{code:0,msg:""}},unbindPermission:async function({roleID:e,permissionList:t}){return"string"==typeof t&&(t=[t]),await j.where({role_id:e}).update({permission:Jr.pull(Jr.in(t))}),{code:0,msg:""}},addRole:async function({roleID:e,roleName:t,comment:r,permission:n=[]}){return e?"admin"===e?{code:U,messageValues:{param:"roleID",reason:this.t("add-role-admin-is-not-allowed")}}:(await j.add({role_id:e,role_name:t,comment:r,permission:n,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},addPermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.add({permission_id:e,permission_name:t,comment:r,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},getRoleList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",roleList:(await j.skip(t).limit(e).get()).data};if(r){const{total:e}=await j.where({_id:Jr.exists(!0)}).count();n.total=e}return n},getRoleInfo:async function(e){const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,...t.data[0]}},updateRole:async function({roleID:e,roleName:t,comment:r,permission:n}){return e?(await j.where({role_id:e}).update({role_name:t,comment:r,permission:n}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},deleteRole:async function({roleID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof roleID must be array or string");return await j.where({role_id:Jr.in(e)}).remove(),await P.where({role:Jr.elemMatch(Jr.in(e))}).update({role:Jr.pullAll(e)}),{code:0,msg:""}},getPermissionList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",permissionList:(await D.skip(t).limit(e).get()).data};if(r){const{total:e}=await D.where({_id:Jr.exists(!0)}).count();n.total=e}return n},getPermissionInfo:async function(e){const t=await D.where({permission_id:e}).get();return 0===t.data.length?{code:N,messageValues:{param:this.t("permission-id")}}:{code:0,...t.data[0]}},updatePermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.where({permission_id:e}).update({permission_name:t,comment:r}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},deletePermission:async function({permissionID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof permissionID must be array or string");return await D.where({permission_id:Jr.in(e)}).remove(),await j.where({permission:Jr.elemMatch(Jr.in(e))}).update({permission:Jr.pullAll(e)}),{code:0,msg:""}},bindAlipay:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,{openid:i}=await this._getAlipayApi({platform:n}).code2Session(t);if(!i)return{code:60401,messageValues:{account:this.t("alipay-account")}};let o=await P.where({ali_openid:i}).get();return o=this._getCurrentAppUser(o.data),o&&o.length>0?{code:60402,messageValues:{type:this.t("alipay-account")}}:(await P.doc(e).update({ali_openid:i}),{code:0,openid:i,msg:""})},bindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!r)return{code:N,messageValues:{param:this.t("email")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const{emailToLowerCase:i}=this._getConfig();i&&(r=r.toLowerCase());let o=await P.where({email:r,email_confirmed:1}).get();if(o=this._getCurrentAppUser(o.data),o&&o.length>0)return{code:60201,messageValues:{type:this.t("email")}};const s=await this.verifyCode({email:r,code:n,type:"bind"});return 0!==s.code?s:(await P.doc(t).update({email:r,email_confirmed:1}),{code:0,msg:"",email:r})},bindMobile:async function(e){let{uid:t,mobile:r,code:n,openid:i,access_token:o,type:s="sms"}=e||{};if("univerify"===s){const e=this._getConfig(),t=e&&e.service&&e.service.univerify;if(!t)throw new Error("请在config.json中配置service.univerify下一键登录相关参数");const n=await Xr.bind(this)({...t,openid:i,access_token:o});if(0!==n.code)return n;r=""+n.phoneNumber}let a=await P.where({mobile:r,mobile_confirmed:1}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0)return{code:60101,messageValues:{type:"手机号"}};if("sms"===s&&"code"in e){if(!r)return{code:N,messageValues:{param:this.t("mobile")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const e=await this.verifyCode({mobile:r,code:n,type:"bind"});if(0!==e.code)return e}return await P.doc(t).update({mobile:r,mobile_confirmed:1}),{code:0,msg:"",mobile:r}},bindWeixin:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,i="mp-weixin"===n,{openid:o,unionid:s,sessionKey:a,accessToken:c,refreshToken:u,expired:d}=await this._getWeixinApi({platform:n})[i?"code2Session":"getOauthAccessToken"](t);if(!o)return{code:60301,messageValues:{account:"微信openid"}};const p=Zr.command,l=[{wx_openid:{[n]:o}}];s&&l.push({wx_unionid:s});let f=await P.where(p.or(...l)).get();if(f=this._getCurrentAppUser(f.data),f&&f.length>0)return{code:60302,messageValues:{type:this.t("wechat-account")}};const m={wx_openid:{[n]:o}};let h;return s&&(m.wx_unionid=s),await P.doc(e).update(m),h=i?{sessionKey:a}:{accessToken:c,refreshToken:u,accessTokenExpired:d},{code:0,msg:"",openid:o,unionid:s,...h}},bindQQ:async function({uid:e,code:t,accessToken:r,platform:n}={}){const i=n||this.context.PLATFORM,o="mp-qq"===i,{openid:s,unionid:a,sessionKey:c}=await this._getQQApi()[o?"code2Session":"getOpenidByToken"]({code:t,accessToken:r});if(!s)return{code:60501,messageValues:{account:"qq openid"}};const u=en.command,d=[{qq_openid:{[i]:s}}];a&&d.push({qq_unionid:a});let p=await P.where(u.or(...d)).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0)return{code:60502,messageValues:{type:this.t("qq-account")}};const l={qq_openid:{[i]:s}};return a&&(l.qq_unionid=a),await P.doc(e).update(l),{code:0,msg:"",openid:s,unionid:a,...{accessToken:r,sessionKey:c}}},unbindAlipay:async function(e){const t=tn.command,r=await P.doc(e).update({ali_openid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70401}},unbindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!t||!r)return{code:N,messageValues:{param:t?this.t("email"):this.t("user-id")}};const{emailToLowerCase:i}=this._getConfig();if("code"in e){const e=await this.verifyCode({email:r,code:n,type:"unbind"});if(0!==e.code)return e}const o=rn.command;let s={_id:t,email:r};if(i){const e=r.toLowerCase();e!==r&&(s=o.or(s,{_id:t,email:e}))}return 1===(await P.where(s).update({email:o.remove(),email_confirmed:o.remove()})).updated?{code:0,msg:""}:{code:70201}},unbindMobile:async function(e){const{uid:t,mobile:r,code:n}=e||{};if("code"in e){const e=await this.verifyCode({mobile:r,code:n,type:"unbind"});if(0!==e.code)return e}const i=nn.command;return 1===(await P.where({_id:t,mobile:r}).update({mobile:i.remove(),mobile_confirmed:i.remove()})).updated?{code:0,msg:""}:{code:70101}},unbindWeixin:async function(e){const t=on.command,r=await P.doc(e).update({wx_openid:t.remove(),wx_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70301}},unbindQQ:async function(e){const t=sn.command,r=await P.doc(e).update({qq_openid:t.remove(),qq_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70501}},getSupportedLoginType:function({appid:e,platform:t}={}){if(!e||!t)throw new Error("Parameter appid and platform is required");const r=this._getConfig({appid:e,platform:t}),n=["username-password","mobile-password","email-password"];for(const e in an)an[e](r)&&n.push(e);return{supportedLoginType:n}},code2SessionAlipay:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getAlipayApi({platform:e}).code2Session(t.code);return r.openid?{code:0,msg:"",...r}:{code:80701,messageValues:{account:this.t("alipay-account")}}}catch(e){return console.error(e),{code:80702,messageValues:{account:this.t("alipay-account")}}}},code2SessionWeixin:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getWeixinApi({platform:e})["mp-weixin"===e?"code2Session":"getOauthAccessToken"](t.code);return r.openid?{code:0,msg:"",...r}:{code:80601,messageValues:{account:"微信openid"}}}catch(e){return console.error(e),{code:80602,messageValues:{account:"微信openid"}}}},verifyAppleIdentityToken:async function({identityToken:e,platform:t}){const r=t||this.context.PLATFORM,{code:n,msg:i}=await Lr({clientType:r}).verifyIdentityToken(e);return 0!==n?{code:n,msg:i}:{code:n,msg:"验证通过",...i}},wxBizDataCrypt:async function({code:e,sessionKey:r,encryptedData:n,iv:i}){if(!n)return{code:N,messageValues:{param:"encryptedData"}};if(!i)return{code:N,messageValues:{param:"iv"}};if(!e&&!r)return{code:N,messageValues:{param:"sessionKey"}};const o=this._getWeixinApi();if(!r){const t=await o.code2Session(e);if(!t.sessionKey)return{code:80801};r=t.sessionKey}r=Buffer.from(r,"base64"),n=Buffer.from(n,"base64"),i=Buffer.from(i,"base64");try{var s=t.createDecipheriv("aes-128-cbc",r,i);s.setAutoPadding(!0);var a=s.update(n,"binary","utf8");a+=s.final("utf8"),a=JSON.parse(a)}catch(e){return console.error(e),{code:80802}}return a.watermark.appid!==o.options.appId?{code:80803}:{code:0,msg:"",...a}},getWeixinUserInfo:async function({accessToken:e,openid:t}={}){const r=this.context.PLATFORM;if("app"!==r&&"app-plus"!==r)throw new Error(this.t("limit-client-platform"));try{return{code:0,msg:"",...await this._getWeixinApi().getUserInfo({accessToken:e,openid:t})}}catch(e){return console.error(e),{code:80901}}},encryptPwd:function(e,{value:r,version:n}={}){if(!(e=e&&e.trim()))throw new Error(this.t("param-required",{param:this.t("password")}));if(!r){const e=this._getConfig(),{passwordSecret:t}=e;if("array"===m(t)){const e=t.sort((e,t)=>e.version-t.version);r=e[e.length-1].value,n=e[e.length-1].version}else r=t}if(!r)throw new Error(this.t("param-error",{param:"passwordSecret",reason:"invalid passwordSecret"}));const i=t.createHmac("sha1",r.toString("ascii"));return i.update(e),{passwordHash:i.digest("hex"),version:n}},checkToken:async function(e,{needPermission:t,needUserInfo:r=!0}={}){const n=this._getConfig(),i=this._verifyToken(e);if(i.code)return i;const{uid:o,needPermission:s,role:a,permission:c,exp:u,iat:d,...p}=i,l=a&&c;t=void 0===t?s:t;const f=n.removePermissionAndRoleFromToken||!l||r,m=!n.removePermissionAndRoleFromToken&&!l||n.removePermissionAndRoleFromToken&&l||n.tokenExpiresThreshold&&u-Date.now()/1e3this._createTokenInternal({signContent:e,config:o})):this._createTokenInternal({signContent:a,config:o})},_updateToken:async function({uid:e,tokenList:t,removeToken:r=[],addToken:n=[]}={}){if(!t){const r=await P.doc(e).get(),n=r.data&&r.data[0];t=n&&n.token||[]}"string"==typeof t&&(t=[t]);const i=this._getExpiredToken(t);(t=t.filter(e=>-1===i.indexOf(e))).push(...n);for(let e=0;ee.version-t.version);let c;if(c=n?a.find(e=>e.version===n):a[0],!c)return{code:3};const u=a[a.length-1],{passwordHash:d}=this.encryptPwd(t,c);if(d===r){const e={code:0};if(c!==u){const{passwordHash:r,version:n}=this.encryptPwd(t,u);e.passwordHash=r,e.passwordVersion=n}return e}return{code:4,message:""}},_verifyToken:function(e){const t=this._getConfig();let r;try{r=Pr(e,t.tokenSecret)}catch(e){return"TokenExpiredError"===e.name?{code:30203,err:e}:{code:30204,err:e}}return t.bindTokenToDevice&&r.clientId&&r.clientId!==this._getClientUaHash()?{code:30201}:{code:0,message:"",...r}},_getExpiredToken:function(e){const t=this._getConfig(),r=[];return e.forEach(e=>{try{Pr(e,t.tokenSecret)}catch(t){r.push(e)}}),r},_getPermissionListByRoleList:async function(e){if(!Array.isArray(e))return[];if(0===e.length)return[];if(e.includes("admin")){return(await D.limit(500).get()).data.map(e=>e.permission_id)}const t=await j.where({role_id:Kr.in(e)}).get(),r=[];return t.data.forEach(e=>{Array.prototype.push.apply(r,e.permission)}),A(r)},_getClientUaHash:function(){const e=t.createHash("md5"),r=/MicroMessenger/i.test(this.context.CLIENTUA)?this.context.CLIENTUA.replace(/(MicroMessenger\S+).*/i,"$1"):this.context.CLIENTUA;return e.update(r),e.digest("hex")},_createTokenInternal:function({signContent:e,config:t}){if(t.tokenExpiresIn&&t.tokenExpiresThreshold&&t.tokenExpiresIn<=t.tokenExpiresThreshold)throw new Error(this.t("token-expires-config-warning"));return"object"===m(e)&&e.uid?(t.bindTokenToDevice&&(e.clientId=this._getClientUaHash()),{token:Rr(e,t.tokenSecret,{expiresIn:t.tokenExpiresIn}),tokenExpired:Date.now()+1e3*t.tokenExpiresIn}):{code:30101,messageValues:{param:this.t("user-id")}}},setVerifyCode:async function({mobile:e,email:t,code:r,expiresIn:n,type:i}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50101,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50102,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};r||(r=C()),n||(n=180);const o=Date.now(),s={mobile:e,email:t,type:i,code:r,state:0,ip:this.context.CLIENTIP,created_at:o,expired_at:o+1e3*n};return await R.add(s),{code:0,mobile:e,email:t}},verifyCode:async function({mobile:e,email:t,code:r,type:n}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50201,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50203,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};if(!r)return{code:50202,messageValues:{type:this.t(e?"sms":"email")}};const i=cn.command,o=Date.now(),s={mobile:e,email:t,type:n,code:r,state:0,expired_at:i.gt(o)},a=await R.where(s).orderBy("created_at","desc").limit(1).get();if(a&&a.data&&a.data.length>0){const e=a.data[0];return await R.doc(e._id).update({state:1}),{code:0,msg:"验证通过"}}return{code:50202,messageValues:{type:this.t(e?"sms":"email")}}},sendSmsCode:async function({mobile:e,code:t,type:r,templateId:n}){if(!e)return{code:N,messageValues:{param:this.t("mobile")}};if(t||(t=C()),!r)return{code:N,messageValues:{param:this.t("verify-code-type")}};const i=this._getConfig();let o=i&&i.service&&i.service.sms;if(!o)throw new Error(this.t("config-param-required",{param:"service.sms"}));o=Object.assign({codeExpiresIn:300},o);const{name:s,smsKey:a,smsSecret:c,codeExpiresIn:u}=o;let d;switch(r){case"login":d=this.t("login");break;default:d=this.t("verify-mobile")}try{const i={name:s,code:t,action:d,expMinute:""+Math.round(u/60)};s&&(i.name=s),await uniCloud.sendSms({smsKey:a,smsSecret:c,phone:e,templateId:n||"uniID_code",data:i});const o=await this.setVerifyCode({mobile:e,code:t,expiresIn:u,type:r});return o.code>=0?o:{code:0,msg:""}}catch(e){return console.error(e),{code:50301}}}});let dn;try{dn=require("uni-config-center")}catch(e){throw new Error("Plugin[uni-config-center] was not found")}class pn{constructor({context:e,clientInfo:t,config:r}={}){const n=dn({pluginId:"uni-id"});this.pluginConfig=n,this.config=r||this._getConfigContent(),this._configCache={},Object.defineProperty(this,"context",{get(){let r;r=t?{OS:t.os,CLIENTIP:t.clientIP,CLIENTUA:t.userAgent,PLATFORM:t.platform,APPID:t.appId,LOCALE:t.locale,DEVICEID:t.deviceId}:Object.assign({},e||global.__ctx__||{});const n=["CLIENTIP","PLATFORM","APPID","LOCALE"];for(let e=0;ee.dcloudAppid===t)||e.find(e=>e.isDefaultConfig):e}_parseConfigContent(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getConfigContent(){if(this.pluginConfig&&this.pluginConfig.hasFile("config.json")){let e;try{e=this.pluginConfig.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseConfigContent(e)}{let e;try{e=require("./config.json")}catch(e){if("MODULE_NOT_FOUND"===e.code||"ENOENT"===e.code)throw new Error("uni-id config file[uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json] not found");throw e}return this._parseConfigContent(e)}}init(){throw new Error("uniID.init has been deprecated, use uniID.createInstance instead")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_getConfig({appid:e,platform:t}={}){const r=`${e=e||this.context.APPID}_${t=t||this.context.PLATFORM}`;if(this._configCache[r])return this._configCache[r];if(!(this.config&&0!==Object.keys(this.config).length))throw new Error(this.t("config-file-not-found"));const n=this._getAppConfig(this.config,e);"app"!==t&&"app-plus"!==t||(t=n.preferedAppPlatform||t),"web"!==t&&"h5"!==t||(t=n.preferedWebPlatform||t);const i=Object.assign(n,n[t])||{},o=Object.assign({bindTokenToDevice:!1,tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600,usernameToLowerCase:!0,emailToLowerCase:!0},i);return["passwordSecret","tokenSecret","tokenExpiresIn","passwordErrorLimit","passwordErrorRetryTime"].forEach(e=>{if(!o||!o[e])throw new Error(this.t("config-param-required",{param:e}))}),this._configCache[r]=o,o}}for(const e in un)pn.prototype[e]=un[e];function ln(e){const t=new pn(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(r=e[t],function(){const e=r.apply(this,arguments);return f(e)?e.then(e=>(S.bind(this)(e),e)):(S.bind(this)(e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var r}})}pn.prototype.createInstance=ln;var fn=ln();module.exports=fn; diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json new file mode 100644 index 0000000..8b89de7 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json @@ -0,0 +1,20 @@ +{ + "name": "uni-id", + "version": "3.3.32", + "description": "uni-id for uniCloud", + "main": "index.js", + "homepage": "https:\/\/uniapp.dcloud.io\/uniCloud\/uni-id", + "repository": { + "type": "git", + "url": "git+https:\/\/gitee.com\/dcloud\/uni-id.git" + }, + "author": "", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center" + }, + "origin-plugin-dev-name": "uni-id", + "origin-plugin-version": "3.3.33", + "plugin-dev-name": "hello-uniapp", + "plugin-version": "3.4.9" +} \ No newline at end of file diff --git a/uni_modules/uni-indexed-list/changelog.md b/uni_modules/uni-indexed-list/changelog.md new file mode 100644 index 0000000..2c86d5d --- /dev/null +++ b/uni_modules/uni-indexed-list/changelog.md @@ -0,0 +1,17 @@ +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 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-indexed-list](https://uniapp.dcloud.io/component/uniui/uni-indexed-list) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.11(2021-05-12) +- 新增 组件示例地址 +## 1.0.10(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.8(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 PC 端 diff --git a/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue new file mode 100644 index 0000000..56f6611 --- /dev/null +++ b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list-item.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue new file mode 100644 index 0000000..fab85a7 --- /dev/null +++ b/uni_modules/uni-indexed-list/components/uni-indexed-list/uni-indexed-list.vue @@ -0,0 +1,367 @@ + + + diff --git a/uni_modules/uni-indexed-list/package.json b/uni_modules/uni-indexed-list/package.json new file mode 100644 index 0000000..a000b6d --- /dev/null +++ b/uni_modules/uni-indexed-list/package.json @@ -0,0 +1,89 @@ +{ + "id": "uni-indexed-list", + "displayName": "uni-indexed-list 索引列表", + "version": "1.2.1", + "description": "索引列表组件,右侧带索引的列表,方便快速定位到具体内容,通常用于城市/机场选择等场景", + "keywords": [ + "uni-ui", + "索引列表", + "索引", + "列表" +], + "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-scss", + "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" + } + } + } + } +} diff --git a/uni_modules/uni-indexed-list/readme.md b/uni_modules/uni-indexed-list/readme.md new file mode 100644 index 0000000..9597cdc --- /dev/null +++ b/uni_modules/uni-indexed-list/readme.md @@ -0,0 +1,11 @@ + + +## IndexedList 索引列表 +> **组件名:uni-indexed-list** +> 代码块: `uIndexedList` + + +用于展示索引列表。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-indexed-list) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-installApk/changelog.md b/uni_modules/uni-installApk/changelog.md new file mode 100644 index 0000000..6ccb23d --- /dev/null +++ b/uni_modules/uni-installApk/changelog.md @@ -0,0 +1,10 @@ +## 1.0.4(2023-12-08) +兼容asset目录文件的处理 +## 1.0.3(2023-10-27) +遵循UniError规范 +## 1.0.2(2023-10-27) +修改文档 +## 1.0.1(2023-10-27) +支持js层调用 +## 1.0.0(2023-10-26) +安装apk的插件 diff --git a/uni_modules/uni-installApk/package.json b/uni_modules/uni-installApk/package.json new file mode 100644 index 0000000..2270fe2 --- /dev/null +++ b/uni_modules/uni-installApk/package.json @@ -0,0 +1,93 @@ +{ + "id": "uni-installApk", + "displayName": "uni-installApk", + "version": "1.0.4", + "description": "uni-installApk", + "keywords": [ + "uni-installApk" + ], + "repository": "", + "engines": { + "HBuilderX": "^3.94" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "android.permission.REQUEST_INSTALL_PACKAGES" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "uni-ext-api": { + "uni": { + "installApk": { + "name": "installApk", + "app": { + "js": true, + "kotlin": true, + "swift": false + } + } + } + }, + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-android": "y", + "app-ios": "n" + }, + "H5-mobile": { + "Safari": "n", + "Android Browser": "n", + "微信浏览器(Android)": "n", + "QQ浏览器(Android)": "n" + }, + "H5-pc": { + "Chrome": "n", + "IE": "n", + "Edge": "n", + "Firefox": "n", + "Safari": "n" + }, + "小程序": { + "微信": "n", + "阿里": "n", + "百度": "n", + "字节跳动": "n", + "QQ": "n", + "钉钉": "n", + "快手": "n", + "飞书": "n", + "京东": "n" + }, + "快应用": { + "华为": "n", + "联盟": "n" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-installApk/readme.md b/uni_modules/uni-installApk/readme.md new file mode 100644 index 0000000..3293125 --- /dev/null +++ b/uni_modules/uni-installApk/readme.md @@ -0,0 +1,37 @@ +# uni-installApk + +## 使用说明 + +Android平台安装Apk + +**注意: 3.95以下需要自定义基座** + +### uni.installApk(options : InstallApkOptions):void + +安装apk + +参数说明 + +``` +type InstallApkOptions = { + /** + * apk文件地址 + */ + filePath : string, + /** + * 接口调用成功的回调函数 + * @defaultValue null + */ + success ?: (res : any) => void, + /** + * 接口调用失败的回调函数 + * @defaultValue null + */ + fail ?: (err : any) => void, + /** + * 接口调用结束的回调函数(调用成功、失败都会执行) + * @defaultValue null + */ + complete ?: (res : any) => void, +} +``` \ No newline at end of file diff --git a/uni_modules/uni-installApk/utssdk/app-android/AndroidManifest.xml b/uni_modules/uni-installApk/utssdk/app-android/AndroidManifest.xml new file mode 100644 index 0000000..5cf3ce2 --- /dev/null +++ b/uni_modules/uni-installApk/utssdk/app-android/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/uni_modules/uni-installApk/utssdk/app-android/index.uts b/uni_modules/uni-installApk/utssdk/app-android/index.uts new file mode 100644 index 0000000..64e7b6b --- /dev/null +++ b/uni_modules/uni-installApk/utssdk/app-android/index.uts @@ -0,0 +1,83 @@ +import { InstallApkOptions, InstallApkSuccess } from "../interface.uts" +import { InstallApkFailImpl } from "../unierror.uts" +import Intent from 'android.content.Intent'; +import Build from 'android.os.Build'; +import File from 'java.io.File'; +import FileProvider from 'androidx.core.content.FileProvider'; +import Context from 'android.content.Context'; +import Uri from 'android.net.Uri'; +import FileOutputStream from 'java.io.FileOutputStream'; + +export function installApk(options : InstallApkOptions) : void { + const context = UTSAndroid.getAppContext() as Context + var filePath = UTSAndroid.convert2AbsFullPath(options.filePath) + var apkFile : File | null = null; + if (filePath.startsWith("/android_asset/")) { + filePath = filePath.replace("/android_asset/", "") + apkFile = copyAssetFileToPrivateDir(context, filePath) + } else { + apkFile = new File(filePath) + } + + if (apkFile != null && !apkFile.exists() && !apkFile.isFile()) { + let error = new InstallApkFailImpl(1300002); + options.fail?.(error) + options.complete?.(error) + return + } + const intent = new Intent() + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.setAction(Intent.ACTION_VIEW) + + if (Build.VERSION.SDK_INT >= 24) { + const authority = context.getPackageName() + ".dc.fileprovider" + const apkUri = FileProvider.getUriForFile(context, authority, apkFile!!) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); + } else { + intent.setDataAndType(Uri.fromFile(apkFile!!), "application/vnd.android.package-archive"); + } + + context.startActivity(intent) + const success : InstallApkSuccess = { + errMsg: "success" + } + options.success?.(success) + options.complete?.(success) +} + + +function copyAssetFileToPrivateDir(context : Context, fileName : string) : File | null { + try { + const destPath = context.getCacheDir().getPath() + "/apks/" + fileName + const outFile = new File(destPath) + const parentFile = outFile.getParentFile() + if (parentFile != null) { + if (!parentFile.exists()) { + parentFile.mkdirs() + } + } + if (!outFile.exists()) { + outFile.createNewFile() + } + const inputStream = context.getAssets().open(fileName) + const outputStream = new FileOutputStream(outFile) + let buffer = new ByteArray(1024); + do { + let len = inputStream.read(buffer); + if (len == -1) { + break; + } + outputStream.write(buffer, 0, len) + } while (true) + + inputStream.close() + outputStream.close() + + return outFile + } catch (e : Exception) { + e.printStackTrace() + } + + return null +} diff --git a/uni_modules/uni-installApk/utssdk/index.d.ts b/uni_modules/uni-installApk/utssdk/index.d.ts new file mode 100644 index 0000000..ad24eff --- /dev/null +++ b/uni_modules/uni-installApk/utssdk/index.d.ts @@ -0,0 +1,78 @@ +declare namespace UniNamespace { + +interface InstallApkSuccess { + /** + * 安装成功消息 + */ + errMsg : string +} + +type InstallApkErrorCode = 1300002 +interface InstallApkFail { + errCode : InstallApkErrorCode +} + +type InstallApkComplete = any + +type InstallApkSuccessCallback = (res : InstallApkSuccess) => void +type InstallApkFailCallback = (err : InstallApkFail) => void +type InstallApkCompleteCallback = (res : InstallApkComplete) => void + +interface InstallApkOptions { + /** + * apk文件地址 + */ + filePath : string, + /** + * 接口调用成功的回调函数 + * @defaultValue null + */ + success ?: InstallApkSuccessCallback | null, + /** + * 接口调用失败的回调函数 + * @defaultValue null + */ + fail ?: InstallApkFailCallback | null, + /** + * 接口调用结束的回调函数(调用成功、失败都会执行) + * @defaultValue null + */ + complete ?: InstallApkCompleteCallback | null +} + +} + + +declare interface Uni { + /** + * installApk() + * @description + * 安装apk + * @param {InstallApkOptions} + * @return {void} + * @uniPlatform { + * "app": { + * "android": { + * "osVer": "4.4", + * "uniVer": "3.94+", + * "unixVer": "3.94+" + * }, + * "ios": { + * "osVer": "x", + * "uniVer": "x", + * "unixVer": "x" + * } + * } + * } + * @example + ```typescript + uni.installApk({ + filePath: "/xx/xx/xx.apk", + complete: (res: any) => { + console.log("complete => " + JSON.stringify(res)); + } + }); + ``` + */ + installApk(options : UniNamespace.InstallApkOptions) : void +} diff --git a/uni_modules/uni-installApk/utssdk/interface.uts b/uni_modules/uni-installApk/utssdk/interface.uts new file mode 100644 index 0000000..35edfcd --- /dev/null +++ b/uni_modules/uni-installApk/utssdk/interface.uts @@ -0,0 +1,76 @@ +export interface Uni { + /** + * installApk() + * @description + * 安装apk + * @param {InstallApkOptions} + * @return {void} + * @uniPlatform { + * "app": { + * "android": { + * "osVer": "4.4", + * "uniVer": "3.94+", + * "unixVer": "3.94+" + * }, + * "ios": { + * "osVer": "x", + * "uniVer": "x", + * "unixVer": "x" + * } + * } + * } + * @example + ```typescript + uni.installApk({ + filePath: "/xx/xx/xx.apk", + complete: (res: any) => { + console.log("complete => " + JSON.stringify(res)); + } + }); + ``` + */ + installApk(options : InstallApkOptions) : void +} +export type InstallApkSuccess = { + /** + * 安装成功消息 + */ + errMsg : string +} +export type InstallApkComplete = any +export type InstallApkSuccessCallback = (res : InstallApkSuccess) => void +/** + * 错误码 + * - 1300002 找不到文件 + */ +export type InstallApkErrorCode = 1300002 +/** + * 网络请求失败的错误回调参数 + */ +export interface InstallApkFail extends IUniError { + errCode : InstallApkErrorCode +}; +export type InstallApkFailCallback = (err : InstallApkFail) => void +export type InstallApkCompleteCallback = (res : InstallApkComplete) => void + +export type InstallApkOptions = { + /** + * apk文件地址 + */ + filePath : string, + /** + * 接口调用成功的回调函数 + * @defaultValue null + */ + success ?: InstallApkSuccessCallback | null, + /** + * 接口调用失败的回调函数 + * @defaultValue null + */ + fail ?: InstallApkFailCallback | null, + /** + * 接口调用结束的回调函数(调用成功、失败都会执行) + * @defaultValue null + */ + complete ?: InstallApkCompleteCallback | null +} \ No newline at end of file diff --git a/uni_modules/uni-installApk/utssdk/unierror.uts b/uni_modules/uni-installApk/utssdk/unierror.uts new file mode 100644 index 0000000..a10c730 --- /dev/null +++ b/uni_modules/uni-installApk/utssdk/unierror.uts @@ -0,0 +1,25 @@ +import { InstallApkErrorCode, InstallApkFail } from "./interface.uts" + +/** + * 错误主题 + */ +export const UniErrorSubject = 'uni-installApk'; +/** + * 错误码 + * @UniError + */ +export const UniErrors : Map = new Map([ + /** + * 找不到文件 + */ + [1300002, 'No such file'], +]); + +export class InstallApkFailImpl extends UniError implements InstallApkFail { + constructor(errCode : InstallApkErrorCode) { + super(); + this.errSubject = UniErrorSubject; + this.errCode = errCode; + this.errMsg = UniErrors[errCode] ?? ""; + } +} \ No newline at end of file diff --git a/uni_modules/uni-link/changelog.md b/uni_modules/uni-link/changelog.md new file mode 100644 index 0000000..7f43317 --- /dev/null +++ b/uni_modules/uni-link/changelog.md @@ -0,0 +1,17 @@ +## 1.0.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-link](https://uniapp.dcloud.io/component/uniui/uni-link) +## 1.1.7(2021-11-08) +## 0.0.7(2021-09-03) +- 修复 在 nvue 下不显示的 bug +## 0.0.6(2021-07-30) +- 新增 支持自定义插槽 +## 0.0.5(2021-06-21) +- 新增 download 属性,H5平台下载文件名 +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-03-09) +- 新增 href 属性支持 tel:|mailto: + +## 0.0.2(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-link/components/uni-link/uni-link.vue b/uni_modules/uni-link/components/uni-link/uni-link.vue new file mode 100644 index 0000000..8d72003 --- /dev/null +++ b/uni_modules/uni-link/components/uni-link/uni-link.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/uni_modules/uni-link/package.json b/uni_modules/uni-link/package.json new file mode 100644 index 0000000..3e99471 --- /dev/null +++ b/uni_modules/uni-link/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-link", + "displayName": "uni-link 超链接", + "version": "1.0.0", + "description": "uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打", + "keywords": [ + "uni-ui", + "uniui", + "link", + "超链接", + "" +], + "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-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-link/readme.md b/uni_modules/uni-link/readme.md new file mode 100644 index 0000000..d40fdca --- /dev/null +++ b/uni_modules/uni-link/readme.md @@ -0,0 +1,11 @@ + + +## Link 链接 +> **组件名:uni-link** +> 代码块: `uLink` + + +uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打开新网页。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-link) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-list/changelog.md b/uni_modules/uni-list/changelog.md new file mode 100644 index 0000000..271a6bd --- /dev/null +++ b/uni_modules/uni-list/changelog.md @@ -0,0 +1,48 @@ +## 1.2.15(2025-01-08) +- 修复 示例中过期图片地址 +## 1.2.14(2023-04-14) +- 优化 uni-list-chat 具名插槽`header` 非app端套一层元素,方便使用时通过外层元素定位实现样式修改 +## 1.2.13(2023-03-03) +- uni-list-chat 新增 支持具名插槽`header` +## 1.2.12(2023-02-01) +- 新增 列表图标新增 customPrefix 属性 ,用法 [详见](https://uniapp.dcloud.net.cn/component/uniui/uni-icons.html#icons-props) +## 1.2.11(2023-01-31) +- 修复 无反馈效果呈现的bug +## 1.2.9(2022-11-22) +- 修复 uni-list-chat 在vue3下跳转报错的bug +## 1.2.8(2022-11-21) +- 修复 uni-list-chat avatar属性 值为本地路径时错误的问题 +## 1.2.7(2022-11-21) +- 修复 uni-list-chat avatar属性 在腾讯云版uniCloud下错误的问题 +## 1.2.6(2022-11-18) +- 修复 uni-list-chat note属性 支持:“草稿”字样功能 文本少1位的问题 +## 1.2.5(2022-11-15) +- 修复 uni-list-item 的 customStyle 属性 padding值在 H5端 无效的bug +## 1.2.4(2022-11-15) +- 修复 uni-list-item 的 customStyle 属性 padding值在nvue(vue2)下无效的bug +## 1.2.3(2022-11-14) +- uni-list-chat 新增 avatar 支持 fileId +## 1.2.2(2022-11-11) +- uni-list 新增属性 render-reverse 详情参考:[https://uniapp.dcloud.net.cn/component/list.html](https://uniapp.dcloud.net.cn/component/list.html) +- uni-list-chat note属性 支持:“草稿”字样 加红显示 详情参考uni-im:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im) +- uni-list-item 新增属性 customStyle 支持设置padding、backgroundColor +## 1.2.1(2022-03-30) +- 删除无用文件 +## 1.2.0(2021-11-23) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-list](https://uniapp.dcloud.io/component/uniui/uni-list) +## 1.1.3(2021-08-30) +- 修复 在vue3中to属性在发行应用的时候报错的bug +## 1.1.2(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.1.1(2021-07-21) +- 修复 与其他组件嵌套使用时,点击失效的Bug +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.17(2021-05-12) +- 新增 组件示例地址 +## 1.0.16(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.0.15(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 uni-list-chat 角标显示不正常的问题 diff --git a/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue b/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue new file mode 100644 index 0000000..d145b54 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss new file mode 100644 index 0000000..7e2708f --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss @@ -0,0 +1,58 @@ +/** + * 这里是 uni-list 组件内置的常用样式变量 + * 如果需要覆盖样式,这里提供了基本的组件样式变量,您可以尝试修改这里的变量,去完成样式替换,而不用去修改源码 + * + */ + +// 背景色 +$background-color : #fff; +// 分割线颜色 +$divide-line-color : #e5e5e5; + +// 默认头像大小,如需要修改此值,注意同步修改 js 中的值 const avatarWidth = xx ,目前只支持方形头像 +// nvue 页面不支持修改头像大小 +$avatar-width : 45px ; + +// 头像边框 +$avatar-border-radius: 5px; +$avatar-border-color: #eee; +$avatar-border-width: 1px; + +// 标题文字样式 +$title-size : 16px; +$title-color : #3b4144; +$title-weight : normal; + +// 描述文字样式 +$note-size : 12px; +$note-color : #999; +$note-weight : normal; + +// 右侧额外内容默认样式 +$right-text-size : 12px; +$right-text-color : #999; +$right-text-weight : normal; + +// 角标样式 +// nvue 页面不支持修改圆点位置以及大小 +// 角标在左侧时,角标的位置,默认为 0 ,负数左/下移动,正数右/上移动 +$badge-left: 0px; +$badge-top: 0px; + +// 显示圆点时,圆点大小 +$dot-width: 10px; +$dot-height: 10px; + +// 显示角标时,角标大小和字体大小 +$badge-size : 18px; +$badge-font : 12px; +// 显示角标时,角标前景色 +$badge-color : #fff; +// 显示角标时,角标背景色 +$badge-background-color : #ff5a5f; +// 显示角标时,角标左右间距 +$badge-space : 6px; + +// 状态样式 +// 选中颜色 +$hover : #f5f5f5; 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 new file mode 100644 index 0000000..27d05dd --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue @@ -0,0 +1,593 @@ + + + + + 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 new file mode 100644 index 0000000..2322373 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue @@ -0,0 +1,534 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-list/components/uni-list/uni-list - 副本.vue b/uni_modules/uni-list/components/uni-list/uni-list - 副本.vue new file mode 100644 index 0000000..8a46cfc --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-list - 副本.vue @@ -0,0 +1,106 @@ + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-list.vue b/uni_modules/uni-list/components/uni-list/uni-list.vue new file mode 100644 index 0000000..38470db --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-list.vue @@ -0,0 +1,123 @@ + + + + diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.vue b/uni_modules/uni-list/components/uni-list/uni-refresh.vue new file mode 100644 index 0000000..2c64158 --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-refresh.vue @@ -0,0 +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 new file mode 100644 index 0000000..9ef364e --- /dev/null +++ b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs @@ -0,0 +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 +} diff --git a/uni_modules/uni-list/package.json b/uni_modules/uni-list/package.json new file mode 100644 index 0000000..4a0242e --- /dev/null +++ b/uni_modules/uni-list/package.json @@ -0,0 +1,91 @@ +{ + "id": "uni-list", + "displayName": "uni-list 列表", + "version": "1.2.15", + "description": "List 组件 ,帮助使用者快速构建列表。", + "keywords": [ + "", + "uni-ui", + "uniui", + "列表", + "", + "list" +], + "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-badge", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-harmony": "u", + "app-uvue": "u" + }, + "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 new file mode 100644 index 0000000..8f598b3 --- /dev/null +++ b/uni_modules/uni-list/readme.md @@ -0,0 +1,46 @@ +## 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) + +### [点击查看详细文档](https://uniapp.dcloud.io/component/uniui/uni-indexed-list) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + +## 基于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) \ No newline at end of file diff --git a/uni_modules/uni-load-more/changelog.md b/uni_modules/uni-load-more/changelog.md new file mode 100644 index 0000000..569e289 --- /dev/null +++ b/uni_modules/uni-load-more/changelog.md @@ -0,0 +1,25 @@ +## 1.3.6(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.5(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.4(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.3(2022-01-20) +- 新增 showText属性 ,是否显示文本 +## 1.3.2(2022-01-19) +- 修复 nvue 平台下不显示文本的bug +## 1.3.1(2022-01-19) +- 修复 微信小程序平台样式选择器报警告的问题 +## 1.3.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-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more) +## 1.2.1(2021-08-24) +- 新增 支持国际化 +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.8(2021-05-12) +- 新增 组件示例地址 +## 1.1.7(2021-03-30) +- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug +## 1.1.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json new file mode 100644 index 0000000..6f45b0e --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "Pull up to show more", + "uni-load-more.contentrefresh": "loading...", + "uni-load-more.contentnomore": "No more data" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js b/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js new file mode 100644 index 0000000..fa8f0f3 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json new file mode 100644 index 0000000..3a14ca0 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉显示更多", + "uni-load-more.contentrefresh": "正在加载...", + "uni-load-more.contentnomore": "没有更多数据了" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json new file mode 100644 index 0000000..ee99b06 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉顯示更多", + "uni-load-more.contentrefresh": "正在加載...", + "uni-load-more.contentnomore": "沒有更多數據了" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue new file mode 100644 index 0000000..e4cfa7b --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,407 @@ + + + + + diff --git a/uni_modules/uni-load-more/package.json b/uni_modules/uni-load-more/package.json new file mode 100644 index 0000000..34c9dff --- /dev/null +++ b/uni_modules/uni-load-more/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-load-more", + "displayName": "uni-load-more 加载更多", + "version": "1.3.6", + "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。", + "keywords": [ + "uni-ui", + "uniui", + "加载更多", + "load-more" +], + "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", + "alipay": "n" + }, + "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" + } + } + } + } +} diff --git a/uni_modules/uni-load-more/readme.md b/uni_modules/uni-load-more/readme.md new file mode 100644 index 0000000..1925a57 --- /dev/null +++ b/uni_modules/uni-load-more/readme.md @@ -0,0 +1,14 @@ + + +### LoadMore 加载更多 +> **组件名:uni-load-more** +> 代码块: `uLoadMore` + + +用于列表中,做滚动加载使用,展示 loading 的各种状态。 + + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-nav-bar/changelog.md b/uni_modules/uni-nav-bar/changelog.md new file mode 100644 index 0000000..f7df340 --- /dev/null +++ b/uni_modules/uni-nav-bar/changelog.md @@ -0,0 +1,57 @@ +## 1.3.14(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.13(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.12(2024-10-12) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.11(2023-03-29) +- 修复 自定义状态栏高度闪动BUG +## 1.3.10(2023-03-29) +- 修复 暗黑模式下边线颜色错误的bug +## 1.3.9(2022-10-13) +- 修复 条件编译错误的bug +## 1.3.8(2022-10-12) +- 修复 nvue 环境 fixed 为 true 的情况下,无法置顶的 bug +## 1.3.7(2022-08-11) +- 修复 nvue 环境下 fixed 为 true 的情况下,无法置顶的 bug +## 1.3.6(2022-06-30) +- 修复 组件示例中插槽用法无法显示内容的bug +## 1.3.5(2022-05-24) +- 新增 stat 属性 ,可开启统计title 上报 ,仅使用了title 属性且项目开启了uni统计生效 +## 1.3.4(2022-01-24) +- 更新 组件示例 +## 1.3.3(2022-01-24) +- 新增 left-width/right-width属性 ,可修改左右两侧的宽度 +## 1.3.2(2022-01-18) +- 修复 在vue下,标题不垂直居中的bug +## 1.3.1(2022-01-18) +- 修复 height 属性类型错误 +## 1.3.0(2022-01-18) +- 新增 height 属性,可修改组件高度 +- 新增 dark 属性可可开启暗黑模式 +- 优化 标题字数过多显示省略号 +- 优化 插槽,插入内容可完全覆盖 +## 1.2.1(2022-01-10) +- 修复 color 属性不生效的bug +## 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-nav-bar](https://uniapp.dcloud.io/component/uniui/uni-nav-bar) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.11(2021-05-12) +- 新增 组件示例地址 +## 1.0.10(2021-04-30) +- 修复 在nvue下fixed为true,宽度不能撑满的Bug +## 1.0.9(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.8(2021-04-14) +- uni-ui 修复 uni-nav-bar 当 fixed 属性为 true 时铺不满屏幕的 bug + +## 1.0.7(2021-02-25) +- 修复 easycom 下,找不到 uni-status-bar 的bug + +## 1.0.6(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue new file mode 100644 index 0000000..ef257f2 --- /dev/null +++ b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue @@ -0,0 +1,357 @@ + + + + + diff --git a/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue new file mode 100644 index 0000000..92aa589 --- /dev/null +++ b/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/uni_modules/uni-nav-bar/package.json b/uni_modules/uni-nav-bar/package.json new file mode 100644 index 0000000..bbe1ccc --- /dev/null +++ b/uni_modules/uni-nav-bar/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-nav-bar", + "displayName": "uni-nav-bar 自定义导航栏", + "version": "1.3.14", + "description": "自定义导航栏组件,主要用于头部导航。", + "keywords": [ + "uni-ui", + "导航", + "导航栏", + "自定义导航栏" +], + "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", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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" + } + } + } + } +} diff --git a/uni_modules/uni-nav-bar/readme.md b/uni_modules/uni-nav-bar/readme.md new file mode 100644 index 0000000..47db1d0 --- /dev/null +++ b/uni_modules/uni-nav-bar/readme.md @@ -0,0 +1,15 @@ + + +## NavBar 导航栏 +> **组件名:uni-nav-bar** +> 代码块: `uNavBar` + +导航栏组件,主要用于头部导航。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-nav-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + + diff --git a/uni_modules/uni-notice-bar/changelog.md b/uni_modules/uni-notice-bar/changelog.md new file mode 100644 index 0000000..a115ea6 --- /dev/null +++ b/uni_modules/uni-notice-bar/changelog.md @@ -0,0 +1,20 @@ +## 1.2.2(2023-12-20) +- 修复动态绑定title时,滚动速度不一致的问题 +## 1.2.1(2022-09-05) +- 新增 属性 fontSize,可修改文字大小。 +## 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-notice-bar](https://uniapp.dcloud.io/component/uniui/uni-notice-bar) +## 1.1.1(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.9(2021-05-12) +- 新增 组件示例地址 +## 1.0.8(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.7(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue b/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue new file mode 100644 index 0000000..e7d0397 --- /dev/null +++ b/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue @@ -0,0 +1,431 @@ + + + + + diff --git a/uni_modules/uni-notice-bar/package.json b/uni_modules/uni-notice-bar/package.json new file mode 100644 index 0000000..996814b --- /dev/null +++ b/uni_modules/uni-notice-bar/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-notice-bar", + "displayName": "uni-notice-bar 通告栏", + "version": "1.2.2", + "description": "NoticeBar 通告栏组件,常用于展示公告信息,可设为滚动公告", + "keywords": [ + "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", + "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" + } + } + } + } +} diff --git a/uni_modules/uni-notice-bar/readme.md b/uni_modules/uni-notice-bar/readme.md new file mode 100644 index 0000000..22d230d --- /dev/null +++ b/uni_modules/uni-notice-bar/readme.md @@ -0,0 +1,13 @@ + + +## NoticeBar 通告栏 +> **组件名:uni-notice-bar** +> 代码块: `uNoticeBar` + + +通告栏组件 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-notice-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-number-box/changelog.md b/uni_modules/uni-number-box/changelog.md new file mode 100644 index 0000000..799fab8 --- /dev/null +++ b/uni_modules/uni-number-box/changelog.md @@ -0,0 +1,39 @@ +## 1.2.8(2024-04-26) +- 修复 在vue2下H5黑边的bug +## 1.2.7(2024-04-26) +- 修复 在vue2手动输入后失焦导致清空数值的严重bug +## 1.2.6(2024-02-22) +- 新增 设置宽度属性width(单位:px) +## 1.2.5(2024-02-21) +- 修复 step步长小于1时,键盘类型为number的bug +## 1.2.4(2024-02-02) +- 修复 加减号垂直位置偏移样式问题 +## 1.2.3(2023-05-23) +- 更新示例工程 +## 1.2.2(2023-05-08) +- 修复 change 事件执行顺序错误的问题 +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 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-number-box](https://uniapp.dcloud.io/component/uniui/uni-number-box) +## 1.1.2(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.1.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-04-20) +- 修复 uni-number-box 浮点数运算不精确的 bug +- 修复 uni-number-box change 事件触发不正确的 bug +- 新增 uni-number-box v-model 双向绑定 +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 + +## 1.0.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 v-model +- 新增 支持 focus、blur 事件 +- 新增 支持 PC 端 diff --git a/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue b/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue new file mode 100644 index 0000000..dd46e26 --- /dev/null +++ b/uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue @@ -0,0 +1,232 @@ + + + diff --git a/uni_modules/uni-number-box/package.json b/uni_modules/uni-number-box/package.json new file mode 100644 index 0000000..fb04e2f --- /dev/null +++ b/uni_modules/uni-number-box/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-number-box", + "displayName": "uni-number-box 数字输入框", + "version": "1.2.8", + "description": "NumberBox 带加减按钮的数字输入框组件,用户可以控制每次点击增加的数值,支持小数。", + "keywords": [ + "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", + "alipay": "n" + }, + "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-number-box/readme.md b/uni_modules/uni-number-box/readme.md new file mode 100644 index 0000000..9b5d60a --- /dev/null +++ b/uni_modules/uni-number-box/readme.md @@ -0,0 +1,13 @@ + + +## NumberBox 数字输入框 +> **组件名:uni-number-box** +> 代码块: `uNumberBox` + + +带加减按钮的数字输入框。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-number-box) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-open-bridge-common/changelog.md b/uni_modules/uni-open-bridge-common/changelog.md new file mode 100644 index 0000000..cebc6eb --- /dev/null +++ b/uni_modules/uni-open-bridge-common/changelog.md @@ -0,0 +1,27 @@ +## 1.2.1(2024-09-13) +- 修复 微信小程序平台 当微信的服务器返回`encrypt_key`的过期时间`expire_in`为`0`时特殊处理为`1`天,否者可能无法验证客户端请求携带的版本 +## 1.2.0(2023-04-27) +- 重要 微信小程序平台 使用微信新增 API getStableAccessToken 获取 access_token, access_token 有效期内重复调用该接口不会更新 access_token, [详情](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getStableAccessToken.html) +## 1.1.5(2023-03-27) +- 修复 微信小程序平台 某些情况下 encrypt_key 插入错误的问题 +## 1.1.4(2023-03-13) +- 修复 平台 weixin-web +## 1.1.3(2023-03-13) +- 新增 支持旧版本 uni-id 配置 +- 新增 支持平台 weixin-app|qq-mp|qq-app +## 1.1.2(2023-02-28) +- 新增 config 配置错误提示语 +## 1.1.1(2023-02-28) +- 新增 支持 provider 参数,和 platform 保持一致 +## 1.1.0(2023-02-27) +- 重要更新 调整数据库key格式,兼容旧版本API,如果开发者通过手动拼接key查询数据库需要修改现有逻辑 + + 原格式: uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket] + + 新格式: uni-id:[provider]:[appid]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket] +## 1.0.4(2022-09-21) +- 新增 支持使用阿里云固定IP获取微信公众号H5凭据 access_token、ticket,开发者需要在微信公众平台配置阿里云固定IP,[固定IP详情](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) +## 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 new file mode 100644 index 0000000..be0b32a --- /dev/null +++ b/uni_modules/uni-open-bridge-common/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-open-bridge-common", + "displayName": "uni-open-bridge-common", + "version": "1.2.1", + "description": "统一接管微信等三方平台认证凭据", + "keywords": [ + "access_token", + "session_key", + "ticket" +], + "repository": "", + "engines": { + "HBuilderX": "^3.5.2" + }, + "dcloudext": { + "type": "unicloud-template-function", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-open-bridge-common/readme.md b/uni_modules/uni-open-bridge-common/readme.md new file mode 100644 index 0000000..de28c36 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/readme.md @@ -0,0 +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) 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 new file mode 100644 index 0000000..63fe093 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js @@ -0,0 +1,26 @@ +'use strict'; + +class BridgeError extends Error { + + constructor(code, message) { + super(message) + + this._code = code + } + + get code() { + return this._code + } + + get errCode() { + return this._code + } + + get errMsg() { + return this.message + } +} + +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 new file mode 100644 index 0000000..063c746 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js @@ -0,0 +1,124 @@ +'use strict'; + +const { + ProviderType +} = require('./consts.js') + +const configCenter = require('uni-config-center') + +// 多维数据为兼容uni-id以前版本配置 +const OauthConfig = { + 'weixin-app': [ + ['app', 'oauth', 'weixin'], + ['app-plus', 'oauth', 'weixin'] + ], + 'weixin-mp': [ + ['mp-weixin', 'oauth', 'weixin'] + ], + 'weixin-h5': [ + ['web', 'oauth', 'weixin-h5'], + ['h5-weixin', 'oauth', 'weixin'], + ['h5', 'oauth', 'weixin'] + ], + 'weixin-web': [ + ['web', 'oauth', 'weixin-web'] + ], + 'qq-app': [ + ['app', 'oauth', 'qq'], + ['app-plus', 'oauth', 'qq'] + ], + 'qq-mp': [ + ['mp-qq', 'oauth', 'qq'] + ] +} + +const Support_Platforms = [ + ProviderType.WEIXIN_MP, + ProviderType.WEIXIN_H5, + ProviderType.WEIXIN_APP, + ProviderType.WEIXIN_WEB, + ProviderType.QQ_MP, + ProviderType.QQ_APP +] + +class ConfigBase { + + constructor() { + const uniIdConfigCenter = configCenter({ + pluginId: 'uni-id' + }) + + this._uniIdConfig = uniIdConfigCenter.config() + } + + getAppConfig(appid) { + if (Array.isArray(this._uniIdConfig)) { + return this._uniIdConfig.find((item) => { + return (item.dcloudAppid === appid) + }) + } + return this._uniIdConfig + } +} + +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 (Support_Platforms.indexOf(platformName) >= 0) + } + + getOauthConfig(appConfig, platformName) { + let treePath = OauthConfig[platformName] + let node = this.findNode(appConfig, treePath) + if (node && node.appid && node.appsecret) { + return { + appid: node.appid, + secret: node.appsecret + } + } + return null + } + + findNode(treeNode, arrayPath) { + let node = treeNode + for (let treePath of arrayPath) { + for (let name of treePath) { + const currentNode = node[name] + if (currentNode) { + node = currentNode + } else { + node = null + break + } + } + if (node === null) { + node = treeNode + } else { + break + } + } + return node + } +} + + +module.exports = { + AppConfig +}; \ No newline at end of file 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 new file mode 100644 index 0000000..7f89917 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js @@ -0,0 +1,30 @@ +'use strict'; + +const TAG = "UNI_OPEN_BRIDGE" + +const HTTP_STATUS = { + SUCCESS: 200 +} + +const ProviderType = { + WEIXIN_MP: 'weixin-mp', + WEIXIN_H5: 'weixin-h5', + WEIXIN_APP: 'weixin-app', + WEIXIN_WEB: 'weixin-web', + QQ_MP: 'qq-mp', + QQ_APP: 'qq-app' +} + +// old +const PlatformType = ProviderType + +const ErrorCodeType = { + SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" +} + +module.exports = { + HTTP_STATUS, + ProviderType, + 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 new file mode 100644 index 0000000..fb4bfd9 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js @@ -0,0 +1,317 @@ +'use strict'; + +const { + PlatformType, + ProviderType, + ErrorCodeType +} = require('./consts.js') + +const { + AppConfig +} = require('./config.js') + +const { + Storage +} = 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', ['provider', 'appid']) + } + + async update(key) { + super.update(key) + + const result = await this.getByWeixinServer(key) + + return this.set(key, result.value, result.duration) + } + + async fallback(key) { + return this.getByWeixinServer(key) + } + + async getByWeixinServer(key) { + const oauthConfig = appConfig.get(key.dcloudAppid, key.provider) + let methodName + if (key.provider === ProviderType.WEIXIN_MP) { + methodName = 'GetMPAccessTokenData' + } else if (key.provider === ProviderType.WEIXIN_H5) { + methodName = 'GetH5AccessTokenData' + } else { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "provider 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', ['provider', 'appid', 'openid']) + } +} + +class SessionKey extends Storage { + + constructor() { + super('session-key', ['provider', 'appid', 'openid']) + } +} + +class Encryptkey extends Storage { + + constructor() { + super('encrypt-key', ['provider', 'appid', 'openid']) + } + + async update(key) { + super.update(key) + + const result = await this.getByWeixinServer(key) + + return this.set(key, result.value, result.duration) + } + + getKeyString(key) { + return `${super.getKeyString(key)}-${key.version}` + } + + getExpiresIn(value) { + if (value <= 0) { + return 60 + } + return value + } + + async fallback(key) { + return this.getByWeixinServer(key) + } + + async getByWeixinServer(key) { + const accessToken = await Factory.Get(AccessToken, key) + const userSession = await Factory.Get(SessionKey, key) + + const responseData = await WeixinServer.GetUserEncryptKeyData({ + openid: key.openid, + access_token: accessToken.access_token, + session_key: userSession.session_key + }) + + const keyInfo = responseData.key_info_list.find((item) => { + return item.version === key.version + }) + + if (!keyInfo) { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, 'key version invalid') + } + + const value = { + encrypt_key: keyInfo.encrypt_key, + iv: keyInfo.iv + } + + return { + value, + duration: keyInfo.expire_in || (24 * 60 * 60) + } + } +} + +class Ticket extends Storage { + + constructor() { + super('ticket', ['provider', 'appid']) + } + + async update(key) { + super.update(key) + + const result = await this.getByWeixinServer(key) + + return this.set(key, result.value, result.duration) + } + + async fallback(key) { + return this.getByWeixinServer(key) + } + + async getByWeixinServer(key) { + const accessToken = await Factory.Get(AccessToken, { + dcloudAppid: key.dcloudAppid, + provider: ProviderType.WEIXIN_H5 + }) + + const responseData = await WeixinServer.GetH5TicketData(accessToken) + + const duration = responseData.expires_in || (60 * 60 * 2) + delete responseData.expires_in + delete responseData.errcode + delete responseData.errmsg + + return { + value: responseData, + duration + } + } +} + + +const Factory = { + + async Get(T, key, fallback) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).get(key, fallback) + }, + + async Set(T, key, value, expiresIn) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).set(key, value, expiresIn) + }, + + async Remove(T, key) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).remove(key) + }, + + async Update(T, key) { + Factory.FixOldKey(key) + return Factory.MakeUnique(T).update(key) + }, + + FixOldKey(key) { + if (!key.provider) { + key.provider = key.platform + } + + const configData = appConfig.get(key.dcloudAppid, key.provider) + if (!configData) { + throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, 'appid or provider invalid') + } + key.appid = configData.appid + }, + + MakeUnique(T) { + return new T() + } +} + + +// exports + +async function getAccessToken(key, fallback) { + return Factory.Get(AccessToken, key, fallback) +} + +async function setAccessToken(key, value, expiresIn) { + return Factory.Set(AccessToken, key, value, expiresIn) +} + +async function removeAccessToken(key) { + return Factory.Remove(AccessToken, key) +} + +async function updateAccessToken(key) { + return Factory.Update(AccessToken, key) +} + +async function getUserAccessToken(key, fallback) { + return Factory.Get(UserAccessToken, key, fallback) +} + +async function setUserAccessToken(key, value, expiresIn) { + return Factory.Set(UserAccessToken, key, value, expiresIn) +} + +async function removeUserAccessToken(key) { + return Factory.Remove(UserAccessToken, key) +} + +async function getSessionKey(key, fallback) { + return Factory.Get(SessionKey, key, fallback) +} + +async function setSessionKey(key, value, expiresIn) { + return Factory.Set(SessionKey, key, value, expiresIn) +} + +async function removeSessionKey(key) { + return Factory.Remove(SessionKey, key) +} + +async function getEncryptKey(key, fallback) { + return Factory.Get(Encryptkey, key, fallback) +} + +async function setEncryptKey(key, value, expiresIn) { + return Factory.Set(Encryptkey, key, value, expiresIn) +} + +async function removeEncryptKey(key) { + return Factory.Remove(Encryptkey, key) +} + +async function updateEncryptKey(key) { + return Factory.Update(Encryptkey, key) +} + +async function getTicket(key, fallback) { + return Factory.Get(Ticket, key, fallback) +} + +async function setTicket(key, value, expiresIn) { + return Factory.Set(Ticket, key, value, expiresIn) +} + +async function removeTicket(key) { + return Factory.Remove(Ticket, key) +} + +async function updateTicket(key) { + return Factory.Update(Ticket, key) +} + +module.exports = { + getAccessToken, + setAccessToken, + removeAccessToken, + updateAccessToken, + getUserAccessToken, + setUserAccessToken, + removeUserAccessToken, + getSessionKey, + setSessionKey, + removeSessionKey, + getEncryptKey, + setEncryptKey, + removeEncryptKey, + updateEncryptKey, + getTicket, + setTicket, + removeTicket, + updateTicket, + ProviderType, + PlatformType, + WeixinServer, + ErrorCodeType +} diff --git a/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json new file mode 100644 index 0000000..0425fac --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json @@ -0,0 +1,19 @@ +{ + "name": "uni-open-bridge-common", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center" + }, + "origin-plugin-dev-name": "uni-open-bridge-common", + "origin-plugin-version": "1.2.1", + "plugin-dev-name": "hello-uniapp", + "plugin-version": "3.4.9" +} \ No newline at end of file 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 new file mode 100644 index 0000000..d24684a --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js @@ -0,0 +1,116 @@ +'use strict'; + +const { + Validator +} = require('./validator.js') + +const { + CacheKeyCascade +} = require('./uni-cloud-cache.js') + +const { + BridgeError +} = require('./bridge-error.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() + } + + // virtual + async update(key) { + this.validateKey(key) + } + + async ttl(key) { + this.validateKey(key) + // 后续考虑支持 + } + + async fallback(key) { + return { + value: null, + duration: -1 + } + } + + 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 + }] + } + + const _this = this + return new CacheKeyCascade({ + ...options, + fallback: async function() { + if (fallback) { + return fallback(key) + } else if (_this.fallback) { + return _this.fallback(key) + } + } + }) + } +} +Storage.Prefix = "uni-id" + +module.exports = { + Storage +}; 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 new file mode 100644 index 0000000..b6e1bc9 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js @@ -0,0 +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 * 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 new file mode 100644 index 0000000..ee9238a --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js @@ -0,0 +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 +} 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 new file mode 100644 index 0000000..ddbce5e --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js @@ -0,0 +1,203 @@ +'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', + contentType: 'json', + 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' + } + }) + } + + getH5AccessToken() { + return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { + dataType: 'json', + method: 'GET', + data: { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + } + }) + } + + getH5Ticket(access_token) { + return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { + dataType: 'json', + dataAsQueryString: true, + method: 'POST', + data: { + access_token + } + }) + } + + getH5AccessTokenForEip() { + return uniCloud.httpProxyForEip.postForm(WeixinServer.AccessToken_H5_Url, { + appid: this._appid, + secret: this._secret, + grant_type: "client_credential" + }, { + dataType: 'json' + }) + } + + getH5TicketForEip(access_token) { + return uniCloud.httpProxyForEip.postForm(WeixinServer.Ticket_Url, { + access_token + }, { + dataType: 'json', + dataAsQueryString: true + }) + } +} + +WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/stable_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).getH5AccessToken() +} + +WeixinServer.GetH5Ticket = function(options) { + return new WeixinServer(options).getH5Ticket(options.access_token) +} + +//////////////////////////////////////////////////////////////// + +function isAliyun() { + return (uniCloud.getCloudInfos()[0].provider === 'aliyun') +} + +WeixinServer.GetResponseData = function(response) { + console.log("WeixinServer::response", response) + + if (!(response.status === HTTP_STATUS.SUCCESS || response.statusCodeValue === HTTP_STATUS.SUCCESS)) { + throw new BridgeError(response.status || response.statusCodeValue, response.status || response.statusCodeValue) + } + + const responseData = response.data || response.body + + 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 ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5AccessTokenForEip() + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5AccessToken() + } + return WeixinServer.GetResponseData(response) +} + +WeixinServer.GetH5TicketData = async function(options) { + const ws = new WeixinServer(options) + let response + if (isAliyun()) { + response = await ws.getH5TicketForEip(options.access_token) + if (typeof response === 'string') { + response = JSON.parse(response) + } + } else { + response = await ws.getH5Ticket(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 new file mode 100644 index 0000000..02432c2 --- /dev/null +++ b/uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json @@ -0,0 +1,19 @@ +// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema +{ + "bsonType": "object", + "required": ["_id", "value"], + "properties": { + "_id": { + "bsonType": "string", + "description": "key,格式:uni-id:[provider]:[appid]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]" + }, + "value": { + "bsonType": "object", + "description": "字段_id对应的值" + }, + "expired": { + "bsonType": "date", + "description": "过期时间" + } + } +} diff --git a/uni_modules/uni-pagination/changelog.md b/uni_modules/uni-pagination/changelog.md new file mode 100644 index 0000000..e09db35 --- /dev/null +++ b/uni_modules/uni-pagination/changelog.md @@ -0,0 +1,27 @@ +## 1.2.4(2022-09-19) +- 修复,未对主题色设置默认色,导致未引入 uni-scss 变量文件报错。 +- 修复,未对移动端当前页文字做主题色适配。 +## 1.2.3(2022-09-15) +- 修复未使用 uni-scss 主题色的 bug。 +## 1.2.2(2022-07-06) +- 修复 es 语言 i18n 错误 +## 1.2.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 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-pagination](https://uniapp.dcloud.io/component/uniui/uni-pagination) +## 1.1.2(2021-10-08) +- 修复 current 、value 属性未监听,导致高亮样式失效的 bug +## 1.1.1(2021-08-20) +- 新增 支持国际化 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-05-12) +- 新增 组件示例地址 +## 1.0.6(2021-04-12) +- 新增 PC 和 移动端适配不同的 ui +## 1.0.5(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json new file mode 100644 index 0000000..5914814 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "prev", + "uni-pagination.nextText": "next", + "uni-pagination.piecePerPage": "piece/page" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json new file mode 100644 index 0000000..b62ab5b --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/es.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "anterior", + "uni-pagination.nextText": "prxima", + "uni-pagination.piecePerPage": "Artculo/Pgina" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json new file mode 100644 index 0000000..0d29b6a --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/fr.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "précédente", + "uni-pagination.nextText": "suivante", + "uni-pagination.piecePerPage": "Articles/Pages" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js b/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js new file mode 100644 index 0000000..01986f1 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/index.js @@ -0,0 +1,12 @@ +import en from './en.json' +import es from './es.json' +import fr from './fr.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + es, + fr, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json new file mode 100644 index 0000000..402768c --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "上一页", + "uni-pagination.nextText": "下一页", + "uni-pagination.piecePerPage": "条/页" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json new file mode 100644 index 0000000..04cfbf0 --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-pagination.prevText": "上一頁", + "uni-pagination.nextText": "下一頁", + "uni-pagination.piecePerPage": "條/頁" +} diff --git a/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue b/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue new file mode 100644 index 0000000..cf0efce --- /dev/null +++ b/uni_modules/uni-pagination/components/uni-pagination/uni-pagination.vue @@ -0,0 +1,465 @@ + + + + + diff --git a/uni_modules/uni-pagination/package.json b/uni_modules/uni-pagination/package.json new file mode 100644 index 0000000..38595f8 --- /dev/null +++ b/uni_modules/uni-pagination/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-pagination", + "displayName": "uni-pagination 分页器", + "version": "1.2.4", + "description": "Pagination 分页器组件,用于展示页码、请求数据等。", + "keywords": [ + "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","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-pagination/readme.md b/uni_modules/uni-pagination/readme.md new file mode 100644 index 0000000..dd418a8 --- /dev/null +++ b/uni_modules/uni-pagination/readme.md @@ -0,0 +1,11 @@ + + +## Pagination 分页器 +> **组件名:uni-pagination** +> 代码块: `uPagination` + + +分页器组件,用于展示页码、请求数据等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-pagination) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-popup/changelog.md b/uni_modules/uni-popup/changelog.md new file mode 100644 index 0000000..c0a6b33 --- /dev/null +++ b/uni_modules/uni-popup/changelog.md @@ -0,0 +1,90 @@ +## 1.9.6(2025-01-08) +- 修复 示例中过期图片地址 +## 1.9.5(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.9.2(2024-09-21) +- 修复 uni-popup在android上的重复点击弹出位置不正确的bug +## 1.9.1(2024-04-02) +- 修复 uni-popup-dialog vue3下使用value无法进行绑定的bug(双向绑定兼容旧写法) +## 1.9.0(2024-03-28) +- 修复 uni-popup-dialog 双向绑定时初始化逻辑修正 +## 1.8.9(2024-03-20) +- 修复 uni-popup-dialog 数据输入时修正为双向绑定 +## 1.8.8(2024-02-20) +- 修复 uni-popup 在微信小程序下出现文字向上闪动的bug +## 1.8.7(2024-02-02) +- 新增 uni-popup-dialog 新增属性focus:input模式下,是否自动自动聚焦 +## 1.8.6(2024-01-30) +- 新增 uni-popup-dialog 新增属性maxLength:限制输入框字数 +## 1.8.5(2024-01-26) +- 新增 uni-popup-dialog 新增属性showClose:控制关闭按钮的显示 +## 1.8.4(2023-11-15) +- 新增 uni-popup 支持uni-app-x 注意暂时仅支持 `maskClick` `@open` `@close` +## 1.8.3(2023-04-17) +- 修复 uni-popup 重复打开时的 bug +## 1.8.2(2023-02-02) +- uni-popup-dialog 组件新增 inputType 属性 +## 1.8.1(2022-12-01) +- 修复 nvue 下 v-show 报错 +## 1.8.0(2022-11-29) +- 优化 主题样式 +## 1.7.9(2022-04-02) +- 修复 弹出层内部无法滚动的bug +## 1.7.8(2022-03-28) +- 修复 小程序中高度错误的bug +## 1.7.7(2022-03-17) +- 修复 快速调用open出现问题的Bug +## 1.7.6(2022-02-14) +- 修复 safeArea 属性不能设置为false的bug +## 1.7.5(2022-01-19) +- 修复 isMaskClick 失效的bug +## 1.7.4(2022-01-19) +- 新增 cancelText \ confirmText 属性 ,可自定义文本 +- 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 +- 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 +## 1.7.3(2022-01-13) +- 修复 设置 safeArea 属性不生效的bug +## 1.7.2(2021-11-26) +- 优化 组件示例 +## 1.7.1(2021-11-26) +- 修复 vuedoc 文字错误 +## 1.7.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-popup](https://uniapp.dcloud.io/component/uniui/uni-popup) +## 1.6.2(2021-08-24) +- 新增 支持国际化 +## 1.6.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.6.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.5.0(2021-06-23) +- 新增 mask-click 遮罩层点击事件 +## 1.4.5(2021-06-22) +- 修复 nvue 平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.4(2021-06-18) +- 修复 H5平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.3(2021-06-08) +- 修复 错误的 watch 字段 +- 修复 safeArea 属性不生效的问题 +- 修复 点击内容,再点击遮罩无法关闭的Bug +## 1.4.2(2021-05-12) +- 新增 组件示例地址 +## 1.4.1(2021-04-29) +- 修复 组件内放置 input 、textarea 组件,无法聚焦的问题 +## 1.4.0 (2021-04-29) +- 新增 type 属性的 left\right 值,支持左右弹出 +- 新增 open(String:type) 方法参数 ,可以省略 type 属性 ,直接传入类型打开指定弹窗 +- 新增 backgroundColor 属性,可定义主窗口背景色,默认不显示背景色 +- 新增 safeArea 属性,是否适配底部安全区 +- 修复 App\h5\微信小程序底部安全区占位不对的Bug +- 修复 App 端弹出等待的Bug +- 优化 提升低配设备性能,优化动画卡顿问题 +- 优化 更简单的组件自定义方式 +## 1.2.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.2.8(2021-02-05) +- 调整为uni_modules目录规范 +## 1.2.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 PC 端 +- 新增 uni-popup-message 、uni-popup-dialog扩展组件支持 PC 端 diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js new file mode 100644 index 0000000..a747b9f --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue new file mode 100644 index 0000000..e42bfaf --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue @@ -0,0 +1,316 @@ + + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue new file mode 100644 index 0000000..7f27a1e --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue @@ -0,0 +1,143 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue new file mode 100644 index 0000000..049cd5c --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue @@ -0,0 +1,188 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/en.json b/uni_modules/uni-popup/components/uni-popup/i18n/en.json new file mode 100644 index 0000000..8c0f5f3 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/en.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "cancel", + "uni-popup.ok": "ok", + "uni-popup.placeholder": "pleace enter", + "uni-popup.title": "Hint", + "uni-popup.shareTitle": "Share to" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/index.js b/uni_modules/uni-popup/components/uni-popup/i18n/index.js new file mode 100644 index 0000000..fa8f0f3 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json new file mode 100644 index 0000000..8e5b99f --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "确定", + "uni-popup.placeholder": "请输入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json new file mode 100644 index 0000000..06ce162 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "確定", + "uni-popup.placeholder": "請輸入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/keypress.js b/uni_modules/uni-popup/components/uni-popup/keypress.js new file mode 100644 index 0000000..16a5818 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + // this.$once('hook:beforeDestroy', () => { + // document.removeEventListener('keyup', listener) + // }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup/popup.js b/uni_modules/uni-popup/components/uni-popup/popup.js new file mode 100644 index 0000000..a37fb9f --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/popup.js @@ -0,0 +1,26 @@ + +export default { + data() { + return { + + } + }, + created(){ + this.popup = this.getParent() + }, + methods:{ + /** + * 获取父元素实例 + */ + getParent(name = 'uniPopup') { + let parent = this.$parent; + let parentName = parent.$options.name; + while (parentName !== name) { + parent = parent.$parent; + if (!parent) return false + parentName = parent.$options.name; + } + return parent; + }, + } +} diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue b/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue new file mode 100644 index 0000000..2680f55 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.vue b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue new file mode 100644 index 0000000..b2431a3 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue @@ -0,0 +1,518 @@ + + + + diff --git a/uni_modules/uni-popup/package.json b/uni_modules/uni-popup/package.json new file mode 100644 index 0000000..fbf34ed --- /dev/null +++ b/uni_modules/uni-popup/package.json @@ -0,0 +1,90 @@ +{ + "id": "uni-popup", + "displayName": "uni-popup 弹出层", + "version": "1.9.6", + "description": " Popup 组件,提供常用的弹层", + "keywords": [ + "uni-ui", + "弹出层", + "弹窗", + "popup", + "弹框" + ], + "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", + "uni-transition" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-harmony": "u", + "app-uvue": "u" + }, + "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" + } + } + } + } +} diff --git a/uni_modules/uni-popup/readme.md b/uni_modules/uni-popup/readme.md new file mode 100644 index 0000000..fb661e7 --- /dev/null +++ b/uni_modules/uni-popup/readme.md @@ -0,0 +1,17 @@ + + +## Popup 弹出层 +> **组件名:uni-popup** +> 代码块: `uPopup` +> 关联组件:`uni-transition` + + +弹出层组件,在应用中弹出一个消息提示窗口、提示框等 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-popup) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + + diff --git a/uni_modules/uni-rate/changelog.md b/uni_modules/uni-rate/changelog.md new file mode 100644 index 0000000..d57d916 --- /dev/null +++ b/uni_modules/uni-rate/changelog.md @@ -0,0 +1,25 @@ +## 1.3.1(2022-02-25) +- 修复 条件判断 `NaN` 错误的 bug +## 1.3.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-rate](https://uniapp.dcloud.io/component/uniui/uni-rate) +## 1.2.2(2021-09-10) +- 优化 默认值修改为 0 颗星 +## 1.2.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.2(2021-05-12) +- 新增 组件示例地址 +## 1.1.1(2021-04-21) +- 修复 布局变化后 uni-rate 星星计算不准确的 bug +- 优化 添加依赖 uni-icons, 导入 uni-rate 自动下载依赖 +## 1.1.0(2021-04-16) +- 修复 uni-rate 属性 margin 值为 string 组件失效的 bug + +## 1.0.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.8(2021-02-05) +- 调整为uni_modules目录规范 +- 支持 pc 端 diff --git a/uni_modules/uni-rate/components/uni-rate/uni-rate.vue b/uni_modules/uni-rate/components/uni-rate/uni-rate.vue new file mode 100644 index 0000000..e535406 --- /dev/null +++ b/uni_modules/uni-rate/components/uni-rate/uni-rate.vue @@ -0,0 +1,361 @@ + + + + + diff --git a/uni_modules/uni-rate/package.json b/uni_modules/uni-rate/package.json new file mode 100644 index 0000000..06eba77 --- /dev/null +++ b/uni_modules/uni-rate/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-rate", + "displayName": "uni-rate 评分", + "version": "1.3.1", + "description": "Rate 评分组件,可自定义评分星星图标的大小、间隔、评分数。", + "keywords": [ + "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": [ + "uni-scss", + "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" + } + } + } + } +} diff --git a/uni_modules/uni-rate/readme.md b/uni_modules/uni-rate/readme.md new file mode 100644 index 0000000..605391f --- /dev/null +++ b/uni_modules/uni-rate/readme.md @@ -0,0 +1,12 @@ + + +## Rate 评分 +> **组件名:uni-rate** +> 代码块: `uRate` +> 关联组件:`uni-icons` + + +评分组件,多用于购买商品后,对商品进行评价等场景 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-rate) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-row/changelog.md b/uni_modules/uni-row/changelog.md new file mode 100644 index 0000000..a97d893 --- /dev/null +++ b/uni_modules/uni-row/changelog.md @@ -0,0 +1,10 @@ +## 1.0.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-row](https://uniapp.dcloud.io/component/uniui/uni-row) +## 0.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-02-05) +- 调整为uni_modules目录规范 +- 新增uni-row组件 diff --git a/uni_modules/uni-row/components/uni-col/uni-col.vue b/uni_modules/uni-row/components/uni-col/uni-col.vue new file mode 100644 index 0000000..5b2ecd8 --- /dev/null +++ b/uni_modules/uni-row/components/uni-col/uni-col.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/uni_modules/uni-row/components/uni-row/uni-row.vue b/uni_modules/uni-row/components/uni-row/uni-row.vue new file mode 100644 index 0000000..3451cc9 --- /dev/null +++ b/uni_modules/uni-row/components/uni-row/uni-row.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/uni_modules/uni-row/package.json b/uni_modules/uni-row/package.json new file mode 100644 index 0000000..b09a8d0 --- /dev/null +++ b/uni_modules/uni-row/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-row", + "displayName": "uni-row 布局-行", + "version": "1.0.0", + "description": "流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。", + "keywords": [ + "uni-ui", + "uniui", + "栅格", + "布局", + "layout" +], + "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-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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-row/readme.md b/uni_modules/uni-row/readme.md new file mode 100644 index 0000000..33a959a --- /dev/null +++ b/uni_modules/uni-row/readme.md @@ -0,0 +1,10 @@ +## Layout 布局 + +> **组件名 uni-row、uni-col** +> 代码块: `uRow`、`uCol` + + +流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-row) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md new file mode 100644 index 0000000..a58bab7 --- /dev/null +++ b/uni_modules/uni-scss/changelog.md @@ -0,0 +1,8 @@ +## 1.0.3(2022-01-21) +- 优化 组件示例 +## 1.0.2(2021-11-22) +- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题 +## 1.0.1(2021-11-22) +- 修复 vue3中scss语法兼容问题 +## 1.0.0(2021-11-18) +- init diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss new file mode 100644 index 0000000..5d43f7f --- /dev/null +++ b/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json new file mode 100644 index 0000000..4db034b --- /dev/null +++ b/uni_modules/uni-scss/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-scss", + "displayName": "uni-scss 辅助样式", + "version": "1.0.3", + "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", + "keywords": [ + "uni-scss", + "uni-ui", + "辅助样式" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "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": "u" + }, + "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" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md new file mode 100644 index 0000000..8fa518a --- /dev/null +++ b/uni_modules/uni-scss/readme.md @@ -0,0 +1,4 @@ +`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 0000000..2106dd1 --- /dev/null +++ b/uni_modules/uni-scss/styles/index.scss @@ -0,0 +1,7 @@ +@import './setting/_variables.scss'; +@import './setting/_border.scss'; +@import './setting/_color.scss'; +@import './setting/_space.scss'; +@import './setting/_radius.scss'; +@import './setting/_text.scss'; +@import './setting/_styles.scss'; diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 0000000..781df64 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_border.scss @@ -0,0 +1,3 @@ +.uni-border { + border: 1px $uni-border-1 solid; +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 0000000..595f5ed --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_color.scss @@ -0,0 +1,66 @@ + +// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 +// @mixin get-styles($k,$c) { +// @if $k == size or $k == weight{ +// font-#{$k}:#{$c} +// }@else{ +// #{$k}:#{$c} +// } +// } +$uni-ui-color:( + // 主色 + primary: $uni-primary, + primary-disable: $uni-primary-disable, + primary-light: $uni-primary-light, + // 辅助色 + success: $uni-success, + success-disable: $uni-success-disable, + success-light: $uni-success-light, + warning: $uni-warning, + warning-disable: $uni-warning-disable, + warning-light: $uni-warning-light, + error: $uni-error, + error-disable: $uni-error-disable, + error-light: $uni-error-light, + info: $uni-info, + info-disable: $uni-info-disable, + info-light: $uni-info-light, + // 中性色 + main-color: $uni-main-color, + base-color: $uni-base-color, + secondary-color: $uni-secondary-color, + extra-color: $uni-extra-color, + // 背景色 + bg-color: $uni-bg-color, + // 边框颜色 + border-1: $uni-border-1, + border-2: $uni-border-2, + border-3: $uni-border-3, + border-4: $uni-border-4, + // 黑色 + black:$uni-black, + // 白色 + white:$uni-white, + // 透明 + transparent:$uni-transparent +) !default; +@each $key, $child in $uni-ui-color { + .uni-#{"" + $key} { + color: $child; + } + .uni-#{"" + $key}-bg { + background-color: $child; + } +} +.uni-shadow-sm { + box-shadow: $uni-shadow-sm; +} +.uni-shadow-base { + box-shadow: $uni-shadow-base; +} +.uni-shadow-lg { + box-shadow: $uni-shadow-lg; +} +.uni-mask { + background-color:$uni-mask; +} diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 0000000..8672a69 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_radius.scss @@ -0,0 +1,55 @@ +@mixin radius($r,$d:null ,$important: false){ + $radius-value:map-get($uni-radius, $r) if($important, !important, null); + // Key exists within the $uni-radius variable + @if (map-has-key($uni-radius, $r) and $d){ + @if $d == t { + border-top-left-radius:$radius-value; + border-top-right-radius:$radius-value; + }@else if $d == r { + border-top-right-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == b { + border-bottom-left-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == l { + border-top-left-radius:$radius-value; + border-bottom-left-radius:$radius-value; + }@else if $d == tl { + border-top-left-radius:$radius-value; + }@else if $d == tr { + border-top-right-radius:$radius-value; + }@else if $d == br { + border-bottom-right-radius:$radius-value; + }@else if $d == bl { + border-bottom-left-radius:$radius-value; + } + }@else{ + border-radius:$radius-value; + } +} + +@each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $key} { + @include radius($key) + } + }@else{ + .uni-radius { + @include radius($key) + } + } +} + +@each $direction in t, r, b, l,tl, tr, br, bl { + @each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $direction}-#{"" + $key} { + @include radius($key,$direction,false) + } + }@else{ + .uni-radius-#{$direction} { + @include radius($key,$direction,false) + } + } + } +} diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 0000000..9c3b17b --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_space.scss @@ -0,0 +1,56 @@ + +@mixin fn($space,$direction,$size,$n) { + @if $n { + #{$space}-#{$direction}: #{$size*$uni-space-root}px + } @else { + #{$space}-#{$direction}: #{-$size*$uni-space-root}px + } +} +@mixin get-styles($direction,$i,$space,$n){ + @if $direction == t { + @include fn($space, top,$i,$n); + } + @if $direction == r { + @include fn($space, right,$i,$n); + } + @if $direction == b { + @include fn($space, bottom,$i,$n); + } + @if $direction == l { + @include fn($space, left,$i,$n); + } + @if $direction == x { + @include fn($space, left,$i,$n); + @include fn($space, right,$i,$n); + } + @if $direction == y { + @include fn($space, top,$i,$n); + @include fn($space, bottom,$i,$n); + } + @if $direction == a { + @if $n { + #{$space}:#{$i*$uni-space-root}px; + } @else { + #{$space}:#{-$i*$uni-space-root}px; + } + } +} + +@each $orientation in m,p { + $space: margin; + @if $orientation == m { + $space: margin; + } @else { + $space: padding; + } + @for $i from 0 through 16 { + @each $direction in t, r, b, l, x, y, a { + .uni-#{$orientation}#{$direction}-#{$i} { + @include get-styles($direction,$i,$space,true); + } + .uni-#{$orientation}#{$direction}-n#{$i} { + @include get-styles($direction,$i,$space,false); + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 0000000..6f882c8 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_styles.scss @@ -0,0 +1,167 @@ +/* #ifndef APP-NVUE */ + +$-color-white:#fff; +$-color-black:#000; +@mixin base-style($color) { + color: #fff; + background-color: $color; + border-color: mix($-color-black, $color, 8%); + &:not([hover-class]):active { + background: mix($-color-black, $color, 10%); + border-color: mix($-color-black, $color, 20%); + color: $-color-white; + outline: none; + } +} +@mixin is-color($color) { + @include base-style($color); + &[loading] { + @include base-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &[loading], + &:not([hover-class]):active { + color: $-color-white; + border-color: mix(darken($color,10%), $-color-white); + background-color: mix($color, $-color-white); + } + } + +} +@mixin base-plain-style($color) { + color:$color; + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 70%); + &:not([hover-class]):active { + background: mix($-color-white, $color, 80%); + color: $color; + outline: none; + border-color: mix($-color-white, $color, 50%); + } +} +@mixin is-plain($color){ + &[plain] { + @include base-plain-style($color); + &[loading] { + @include base-plain-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &:active { + color: mix($-color-white, $color, 40%); + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 80%); + } + } + } +} + + +.uni-btn { + margin: 5px; + color: #393939; + border:1px solid #ccc; + font-size: 16px; + font-weight: 200; + background-color: #F9F9F9; + // TODO 暂时处理边框隐藏一边的问题 + overflow: visible; + &::after{ + border: none; + } + + &:not([type]),&[type=default] { + color: #999; + &[loading] { + background: none; + &::before { + margin-right:5px; + } + } + + + + &[disabled]{ + color: mix($-color-white, #999, 60%); + &, + &[loading], + &:active { + color: mix($-color-white, #999, 60%); + background-color: mix($-color-white,$-color-black , 98%); + border-color: mix($-color-white, #999, 85%); + } + } + + &[plain] { + color: #999; + background: none; + border-color: $uni-border-1; + &:not([hover-class]):active { + background: none; + color: mix($-color-white, $-color-black, 80%); + border-color: mix($-color-white, $-color-black, 90%); + outline: none; + } + &[disabled]{ + &, + &[loading], + &:active { + background: none; + color: mix($-color-white, #999, 60%); + border-color: mix($-color-white, #999, 85%); + } + } + } + } + + &:not([hover-class]):active { + color: mix($-color-white, $-color-black, 50%); + } + + &[size=mini] { + font-size: 16px; + font-weight: 200; + border-radius: 8px; + } + + + + &.uni-btn-small { + font-size: 14px; + } + &.uni-btn-mini { + font-size: 12px; + } + + &.uni-btn-radius { + border-radius: 999px; + } + &[type=primary] { + @include is-color($uni-primary); + @include is-plain($uni-primary) + } + &[type=success] { + @include is-color($uni-success); + @include is-plain($uni-success) + } + &[type=error] { + @include is-color($uni-error); + @include is-plain($uni-error) + } + &[type=warning] { + @include is-color($uni-warning); + @include is-plain($uni-warning) + } + &[type=info] { + @include is-color($uni-info); + @include is-plain($uni-info) + } +} +/* #endif */ diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 0000000..0a89590 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_text.scss @@ -0,0 +1,24 @@ +@mixin get-styles($k,$c) { + @if $k == size or $k == weight{ + font-#{$k}:#{$c} + }@else{ + #{$k}:#{$c} + } +} + +@each $key, $child in $uni-headings { + /* #ifndef APP-NVUE */ + .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ + /* #ifdef APP-NVUE */ + .container .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ +} diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 0000000..5fb5d9b --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_variables.scss @@ -0,0 +1,146 @@ +// @use "sass:math"; +@import '../tools/functions.scss'; +// 间距基础倍数 +$uni-space-root: 2 !default; +// 边框半径默认值 +$uni-radius-root:5px !default; +$uni-radius: () !default; +// 边框半径断点 +$uni-radius: map-deep-merge( + ( + 0: 0, + // TODO 当前版本暂时不支持 sm 属性 + // 'sm': math.div($uni-radius-root, 2), + null: $uni-radius-root, + 'lg': $uni-radius-root * 2, + 'xl': $uni-radius-root * 6, + 'pill': 9999px, + 'circle': 50% + ), + $uni-radius +); +// 字体家族 +$body-font-family: 'Roboto', sans-serif !default; +// 文本 +$heading-font-family: $body-font-family !default; +$uni-headings: () !default; +$letterSpacing: -0.01562em; +$uni-headings: map-deep-merge( + ( + 'h1': ( + size: 32px, + weight: 300, + line-height: 50px, + // letter-spacing:-0.01562em + ), + 'h2': ( + size: 28px, + weight: 300, + line-height: 40px, + // letter-spacing: -0.00833em + ), + 'h3': ( + size: 24px, + weight: 400, + line-height: 32px, + // letter-spacing: normal + ), + 'h4': ( + size: 20px, + weight: 400, + line-height: 30px, + // letter-spacing: 0.00735em + ), + 'h5': ( + size: 16px, + weight: 400, + line-height: 24px, + // letter-spacing: normal + ), + 'h6': ( + size: 14px, + weight: 500, + line-height: 18px, + // letter-spacing: 0.0125em + ), + 'subtitle': ( + size: 12px, + weight: 400, + line-height: 20px, + // letter-spacing: 0.00937em + ), + 'body': ( + font-size: 14px, + font-weight: 400, + line-height: 22px, + // letter-spacing: 0.03125em + ), + 'caption': ( + 'size': 12px, + 'weight': 400, + 'line-height': 20px, + // 'letter-spacing': 0.03333em, + // 'text-transform': false + ) + ), + $uni-headings +); + + + +// 主色 +$uni-primary: #2979ff !default; +$uni-primary-disable:lighten($uni-primary,20%) !default; +$uni-primary-light: lighten($uni-primary,25%) !default; + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37 !default; +$uni-success-disable:lighten($uni-success,20%) !default; +$uni-success-light: lighten($uni-success,25%) !default; + +$uni-warning: #f3a73f !default; +$uni-warning-disable:lighten($uni-warning,20%) !default; +$uni-warning-light: lighten($uni-warning,25%) !default; + +$uni-error: #e43d33 !default; +$uni-error-disable:lighten($uni-error,20%) !default; +$uni-error-light: lighten($uni-error,25%) !default; + +$uni-info: #8f939c !default; +$uni-info-disable:lighten($uni-info,20%) !default; +$uni-info-light: lighten($uni-info,25%) !default; + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a !default; // 主要文字 +$uni-base-color: #6a6a6a !default; // 常规文字 +$uni-secondary-color: #909399 !default; // 次要文字 +$uni-extra-color: #c7c7c7 !default; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0 !default; +$uni-border-2: #EDEDED !default; +$uni-border-3: #DCDCDC !default; +$uni-border-4: #B9B9B9 !default; + +// 常规色 +$uni-black: #000000 !default; +$uni-white: #ffffff !default; +$uni-transparent: rgba($color: #000000, $alpha: 0) !default; + +// 背景色 +$uni-bg-color: #f7f7f7 !default; + +/* 水平间距 */ +$uni-spacing-sm: 8px !default; +$uni-spacing-base: 15px !default; +$uni-spacing-lg: 30px !default; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default; +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default; + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4) !default; diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 0000000..a71beeb --- /dev/null +++ b/uni_modules/uni-scss/styles/tools/functions.scss @@ -0,0 +1,19 @@ +// 合并 map +@function map-deep-merge($parent-map, $child-map){ + $result: $parent-map; + @each $key, $child in $child-map { + $parent-has-key: map-has-key($result, $key); + $parent-value: map-get($result, $key); + $parent-type: type-of($parent-value); + $child-type: type-of($child); + $parent-is-map: $parent-type == map; + $child-is-map: $child-type == map; + + @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){ + $result: map-merge($result, ( $key: $child )); + }@else { + $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) )); + } + } + @return $result; +}; diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss new file mode 100644 index 0000000..20cdf5e --- /dev/null +++ b/uni_modules/uni-scss/theme.scss @@ -0,0 +1,31 @@ +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; +// 主色 +$uni-primary: #2979ff; +// 辅助色 +$uni-success: #4cd964; +// 警告色 +$uni-warning: #f0ad4e; +// 错误色 +$uni-error: #dd524d; +// 描述色 +$uni-info: #909399; +// 中性色 +$uni-main-color: #303133; +$uni-base-color: #606266; +$uni-secondary-color: #909399; +$uni-extra-color: #C0C4CC; +// 背景色 +$uni-bg-color: #f5f5f5; +// 边框颜色 +$uni-border-1: #DCDFE6; +$uni-border-2: #E4E7ED; +$uni-border-3: #EBEEF5; +$uni-border-4: #F2F6FC; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss new file mode 100644 index 0000000..49a89b6 --- /dev/null +++ b/uni_modules/uni-scss/variables.scss @@ -0,0 +1,62 @@ +@import './styles/setting/_variables.scss'; +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; + +// 主色 +$uni-primary: #2979ff; +$uni-primary-disable:mix(#fff,$uni-primary,50%); +$uni-primary-light: mix(#fff,$uni-primary,80%); + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37; +$uni-success-disable:mix(#fff,$uni-success,50%); +$uni-success-light: mix(#fff,$uni-success,80%); + +$uni-warning: #f3a73f; +$uni-warning-disable:mix(#fff,$uni-warning,50%); +$uni-warning-light: mix(#fff,$uni-warning,80%); + +$uni-error: #e43d33; +$uni-error-disable:mix(#fff,$uni-error,50%); +$uni-error-light: mix(#fff,$uni-error,80%); + +$uni-info: #8f939c; +$uni-info-disable:mix(#fff,$uni-info,50%); +$uni-info-light: mix(#fff,$uni-info,80%); + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a; // 主要文字 +$uni-base-color: #6a6a6a; // 常规文字 +$uni-secondary-color: #909399; // 次要文字 +$uni-extra-color: #c7c7c7; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0; +$uni-border-2: #EDEDED; +$uni-border-3: #DCDCDC; +$uni-border-4: #B9B9B9; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); + +// 背景色 +$uni-bg-color: #f7f7f7; + +/* 水平间距 */ +$uni-spacing-sm: 8px; +$uni-spacing-base: 15px; +$uni-spacing-lg: 30px; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5); +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2); +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5); + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4); diff --git a/uni_modules/uni-search-bar/changelog.md b/uni_modules/uni-search-bar/changelog.md new file mode 100644 index 0000000..f9a72dd --- /dev/null +++ b/uni_modules/uni-search-bar/changelog.md @@ -0,0 +1,47 @@ +## 1.3.0(2024-04-22) +- 修复 textColor默认值导致的文字不显示的bug +## 1.2.9(2024-04-17) +- 修复 textColor不生效的bug +## 1.2.8(2024-02-22) +- 修复 清空按钮emit值错误的bug +## 1.2.7(2024-02-21) +- 新增 设置输入框字体颜色:textColor +## 1.2.6(2024-02-20) +- 修复 uni-search-bar在支付宝小程序下样式兼容问题 +## 1.2.5(2024-01-31) +- 修复 uni-search-bar居中问题,现在默认居左,并修复样式偏移问题 +## 1.2.4(2023-05-09) +- 修复 i18n 国际化不正确的 Bug +## 1.2.3(2022-05-24) +- 新增 readonly 属性,组件只读 +## 1.2.2(2022-05-06) +- 修复 vue3 input 事件不生效的bug +## 1.2.1(2022-05-06) +- 修复 多余代码导致的bug +## 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-search-bar](https://uniapp.dcloud.io/component/uniui/uni-search-bar) +## 1.1.2(2021-08-30) +- 修复 value 属性与 modelValue 属性不兼容的Bug +## 1.1.1(2021-08-24) +- 新增 支持国际化 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.9(2021-05-12) +- 新增 项目示例地址 +## 1.0.8(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.7(2021-04-15) +- uni-ui 新增 uni-search-bar 的 focus 事件 + +## 1.0.6(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持双向绑定 +- 更改 input 事件的返回值,e={value:Number} --> e=value +- 新增 支持图标插槽 +- 新增 支持 clear、blur 事件 +- 新增 支持 focus 属性 +- 去掉组件背景色 diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json new file mode 100644 index 0000000..0c72ffb --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "cancel", + "uni-search-bar.placeholder": "Search enter content" +} \ No newline at end of file diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js new file mode 100644 index 0000000..fa8f0f3 --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json new file mode 100644 index 0000000..70eacc0 --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "取消", + "uni-search-bar.placeholder": "请输入搜索内容" +} diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json new file mode 100644 index 0000000..9a71f2a --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json @@ -0,0 +1,4 @@ +{ + "uni-search-bar.cancel": "取消", + "uni-search-bar.placeholder": "請輸入搜索內容" +} diff --git a/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue b/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue new file mode 100644 index 0000000..6796902 --- /dev/null +++ b/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue @@ -0,0 +1,309 @@ + + + + + diff --git a/uni_modules/uni-search-bar/package.json b/uni_modules/uni-search-bar/package.json new file mode 100644 index 0000000..58c9683 --- /dev/null +++ b/uni_modules/uni-search-bar/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-search-bar", + "displayName": "uni-search-bar 搜索栏", + "version": "1.3.0", + "description": "搜索栏组件,通常用于搜索商品、文章等", + "keywords": [ + "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", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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-search-bar/readme.md b/uni_modules/uni-search-bar/readme.md new file mode 100644 index 0000000..b9f2373 --- /dev/null +++ b/uni_modules/uni-search-bar/readme.md @@ -0,0 +1,14 @@ + + +## SearchBar 搜索栏 + +> **组件名:uni-search-bar** +> 代码块: `uSearchBar` + + +搜索栏组件 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-search-bar) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-section/changelog.md b/uni_modules/uni-section/changelog.md new file mode 100644 index 0000000..e904d41 --- /dev/null +++ b/uni_modules/uni-section/changelog.md @@ -0,0 +1,2 @@ +## 0.0.1(2022-07-22) +- 初始化 diff --git a/uni_modules/uni-section/components/uni-section/uni-section.vue b/uni_modules/uni-section/components/uni-section/uni-section.vue new file mode 100644 index 0000000..3c0b7a3 --- /dev/null +++ b/uni_modules/uni-section/components/uni-section/uni-section.vue @@ -0,0 +1,167 @@ + + + + diff --git a/uni_modules/uni-section/package.json b/uni_modules/uni-section/package.json new file mode 100644 index 0000000..e28f356 --- /dev/null +++ b/uni_modules/uni-section/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-section", + "displayName": "uni-section 标题栏", + "version": "0.0.1", + "description": "标题栏组件", + "keywords": [ + "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": [ + "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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-section/readme.md b/uni_modules/uni-section/readme.md new file mode 100644 index 0000000..b4bc0d2 --- /dev/null +++ b/uni_modules/uni-section/readme.md @@ -0,0 +1,8 @@ +## Section 标题栏 +> **组件名:uni-section** +> 代码块: `uSection` + +uni-section 组件主要用于文章、列表详情等标题展示 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-section) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-segmented-control/changelog.md b/uni_modules/uni-segmented-control/changelog.md new file mode 100644 index 0000000..7d26c78 --- /dev/null +++ b/uni_modules/uni-segmented-control/changelog.md @@ -0,0 +1,15 @@ +## 1.2.3(2024-04-02) +- 修复 修复在微信小程序下inactiveColor失效bug +## 1.2.2(2024-03-28) +- 修复 在vue2下:style动态绑定导致编译失败的bug +## 1.2.1(2024-03-20) +- 新增 inActiveColor属性,可供配置未激活时的颜色 +## 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-segmented-control](https://uniapp.dcloud.io/component/uniui/uni-segmented-control) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.5(2021-05-12) +- 新增 项目示例地址 +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue b/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue new file mode 100644 index 0000000..272cbf5 --- /dev/null +++ b/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/uni_modules/uni-segmented-control/package.json b/uni_modules/uni-segmented-control/package.json new file mode 100644 index 0000000..4d3b7a3 --- /dev/null +++ b/uni_modules/uni-segmented-control/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-segmented-control", + "displayName": "uni-segmented-control 分段器", + "version": "1.2.3", + "description": "分段器由至少 2 个分段控件组成,用作不同视图的显示", + "keywords": [ + "uni-ui", + "uniui", + "分段器", + "segement", + "顶部选择" +], + "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", + "alipay": "n" + }, + "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-segmented-control/readme.md b/uni_modules/uni-segmented-control/readme.md new file mode 100644 index 0000000..3278ea6 --- /dev/null +++ b/uni_modules/uni-segmented-control/readme.md @@ -0,0 +1,13 @@ + + +## SegmentedControl 分段器 +> **组件名:uni-segmented-control** +> 代码块: `uSegmentedControl` + + +用作不同视图的显示 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-segmented-control) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-steps/changelog.md b/uni_modules/uni-steps/changelog.md new file mode 100644 index 0000000..b896391 --- /dev/null +++ b/uni_modules/uni-steps/changelog.md @@ -0,0 +1,18 @@ +## 1.1.2(2024-03-28) +- 修复 uni-steps为竖排列时,文本长度过长引起点错乱的bug +## 1.1.1(2021-11-22) +- 修复 vue3中某些scss变量无法找到的问题 +## 1.1.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-steps](https://uniapp.dcloud.io/component/uniui/uni-steps) +## 1.0.8(2021-05-12) +- 新增 项目示例地址 +## 1.0.7(2021-05-06) +- 修复 uni-steps 横向布局时,多行文字高度不合理的 bug +## 1.0.6(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 1.0.5(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 + +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-steps/components/uni-steps/uni-steps.vue b/uni_modules/uni-steps/components/uni-steps/uni-steps.vue new file mode 100644 index 0000000..473d9c9 --- /dev/null +++ b/uni_modules/uni-steps/components/uni-steps/uni-steps.vue @@ -0,0 +1,280 @@ + + + + + diff --git a/uni_modules/uni-steps/package.json b/uni_modules/uni-steps/package.json new file mode 100644 index 0000000..701d884 --- /dev/null +++ b/uni_modules/uni-steps/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-steps", + "displayName": "uni-steps 步骤条", + "version": "1.1.2", + "description": "步骤条组件,提供横向和纵向两种布局格式。", + "keywords": [ + "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", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "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-steps/readme.md b/uni_modules/uni-steps/readme.md new file mode 100644 index 0000000..7c0a94e --- /dev/null +++ b/uni_modules/uni-steps/readme.md @@ -0,0 +1,13 @@ + + +## Steps 步骤条 +> **组件名:uni-steps** +> 代码块: `uSteps` + + +步骤条,常用于显示进度 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-steps) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-swipe-action/changelog.md b/uni_modules/uni-swipe-action/changelog.md new file mode 100644 index 0000000..5f5ed93 --- /dev/null +++ b/uni_modules/uni-swipe-action/changelog.md @@ -0,0 +1,54 @@ +## 1.3.13(2025-04-15) +- 修复 app 端 缺少leftOptions 或 rightOptions 时无法滑动的问题 +## 1.3.12(2025-04-14) +- 修复 由上一个兼容版本引发的 安卓运行报错且无法回弹的问题 +## 1.3.11(2025-04-08) +- 优化 兼容鸿蒙平台 +- 修复 WEB 平台控制台报错 +## 1.3.10(2024-01-17) +- 修复 点击按钮时,按钮会被点击穿透导致自动收缩的 bug(兼容阿里/百度/抖音小程序) +## 1.3.9(2024-01-17) +- 修复 点击按钮时,按钮会被点击穿透导致自动收缩的 bug +## 1.3.8(2023-04-13) +- 修复`uni-swipe-action`和`uni-swipe-action-item`不同时使用导致 closeOther 方法报错的 bug +## 1.3.7(2022-06-06) +- 修复 vue3 下使用组件不能正常运行的Bug +## 1.3.6(2022-05-31) +- 修复 h5端点击click触发两次的Bug +## 1.3.5(2022-05-23) +- 修复 isPC 找不到的Bug +## 1.3.4(2022-05-19) +- 修复 在 nvue 下 disabled 失效的bug +## 1.3.3(2022-03-31) +- 修复 按钮字体大小不能设置的bug +## 1.3.2(2022-03-16) +- 修复 h5和app端下报el错误的bug +## 1.3.1(2022-03-07) +- 修复 HBuilderX 1.4.X 版本中,h5和app端下报错的bug +## 1.3.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-swipe-action](https://uniapp.dcloud.io/component/uniui/uni-swipe-action) +## 1.2.4(2021-08-20) +- 优化 close-all 方法 +## 1.2.3(2021-08-20) +- 新增 close-all 方法,关闭所有已打开的组件 +## 1.2.2(2021-08-17) +- 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件 +- 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 +- 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题 +## 1.2.1(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +- 修复 跨页面修改组件数据 ,导致不能滑动的问题 +## 1.1.10(2021-06-17) +- 修复 按钮点击执行两次的bug +## 1.1.9(2021-05-12) +- 新增 项目示例地址 +## 1.1.8(2021-03-26) +- 修复 微信小程序 nv_navigator is not defined 报错的bug +## 1.1.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 左侧滑动 +- 新增 插槽使用方式 +- 新增 threshold 属性,可以控制滑动缺省值 +- 优化 长列表滚动性能 +- 修复 滚动页面时触发组件滑动的Bug diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js new file mode 100644 index 0000000..caa34a6 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js @@ -0,0 +1,302 @@ +let bindIngXMixins = {} + +// #ifdef APP-NVUE +const BindingX = uni.requireNativePlugin('bindingx'); +const dom = uni.requireNativePlugin('dom'); +const animation = uni.requireNativePlugin('animation'); + +bindIngXMixins = { + data() { + return {} + }, + + watch: { + show(newVal) { + if (this.autoClose) return + if (this.stop) return + this.stop = true + if (newVal) { + this.open(newVal) + } else { + this.close() + } + }, + leftOptions() { + this.getSelectorQuery() + this.init() + }, + rightOptions(newVal) { + this.init() + } + }, + created() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.box = this.getEl(this.$refs['selector-box--hock']) + this.selector = this.getEl(this.$refs['selector-content--hock']); + this.leftButton = this.getEl(this.$refs['selector-left-button--hock']); + this.rightButton = this.getEl(this.$refs['selector-right-button--hock']); + this.init() + }, + // beforeDestroy() { + // this.swipeaction.children.forEach((item, index) => { + // if (item === this) { + // this.swipeaction.children.splice(index, 1) + // } + // }) + // }, + methods: { + init() { + this.$nextTick(() => { + this.x = 0 + this.button = { + show: false + } + setTimeout(() => { + this.getSelectorQuery() + }, 200) + }) + }, + onClick(index, item, position) { + this.$emit('click', { + content: item, + index, + position + }) + }, + touchstart(e) { + // fix by mehaotian 禁止滑动 + if (this.disabled) return + // 每次只触发一次,避免多次监听造成闪烁 + if (this.stop) return + this.stop = true + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + let expression = this.range(this.x, -rightWidth, leftWidth) + let leftExpression = this.range(this.x - leftWidth, -leftWidth, 0) + let rightExpression = this.range(this.x + rightWidth, 0, rightWidth) + + this.eventpan = BindingX.bind({ + anchor: this.box, + eventType: 'pan', + props: [{ + element: this.selector, + property: 'transform.translateX', + expression + }, { + element: this.leftButton, + property: 'transform.translateX', + expression: leftExpression + }, { + element: this.rightButton, + property: 'transform.translateX', + expression: rightExpression + }, ] + }, (e) => { + // nope + if (e.state === 'end') { + this.x = e.deltaX + this.x; + this.isclick = true + this.bindTiming(e.deltaX) + } + }); + }, + touchend(e) { + if (this.isopen !== 'none' && !this.isclick) { + this.open('none') + } + }, + bindTiming(x) { + const left = this.x + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + const threshold = this.threshold + if (!this.isopen || this.isopen === 'none') { + if (left > threshold) { + this.open('left') + } else if (left < -threshold) { + this.open('right') + } else { + this.open('none') + } + } else { + if ((x > -leftWidth && x < 0) || x > rightWidth) { + if ((x > -threshold && x < 0) || (x - rightWidth > threshold)) { + this.open('left') + } else { + this.open('none') + } + } else { + if ((x < threshold && x > 0) || (x + leftWidth < -threshold)) { + this.open('right') + } else { + this.open('none') + } + } + } + }, + + /** + * 移动范围 + * @param {Object} num + * @param {Object} mix + * @param {Object} max + */ + range(num, mix, max) { + return `min(max(x+${num}, ${mix}), ${max})` + }, + + /** + * 开启swipe + */ + open(type) { + this.animation(type) + }, + + /** + * 关闭swipe + */ + close() { + this.animation('none') + }, + + /** + * 开启关闭动画 + * @param {Object} type + */ + animation(type) { + const time = 300 + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + if (this.eventpan && this.eventpan.token) { + BindingX.unbind({ + token: this.eventpan.token, + eventType: 'pan' + }) + } + + switch (type) { + case 'left': + Promise.all([ + this.move(this.selector, leftWidth), + this.move(this.leftButton, 0), + this.move(this.rightButton, rightWidth * 2) + ]).then(() => { + this.setEmit(leftWidth, type) + }) + break + case 'right': + Promise.all([ + this.move(this.selector, -rightWidth), + this.move(this.leftButton, -leftWidth * 2), + this.move(this.rightButton, 0) + ]).then(() => { + this.setEmit(-rightWidth, type) + }) + break + default: + Promise.all([ + this.move(this.selector, 0), + this.move(this.leftButton, -leftWidth), + this.move(this.rightButton, rightWidth) + ]).then(() => { + this.setEmit(0, type) + }) + + } + }, + setEmit(x, type) { + const leftWidth = this.button.left.width + const rightWidth = this.button.right.width + this.isopen = this.isopen || 'none' + this.stop = false + this.isclick = false + // 只有状态不一致才会返回结果 + if (this.isopen !== type && this.x !== x) { + if (type === 'left' && leftWidth > 0) { + this.$emit('change', 'left') + } + if (type === 'right' && rightWidth > 0) { + this.$emit('change', 'right') + } + if (type === 'none') { + this.$emit('change', 'none') + } + } + this.x = x + this.isopen = type + }, + move(ref, value) { + return new Promise((resolve, reject) => { + animation.transition(ref, { + styles: { + transform: `translateX(${value})`, + }, + duration: 150, //ms + timingFunction: 'linear', + needLayout: false, + delay: 0 //ms + }, function(res) { + resolve(res) + }) + }) + + }, + + /** + * 获取ref + * @param {Object} el + */ + getEl(el) { + return el.ref + }, + /** + * 获取节点信息 + */ + getSelectorQuery() { + Promise.all([ + this.getDom('left'), + this.getDom('right'), + ]).then((data) => { + let show = 'none' + if (this.autoClose) { + show = 'none' + } else { + show = this.show + } + + if (show === 'none') { + // this.close() + } else { + this.open(show) + } + + }) + + }, + getDom(str) { + return new Promise((resolve, reject) => { + dom.getComponentRect(this.$refs[`selector-${str}-button--hock`], (data) => { + if (data) { + this.button[str] = data.size + resolve(data) + } else { + reject() + } + }) + }) + } + } +} + +// #endif + +export default bindIngXMixins diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs new file mode 100644 index 0000000..886bc75 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/index.wxs @@ -0,0 +1,323 @@ +var MIN_DISTANCE = 10; + +/** + * 判断当前是否为H5、app-vue + */ +var IS_HTML5 = false +if (typeof window === 'object') IS_HTML5 = true + +/** + * 监听页面内值的变化,主要用于动态开关swipe-action + * @param {Object} newValue + * @param {Object} oldValue + * @param {Object} ownerInstance + * @param {Object} instance + */ +function sizeReady(newValue, oldValue, ownerInstance, instance) { + var state = instance.getState() + var buttonPositions = JSON.parse(newValue) + if (!buttonPositions || !buttonPositions.data || buttonPositions.data.length === 0) return + state.leftWidth = buttonPositions.data[0].width + state.rightWidth = buttonPositions.data[1].width + state.threshold = instance.getDataset().threshold + + if (buttonPositions.show && buttonPositions.show !== 'none') { + openState(buttonPositions.show, instance, ownerInstance) + return + } + + if (state.left) { + openState('none', instance, ownerInstance) + } + resetTouchStatus(instance) +} + +/** + * 开始触摸操作 + * @param {Object} e + * @param {Object} ins + */ +function touchstart(e, ins) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState(); + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 开始触摸时移除动画类 + instance.requestAnimationFrame(function() { + instance.removeClass('ani'); + ins.callMethod('closeSwipe'); + }) + + // 记录上次的位置 + state.x = state.left || 0 + // 计算滑动开始位置 + stopTouchStart(e, ins) +} + +/** + * 开始滑动操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchmove(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 是否可以滑动页面 + stopTouchMove(e); + if (state.direction !== 'horizontal') { + return; + } + + if (e.preventDefault) { + // 阻止页面滚动 + e.preventDefault() + } + + move(state.x + state.deltaX, instance, ownerInstance) +} + +/** + * 结束触摸操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchend(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + + if (disabled) return + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 + moveDirection(state.left, instance, ownerInstance) + +} + +/** + * 设置移动距离 + * @param {Object} value + * @param {Object} instance + * @param {Object} ownerInstance + */ +function move(value, instance, ownerInstance) { + value = value || 0 + var state = instance.getState() + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + // 获取可滑动范围 + state.left = range(value, -rightWidth, leftWidth); + instance.requestAnimationFrame(function() { + instance.setStyle({ + transform: 'translateX(' + state.left + 'px)', + '-webkit-transform': 'translateX(' + state.left + 'px)' + }) + }) + +} + +/** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ +function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} + + +/** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + * @param {Object} ownerInstance + * @param {Object} ins + */ +function moveDirection(left, ins, ownerInstance) { + var state = ins.getState() + var threshold = state.threshold + var position = state.position + var isopen = state.isopen || 'none' + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + if (state.deltaX === 0) { + openState('none', ins, ownerInstance) + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && + rightWidth + + left < threshold)) { + // right + openState('right', ins, ownerInstance) + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 && + leftWidth - left < threshold)) { + // left + openState('left', ins, ownerInstance) + } else { + // default + openState('none', ins, ownerInstance) + } +} + + +/** + * 开启状态 + * @param {Boolean} type + * @param {Object} ins + * @param {Object} ownerInstance + */ +function openState(type, ins, ownerInstance) { + var state = ins.getState() + var position = state.position + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + var left = '' + state.isopen = state.isopen ? state.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + // && !state.throttle + + if (state.isopen !== type) { + state.throttle = true + ownerInstance.callMethod('change', { + open: type + }) + + } + + state.isopen = type + // 添加动画类 + ins.requestAnimationFrame(function() { + ins.addClass('ani'); + move(left, ins, ownerInstance) + }) + // 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的 +} + + +function getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} + +/** + * 重置滑动状态 + * @param {Object} event + */ +function resetTouchStatus(instance) { + var state = instance.getState(); + state.direction = ''; + state.deltaX = 0; + state.deltaY = 0; + state.offsetX = 0; + state.offsetY = 0; +} + +/** + * 设置滑动开始位置 + * @param {Object} event + */ +function stopTouchStart(event) { + var instance = event.instance; + var state = instance.getState(); + resetTouchStatus(instance); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.startX = touch.clientX; + state.startY = touch.clientY; +} + +/** + * 滑动中,是否禁止打开 + * @param {Object} event + */ +function stopTouchMove(event) { + var instance = event.instance; + var state = instance.getState(); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.deltaX = touch.clientX - state.startX; + state.deltaY = touch.clientY - state.startY; + state.offsetY = Math.abs(state.deltaY); + state.offsetX = Math.abs(state.deltaX); + state.direction = state.direction || getDirection(state.offsetX, state.offsetY); +} + +function isPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (var v = 0; v < Agents.length - 1; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} + +var movable = false + +function mousedown(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchstart(e, ins) + movable = true +} + +function mousemove(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + if (!movable) return + touchmove(e, ins) +} + +function mouseup(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchend(e, ins) + movable = false +} + +function mouseleave(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + movable = false +} + +module.exports = { + sizeReady: sizeReady, + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + mousedown: mousedown, + mousemove: mousemove, + mouseup: mouseup, + mouseleave: mouseleave +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js new file mode 100644 index 0000000..e7ea284 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js @@ -0,0 +1,12 @@ +export function isPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (let v = 0; v < Agents.length - 1; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js new file mode 100644 index 0000000..6e5ad7c --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js @@ -0,0 +1,195 @@ +export default { + data() { + return { + x: 0, + transition: false, + width: 0, + viewWidth: 0, + swipeShow: 0 + } + }, + watch: { + show(newVal) { + if (this.autoClose) return + if (newVal && newVal !== 'none') { + this.transition = true + this.open(newVal) + } else { + this.close() + } + } + }, + created() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.isopen = false + setTimeout(() => { + this.getQuerySelect() + }, 50) + }, + methods: { + appTouchStart(e) { + const { + clientX + } = e.changedTouches[0] + this.clientX = clientX + this.timestamp = new Date().getTime() + }, + appTouchEnd(e, index, item, position) { + const { + clientX + } = e.changedTouches[0] + // fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题 + let diff = Math.abs(this.clientX - clientX) + let time = (new Date().getTime()) - this.timestamp + if (diff < 40 && time < 300) { + this.$emit('click', { + content: item, + index, + position + }) + } + }, + /** + * 移动触发 + * @param {Object} e + */ + onChange(e) { + this.moveX = e.detail.x + this.isclose = false + }, + touchstart(e) { + this.transition = false + this.isclose = true + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + }, + touchmove(e) {}, + touchend(e) { + // 0的位置什么都不执行 + if (this.isclose && this.isopen === 'none') return + if (this.isclose && this.isopen !== 'none') { + this.transition = true + this.close() + } else { + this.move(this.moveX + this.leftWidth) + } + }, + + /** + * 移动 + * @param {Object} moveX + */ + move(moveX) { + // 打开关闭的处理逻辑不太一样 + this.transition = true + // 未打开状态 + if (!this.isopen || this.isopen === 'none') { + if (moveX > this.threshold) { + this.open('left') + } else if (moveX < -this.threshold) { + this.open('right') + } else { + this.close() + } + } else { + if (moveX < 0 && moveX < this.rightWidth) { + const rightX = this.rightWidth + moveX + if (rightX < this.threshold) { + this.open('right') + } else { + this.close() + } + } else if (moveX > 0 && moveX < this.leftWidth) { + const leftX = this.leftWidth - moveX + if (leftX < this.threshold) { + this.open('left') + } else { + this.close() + } + } + + } + + }, + + /** + * 打开 + */ + open(type) { + this.x = this.moveX + this.animation(type) + }, + + /** + * 关闭 + */ + close() { + this.x = this.moveX + // TODO 解决 x 值不更新的问题,所以会多触发一次 nextTick ,待优化 + this.$nextTick(() => { + this.x = -this.leftWidth + if (this.isopen !== 'none') { + this.$emit('change', 'none') + } + this.isopen = 'none' + }) + }, + + /** + * 执行结束动画 + * @param {Object} type + */ + animation(type) { + this.$nextTick(() => { + if (type === 'left') { + this.x = 0 + } else { + this.x = -this.rightWidth - this.leftWidth + } + + if (this.isopen !== type) { + this.$emit('change', type) + } + this.isopen = type + }) + + }, + getSlide(x) {}, + getQuerySelect() { + const query = uni.createSelectorQuery().in(this); + query.selectAll('.movable-view--hock').boundingClientRect(data => { + this.leftWidth = data[1].width + this.rightWidth = data[2].width + this.width = data[0].width + this.viewWidth = this.width + this.rightWidth + this.leftWidth + if (this.leftWidth === 0) { + // TODO 疑似bug ,初始化的时候如果x 是0,会导致移动位置错误,所以让元素超出一点 + this.x = -0.1 + } else { + this.x = -this.leftWidth + } + this.moveX = this.x + this.$nextTick(() => { + this.swipeShow = 1 + }) + + if (!this.buttonWidth) { + this.disabledView = true + } + + if (this.autoClose) return + if (this.show !== 'none') { + this.transition = true + this.open(this.shows) + } + }).exec(); + + } + } +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js new file mode 100644 index 0000000..7d1702e --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js @@ -0,0 +1,260 @@ +let otherMixins = {} + +// #ifndef APP-PLUS|| MP-WEIXIN || H5 +const MIN_DISTANCE = 10; +otherMixins = { + data() { + // TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug + const elClass = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}` + return { + uniShow: false, + left: 0, + buttonShow: 'none', + ani: false, + moveLeft: '', + elClass + } + }, + watch: { + show(newVal) { + if (this.autoClose) return + this.openState(newVal) + }, + left() { + this.moveLeft = `translateX(${this.left}px)` + }, + buttonShow(newVal) { + if (this.autoClose) return + this.openState(newVal) + }, + leftOptions() { + this.init() + }, + rightOptions() { + this.init() + } + }, + mounted() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + this.init() + }, + methods: { + init() { + clearTimeout(this.timer) + this.timer = setTimeout(() => { + this.getSelectorQuery() + }, 100) + // 移动距离 + this.left = 0 + this.x = 0 + }, + + closeSwipe(e) { + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + }, + appTouchStart(e) { + const { + clientX + } = e.changedTouches[0] + this.clientX = clientX + this.timestamp = new Date().getTime() + }, + appTouchEnd(e, index, item, position) { + const { + clientX + } = e.changedTouches[0] + // fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题 + let diff = Math.abs(this.clientX - clientX) + let time = (new Date().getTime()) - this.timestamp + if (diff < 40 && time < 300) { + this.$emit('click', { + content: item, + index, + position + }) + } + }, + touchstart(e) { + if (this.disabled) return + this.ani = false + this.x = this.left || 0 + this.stopTouchStart(e) + this.autoClose && this.closeSwipe() + }, + touchmove(e) { + if (this.disabled) return + // 是否可以滑动页面 + this.stopTouchMove(e); + if (this.direction !== 'horizontal') { + return; + } + this.move(this.x + this.deltaX) + return false + }, + touchend() { + if (this.disabled) return + this.moveDirection(this.left) + }, + /** + * 设置移动距离 + * @param {Object} value + */ + move(value) { + value = value || 0 + const leftWidth = this.leftWidth + const rightWidth = this.rightWidth + // 获取可滑动范围 + this.left = this.range(value, -rightWidth, leftWidth); + }, + + /** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ + range(num, min, max) { + return Math.min(Math.max(num, min), max); + }, + /** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + */ + moveDirection(left) { + const threshold = this.threshold + const isopen = this.isopen || 'none' + const leftWidth = this.leftWidth + const rightWidth = this.rightWidth + if (this.deltaX === 0) { + this.openState('none') + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > + 0 && rightWidth + + left < threshold)) { + // right + this.openState('right') + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > + 0 && + leftWidth - left < threshold)) { + // left + this.openState('left') + } else { + // default + this.openState('none') + } + }, + + /** + * 开启状态 + * @param {Boolean} type + */ + openState(type) { + const leftWidth = this.leftWidth + const rightWidth = this.rightWidth + let left = '' + this.isopen = this.isopen ? this.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + + if (this.isopen !== type) { + this.throttle = true + this.$emit('change', type) + } + + this.isopen = type + // 添加动画类 + this.ani = true + this.$nextTick(() => { + this.move(left) + }) + // 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的 + }, + close() { + this.openState('none') + }, + getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; + }, + + /** + * 重置滑动状态 + * @param {Object} event + */ + resetTouchStatus() { + this.direction = ''; + this.deltaX = 0; + this.deltaY = 0; + this.offsetX = 0; + this.offsetY = 0; + }, + + /** + * 设置滑动开始位置 + * @param {Object} event + */ + stopTouchStart(event) { + this.resetTouchStatus(); + const touch = event.touches[0]; + this.startX = touch.clientX; + this.startY = touch.clientY; + }, + + /** + * 滑动中,是否禁止打开 + * @param {Object} event + */ + stopTouchMove(event) { + const touch = event.touches[0]; + this.deltaX = touch.clientX - this.startX; + this.deltaY = touch.clientY - this.startY; + this.offsetX = Math.abs(this.deltaX); + this.offsetY = Math.abs(this.deltaY); + this.direction = this.direction || this.getDirection(this.offsetX, this.offsetY); + }, + + getSelectorQuery() { + const views = uni.createSelectorQuery().in(this) + views + .selectAll('.' + this.elClass) + .boundingClientRect(data => { + if (data.length === 0) return + let show = 'none' + if (this.autoClose) { + show = 'none' + } else { + show = this.show + } + this.leftWidth = data[0].width || 0 + this.rightWidth = data[1].width || 0 + this.buttonShow = show + }) + .exec() + } + } +} + +// #endif + +export default otherMixins diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js new file mode 100644 index 0000000..bfea96e --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js @@ -0,0 +1,84 @@ +let mpMixins = {} +let is_pc = null +// #ifdef H5 +import { + isPC +} from "./isPC" +is_pc = isPC() +// #endif +// #ifdef APP-VUE || APP-HARMONY || MP-WEIXIN || H5 + +mpMixins = { + data() { + return { + is_show: 'none' + } + }, + watch: { + show(newVal) { + this.is_show = this.show + } + }, + created() { + this.swipeaction = this.getSwipeAction() + if (this.swipeaction && Array.isArray(this.swipeaction.children)) { + this.swipeaction.children.push(this) + } + }, + mounted() { + this.is_show = this.show + }, + methods: { + // wxs 中调用 + closeSwipe(e) { + if (this.autoClose && this.swipeaction) { + this.swipeaction.closeOther(this) + } + }, + + change(e) { + this.$emit('change', e.open) + if (this.is_show !== e.open) { + this.is_show = e.open + } + }, + + appTouchStart(e) { + if (is_pc) return + const { + clientX + } = e.changedTouches[0] + this.clientX = clientX + this.timestamp = new Date().getTime() + }, + appTouchEnd(e, index, item, position) { + if (is_pc) return + const { + clientX + } = e.changedTouches[0] + // fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题 + let diff = Math.abs(this.clientX - clientX) + let time = (new Date().getTime()) - this.timestamp + if (diff < 40 && time < 300) { + this.$emit('click', { + content: item, + index, + position + }) + } + }, + onClickForPC(index, item, position) { + if (!is_pc) return + // #ifdef H5 + this.$emit('click', { + content: item, + index, + position + }) + // #endif + } + } +} + +// #endif +export default mpMixins diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js new file mode 100644 index 0000000..2fb81a4 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js @@ -0,0 +1,277 @@ +const MIN_DISTANCE = 10; +export default { + showWatch(newVal, oldVal, ownerInstance, instance, self) { + var state = self.state || {} + var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el + if (!$el) return + this.getDom(instance, ownerInstance, self) + if (newVal && newVal !== 'none') { + this.openState(newVal, instance, ownerInstance, self) + return + } + + if (state.left) { + this.openState('none', instance, ownerInstance, self) + } + this.resetTouchStatus(instance, self) + }, + + /** + * 开始触摸操作 + * @param {Object} e + * @param {Object} ins + */ + touchstart(e, ownerInstance, self) { + let instance = e.instance; + let disabled = instance.getDataset().disabled + let state = self.state || {}; + this.getDom(instance, ownerInstance, self) + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = this.getDisabledType(disabled) + if (disabled) return + // 开始触摸时移除动画类 + instance.requestAnimationFrame(function() { + instance.removeClass('ani'); + ownerInstance.callMethod('closeSwipe'); + }) + + // 记录上次的位置 + state.x = state.left || 0 + // 计算滑动开始位置 + this.stopTouchStart(e, ownerInstance, self) + }, + + /** + * 开始滑动操作 + * @param {Object} e + * @param {Object} ownerInstance + */ + touchmove(e, ownerInstance, self) { + let instance = e.instance; + // 删除之后已经那不到实例了 + if (!instance) return; + let disabled = instance.getDataset().disabled + let state = self.state || {} + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = this.getDisabledType(disabled) + if (disabled) return + // 是否可以滑动页面 + this.stopTouchMove(e, self); + if (state.direction !== 'horizontal') { + return; + } + if (e.preventDefault) { + // 阻止页面滚动 + e.preventDefault() + } + let x = state.x + state.deltaX + this.move(x, instance, ownerInstance, self) + }, + + /** + * 结束触摸操作 + * @param {Object} e + * @param {Object} ownerInstance + */ + touchend(e, ownerInstance, self) { + let instance = e.instance; + let disabled = instance.getDataset().disabled + let state = self.state || {} + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = this.getDisabledType(disabled) + + if (disabled) return + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 + this.moveDirection(state.left, instance, ownerInstance, self) + + }, + + /** + * 设置移动距离 + * @param {Object} value + * @param {Object} instance + * @param {Object} ownerInstance + */ + move(value, instance, ownerInstance, self) { + value = value || 0 + let state = self.state || {} + let leftWidth = state.leftWidth + let rightWidth = state.rightWidth + // 获取可滑动范围 + state.left = this.range(value, -rightWidth, leftWidth); + instance.requestAnimationFrame(function() { + instance.setStyle({ + transform: 'translateX(' + state.left + 'px)', + '-webkit-transform': 'translateX(' + state.left + 'px)' + }) + }) + + }, + + /** + * 获取元素信息 + * @param {Object} instance + * @param {Object} ownerInstance + */ + getDom(instance, ownerInstance, self) { + var state = self.state || {} + var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el + var leftDom = $el.querySelector('.button-group--left') + var rightDom = $el.querySelector('.button-group--right') + if (leftDom && leftDom.offsetWidth) { + state.leftWidth = leftDom.offsetWidth || 0 + } else { + state.leftWidth = 0 + } + if (rightDom && rightDom.offsetWidth) { + state.rightWidth = rightDom.offsetWidth || 0 + } else { + state.rightWidth = 0 + } + state.threshold = instance.getDataset().threshold + }, + + getDisabledType(value) { + return (typeof(value) === 'string' ? JSON.parse(value) : value) || false; + }, + + /** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ + range(num, min, max) { + return Math.min(Math.max(num, min), max); + }, + + + /** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + * @param {Object} ownerInstance + * @param {Object} ins + */ + moveDirection(left, ins, ownerInstance, self) { + var state = self.state || {} + var threshold = state.threshold + var position = state.position + var isopen = state.isopen || 'none' + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + if (state.deltaX === 0) { + this.openState('none', ins, ownerInstance, self) + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && + rightWidth + + left < threshold)) { + // right + this.openState('right', ins, ownerInstance, self) + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 && + leftWidth - left < threshold)) { + // left + this.openState('left', ins, ownerInstance, self) + } else { + // default + this.openState('none', ins, ownerInstance, self) + } + }, + + + /** + * 开启状态 + * @param {Boolean} type + * @param {Object} ins + * @param {Object} ownerInstance + */ + openState(type, ins, ownerInstance, self) { + let state = self.state || {} + let leftWidth = state.leftWidth + let rightWidth = state.rightWidth + let left = '' + state.isopen = state.isopen ? state.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + // && !state.throttle + + if (state.isopen !== type) { + state.throttle = true + ownerInstance.callMethod('change', { + open: type + }) + + } + + state.isopen = type + // 添加动画类 + ins.requestAnimationFrame(() => { + ins.addClass('ani'); + this.move(left, ins, ownerInstance, self) + }) + }, + + + getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; + }, + + /** + * 重置滑动状态 + * @param {Object} event + */ + resetTouchStatus(instance, self) { + let state = self.state || {}; + state.direction = ''; + state.deltaX = 0; + state.deltaY = 0; + state.offsetX = 0; + state.offsetY = 0; + }, + + /** + * 设置滑动开始位置 + * @param {Object} event + */ + stopTouchStart(event, ownerInstance, self) { + let instance = event.instance; + let state = self.state || {} + this.resetTouchStatus(instance, self); + var touch = event.touches[0]; + state.startX = touch.clientX; + state.startY = touch.clientY; + }, + + /** + * 滑动中,是否禁止打开 + * @param {Object} event + */ + stopTouchMove(event, self) { + let instance = event.instance; + let state = self.state || {}; + let touch = event.touches[0]; + + state.deltaX = touch.clientX - state.startX; + state.deltaY = touch.clientY - state.startY; + state.offsetY = Math.abs(state.deltaY); + state.offsetX = Math.abs(state.deltaX); + state.direction = state.direction || this.getDirection(state.offsetX, state.offsetY); + } +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue new file mode 100644 index 0000000..a62c95b --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue @@ -0,0 +1,348 @@ + + + + + + diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs new file mode 100644 index 0000000..c5bc1f8 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs @@ -0,0 +1,346 @@ +var MIN_DISTANCE = 10; + +/** + * 判断当前是否为H5、app-vue + */ +var IS_HTML5 = false +if (typeof window === 'object') IS_HTML5 = true + +/** + * 监听页面内值的变化,主要用于动态开关swipe-action + * @param {Object} newValue + * @param {Object} oldValue + * @param {Object} ownerInstance + * @param {Object} instance + */ +function showWatch(newVal, oldVal, ownerInstance, instance) { + var state = instance.getState() + getDom(instance, ownerInstance) + if (newVal && newVal !== 'none') { + openState(newVal, instance, ownerInstance) + return + } + + if (state.left) { + openState('none', instance, ownerInstance) + } + resetTouchStatus(instance) +} + +/** + * 开始触摸操作 + * @param {Object} e + * @param {Object} ins + */ +function touchstart(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState(); + getDom(instance, ownerInstance) + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 开始触摸时移除动画类 + instance.requestAnimationFrame(function() { + instance.removeClass('ani'); + ownerInstance.callMethod('closeSwipe'); + }) + + // 记录上次的位置 + state.x = state.left || 0 + // 计算滑动开始位置 + stopTouchStart(e, ownerInstance) +} + +/** + * 开始滑动操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchmove(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + if (disabled) return + // 是否可以滑动页面 + stopTouchMove(e); + if (state.direction !== 'horizontal') { + return; + } + + if (e.preventDefault) { + // 阻止页面滚动 + e.preventDefault() + } + + move(state.x + state.deltaX, instance, ownerInstance) +} + +/** + * 结束触摸操作 + * @param {Object} e + * @param {Object} ownerInstance + */ +function touchend(e, ownerInstance) { + var instance = e.instance; + var disabled = instance.getDataset().disabled + var state = instance.getState() + // fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复 + disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false; + + if (disabled) return + // 滑动过程中触摸结束,通过阙值判断是开启还是关闭 + // fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13 + moveDirection(state.left, instance, ownerInstance) + +} + +/** + * 设置移动距离 + * @param {Object} value + * @param {Object} instance + * @param {Object} ownerInstance + */ +function move(value, instance, ownerInstance) { + value = value || 0 + var state = instance.getState() + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + // 获取可滑动范围 + state.left = range(value, -rightWidth, leftWidth); + instance.requestAnimationFrame(function() { + instance.setStyle({ + transform: 'translateX(' + state.left + 'px)', + '-webkit-transform': 'translateX(' + state.left + 'px)' + }) + }) + +} + +/** + * 获取元素信息 + * @param {Object} instance + * @param {Object} ownerInstance + */ +function getDom(instance, ownerInstance) { + var state = instance.getState() + var leftDom = ownerInstance.selectComponent('.button-group--left') + var rightDom = ownerInstance.selectComponent('.button-group--right') + var leftStyles = { + width: 0 + } + var rightStyles = { + width: 0 + } + + if (leftDom) { + leftStyles = leftDom.getBoundingClientRect() + } + + if (rightDom) { + rightStyles = rightDom.getBoundingClientRect() + } + state.leftWidth = leftStyles.width || 0 + state.rightWidth = rightStyles.width || 0 + state.threshold = instance.getDataset().threshold +} + +/** + * 获取范围 + * @param {Object} num + * @param {Object} min + * @param {Object} max + */ +function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} + + +/** + * 移动方向判断 + * @param {Object} left + * @param {Object} value + * @param {Object} ownerInstance + * @param {Object} ins + */ +function moveDirection(left, ins, ownerInstance) { + var state = ins.getState() + var threshold = state.threshold + var position = state.position + var isopen = state.isopen || 'none' + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + if (state.deltaX === 0) { + openState('none', ins, ownerInstance) + return + } + if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && + rightWidth + + left < threshold)) { + // right + openState('right', ins, ownerInstance) + } else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 && + leftWidth - left < threshold)) { + // left + openState('left', ins, ownerInstance) + } else { + // default + openState('none', ins, ownerInstance) + } +} + + +/** + * 开启状态 + * @param {Boolean} type + * @param {Object} ins + * @param {Object} ownerInstance + */ +function openState(type, ins, ownerInstance) { + var state = ins.getState() + var leftWidth = state.leftWidth + var rightWidth = state.rightWidth + var left = '' + state.isopen = state.isopen ? state.isopen : 'none' + switch (type) { + case "left": + left = leftWidth + break + case "right": + left = -rightWidth + break + default: + left = 0 + } + + // && !state.throttle + + if (state.isopen !== type) { + state.throttle = true + ownerInstance.callMethod('change', { + open: type + }) + + } + + state.isopen = type + // 添加动画类 + ins.requestAnimationFrame(function() { + ins.addClass('ani'); + move(left, ins, ownerInstance) + }) + // 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的 +} + + +function getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} + +/** + * 重置滑动状态 + * @param {Object} event + */ +function resetTouchStatus(instance) { + var state = instance.getState(); + state.direction = ''; + state.deltaX = 0; + state.deltaY = 0; + state.offsetX = 0; + state.offsetY = 0; +} + +/** + * 设置滑动开始位置 + * @param {Object} event + */ +function stopTouchStart(event) { + var instance = event.instance; + var state = instance.getState(); + resetTouchStatus(instance); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.startX = touch.clientX; + state.startY = touch.clientY; +} + +/** + * 滑动中,是否禁止打开 + * @param {Object} event + */ +function stopTouchMove(event) { + var instance = event.instance; + var state = instance.getState(); + var touch = event.touches[0]; + if (IS_HTML5 && isPC()) { + touch = event; + } + state.deltaX = touch.clientX - state.startX; + state.deltaY = touch.clientY - state.startY; + state.offsetY = Math.abs(state.deltaY); + state.offsetX = Math.abs(state.deltaX); + state.direction = state.direction || getDirection(state.offsetX, state.offsetY); +} + +function isPC() { + var userAgentInfo = navigator.userAgent; + var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]; + var flag = true; + for (var v = 0; v < Agents.length - 1; v++) { + if (userAgentInfo.indexOf(Agents[v]) > 0) { + flag = false; + break; + } + } + return flag; +} + +var movable = false + +function mousedown(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchstart(e, ins) + movable = true +} + +function mousemove(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + if (!movable) return + touchmove(e, ins) +} + +function mouseup(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + touchend(e, ins) + movable = false +} + +function mouseleave(e, ins) { + if (!IS_HTML5) return + if (!isPC()) return + movable = false +} + +module.exports = { + showWatch: showWatch, + touchstart: touchstart, + touchmove: touchmove, + touchend: touchend, + mousedown: mousedown, + mousemove: mousemove, + mouseup: mouseup, + mouseleave: mouseleave +} diff --git a/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue b/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue new file mode 100644 index 0000000..87e5572 --- /dev/null +++ b/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/uni_modules/uni-swipe-action/package.json b/uni_modules/uni-swipe-action/package.json new file mode 100644 index 0000000..9eeb5bc --- /dev/null +++ b/uni_modules/uni-swipe-action/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-swipe-action", + "displayName": "uni-swipe-action 滑动操作", + "version": "1.3.13", + "description": "SwipeAction 滑动操作操作组件", + "keywords": [ + "", + "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", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-harmony": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "y", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-swipe-action/readme.md b/uni_modules/uni-swipe-action/readme.md new file mode 100644 index 0000000..c8f8c53 --- /dev/null +++ b/uni_modules/uni-swipe-action/readme.md @@ -0,0 +1,11 @@ + + +## SwipeAction 滑动操作 +> **组件名:uni-swipe-action** +> 代码块: `uSwipeAction`、`uSwipeActionItem` + + +通过滑动触发选项的容器 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-swipe-action) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-swiper-dot/changelog.md b/uni_modules/uni-swiper-dot/changelog.md new file mode 100644 index 0000000..ca5ef1c --- /dev/null +++ b/uni_modules/uni-swiper-dot/changelog.md @@ -0,0 +1,12 @@ +## 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-swiper-dot](https://uniapp.dcloud.io/component/uniui/uni-swiper-dot) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.6(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的Bug +## 1.0.5(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 clickItem 事件,支持指示点控制轮播 +- 新增 支持 pc 可用 diff --git a/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue b/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue new file mode 100644 index 0000000..c0725a4 --- /dev/null +++ b/uni_modules/uni-swiper-dot/components/uni-swiper-dot/uni-swiper-dot.vue @@ -0,0 +1,218 @@ + + + + + diff --git a/uni_modules/uni-swiper-dot/package.json b/uni_modules/uni-swiper-dot/package.json new file mode 100644 index 0000000..b9b126a --- /dev/null +++ b/uni_modules/uni-swiper-dot/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-swiper-dot", + "displayName": "uni-swiper-dot 轮播图指示点", + "version": "1.2.0", + "description": "自定义轮播图指示点组件", + "keywords": [ + "uni-ui", + "uniui", + "轮播图指示点", + "dot", + "swiper" +], + "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-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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-swiper-dot/readme.md b/uni_modules/uni-swiper-dot/readme.md new file mode 100644 index 0000000..badf99b --- /dev/null +++ b/uni_modules/uni-swiper-dot/readme.md @@ -0,0 +1,11 @@ + + +## SwiperDot 轮播图指示点 +> **组件名:uni-swiper-dot** +> 代码块: `uSwiperDot` + + +自定义轮播图指示点 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-swiper-dot) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-table/changelog.md b/uni_modules/uni-table/changelog.md new file mode 100644 index 0000000..3495e0f --- /dev/null +++ b/uni_modules/uni-table/changelog.md @@ -0,0 +1,33 @@ +## 1.2.8(2024-10-15) +- 修复 运行到抖音小程序上出现的问题 +## 1.2.7(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.2.4(2023-12-19) +- 修复 uni-tr只有一列时minWidth计算错误,列变化实时计算更新 +## 1.2.3(2023-03-28) +- 修复 在vue3模式下可能会出现错误的问题 +## 1.2.2(2022-11-29) +- 优化 主题样式 +## 1.2.1(2022-06-06) +- 修复 微信小程序存在无使用组件的问题 +## 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-table](https://uniapp.dcloud.io/component/uniui/uni-table) +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-07-08) +- 新增 uni-th 支持 date 日期筛选范围 +## 1.0.6(2021-07-05) +- 新增 uni-th 支持 range 筛选范围 +## 1.0.5(2021-06-28) +- 新增 uni-th 筛选功能 +## 1.0.4(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的Bug +## 1.0.3(2021-04-16) +- 新增 sortable 属性,是否开启单列排序 +- 优化 表格多选逻辑 +## 1.0.2(2021-03-22) +- uni-tr 添加 disabled 属性,用于 type=selection 时,设置某行是否可由全选按钮控制 +## 1.0.1(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-table/components/uni-table/uni-table.vue b/uni_modules/uni-table/components/uni-table/uni-table.vue new file mode 100644 index 0000000..b37e067 --- /dev/null +++ b/uni_modules/uni-table/components/uni-table/uni-table.vue @@ -0,0 +1,460 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue b/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue new file mode 100644 index 0000000..d7cb129 --- /dev/null +++ b/uni_modules/uni-table/components/uni-tbody/uni-tbody.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-td/uni-td.vue b/uni_modules/uni-table/components/uni-td/uni-td.vue new file mode 100644 index 0000000..0f01f65 --- /dev/null +++ b/uni_modules/uni-table/components/uni-td/uni-td.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-th/filter-dropdown.vue b/uni_modules/uni-table/components/uni-th/filter-dropdown.vue new file mode 100644 index 0000000..add1098 --- /dev/null +++ b/uni_modules/uni-table/components/uni-th/filter-dropdown.vue @@ -0,0 +1,511 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-th/uni-th.vue b/uni_modules/uni-table/components/uni-th/uni-th.vue new file mode 100644 index 0000000..d2c27c3 --- /dev/null +++ b/uni_modules/uni-table/components/uni-th/uni-th.vue @@ -0,0 +1,295 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-thead/uni-thead.vue b/uni_modules/uni-table/components/uni-thead/uni-thead.vue new file mode 100644 index 0000000..dea6e2b --- /dev/null +++ b/uni_modules/uni-table/components/uni-thead/uni-thead.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-tr/table-checkbox.vue b/uni_modules/uni-table/components/uni-tr/table-checkbox.vue new file mode 100644 index 0000000..f22936b --- /dev/null +++ b/uni_modules/uni-table/components/uni-tr/table-checkbox.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/uni_modules/uni-table/components/uni-tr/uni-tr.vue b/uni_modules/uni-table/components/uni-tr/uni-tr.vue new file mode 100644 index 0000000..56abd4b --- /dev/null +++ b/uni_modules/uni-table/components/uni-tr/uni-tr.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/uni_modules/uni-table/i18n/en.json b/uni_modules/uni-table/i18n/en.json new file mode 100644 index 0000000..cc9c4a3 --- /dev/null +++ b/uni_modules/uni-table/i18n/en.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "Reset", + "filter-dropdown.search": "Search", + "filter-dropdown.submit": "Submit", + "filter-dropdown.filter": "Filter", + "filter-dropdown.gt": "Greater or equal to", + "filter-dropdown.lt": "Less than or equal to", + "filter-dropdown.date": "Date" +} diff --git a/uni_modules/uni-table/i18n/es.json b/uni_modules/uni-table/i18n/es.json new file mode 100644 index 0000000..9c4705c --- /dev/null +++ b/uni_modules/uni-table/i18n/es.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "Reiniciar", + "filter-dropdown.search": "Búsqueda", + "filter-dropdown.submit": "Entregar", + "filter-dropdown.filter": "Filtrar", + "filter-dropdown.gt": "Mayor o igual a", + "filter-dropdown.lt": "Menos que o igual a", + "filter-dropdown.date": "Fecha" +} diff --git a/uni_modules/uni-table/i18n/fr.json b/uni_modules/uni-table/i18n/fr.json new file mode 100644 index 0000000..389a9ae --- /dev/null +++ b/uni_modules/uni-table/i18n/fr.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "Réinitialiser", + "filter-dropdown.search": "Chercher", + "filter-dropdown.submit": "Soumettre", + "filter-dropdown.filter": "Filtre", + "filter-dropdown.gt": "Supérieur ou égal à", + "filter-dropdown.lt": "Inférieur ou égal à", + "filter-dropdown.date": "Date" +} diff --git a/uni_modules/uni-table/i18n/index.js b/uni_modules/uni-table/i18n/index.js new file mode 100644 index 0000000..2293b0d --- /dev/null +++ b/uni_modules/uni-table/i18n/index.js @@ -0,0 +1,12 @@ +import en from './en.json' +import es from './es.json' +import fr from './fr.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + es, + fr, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-table/i18n/zh-Hans.json b/uni_modules/uni-table/i18n/zh-Hans.json new file mode 100644 index 0000000..0b1afab --- /dev/null +++ b/uni_modules/uni-table/i18n/zh-Hans.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "重置", + "filter-dropdown.search": "搜索", + "filter-dropdown.submit": "确定", + "filter-dropdown.filter": "筛选", + "filter-dropdown.gt": "大于等于", + "filter-dropdown.lt": "小于等于", + "filter-dropdown.date": "日期范围" +} diff --git a/uni_modules/uni-table/i18n/zh-Hant.json b/uni_modules/uni-table/i18n/zh-Hant.json new file mode 100644 index 0000000..d633f2d --- /dev/null +++ b/uni_modules/uni-table/i18n/zh-Hant.json @@ -0,0 +1,9 @@ +{ + "filter-dropdown.reset": "重置", + "filter-dropdown.search": "搜索", + "filter-dropdown.submit": "確定", + "filter-dropdown.filter": "篩選", + "filter-dropdown.gt": "大於等於", + "filter-dropdown.lt": "小於等於", + "filter-dropdown.date": "日期範圍" +} diff --git a/uni_modules/uni-table/package.json b/uni_modules/uni-table/package.json new file mode 100644 index 0000000..e881aad --- /dev/null +++ b/uni_modules/uni-table/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-table", + "displayName": "uni-table 表格", + "version": "1.2.8", + "description": "表格组件,多用于展示多条结构类似的数据,如", + "keywords": [ + "uni-ui", + "uniui", + "table", + "表格" +], + "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","uni-datetime-picker"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "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", + "字节跳动": "n", + "QQ": "y" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-table/readme.md b/uni_modules/uni-table/readme.md new file mode 100644 index 0000000..a0f93cf --- /dev/null +++ b/uni_modules/uni-table/readme.md @@ -0,0 +1,13 @@ + + +## Table 表单 +> 组件名:``uni-table``,代码块: `uTable`。 + +用于展示多条结构类似的数据 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-table) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + diff --git a/uni_modules/uni-tag/changelog.md b/uni_modules/uni-tag/changelog.md new file mode 100644 index 0000000..8d2baa2 --- /dev/null +++ b/uni_modules/uni-tag/changelog.md @@ -0,0 +1,23 @@ +## 2.1.1(2024-03-20) +- 优化 app下边框过窄导致不显示的bug +## 2.1.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-tag](https://uniapp.dcloud.io/component/uniui/uni-tag) +## 2.0.0(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +- 移除 插槽 +- 移除 type 属性的 royal 选项 +## 1.1.1(2021-08-11) +- type 不是 default 时,size 为 small 字体大小显示不正确 +## 1.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.0.7(2021-06-18) +- 修复 uni-tag 在字节跳动小程序上 css 类名编译错误的 bug +## 1.0.6(2021-06-04) +- 修复 未定义 sass 变量 "$uni-color-royal" 的bug +## 1.0.5(2021-05-10) +- 修复 royal 类型无效的bug +- 修复 uni-tag 宽度不自适应的bug +- 新增 uni-tag 支持属性 custom-style 自定义样式 +## 1.0.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-tag/components/uni-tag/uni-tag.vue b/uni_modules/uni-tag/components/uni-tag/uni-tag.vue new file mode 100644 index 0000000..2692488 --- /dev/null +++ b/uni_modules/uni-tag/components/uni-tag/uni-tag.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/uni_modules/uni-tag/package.json b/uni_modules/uni-tag/package.json new file mode 100644 index 0000000..50881f8 --- /dev/null +++ b/uni_modules/uni-tag/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-tag", + "displayName": "uni-tag 标签", + "version": "2.1.1", + "description": "Tag 组件,用于展示1个或多个文字标签,可点击切换选中、不选中的状态。", + "keywords": [ + "uni-ui", + "uniui", + "", + "tag", + "标签" +], + "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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-tag/readme.md b/uni_modules/uni-tag/readme.md new file mode 100644 index 0000000..e8f7d82 --- /dev/null +++ b/uni_modules/uni-tag/readme.md @@ -0,0 +1,13 @@ + + +## Tag 标签 +> **组件名:uni-tag** +> 代码块: `uTag` + + +用于展示1个或多个文字标签,可点击切换选中、不选中的状态 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-tag) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-title/changelog.md b/uni_modules/uni-title/changelog.md new file mode 100644 index 0000000..2121c5b --- /dev/null +++ b/uni_modules/uni-title/changelog.md @@ -0,0 +1,10 @@ +## 1.1.1(2022-05-19) +- 修改组件描述 +## 1.1.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-title](https://uniapp.dcloud.io/component/uniui/uni-title) +## 1.0.2(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的Bug +## 1.0.1(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-title/components/uni-title/uni-title.vue b/uni_modules/uni-title/components/uni-title/uni-title.vue new file mode 100644 index 0000000..0d5b848 --- /dev/null +++ b/uni_modules/uni-title/components/uni-title/uni-title.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/uni_modules/uni-title/package.json b/uni_modules/uni-title/package.json new file mode 100644 index 0000000..76255ab --- /dev/null +++ b/uni_modules/uni-title/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-title", + "displayName": "uni-title 章节标题", + "version": "1.1.1", + "description": "章节标题,通常用于记录页面标题,使用当前组件,uni-app 如果开启统计,将会自动统计页面标题", + "keywords": [ + "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": ["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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-title/readme.md b/uni_modules/uni-title/readme.md new file mode 100644 index 0000000..7d43b7e --- /dev/null +++ b/uni_modules/uni-title/readme.md @@ -0,0 +1,14 @@ + + +## Title 标题 +> **组件名:uni-title** +> 代码块: `uTitle` + + +章节标题,通常用于记录页面标题,使用当前组件,uni-app 如果开启统计,将会自动统计页面标题 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-title) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + diff --git a/uni_modules/uni-tooltip/changelog.md b/uni_modules/uni-tooltip/changelog.md new file mode 100644 index 0000000..4c9487a --- /dev/null +++ b/uni_modules/uni-tooltip/changelog.md @@ -0,0 +1,16 @@ +## 0.2.4(2024-04-23) +- 修复 弹出位置默认值不一致导致的错位 +## 0.2.3(2024-03-20) +- 修复 弹出位置修正 +## 0.2.2(2024-01-15) +- 新增 placement支持设置四个方向:top bottom left right +## 0.2.1(2022-05-09) +- 修复 content 为空时仍然弹出的bug +## 0.2.0(2022-05-07) +**注意:破坏性更新** +- 更新 text 属性变更为 content +- 更新 移除 width 属性 +## 0.1.1(2022-04-27) +- 修复 组件根 text 嵌套组件 warning +## 0.1.0(2022-04-21) +- 初始化 diff --git a/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue b/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue new file mode 100644 index 0000000..7dfdbf1 --- /dev/null +++ b/uni_modules/uni-tooltip/components/uni-tooltip/uni-tooltip.vue @@ -0,0 +1,108 @@ + + + + + + diff --git a/uni_modules/uni-tooltip/package.json b/uni_modules/uni-tooltip/package.json new file mode 100644 index 0000000..2ec1ee9 --- /dev/null +++ b/uni_modules/uni-tooltip/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-tooltip", + "displayName": "uni-tooltip 提示文字", + "version": "0.2.4", + "description": "Tooltip 提示文字", + "keywords": [ + "uni-tooltip", + "uni-ui", + "tooltip", + "tip", + "文字提示" +], + "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": "", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "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", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-tooltip/readme.md b/uni_modules/uni-tooltip/readme.md new file mode 100644 index 0000000..db86f06 --- /dev/null +++ b/uni_modules/uni-tooltip/readme.md @@ -0,0 +1,8 @@ +## Badge 数字角标 +> **组件名:uni-tooltip** +> 代码块: `uTooltip` + +数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景, + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-tooltip) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-transition/changelog.md b/uni_modules/uni-transition/changelog.md new file mode 100644 index 0000000..ab1c62b --- /dev/null +++ b/uni_modules/uni-transition/changelog.md @@ -0,0 +1,24 @@ +## 1.3.3(2024-04-23) +- 修复 当元素会受变量影响自动隐藏的bug +## 1.3.2(2023-05-04) +- 修复 NVUE 平台报错的问题 +## 1.3.1(2021-11-23) +- 修复 init 方法初始化问题 +## 1.3.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-transition](https://uniapp.dcloud.io/component/uniui/uni-transition) +## 1.2.1(2021-09-27) +- 修复 init 方法不生效的 Bug +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.1(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的 Bug +## 1.1.0(2021-04-22) +- 新增 通过方法自定义动画 +- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式 +- 优化 动画触发逻辑,使动画更流畅 +- 优化 支持单独的动画类型 +- 优化 文档示例 +## 1.0.2(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/uni_modules/uni-transition/components/uni-transition/createAnimation.js b/uni_modules/uni-transition/components/uni-transition/createAnimation.js new file mode 100644 index 0000000..bd79e8b --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/createAnimation.js @@ -0,0 +1,131 @@ +// const defaultOption = { +// duration: 300, +// timingFunction: 'linear', +// delay: 0, +// transformOrigin: '50% 50% 0' +// } +// #ifdef APP-NVUE +const nvueAnimation = uni.requireNativePlugin('animation') +// #endif +class MPAnimation { + constructor(options, _this) { + this.options = options + // 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误 + this.animation = uni.createAnimation({ + ...options + }) + this.currentStepAnimates = {} + this.next = 0 + this.$ = _this + + } + + _nvuePushAnimates(type, args) { + let aniObj = this.currentStepAnimates[this.next] + let styles = {} + if (!aniObj) { + styles = { + styles: {}, + config: {} + } + } else { + styles = aniObj + } + if (animateTypes1.includes(type)) { + if (!styles.styles.transform) { + styles.styles.transform = '' + } + let unit = '' + if(type === 'rotate'){ + unit = 'deg' + } + styles.styles.transform += `${type}(${args+unit}) ` + } else { + styles.styles[type] = `${args}` + } + this.currentStepAnimates[this.next] = styles + } + _animateRun(styles = {}, config = {}) { + let ref = this.$.$refs['ani'].ref + if (!ref) return + return new Promise((resolve, reject) => { + nvueAnimation.transition(ref, { + styles, + ...config + }, res => { + resolve() + }) + }) + } + + _nvueNextAnimate(animates, step = 0, fn) { + let obj = animates[step] + if (obj) { + let { + styles, + config + } = obj + this._animateRun(styles, config).then(() => { + step += 1 + this._nvueNextAnimate(animates, step, fn) + }) + } else { + this.currentStepAnimates = {} + typeof fn === 'function' && fn() + this.isEnd = true + } + } + + step(config = {}) { + // #ifndef APP-NVUE + this.animation.step(config) + // #endif + // #ifdef APP-NVUE + this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config) + this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin + this.next++ + // #endif + return this + } + + run(fn) { + // #ifndef APP-NVUE + this.$.animationData = this.animation.export() + this.$.timer = setTimeout(() => { + typeof fn === 'function' && fn() + }, this.$.durationTime) + // #endif + // #ifdef APP-NVUE + this.isEnd = false + let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref + if(!ref) return + this._nvueNextAnimate(this.currentStepAnimates, 0, fn) + this.next = 0 + // #endif + } +} + + +const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d', + 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY', + 'translateZ' +] +const animateTypes2 = ['opacity', 'backgroundColor'] +const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom'] +animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => { + MPAnimation.prototype[type] = function(...args) { + // #ifndef APP-NVUE + this.animation[type](...args) + // #endif + // #ifdef APP-NVUE + this._nvuePushAnimates(type, args) + // #endif + return this + } +}) + +export function createAnimation(option, _this) { + if(!_this) return + clearTimeout(_this.timer) + return new MPAnimation(option, _this) +} diff --git a/uni_modules/uni-transition/components/uni-transition/uni-transition.vue b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue new file mode 100644 index 0000000..2716209 --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/uni_modules/uni-transition/package.json b/uni_modules/uni-transition/package.json new file mode 100644 index 0000000..5d830b8 --- /dev/null +++ b/uni_modules/uni-transition/package.json @@ -0,0 +1,85 @@ +{ + "id": "uni-transition", + "displayName": "uni-transition 过渡动画", + "version": "1.3.3", + "description": "元素的简单过渡动画", + "keywords": [ + "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", + "alipay": "n" + }, + "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-transition/readme.md b/uni_modules/uni-transition/readme.md new file mode 100644 index 0000000..1e104fe --- /dev/null +++ b/uni_modules/uni-transition/readme.md @@ -0,0 +1,11 @@ + + +## Transition 过渡动画 +> **组件名:uni-transition** +> 代码块: `uTransition` + + +元素过渡动画 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-transition) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/changelog.md b/uni_modules/uni-upgrade-center-app/changelog.md new file mode 100644 index 0000000..af0fc53 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/changelog.md @@ -0,0 +1,94 @@ +## 0.7.9(2024-03-15) +- 移除无用代码 +- 调整 is_silently 类型为可为 null +## 0.7.8(2024-01-04) +- 新增 移除无用代码 +## 0.7.7(2024-01-04) +- 新增 uni-app x 项目中新增 @show 回调 +## 0.7.6(2023-12-21) +- 修复 iOS使用升级中心云打包时报错(使用新版的 [uts-progressNotification](https://ext.dcloud.net.cn/plugin?name=uts-progressNotification) 插件,如果之前下载过请删除 `uts-progressNotification\utssdk\app-ios` 文件夹) +## 0.7.5(2023-12-12) +- 新增 通知栏进度条使用 uts-progressNotification 插件 +- 新增 依赖 uni-installApk、uts-progressNotification。使用前要安装插件三方依赖 +## 0.7.4(2023-11-29) +- 修复 uni-app-x 项目中由上版引发的无法升级的Bug +## 0.7.3(2023-11-27) +- 修复 在 uni-app x 中无更新时报错的Bug +## 0.7.2(2023-11-20) +- 新增 插件根目录 utils 文件夹中新增 check-update-nvue.js 文件(vue2 的 nvue 页面请引用该文件) +## 0.7.1(2023-11-17) +- 修复 运行至浏览器 ts 语法报错 +## 0.7.0(2023-11-10) +- 新增 兼容 uni-app x 项目 [详情](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html) +## 0.6.5(2023-10-27) +- 修复 安装 wgt 报错 manifest.json 文件不存在的Bug +## 0.6.4(2023-09-01) +chore: 优化代码结构 +## 0.6.3(2023-08-30) +- 修复 下载 wgt 时如果后缀名不正确,重命名后安装 +## 0.6.2(2022-11-21) +- 处理 cloudfunctions 目录 +## 0.6.1(2022-08-17) +- 修复 后台添加应用市场,但都没有启用的情况下报错的Bug (需要 uni-admin 1.9.3+) +## 0.6.0(2022-07-19) +- 新增 支持多应用商店配置(需要 uni-admin 1.9.3+) +## 0.4.1(2022-05-27) +- 修复 上版引出的报错问题 +## 0.4.0(2022-05-27) +- 新增 Android 支持跳转手机自带商店,填写升级包地址时请填写跳转商店链接 +- 新增 改为云对象调用方式,使用更直观 +## 0.3.3(2022-04-14) +- 修复 调用 check-update,当 code 为 0 时没有回调 +## 0.3.2(2022-01-12) +- 优化显示逻辑 +## 0.3.1(2021-11-24) +- 修复 vue3 上图片不显示的Bug +## 0.3.0(2021-11-18) +- 移除 wgt 安装成功后提示,防止重启过快弹框不消失 +## 0.2.2(2021-08-25) +- 兼容vue3.0 +## 0.2.1(2021-07-26) +- 修复 使用腾讯云并手动填写地址时,导致下载链接失效的bug +## 0.2.0(2021-07-13) +- 更新文档 关于报错local_storage_key 为空,请不要将页面路径设置为pages.json中第一项 +## 0.1.9(2021-06-28) +- 更新文档 +- 修复 wgt安装失败时,按钮状态不对 +## 0.1.8(2021-06-16) +- 修复 跳转安装时,导致上次下载的apk还没安装就被删掉的bug +## 0.1.7(2021-06-03) +- 修改 移除static中的图片 +## 0.1.6(2021-06-03) +- 修改 下载更新按钮使用CSS渐变色 +## 0.1.5(2021-04-22) +- 更新check-update函数。现在返回一个Promise,有更新时成功回调,其他情况错误回调 +## 0.1.4(2021-04-13) +- 更新文档。明确云函数调用结果 +## 0.1.3(2021-04-13) +- 解耦云函数与弹框处理。utils中新增 call-check-version.js,可用于单独检测是否有更新 +## 0.1.2(2021-04-07) +- 更新版本对比函数 compare +## 0.1.1(2021-04-07) +- 修复 腾讯云空间下载链接不能下载问题 +## 0.1.0(2021-04-07) +- 新增使用uni.showModal提示升级示例 +- 修改iOS升级提示方式 +## 0.0.7(2021-04-02) +- 修复在iOS上打开弹框报错 +## 0.0.6(2021-04-01) +- 兼容旧版本安卓 +## 0.0.5(2021-04-01) +- 修复低版本安卓上进度条错位 +## 0.0.4(2021-04-01) +- 更新readme +- 修复check-update语法错误 +## 0.0.3(2021-04-01) +- 新增前台更新弹框,详见readme +- 更新前台检查更新方法 + +## 0.0.2(2021-03-29) +- 更新文档 +- 移除 dependencies + +## 0.0.1(2021-03-25) +- 升级中心前台检查更新 diff --git a/uni_modules/uni-upgrade-center-app/components/uni-upgrade-center-app/uni-upgrade-center-app.uvue b/uni_modules/uni-upgrade-center-app/components/uni-upgrade-center-app/uni-upgrade-center-app.uvue new file mode 100644 index 0000000..e6d9a23 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/components/uni-upgrade-center-app/uni-upgrade-center-app.uvue @@ -0,0 +1,474 @@ + + + + + diff --git a/uni_modules/uni-upgrade-center-app/images/app_update_close.png b/uni_modules/uni-upgrade-center-app/images/app_update_close.png new file mode 100644 index 0000000..8b2ffe6 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/images/app_update_close.png differ diff --git a/uni_modules/uni-upgrade-center-app/images/bg_top.png b/uni_modules/uni-upgrade-center-app/images/bg_top.png new file mode 100644 index 0000000..015f698 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/images/bg_top.png differ diff --git a/uni_modules/uni-upgrade-center-app/package.json b/uni_modules/uni-upgrade-center-app/package.json new file mode 100644 index 0000000..70db691 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/package.json @@ -0,0 +1,84 @@ +{ + "id": "uni-upgrade-center-app", + "displayName": "升级中心 uni-upgrade-center - App", + "version": "0.7.9", + "description": "uni升级中心 - 客户端检查更新", + "keywords": [ + "uniCloud", + "update", + "升级", + "wgt" +], + "repository": "https://gitee.com/dcloud/uni-upgrade-center/tree/master/uni_modules/uni-upgrade-center-app", + "engines": { + "HBuilderX": "^3.97" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-page" + }, + "uni_modules": { + "dependencies": [ + "uni-installApk", + "uts-progressNotification" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue new file mode 100644 index 0000000..aa4edfc --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue @@ -0,0 +1,611 @@ + + + + + diff --git a/uni_modules/uni-upgrade-center-app/pages_init.json b/uni_modules/uni-upgrade-center-app/pages_init.json new file mode 100644 index 0000000..7021d99 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/pages_init.json @@ -0,0 +1,18 @@ +{ + "pages": [{ + "path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup", + "style": { + "disableScroll": true, + "app-plus": { + "backgroundColorTop": "transparent", + "background": "transparent", + "titleNView": false, + "scrollIndicator": false, + "popGesture": "none", + "animationType": "fade-in", + "animationDuration": 200 + + } + } + }] +} diff --git a/uni_modules/uni-upgrade-center-app/readme.md b/uni_modules/uni-upgrade-center-app/readme.md new file mode 100644 index 0000000..53ff781 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/readme.md @@ -0,0 +1 @@ +文档已移至 [uni-upgrade-center](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html) \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/static/app_update_close.png b/uni_modules/uni-upgrade-center-app/static/app_update_close.png new file mode 100644 index 0000000..8b2ffe6 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/static/app_update_close.png differ diff --git a/uni_modules/uni-upgrade-center-app/static/bg_top.png b/uni_modules/uni-upgrade-center-app/static/bg_top.png new file mode 100644 index 0000000..015f698 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/static/bg_top.png differ diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/check-version.param.json b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/check-version.param.json new file mode 100644 index 0000000..b45ad7c --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/check-version.param.json @@ -0,0 +1,9 @@ +// 本文件中的json内容将在云函数【运行】时作为参数传给云函数。 + +// 配置教程参考:https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam + +{ + "appid": "__YOUR_APPID__", + "appVersion": "2.2.0", + "wgtVersion": "2.2.2" +} diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/index.js b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/index.js new file mode 100644 index 0000000..76f4247 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/index.js @@ -0,0 +1,167 @@ +'use strict'; +exports.main = async (event, context) => { + /** + * 检测升级 使用说明 + * 上传包: + * 1. 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传 + * 2. 先从数据库取出所有该平台(从上下文读取平台信息,默认 Andriod)的所有线上发行更新 + * 3. 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新 + * 4. 使用上步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新,必须同时大于这两项,否则返回暂无更新 + * 5. 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion + */ + + let { + appid, + appVersion, + wgtVersion, + } = event; + + const platform_Android = 'Android'; + const platform_iOS = 'iOS'; + const package_app = 'native_app'; + const package_wgt = 'wgt'; + const app_version_db_name = 'opendb-app-versions' + + let platform = platform_Android; + + // 云函数URL化请求 + if (event.headers) { + let body; + try { + if (event.httpMethod.toLocaleLowerCase() === 'get') { + body = event.queryStringParameters; + } else { + body = JSON.parse(event.body); + } + } catch (e) { + return { + code: 500, + msg: '请求错误' + }; + } + + appid = body.appid; + appVersion = body.appVersion; + wgtVersion = body.wgtVersion; + + platform = /iPhone|iPad/.test(event.headers) ? platform_iOS : platform_Android; + } else if (context.OS) { + platform = context.OS === 'android' + ? platform_Android + : context.OS === 'ios' + ? platform_iOS + : platform_Android; + } + + if (appid && appVersion && wgtVersion && platform) { + const collection = uniCloud.database().collection(app_version_db_name); + + const record = await collection.where({ + appid, + platform, + stable_publish: true + }) + .orderBy('create_date', 'desc') + .get(); + + if (record && record.data && record.data.length > 0) { + const appVersionInDb = record.data.find(item => item.type === package_app) || {}; + const wgtVersionInDb = record.data.find(item => item.type === package_wgt) || {}; + const hasAppPackage = !!Object.keys(appVersionInDb).length; + const hasWgtPackage = !!Object.keys(wgtVersionInDb).length; + + // 取两个版本中版本号最大的包,版本一样,使用wgt包 + let stablePublishDb = hasAppPackage + ? hasWgtPackage + ? compare(wgtVersionInDb.version, appVersionInDb.version) >= 0 + ? wgtVersionInDb + : appVersionInDb + : appVersionInDb + : wgtVersionInDb; + + const { + version, + min_uni_version + } = stablePublishDb; + + // 库中的version必须满足同时大于appVersion和wgtVersion才行,因为上次更新可能是wgt更新 + const appUpdate = compare(version, appVersion) === 1; // app包可用更新 + const wgtUpdate = compare(version, wgtVersion) === 1; // wgt包可用更新 + + if (Object.keys(stablePublishDb).length && appUpdate && wgtUpdate) { + // 判断是否可用wgt更新 + if (min_uni_version && compare(min_uni_version, appVersion) < 1) { + return { + code: 101, + message: 'wgt更新', + ...stablePublishDb + }; + } else if (hasAppPackage && compare(appVersionInDb.version, appVersion) === 1) { + return { + code: 102, + message: '整包更新', + ...appVersionInDb + }; + } + } + + return { + code: 0, + message: '当前版本已经是最新的,不需要更新' + }; + } + + return { + code: -101, + message: '暂无更新或检查appid是否填写正确' + }; + } + + return { + code: -102, + message: '请检查传参是否填写正确' + }; +}; + +/** + * 对比版本号,如需要,请自行修改判断规则 + * 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 + * @param {Object} v1 + * @param {Object} v2 + * v1 > v2 return 1 + * v1 < v2 return -1 + * v1 == v2 return 0 + */ +function compare(v1 = '0', v2 = '0') { + v1 = String(v1).split('.') + v2 = String(v2).split('.') + const minVersionLens = Math.min(v1.length, v2.length); + + let result = 0; + for (let i = 0; i < minVersionLens; i++) { + const curV1 = Number(v1[i]) + const curV2 = Number(v2[i]) + + if (curV1 > curV2) { + result = 1 + break; + } else if(curV1 < curV2) { + result = -1 + break; + } + } + + if (result === 0 && (v1.length !== v2.length)) { + const v1BiggerThenv2 = v1.length > v2.length; + const maxLensVersion = v1BiggerThenv2 ? v1 : v2; + for (let i = minVersionLens; i < maxLensVersion.length; i++) { + const curVersion = Number(maxLensVersion[i]) + if (curVersion > 0) { + v1BiggerThenv2 ? result = 1 : result = -1 + break; + } + } + } + + return result; +} diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/package.json b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/package.json new file mode 100644 index 0000000..b1e7846 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version/package.json @@ -0,0 +1,8 @@ +{ + "name": "check-version", + "origin-plugin-dev-name": "hello-uniapp", + "origin-plugin-version": "3.4.9", + "plugin-dev-name": "hello-uniapp", + "plugin-version": "3.4.9", + "description": "" +} \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/checkVersion.param.json b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/checkVersion.param.json new file mode 100644 index 0000000..f5e0890 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/checkVersion.param.json @@ -0,0 +1,14 @@ +// 本文件中的json内容将在云对象【运行】时作为参数传给云对象。 +// 配置教程参考:https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam +{ + // 调用云对象的方法名称 + "method": "checkVersion", + // 传递给调用方法的参数列表 + "params": [ + { + "appid": "__UNI__HelloUNIApp", + "appVersion": "1.0.0", + "wgtVersion": "1.0.0" + } + ] +} diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/index.obj.js b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/index.obj.js new file mode 100644 index 0000000..ddfd02f --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/index.obj.js @@ -0,0 +1,148 @@ +// 开发文档: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj +module.exports = { + checkVersion: async function(event) { + /** + * 检测升级 使用说明 + * 上传包: + * 1. 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传 + * 2. 先从数据库取出所有该平台(从上下文读取平台信息,默认 Andriod)的所有线上发行更新 + * 3. 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新 + * 4. 使用上步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新,必须同时大于这两项,否则返回暂无更新 + * 5. 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion + */ + + const clientInfo = this.getClientInfo() + + let { + appid, + appVersion, + wgtVersion, + } = event; + + const platform_Android = 'Android'; + const platform_iOS = 'iOS'; + const package_app = 'native_app'; + const package_wgt = 'wgt'; + const app_version_db_name = 'opendb-app-versions' + + let platform = platform_Android; + + platform = clientInfo.OS === 'android' ? + platform_Android : + clientInfo.OS === 'ios' ? + platform_iOS : + platform_Android; + + if (appid && appVersion && wgtVersion && platform) { + const collection = uniCloud.database().collection(app_version_db_name); + + const record = await collection.where({ + appid, + platform, + stable_publish: true + }) + .orderBy('create_date', 'desc') + .get(); + + if (record && record.data && record.data.length > 0) { + const appVersionInDb = record.data.find(item => item.type === package_app) || {}; + const wgtVersionInDb = record.data.find(item => item.type === package_wgt) || {}; + const hasAppPackage = !!Object.keys(appVersionInDb).length; + const hasWgtPackage = !!Object.keys(wgtVersionInDb).length; + + // 取两个版本中版本号最大的包,版本一样,使用wgt包 + let stablePublishDb = hasAppPackage ? + hasWgtPackage ? + compare(wgtVersionInDb.version, appVersionInDb.version) >= 0 ? + wgtVersionInDb : + appVersionInDb : + appVersionInDb : + wgtVersionInDb; + + const { + version, + min_uni_version + } = stablePublishDb; + + // 库中的version必须满足同时大于appVersion和wgtVersion才行,因为上次更新可能是wgt更新 + const appUpdate = compare(version, appVersion) === 1; // app包可用更新 + const wgtUpdate = compare(version, wgtVersion) === 1; // wgt包可用更新 + + if (Object.keys(stablePublishDb).length && appUpdate && wgtUpdate) { + // 判断是否可用wgt更新 + if (min_uni_version && compare(min_uni_version, appVersion) < 1) { + return { + code: 101, + message: 'wgt更新', + ...stablePublishDb + }; + } else if (hasAppPackage && compare(appVersionInDb.version, appVersion) === 1) { + return { + code: 102, + message: '整包更新', + ...appVersionInDb + }; + } + } + + return { + code: 0, + message: '当前版本已经是最新的,不需要更新' + }; + } + + return { + code: -101, + message: '暂无更新或检查appid是否填写正确' + }; + } + + return { + code: -102, + message: '请检查传参是否填写正确' + }; + } +} + +/** + * 对比版本号,如需要,请自行修改判断规则 + * 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 + * @param {Object} v1 + * @param {Object} v2 + * v1 > v2 return 1 + * v1 < v2 return -1 + * v1 == v2 return 0 + */ +function compare(v1 = '0', v2 = '0') { + v1 = String(v1).split('.') + v2 = String(v2).split('.') + const minVersionLens = Math.min(v1.length, v2.length); + + let result = 0; + for (let i = 0; i < minVersionLens; i++) { + const curV1 = Number(v1[i]) + const curV2 = Number(v2[i]) + + if (curV1 > curV2) { + result = 1 + break; + } else if (curV1 < curV2) { + result = -1 + break; + } + } + + if (result === 0 && (v1.length !== v2.length)) { + const v1BiggerThenv2 = v1.length > v2.length; + const maxLensVersion = v1BiggerThenv2 ? v1 : v2; + for (let i = minVersionLens; i < maxLensVersion.length; i++) { + const curVersion = Number(maxLensVersion[i]) + if (curVersion > 0) { + v1BiggerThenv2 ? result = 1 : result = -1 + break; + } + } + } + + return result; +} diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/package.json b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/package.json new file mode 100644 index 0000000..684e4d5 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/checkVersion/package.json @@ -0,0 +1,11 @@ +{ + "name": "checkVersion", + "dependencies": {}, + "extensions": { + "uni-cloud-jql": {} + }, + "origin-plugin-dev-name": "hello-uniapp", + "origin-plugin-version": "3.4.9", + "plugin-dev-name": "hello-uniapp", + "plugin-version": "3.4.9" +} \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/temp.png b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/temp.png new file mode 100644 index 0000000..8b2ffe6 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/temp.png differ diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json b/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json new file mode 100644 index 0000000..69a88e3 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json @@ -0,0 +1 @@ +{} diff --git a/uni_modules/uni-upgrade-center-app/utils/call-check-version.js b/uni_modules/uni-upgrade-center-app/utils/call-check-version.js new file mode 100644 index 0000000..1a28bd8 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/call-check-version.js @@ -0,0 +1,33 @@ +export default function() { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { + const data = { + action: 'checkVersion', + appid: plus.runtime.appid, + appVersion: plus.runtime.version, + wgtVersion: widgetInfo.version + } + console.log("data: ",data); + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data, + success: (e) => { + console.log("e: ", e); + resolve(e) + }, + fail: (error) => { + reject(error) + } + }) + }) + }) + // #endif + // #ifndef APP-PLUS + return new Promise((resolve, reject) => { + reject({ + message: '请在App中使用' + }) + }) + // #endif +} diff --git a/uni_modules/uni-upgrade-center-app/utils/call-check-version.ts b/uni_modules/uni-upgrade-center-app/utils/call-check-version.ts new file mode 100644 index 0000000..26ea927 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/call-check-version.ts @@ -0,0 +1,120 @@ +export type StoreListItem = { + enable : boolean + id : string + name : string + scheme : string + priority : number // 优先级 +} + +export type UniUpgradeCenterResult = { + _id : string + appid : string + name : string + title : string + contents : string + url : string // 安装包下载地址 + platform : Array // Array<'Android' | 'iOS'> + version : string // 版本号 1.0.0 + uni_platform : string // "android" | "ios" // 版本号 1.0.0 + stable_publish : boolean // 是否是稳定版 + is_mandatory : boolean // 是否强制更新 + is_silently : boolean | null // 是否静默更新 + create_env : string // "upgrade-center" + create_date : number + message : string + code : number + + type : string // "native_app" | "wgt" + store_list : StoreListItem[] | null + min_uni_version : string | null // 升级 wgt 的最低 uni-app 版本 +} + +export default function () : Promise { + // #ifdef APP + return new Promise((resolve, reject) => { + const systemInfo = uni.getSystemInfoSync() + const appId = systemInfo.appId + const appVersion = systemInfo.appVersion //systemInfo.appVersion + // #ifndef UNI-APP-X + if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) { + plus.runtime.getProperty(appId, function (widgetInfo) { + if (widgetInfo.version) { + let data = { + action: 'checkVersion', + appid: appId, + appVersion: appVersion, + wgtVersion: widgetInfo.version + } + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data, + success: (e) => { + resolve(e.result as UniUpgradeCenterResult) + }, + fail: (error) => { + reject(error) + } + }) + } else { + reject('widgetInfo.version is EMPTY') + } + }) + } else { + reject('plus.runtime.appid is EMPTY') + } + // #endif + // #ifdef UNI-APP-X + if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) { + let data = { + action: 'checkVersion', + appid: appId, + appVersion: appVersion, + is_uniapp_x: true, + wgtVersion: '0.0.0.0.0.1' + } + try { + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data: data + }).then(res => { + const code = res.result['code'] + const codeIsNumber = ['Int', 'Long', 'number'].includes(typeof code) + if (codeIsNumber) { + if ((code as number) == 0) { + reject({ + code: res.result['code'], + message: res.result['message'] + }) + } else if ((code as number) < 0) { + reject({ + code: res.result['code'], + message: res.result['message'] + }) + } else { + const result = JSON.parse(JSON.stringify(res.result)) as UniUpgradeCenterResult + resolve(result) + } + } + }).catch((err : any | null) => { + const error = err as UniCloudError + if (error.errMsg == '未匹配到云函数[uni-upgrade-center]') + error.errMsg = '【uni-upgrade-center-app】未配置uni-upgrade-center,无法升级。参考: https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html' + reject(error.errMsg) + }) + } catch (e) { + reject(e.message) + } + } else { + reject('invalid appid or appVersion') + } + // #endif + }) + // #endif + // #ifndef APP-PLUS + return new Promise((resolve, reject) => { + reject({ + message: '请在App中使用' + }) + }) + // #endif +} diff --git a/uni_modules/uni-upgrade-center-app/utils/check-update-nvue.js b/uni_modules/uni-upgrade-center-app/utils/check-update-nvue.js new file mode 100644 index 0000000..e6ed43d --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/check-update-nvue.js @@ -0,0 +1,184 @@ +function callCheckVersion() { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { + let data = { + action: 'checkVersion', + appid: plus.runtime.appid, + appVersion: plus.runtime.version, + wgtVersion: widgetInfo.version + } + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data, + success: (e) => { + resolve(e) + }, + fail: (error) => { + reject(error) + } + }) + }) + }) + // #endif + // #ifndef APP-PLUS + return new Promise((resolve, reject) => {}) + // #endif +} + +// 推荐再App.vue中使用 +const PACKAGE_INFO_KEY = '__package_info__' + +export default function() { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + callCheckVersion().then(async (e) => { + if (!e.result) return; + const { + code, + message, + is_silently, // 是否静默更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = e.result; + + // 此处逻辑仅为实例,可自行编写 + if (code > 0) { + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const { + fileList + } = await uniCloud.getTempFileURL({ + fileList: [url] + }); + if (fileList[0].tempFileURL) + e.result.url = fileList[0].tempFileURL; + + resolve(e) + + // 静默更新,只有wgt有 + if (is_silently) { + uni.downloadFile({ + url: e.result.url, + success: res => { + if (res.statusCode == 200) { + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }); + } + } + }); + return; + } + + /** + * 提示升级一 + * 使用 uni.showModal + */ + // return updateUseModal(e.result) + + /** + * 提示升级二 + * 官方适配的升级弹窗,可自行替换资源适配UI风格 + */ + uni.setStorageSync(PACKAGE_INFO_KEY, e.result) + uni.navigateTo({ + url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`, + fail: (err) => { + console.error('更新弹框跳转失败', err) + uni.removeStorageSync(PACKAGE_INFO_KEY) + } + }) + + return + } else if (code < 0) { + // TODO 云函数报错处理 + console.error(message) + return reject(e) + } + return resolve(e) + }).catch(err => { + // TODO 云函数报错处理 + console.error(err.message) + reject(err) + }) + }); + // #endif +} + +/** + * 使用 uni.showModal 升级 + */ +function updateUseModal(packageInfo) { + const { + title, // 标题 + contents, // 升级内容 + is_mandatory, // 是否强制更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = packageInfo; + + let isWGT = type === 'wgt' + let isiOS = !isWGT ? platform.includes('iOS') : false; + let confirmText = isiOS ? '立即跳转更新' : '立即下载更新' + + return uni.showModal({ + title, + content: contents, + showCancel: !is_mandatory, + confirmText, + success: res => { + if (res.cancel) return; + + // 安装包下载 + if (isiOS) { + plus.runtime.openURL(url); + return; + } + + uni.showToast({ + title: '后台下载中……', + duration: 1000 + }); + + // wgt 和 安卓下载更新 + downloadTask = uni.downloadFile({ + url, + success: res => { + if (res.statusCode !== 200) { + console.error('下载安装包失败', err); + return; + } + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }, () => { + if (is_mandatory) { + //更新完重启app + plus.runtime.restart(); + return; + } + uni.showModal({ + title: '安装成功是否重启?', + success: res => { + if (res.confirm) { + //更新完重启app + plus.runtime.restart(); + } + } + }); + }, err => { + uni.showModal({ + title: '更新失败', + content: err + .message, + showCancel: false + }); + }); + } + }); + } + }); +} diff --git a/uni_modules/uni-upgrade-center-app/utils/check-update.js b/uni_modules/uni-upgrade-center-app/utils/check-update.js new file mode 100644 index 0000000..f45e5fb --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/check-update.js @@ -0,0 +1,158 @@ +import callCheckVersion from './call-check-version' + +// 推荐再App.vue中使用 +const PACKAGE_INFO_KEY = '__package_info__' + +export default function() { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + callCheckVersion().then(async (e) => { + if (!e.result) return; + const { + code, + message, + is_silently, // 是否静默更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = e.result; + + // 此处逻辑仅为实例,可自行编写 + if (code > 0) { + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const { + fileList + } = await uniCloud.getTempFileURL({ + fileList: [url] + }); + if (fileList[0].tempFileURL) + e.result.url = fileList[0].tempFileURL; + + resolve(e) + + // 静默更新,只有wgt有 + if (is_silently) { + uni.downloadFile({ + url: e.result.url, + success: res => { + if (res.statusCode == 200) { + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }); + } + } + }); + return; + } + + /** + * 提示升级一 + * 使用 uni.showModal + */ + // return updateUseModal(e.result) + + /** + * 提示升级二 + * 官方适配的升级弹窗,可自行替换资源适配UI风格 + */ + uni.setStorageSync(PACKAGE_INFO_KEY, e.result) + uni.navigateTo({ + url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`, + fail: (err) => { + console.error('更新弹框跳转失败', err) + uni.removeStorageSync(PACKAGE_INFO_KEY) + } + }) + + return + } else if (code < 0) { + // TODO 云函数报错处理 + console.error(message) + return reject(e) + } + return resolve(e) + }).catch(err => { + // TODO 云函数报错处理 + console.error(err.message) + reject(err) + }) + }); + // #endif +} + +/** + * 使用 uni.showModal 升级 + */ +function updateUseModal(packageInfo) { + const { + title, // 标题 + contents, // 升级内容 + is_mandatory, // 是否强制更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = packageInfo; + + let isWGT = type === 'wgt' + let isiOS = !isWGT ? platform.includes('iOS') : false; + let confirmText = isiOS ? '立即跳转更新' : '立即下载更新' + + return uni.showModal({ + title, + content: contents, + showCancel: !is_mandatory, + confirmText, + success: res => { + if (res.cancel) return; + + // 安装包下载 + if (isiOS) { + plus.runtime.openURL(url); + return; + } + + uni.showToast({ + title: '后台下载中……', + duration: 1000 + }); + + // wgt 和 安卓下载更新 + downloadTask = uni.downloadFile({ + url, + success: res => { + if (res.statusCode !== 200) { + console.error('下载安装包失败', err); + return; + } + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }, () => { + if (is_mandatory) { + //更新完重启app + plus.runtime.restart(); + return; + } + uni.showModal({ + title: '安装成功是否重启?', + success: res => { + if (res.confirm) { + //更新完重启app + plus.runtime.restart(); + } + } + }); + }, err => { + uni.showModal({ + title: '更新失败', + content: err + .message, + showCancel: false + }); + }); + } + }); + } + }); +} diff --git a/uni_modules/uni-upgrade-center-app/utils/check-update.ts b/uni_modules/uni-upgrade-center-app/utils/check-update.ts new file mode 100644 index 0000000..ae2b4a1 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/check-update.ts @@ -0,0 +1,191 @@ +import callCheckVersion, { UniUpgradeCenterResult } from "./call-check-version" +// #ifdef UNI-APP-X +import { openSchema } from './utils.uts' +// #endif + +// 推荐再App.vue中使用 +const PACKAGE_INFO_KEY = '__package_info__' + +// uni-app 项目无法从 vue 中导出 ComponentPublicInstance 类型,故使用条件编译 +// #ifdef UNI-APP-X +export default function (component : ComponentPublicInstance | null = null) : Promise { +// #endif +// #ifndef UNI-APP-X +export default function () : Promise { +// #endif + return new Promise((resolve, reject) => { + callCheckVersion().then(async (uniUpgradeCenterResult) => { + // NOTE uni-app x 3.96 解构有问题 + const code = uniUpgradeCenterResult.code + const message = uniUpgradeCenterResult.message + const url = uniUpgradeCenterResult.url // 安装包下载地址 + + // 此处逻辑仅为示例,可自行编写 + if (code > 0) { + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const tcbRes = await uniCloud.getTempFileURL({ fileList: [url] }); + if (typeof tcbRes.fileList[0].tempFileURL !== 'undefined') uniUpgradeCenterResult.url = tcbRes.fileList[0].tempFileURL; + + /** + * 提示升级一 + * 使用 uni.showModal + */ + // return updateUseModal(uniUpgradeCenterResult) + + // #ifndef UNI-APP-X + // 静默更新,只有wgt有 + if (uniUpgradeCenterResult.is_silently) { + uni.downloadFile({ + url, + success: res => { + if (res.statusCode == 200) { + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }); + } + } + }); + return; + } + // #endif + + /** + * 提示升级二 + * 官方适配的升级弹窗,可自行替换资源适配UI风格 + */ + // #ifndef UNI-APP-X + uni.setStorageSync(PACKAGE_INFO_KEY, uniUpgradeCenterResult) + uni.navigateTo({ + url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`, + fail: (err) => { + console.error('更新弹框跳转失败', err) + uni.removeStorageSync(PACKAGE_INFO_KEY) + } + }) + // #endif + // #ifdef UNI-APP-X + component?.$callMethod('show', true, uniUpgradeCenterResult) + // #endif + + return resolve(uniUpgradeCenterResult) + } else if (code < 0) { + console.error(message) + return reject(uniUpgradeCenterResult) + } + return resolve(uniUpgradeCenterResult) + }).catch((err) => { + reject(err) + }) + }); + } + +/** + * 使用 uni.showModal 升级 + */ +function updateUseModal(packageInfo : UniUpgradeCenterResult) : void { + // #ifdef APP + const { + title, // 标题 + contents, // 升级内容 + is_mandatory, // 是否强制更新 + url, // 安装包下载地址 + type, + platform + } = packageInfo; + + let isWGT = type === 'wgt' + let isiOS = !isWGT ? platform.includes('iOS') : false; + + // #ifndef UNI-APP-X + let confirmText = isiOS ? '立即跳转更新' : '立即下载更新' + // #endif + // #ifdef UNI-APP-X + let confirmText = '立即下载更新' + // #endif + + return uni.showModal({ + title, + content: contents, + showCancel: !is_mandatory, + confirmText, + success: res => { + if (res.cancel) return; + + if (isiOS) { + // iOS 平台跳转 AppStore + // #ifndef UNI-APP-X + plus.runtime.openURL(url); + // #endif + // #ifdef UNI-APP-X + openSchema(url) + // #endif + return; + } + + uni.showToast({ + title: '后台下载中……', + duration: 1000 + }); + + // wgt 和 安卓下载更新 + uni.downloadFile({ + url, + success: res => { + if (res.statusCode !== 200) { + console.error('下载安装包失败'); + return; + } + // 下载好直接安装,下次启动生效 + // uni-app x 项目没有 plus5+ 故使用条件编译 + // #ifndef UNI-APP-X + plus.runtime.install(res.tempFilePath, { + force: false + }, () => { + if (is_mandatory) { + //更新完重启app + plus.runtime.restart(); + return; + } + uni.showModal({ + title: '安装成功是否重启?', + success: res => { + if (res.confirm) { + //更新完重启app + plus.runtime.restart(); + } + } + }); + }, err => { + uni.showModal({ + title: '更新失败', + content: err + .message, + showCancel: false + }); + }); + // #endif + + // #ifdef UNI-APP-X + uni.installApk({ + filePath: res.tempFilePath, + success: () => { + uni.showModal({ + title: '安装成功请手动重启' + }); + }, + fail: err => { + uni.showModal({ + title: '更新失败', + content: err.message, + showCancel: false + }); + } + }); + // #endif + } + }); + } + }); + // #endif +} diff --git a/uni_modules/uni-upgrade-center-app/utils/utils.uts b/uni_modules/uni-upgrade-center-app/utils/utils.uts new file mode 100644 index 0000000..341ca5f --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/utils.uts @@ -0,0 +1,17 @@ +import Intent from 'android.content.Intent'; +import Uri from 'android.net.Uri'; + +export function openSchema(url : string) : Promise { + return new Promise((resolve, reject) => { + try { + const context = UTSAndroid.getUniActivity()!; + const uri = Uri.parse(url) + const intent = new Intent(Intent.ACTION_VIEW, uri) + intent.setData(uri); + context.startActivity(intent); + resolve(true) + } catch (e) { + reject(e) + } + }) +} diff --git a/uni_modules/uts-progressNotification/changelog.md b/uni_modules/uts-progressNotification/changelog.md new file mode 100644 index 0000000..af4e6df --- /dev/null +++ b/uni_modules/uts-progressNotification/changelog.md @@ -0,0 +1,24 @@ +## 1.1.0(2024-03-08) +修复uniapp打包报错问题 +## 1.0.9(2024-02-29) +去除代码过时警告 +## 1.0.8(2023-12-21) +去除app-ios目录 +## 1.0.7(2023-12-11) +去除无用代码 +## 1.0.6(2023-12-11) +修改文档 +## 1.0.5(2023-12-11) +1.修改插件名称 +2.修改插件引入方式为import导入 +## 1.0.4(2023-11-30) +1. createNotificationProgress增加`onClick`回调 +2.修复在小米部分系统上,通知消息会归类于不重要通知的bug +## 1.0.3(2023-11-28) +更新截图 +## 1.0.2(2023-11-28) +修改资源的包名 +## 1.0.1(2023-11-28) +更新文档 +## 1.0.0(2023-11-28) +Android通知栏显示进度插件 diff --git a/uni_modules/uts-progressNotification/package.json b/uni_modules/uts-progressNotification/package.json new file mode 100644 index 0000000..137aac5 --- /dev/null +++ b/uni_modules/uts-progressNotification/package.json @@ -0,0 +1,83 @@ +{ + "id": "uts-progressNotification", + "displayName": "uts-progressNotification", + "version": "1.1.0", + "description": "uts-progressNotification", + "keywords": [ + "uts-progressNotification" +], + "repository": "", + "engines": { + "HBuilderX": "^3.91" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "TargetSDKVersion33以上时需配置\n`android.permission.POST_NOTIFICATIONS`" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-android": { + "minVersion": "19" + }, + "app-ios": "n" + }, + "H5-mobile": { + "Safari": "n", + "Android Browser": "n", + "微信浏览器(Android)": "n", + "QQ浏览器(Android)": "n" + }, + "H5-pc": { + "Chrome": "n", + "IE": "n", + "Edge": "n", + "Firefox": "n", + "Safari": "n" + }, + "小程序": { + "微信": "n", + "阿里": "n", + "百度": "n", + "字节跳动": "n", + "QQ": "n", + "钉钉": "n", + "快手": "n", + "飞书": "n", + "京东": "n" + }, + "快应用": { + "华为": "n", + "联盟": "n" + } + } + } + } +} diff --git a/uni_modules/uts-progressNotification/readme.md b/uni_modules/uts-progressNotification/readme.md new file mode 100644 index 0000000..87d8576 --- /dev/null +++ b/uni_modules/uts-progressNotification/readme.md @@ -0,0 +1,71 @@ +# uts-progressNotification + +## 使用说明 + +Android平台创建显示进度的通知栏消息 + +**注意: 需要自定义基座,否则点击通知栏消息不会拉起应用** + +### 导入 + +需要import导入插件 + +### createNotificationProgress(options : CreateNotificationProgressOptions) : void, + +创建显示进度的通知栏消息 + +参数说明 + +``` +export type CreateNotificationProgressOptions = { + /** + * 通知标题 + * @defaultValue 应用名称 + */ + title ?: string | null + /** + * 通知内容 + */ + content : string, + /** + * 进度 + */ + progress : number, + /** + * 点击通知消息回调 + * @defaultValue null + */ + onClick? : (() => void) | null +} +``` + +### finishNotificationProgress(options: FinishNotificationProgressOptions) : void + +完成时调用的API,比如下载完成后需要显示下载完成并隐藏进度时调用。 + +参数说明 + + +``` +export type FinishNotificationProgressOptions = { + /** + * 通知标题 + * @defaultValue 应用名称 + */ + title ?: string | null + /** + * 通知内容 + */ + content : string, + /** + * 点击通知消息回调 + */ + onClick : () => void +} +``` + + +### cancelNotificationProgress() : void + +取消通知消息显示 + diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/AndroidManifest.xml b/uni_modules/uts-progressNotification/utssdk/app-android/AndroidManifest.xml new file mode 100644 index 0000000..93749e9 --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/TransparentActivity.uts b/uni_modules/uts-progressNotification/utssdk/app-android/TransparentActivity.uts new file mode 100644 index 0000000..1967899 --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/TransparentActivity.uts @@ -0,0 +1,62 @@ +import Activity from "android.app.Activity"; +import Bundle from 'android.os.Bundle'; +import Build from 'android.os.Build'; +import View from 'android.view.View'; +import Color from 'android.graphics.Color'; +import WindowManager from 'android.view.WindowManager'; +import { globalNotificationProgressFinishCallBack, globalNotificationProgressCallBack } from './callbacks.uts'; +import { ACTION_DOWNLOAD_FINISH, ACTION_DOWNLOAD_PROGRESS } from "./constant.uts" + + +export class TransparentActivity extends Activity { + constructor() { + super() + } + + @Suppress("DEPRECATION") + override onCreate(savedInstanceState : Bundle | null) { + super.onCreate(savedInstanceState) + this.fullScreen(this) + const action = this.getIntent().getAction() + if (action == ACTION_DOWNLOAD_FINISH) { + setTimeout(() => { + globalNotificationProgressFinishCallBack() + globalNotificationProgressFinishCallBack = () => { } + }, 100) + this.overridePendingTransition(0, 0) + } + + if (action == ACTION_DOWNLOAD_PROGRESS) { + setTimeout(() => { + globalNotificationProgressCallBack?.() + globalNotificationProgressCallBack = () => { } + }, 100) + this.overridePendingTransition(0, 0) + } + + setTimeout(() => { + this.finish() + }, 20) + } + + + @Suppress("DEPRECATION") + private fullScreen(activity : Activity) { + if (Build.VERSION.SDK_INT >= 19) { + if (Build.VERSION.SDK_INT >= 21) { + const window = activity.getWindow(); + const decorView = window.getDecorView(); + const option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; + decorView.setSystemUiVisibility(option); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.TRANSPARENT); + } else { + const window = activity.getWindow(); + const attributes = window.getAttributes(); + const flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; + attributes.flags |= flagTranslucentStatus; + window.setAttributes(attributes); + } + } + } +} diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/callbacks.uts b/uni_modules/uts-progressNotification/utssdk/app-android/callbacks.uts new file mode 100644 index 0000000..1e5604d --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/callbacks.uts @@ -0,0 +1,4 @@ + + +export let globalNotificationProgressCallBack : (() => void) | null = () => { } +export let globalNotificationProgressFinishCallBack = () => { } diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/config.json b/uni_modules/uts-progressNotification/utssdk/app-android/config.json new file mode 100644 index 0000000..7deedfa --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/config.json @@ -0,0 +1,3 @@ +{ + "minSdkVersion": "19" +} \ No newline at end of file diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/constant.uts b/uni_modules/uts-progressNotification/utssdk/app-android/constant.uts new file mode 100644 index 0000000..8652ac4 --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/constant.uts @@ -0,0 +1,2 @@ +export const ACTION_DOWNLOAD_FINISH = "ACTION_DOWNLOAD_FINISH" +export const ACTION_DOWNLOAD_PROGRESS = "ACTION_DOWNLOAD_PROGRESS" \ No newline at end of file diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/index.uts b/uni_modules/uts-progressNotification/utssdk/app-android/index.uts new file mode 100644 index 0000000..0782f61 --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/index.uts @@ -0,0 +1,159 @@ +import Build from 'android.os.Build'; +import Context from 'android.content.Context'; +import NotificationManager from 'android.app.NotificationManager'; +import NotificationChannel from 'android.app.NotificationChannel'; +import Notification from 'android.app.Notification'; +import Intent from 'android.content.Intent'; +import ComponentName from 'android.content.ComponentName'; +import PendingIntent from 'android.app.PendingIntent'; +import { CreateNotificationProgressOptions, FinishNotificationProgressOptions } from '../interface.uts'; +import { ACTION_DOWNLOAD_FINISH, ACTION_DOWNLOAD_PROGRESS } from "./constant.uts" + +import { globalNotificationProgressFinishCallBack, globalNotificationProgressCallBack } from './callbacks.uts'; + +export { TransparentActivity } from './TransparentActivity.uts'; + + +const DOWNLOAD_PROGRESS_NOTIFICATION_ID : Int = 7890 +const DC_DOWNLOAD_CHANNEL_ID = "下载文件" +const DC_DOWNLOAD_CHANNEL_NAME = "用于显示现在进度的渠道" + + +let notificationBuilder : Notification.Builder | null = null + +let timeId = -1 + +let histroyProgress = 0 + +let isProgress = false + + + +export function createNotificationProgress(options : CreateNotificationProgressOptions) : void { + const { content, progress, onClick } = options + + if (progress == 100) { + clearTimeout(timeId) + const context = UTSAndroid.getAppContext() as Context + realCreateNotificationProgress(options.title ?? getAppName(context), content, progress, onClick) + reset() + return + } + + histroyProgress = progress + if (timeId != -1) { + return + } + + const context = UTSAndroid.getAppContext() as Context + if (!isProgress) { + realCreateNotificationProgress(options.title ?? getAppName(context), content, histroyProgress, onClick) + isProgress = true + } else { + timeId = setTimeout(() => { + realCreateNotificationProgress(options.title ?? getAppName(context), content, histroyProgress, onClick) + timeId = -1 + }, 1000) + } +} + + +export function cancelNotificationProgress() : void { + const context = UTSAndroid.getAppContext() as Context + const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancel(DOWNLOAD_PROGRESS_NOTIFICATION_ID) + reset() +} + + +function realCreateNotificationProgress(title : string, content : string, progress : number, cb : (() => void) | null) : void { + globalNotificationProgressCallBack = cb + const context = UTSAndroid.getAppContext() as Context + const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + createDownloadChannel(notificationManager) + const builder = createNotificationBuilder(context) + builder.setProgress(100, progress.toInt(), false) + builder.setContentTitle(title) + builder.setContentText(content) + builder.setContentIntent(createPendingIntent(context, ACTION_DOWNLOAD_PROGRESS)); + notificationManager.notify(DOWNLOAD_PROGRESS_NOTIFICATION_ID, builder.build()) +} + + +export function finishNotificationProgress(options : FinishNotificationProgressOptions) { + globalNotificationProgressFinishCallBack = options.onClick + const context = UTSAndroid.getAppContext() as Context + const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + createDownloadChannel(notificationManager) + const builder = createNotificationBuilder(context) + builder.setProgress(0, 0, false) + builder.setContentTitle(options.title ?? getAppName(context)) + builder.setContentText(options.content) + //小米rom setOngoing未false的时候,会被通知管理器归为不重要通知 + // builder.setOngoing(false) + builder.setAutoCancel(true); + builder.setContentIntent(createPendingIntent(context, ACTION_DOWNLOAD_FINISH)); + notificationManager.notify(DOWNLOAD_PROGRESS_NOTIFICATION_ID, builder.build()) + reset() +} + +function reset() { + isProgress = false + notificationBuilder = null + histroyProgress = 0 + if (timeId != -1) { + clearTimeout(timeId) + timeId = -1 + } +} + + + +function createPendingIntent(context : Context, action : string) : PendingIntent { + const i = new Intent(action); + i.setComponent(new ComponentName(context.getPackageName(), "uts.sdk.modules.utsProgressNotification.TransparentActivity")); + let flags = PendingIntent.FLAG_ONE_SHOT; + if (Build.VERSION.SDK_INT >= 23) { + flags = PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE; + } + return PendingIntent.getActivity(context, DOWNLOAD_PROGRESS_NOTIFICATION_ID, i, flags); +} + + +function createDownloadChannel(notificationManager : NotificationManager) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + const channel = new NotificationChannel( + DC_DOWNLOAD_CHANNEL_ID, + DC_DOWNLOAD_CHANNEL_NAME, + NotificationManager.IMPORTANCE_LOW + ) + notificationManager.createNotificationChannel(channel) + } +} +@Suppress("DEPRECATION") +function createNotificationBuilder(context : Context) : Notification.Builder { + if (notificationBuilder == null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder = new Notification.Builder(context, DC_DOWNLOAD_CHANNEL_ID) + } else { + notificationBuilder = new Notification.Builder(context) + } + notificationBuilder!.setSmallIcon(context.getApplicationInfo().icon) + notificationBuilder!.setOngoing(true) + notificationBuilder!.setSound(null) + } + return notificationBuilder! +} + +@Suppress("DEPRECATION") +function getAppName(context : Context) : string { + let appName = "" + try { + const packageManager = context.getPackageManager() + const applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0) + appName = packageManager.getApplicationLabel(applicationInfo) as string + } catch (e : Exception) { + e.printStackTrace() + } + return appName +} diff --git a/uni_modules/uts-progressNotification/utssdk/app-android/res/values/notification_progress_styles.xml b/uni_modules/uts-progressNotification/utssdk/app-android/res/values/notification_progress_styles.xml new file mode 100644 index 0000000..90db6f0 --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/app-android/res/values/notification_progress_styles.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/uni_modules/uts-progressNotification/utssdk/interface.uts b/uni_modules/uts-progressNotification/utssdk/interface.uts new file mode 100644 index 0000000..9570353 --- /dev/null +++ b/uni_modules/uts-progressNotification/utssdk/interface.uts @@ -0,0 +1,46 @@ +export type CreateNotificationProgressOptions = { + /** + * 通知标题 + * @defaultValue 应用名称 + */ + title ?: string | null + /** + * 通知内容 + */ + content : string, + /** + * 进度 + */ + progress : number, + /** + * 点击通知消息回调 + * @defaultValue null + */ + onClick? : (() => void) | null +} + + +export type FinishNotificationProgressOptions = { + /** + * 通知标题 + * @defaultValue 应用名称 + */ + title ?: string | null + /** + * 通知内容 + */ + content : string, + /** + * 点击通知消息回调 + */ + onClick : () => void +} + + +export type CreateNotificationProgress = (options : CreateNotificationProgressOptions) => void; + + +export type CancelNotificationProgress = () => void; + + +export type FinishNotificationProgress = (options: FinishNotificationProgressOptions) => void diff --git a/windows/left-window.vue b/windows/left-window.vue new file mode 100644 index 0000000..f8507de --- /dev/null +++ b/windows/left-window.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/windows/top-window.vue b/windows/top-window.vue new file mode 100644 index 0000000..cbda035 --- /dev/null +++ b/windows/top-window.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/wxcomponents/vant/button/index.d.ts b/wxcomponents/vant/button/index.d.ts new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/wxcomponents/vant/button/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/wxcomponents/vant/button/index.js b/wxcomponents/vant/button/index.js new file mode 100644 index 0000000..5248eff --- /dev/null +++ b/wxcomponents/vant/button/index.js @@ -0,0 +1,68 @@ +import { VantComponent } from '../common/component'; +import { button } from '../mixins/button'; +import { openType } from '../mixins/open-type'; +VantComponent({ + mixins: [button, openType], + classes: ['hover-class', 'loading-class'], + data: { + style: '' + }, + props: { + icon: String, + plain: Boolean, + block: Boolean, + round: Boolean, + square: Boolean, + loading: Boolean, + hairline: Boolean, + disabled: Boolean, + loadingText: String, + customStyle: String, + loadingType: { + type: String, + value: 'circular' + }, + type: { + type: String, + value: 'default' + }, + size: { + type: String, + value: 'normal' + }, + loadingSize: { + type: String, + value: '20px' + }, + color: { + type: String, + observer(color) { + let style = ''; + if (color) { + style += `color: ${this.data.plain ? color : 'white'};`; + if (!this.data.plain) { + // Use background instead of backgroundColor to make linear-gradient work + style += `background: ${color};`; + } + // hide border when color is linear-gradient + if (color.indexOf('gradient') !== -1) { + style += 'border: 0;'; + } + else { + style += `border-color: ${color};`; + } + } + if (style !== this.data.style) { + this.setData({ style }); + } + } + } + }, + methods: { + onClick() { + if (!this.data.disabled && !this.data.loading) { + this.$emit('click'); + } + } + } +}); diff --git a/wxcomponents/vant/button/index.json b/wxcomponents/vant/button/index.json new file mode 100644 index 0000000..8e23ad6 --- /dev/null +++ b/wxcomponents/vant/button/index.json @@ -0,0 +1,7 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index", + "van-loading": "../loading/index" + } +} diff --git a/wxcomponents/vant/button/index.wxml b/wxcomponents/vant/button/index.wxml new file mode 100644 index 0000000..7abf6a4 --- /dev/null +++ b/wxcomponents/vant/button/index.wxml @@ -0,0 +1,52 @@ + + + diff --git a/wxcomponents/vant/button/index.wxss b/wxcomponents/vant/button/index.wxss new file mode 100644 index 0000000..0d302cb --- /dev/null +++ b/wxcomponents/vant/button/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-button{position:relative;display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;padding:0;line-height:20px;text-align:center;vertical-align:middle;-webkit-appearance:none;-webkit-text-size-adjust:100%;height:44px;height:var(--button-default-height,44px);font-size:16px;font-size:var(--button-default-font-size,16px);transition:opacity .2s;transition:opacity var(--animation-duration-fast,.2s);border-radius:2px;border-radius:var(--button-border-radius,2px)}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#323233;color:var(--button-default-color,#323233);background-color:#fff;background-color:var(--button-default-background-color,#fff);border:1px solid #ebedf0;border:1px solid var(--button-default-border-color,#ebedf0)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background-color:#07c160;background-color:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:1px solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background-color:#1989fa;background-color:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:1px solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background-color:#ee0a24;background-color:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:1px solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background-color:#ff976a;background-color:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:1px solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background-color:#fff;background-color:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;height:var(--button-large-height,50px)}.van-button--normal{padding:0 15px;font-size:14px;font-size:var(--button-normal-font-size,14px)}.van-button--small{min-width:60px;min-width:var(--button-small-min-width,60px);height:30px;height:var(--button-small-height,30px);padding:0 8px;padding:0 var(--padding-xs,8px);font-size:12px;font-size:var(--button-small-font-size,12px)}.van-button--mini{display:inline-block;min-width:50px;min-width:var(--button-mini-min-width,50px);height:22px;height:var(--button-mini-height,22px);font-size:10px;font-size:var(--button-mini-font-size,10px)}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:-webkit-flex;display:flex;width:100%}.van-button--round{border-radius:999px;border-radius:var(--button-round-border-radius,999px)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5;opacity:var(--button-disabled-opacity,.5)}.van-button__text{display:inline}.van-button__icon+.van-button__text:not(:empty),.van-button__loading-text{margin-left:4px}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:999px;border-radius:var(--button-round-border-radius,999px)}.van-button--hairline.van-button--square:after{border-radius:0} \ No newline at end of file diff --git a/wxcomponents/vant/common/color.d.ts b/wxcomponents/vant/common/color.d.ts new file mode 100644 index 0000000..6475dd2 --- /dev/null +++ b/wxcomponents/vant/common/color.d.ts @@ -0,0 +1,7 @@ +export declare const RED = "#ee0a24"; +export declare const BLUE = "#1989fa"; +export declare const WHITE = "#fff"; +export declare const GREEN = "#07c160"; +export declare const ORANGE = "#ff976a"; +export declare const GRAY = "#323233"; +export declare const GRAY_DARK = "#969799"; diff --git a/wxcomponents/vant/common/color.js b/wxcomponents/vant/common/color.js new file mode 100644 index 0000000..9f9f265 --- /dev/null +++ b/wxcomponents/vant/common/color.js @@ -0,0 +1,7 @@ +export const RED = '#ee0a24'; +export const BLUE = '#1989fa'; +export const WHITE = '#fff'; +export const GREEN = '#07c160'; +export const ORANGE = '#ff976a'; +export const GRAY = '#323233'; +export const GRAY_DARK = '#969799'; diff --git a/wxcomponents/vant/common/component.d.ts b/wxcomponents/vant/common/component.d.ts new file mode 100644 index 0000000..0195c84 --- /dev/null +++ b/wxcomponents/vant/common/component.d.ts @@ -0,0 +1,3 @@ +import { VantComponentOptions, CombinedComponentInstance } from '../definitions/index'; +declare function VantComponent(vantOptions?: VantComponentOptions>): void; +export { VantComponent }; diff --git a/wxcomponents/vant/common/component.js b/wxcomponents/vant/common/component.js new file mode 100644 index 0000000..874e6d0 --- /dev/null +++ b/wxcomponents/vant/common/component.js @@ -0,0 +1,48 @@ +import { basic } from '../mixins/basic'; +import { observe } from '../mixins/observer/index'; +function mapKeys(source, target, map) { + Object.keys(map).forEach(key => { + if (source[key]) { + target[map[key]] = source[key]; + } + }); +} +function VantComponent(vantOptions = {}) { + const options = {}; + mapKeys(vantOptions, options, { + data: 'data', + props: 'properties', + mixins: 'behaviors', + methods: 'methods', + beforeCreate: 'created', + created: 'attached', + mounted: 'ready', + relations: 'relations', + destroyed: 'detached', + classes: 'externalClasses' + }); + const { relation } = vantOptions; + if (relation) { + options.relations = Object.assign(options.relations || {}, { + [`../${relation.name}/index`]: relation + }); + } + // add default externalClasses + options.externalClasses = options.externalClasses || []; + options.externalClasses.push('custom-class'); + // add default behaviors + options.behaviors = options.behaviors || []; + options.behaviors.push(basic); + // map field to form-field behavior + if (vantOptions.field) { + options.behaviors.push('wx://form-field'); + } + // add default options + options.options = { + multipleSlots: true, + addGlobalClass: true + }; + observe(vantOptions, options); + Component(options); +} +export { VantComponent }; diff --git a/wxcomponents/vant/common/index.wxss b/wxcomponents/vant/common/index.wxss new file mode 100644 index 0000000..6e6891f --- /dev/null +++ b/wxcomponents/vant/common/index.wxss @@ -0,0 +1 @@ +.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3}.van-clearfix:after{display:table;clear:both;content:""}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px} \ No newline at end of file diff --git a/wxcomponents/vant/common/style/clearfix.wxss b/wxcomponents/vant/common/style/clearfix.wxss new file mode 100644 index 0000000..a0ca838 --- /dev/null +++ b/wxcomponents/vant/common/style/clearfix.wxss @@ -0,0 +1 @@ +.van-clearfix:after{display:table;clear:both;content:""} \ No newline at end of file diff --git a/wxcomponents/vant/common/style/ellipsis.wxss b/wxcomponents/vant/common/style/ellipsis.wxss new file mode 100644 index 0000000..1e9dbc9 --- /dev/null +++ b/wxcomponents/vant/common/style/ellipsis.wxss @@ -0,0 +1 @@ +.van-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical}.van-multi-ellipsis--l3{-webkit-line-clamp:3} \ No newline at end of file diff --git a/wxcomponents/vant/common/style/hairline.wxss b/wxcomponents/vant/common/style/hairline.wxss new file mode 100644 index 0000000..f64e2f8 --- /dev/null +++ b/wxcomponents/vant/common/style/hairline.wxss @@ -0,0 +1 @@ +.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;top:-50%;right:-50%;bottom:-50%;left:-50%;border:0 solid #eee;-webkit-transform:scale(.5);transform:scale(.5)}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px} \ No newline at end of file diff --git a/wxcomponents/vant/common/utils.d.ts b/wxcomponents/vant/common/utils.d.ts new file mode 100644 index 0000000..d222e08 --- /dev/null +++ b/wxcomponents/vant/common/utils.d.ts @@ -0,0 +1,8 @@ +/// +export declare function isDef(value: any): boolean; +export declare function isObj(x: any): boolean; +export declare function isNumber(value: any): boolean; +export declare function range(num: number, min: number, max: number): number; +export declare function nextTick(fn: Function): void; +export declare function getSystemInfoSync(): WechatMiniprogram.GetSystemInfoSuccessCallbackResult; +export declare function addUnit(value?: string | number): string | undefined; diff --git a/wxcomponents/vant/common/utils.js b/wxcomponents/vant/common/utils.js new file mode 100644 index 0000000..d1256aa --- /dev/null +++ b/wxcomponents/vant/common/utils.js @@ -0,0 +1,32 @@ +export function isDef(value) { + return value !== undefined && value !== null; +} +export function isObj(x) { + const type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} +export function isNumber(value) { + return /^\d+(\.\d+)?$/.test(value); +} +export function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} +export function nextTick(fn) { + setTimeout(() => { + fn(); + }, 1000 / 30); +} +let systemInfo = null; +export function getSystemInfoSync() { + if (systemInfo == null) { + systemInfo = wx.getSystemInfoSync(); + } + return systemInfo; +} +export function addUnit(value) { + if (!isDef(value)) { + return undefined; + } + value = String(value); + return isNumber(value) ? `${value}px` : value; +} diff --git a/wxcomponents/vant/icon/index.d.ts b/wxcomponents/vant/icon/index.d.ts new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/wxcomponents/vant/icon/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/wxcomponents/vant/icon/index.js b/wxcomponents/vant/icon/index.js new file mode 100644 index 0000000..587ace9 --- /dev/null +++ b/wxcomponents/vant/icon/index.js @@ -0,0 +1,39 @@ +import { VantComponent } from '../common/component'; +import { addUnit } from '../common/utils'; +VantComponent({ + props: { + dot: Boolean, + info: null, + size: { + type: null, + observer: 'setSizeWithUnit' + }, + color: String, + customStyle: String, + classPrefix: { + type: String, + value: 'van-icon' + }, + name: { + type: String, + observer(val) { + this.setData({ + isImageName: val.indexOf('/') !== -1 + }); + } + } + }, + data: { + sizeWithUnit: null, + }, + methods: { + onClick() { + this.$emit('click'); + }, + setSizeWithUnit(size) { + this.setData({ + sizeWithUnit: addUnit(size) + }); + } + } +}); diff --git a/wxcomponents/vant/icon/index.json b/wxcomponents/vant/icon/index.json new file mode 100644 index 0000000..82369bf --- /dev/null +++ b/wxcomponents/vant/icon/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-info": "../info/index" + } +} diff --git a/wxcomponents/vant/icon/index.wxml b/wxcomponents/vant/icon/index.wxml new file mode 100644 index 0000000..6b4c609 --- /dev/null +++ b/wxcomponents/vant/icon/index.wxml @@ -0,0 +1,18 @@ + + + + diff --git a/wxcomponents/vant/icon/index.wxss b/wxcomponents/vant/icon/index.wxss new file mode 100644 index 0000000..14ef793 --- /dev/null +++ b/wxcomponents/vant/icon/index.wxss @@ -0,0 +1,957 @@ +@import '../common/index.wxss'; + +@font-face { + font-weight: 400; + font-family: vant-icon; + font-style: normal; + font-display: auto; + src: url(https://img.yzcdn.cn/vant/vant-icon-d3825a.woff2) format("woff2"), url(https://img.yzcdn.cn/vant/vant-icon-d3825a.woff) format("woff"), url(https://img.yzcdn.cn/vant/vant-icon-d3825a.ttf) format("truetype") +} + +.van-icon { + position: relative; + font: normal normal normal 14px/1 vant-icon; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased +} + +.van-icon, +.van-icon:before { + display: inline-block +} + +.van-icon-add-o:before { + content: "\F000" +} + +.van-icon-add-square:before { + content: "\F001" +} + +.van-icon-add:before { + content: "\F002" +} + +.van-icon-after-sale:before { + content: "\F003" +} + +.van-icon-aim:before { + content: "\F004" +} + +.van-icon-alipay:before { + content: "\F005" +} + +.van-icon-apps-o:before { + content: "\F006" +} + +.van-icon-arrow-down:before { + content: "\F007" +} + +.van-icon-arrow-left:before { + content: "\F008" +} + +.van-icon-arrow-up:before { + content: "\F009" +} + +.van-icon-arrow:before { + content: "\F00A" +} + +.van-icon-ascending:before { + content: "\F00B" +} + +.van-icon-audio:before { + content: "\F00C" +} + +.van-icon-award-o:before { + content: "\F00D" +} + +.van-icon-award:before { + content: "\F00E" +} + +.van-icon-bag-o:before { + content: "\F00F" +} + +.van-icon-bag:before { + content: "\F010" +} + +.van-icon-balance-list-o:before { + content: "\F011" +} + +.van-icon-balance-list:before { + content: "\F012" +} + +.van-icon-balance-o:before { + content: "\F013" +} + +.van-icon-balance-pay:before { + content: "\F014" +} + +.van-icon-bar-chart-o:before { + content: "\F015" +} + +.van-icon-bars:before { + content: "\F016" +} + +.van-icon-bell:before { + content: "\F017" +} + +.van-icon-bill-o:before { + content: "\F018" +} + +.van-icon-bill:before { + content: "\F019" +} + +.van-icon-birthday-cake-o:before { + content: "\F01A" +} + +.van-icon-bookmark-o:before { + content: "\F01B" +} + +.van-icon-bookmark:before { + content: "\F01C" +} + +.van-icon-browsing-history-o:before { + content: "\F01D" +} + +.van-icon-browsing-history:before { + content: "\F01E" +} + +.van-icon-brush-o:before { + content: "\F01F" +} + +.van-icon-bulb-o:before { + content: "\F020" +} + +.van-icon-bullhorn-o:before { + content: "\F021" +} + +.van-icon-calender-o:before { + content: "\F022" +} + +.van-icon-card:before { + content: "\F023" +} + +.van-icon-cart-circle-o:before { + content: "\F024" +} + +.van-icon-cart-circle:before { + content: "\F025" +} + +.van-icon-cart-o:before { + content: "\F026" +} + +.van-icon-cart:before { + content: "\F027" +} + +.van-icon-cash-back-record:before { + content: "\F028" +} + +.van-icon-cash-on-deliver:before { + content: "\F029" +} + +.van-icon-cashier-o:before { + content: "\F02A" +} + +.van-icon-certificate:before { + content: "\F02B" +} + +.van-icon-chart-trending-o:before { + content: "\F02C" +} + +.van-icon-chat-o:before { + content: "\F02D" +} + +.van-icon-chat:before { + content: "\F02E" +} + +.van-icon-checked:before { + content: "\F02F" +} + +.van-icon-circle:before { + content: "\F030" +} + +.van-icon-clear:before { + content: "\F031" +} + +.van-icon-clock-o:before { + content: "\F032" +} + +.van-icon-clock:before { + content: "\F033" +} + +.van-icon-close:before { + content: "\F034" +} + +.van-icon-closed-eye:before { + content: "\F035" +} + +.van-icon-cluster-o:before { + content: "\F036" +} + +.van-icon-cluster:before { + content: "\F037" +} + +.van-icon-column:before { + content: "\F038" +} + +.van-icon-comment-circle-o:before { + content: "\F039" +} + +.van-icon-comment-circle:before { + content: "\F03A" +} + +.van-icon-comment-o:before { + content: "\F03B" +} + +.van-icon-comment:before { + content: "\F03C" +} + +.van-icon-completed:before { + content: "\F03D" +} + +.van-icon-contact:before { + content: "\F03E" +} + +.van-icon-coupon-o:before { + content: "\F03F" +} + +.van-icon-coupon:before { + content: "\F040" +} + +.van-icon-credit-pay:before { + content: "\F041" +} + +.van-icon-cross:before { + content: "\F042" +} + +.van-icon-debit-pay:before { + content: "\F043" +} + +.van-icon-delete:before { + content: "\F044" +} + +.van-icon-descending:before { + content: "\F045" +} + +.van-icon-description:before { + content: "\F046" +} + +.van-icon-desktop-o:before { + content: "\F047" +} + +.van-icon-diamond-o:before { + content: "\F048" +} + +.van-icon-diamond:before { + content: "\F049" +} + +.van-icon-discount:before { + content: "\F04A" +} + +.van-icon-down:before { + content: "\F04B" +} + +.van-icon-ecard-pay:before { + content: "\F04C" +} + +.van-icon-edit:before { + content: "\F04D" +} + +.van-icon-ellipsis:before { + content: "\F04E" +} + +.van-icon-empty:before { + content: "\F04F" +} + +.van-icon-envelop-o:before { + content: "\F050" +} + +.van-icon-exchange:before { + content: "\F051" +} + +.van-icon-expand-o:before { + content: "\F052" +} + +.van-icon-expand:before { + content: "\F053" +} + +.van-icon-eye-o:before { + content: "\F054" +} + +.van-icon-eye:before { + content: "\F055" +} + +.van-icon-fail:before { + content: "\F056" +} + +.van-icon-failure:before { + content: "\F057" +} + +.van-icon-filter-o:before { + content: "\F058" +} + +.van-icon-fire-o:before { + content: "\F059" +} + +.van-icon-fire:before { + content: "\F05A" +} + +.van-icon-flag-o:before { + content: "\F05B" +} + +.van-icon-flower-o:before { + content: "\F05C" +} + +.van-icon-free-postage:before { + content: "\F05D" +} + +.van-icon-friends-o:before { + content: "\F05E" +} + +.van-icon-friends:before { + content: "\F05F" +} + +.van-icon-gem-o:before { + content: "\F060" +} + +.van-icon-gem:before { + content: "\F061" +} + +.van-icon-gift-card-o:before { + content: "\F062" +} + +.van-icon-gift-card:before { + content: "\F063" +} + +.van-icon-gift-o:before { + content: "\F064" +} + +.van-icon-gift:before { + content: "\F065" +} + +.van-icon-gold-coin-o:before { + content: "\F066" +} + +.van-icon-gold-coin:before { + content: "\F067" +} + +.van-icon-good-job-o:before { + content: "\F068" +} + +.van-icon-good-job:before { + content: "\F069" +} + +.van-icon-goods-collect-o:before { + content: "\F06A" +} + +.van-icon-goods-collect:before { + content: "\F06B" +} + +.van-icon-graphic:before { + content: "\F06C" +} + +.van-icon-home-o:before { + content: "\F06D" +} + +.van-icon-hot-o:before { + content: "\F06E" +} + +.van-icon-hot-sale-o:before { + content: "\F06F" +} + +.van-icon-hot-sale:before { + content: "\F070" +} + +.van-icon-hot:before { + content: "\F071" +} + +.van-icon-hotel-o:before { + content: "\F072" +} + +.van-icon-idcard:before { + content: "\F073" +} + +.van-icon-info-o:before { + content: "\F074" +} + +.van-icon-info:before { + content: "\F075" +} + +.van-icon-invition:before { + content: "\F076" +} + +.van-icon-label-o:before { + content: "\F077" +} + +.van-icon-label:before { + content: "\F078" +} + +.van-icon-like-o:before { + content: "\F079" +} + +.van-icon-like:before { + content: "\F07A" +} + +.van-icon-live:before { + content: "\F07B" +} + +.van-icon-location-o:before { + content: "\F07C" +} + +.van-icon-location:before { + content: "\F07D" +} + +.van-icon-lock:before { + content: "\F07E" +} + +.van-icon-logistics:before { + content: "\F07F" +} + +.van-icon-manager-o:before { + content: "\F080" +} + +.van-icon-manager:before { + content: "\F081" +} + +.van-icon-map-marked:before { + content: "\F082" +} + +.van-icon-medal-o:before { + content: "\F083" +} + +.van-icon-medal:before { + content: "\F084" +} + +.van-icon-more-o:before { + content: "\F085" +} + +.van-icon-more:before { + content: "\F086" +} + +.van-icon-music-o:before { + content: "\F087" +} + +.van-icon-music:before { + content: "\F088" +} + +.van-icon-new-arrival-o:before { + content: "\F089" +} + +.van-icon-new-arrival:before { + content: "\F08A" +} + +.van-icon-new-o:before { + content: "\F08B" +} + +.van-icon-new:before { + content: "\F08C" +} + +.van-icon-newspaper-o:before { + content: "\F08D" +} + +.van-icon-notes-o:before { + content: "\F08E" +} + +.van-icon-orders-o:before { + content: "\F08F" +} + +.van-icon-other-pay:before { + content: "\F090" +} + +.van-icon-paid:before { + content: "\F091" +} + +.van-icon-passed:before { + content: "\F092" +} + +.van-icon-pause-circle-o:before { + content: "\F093" +} + +.van-icon-pause-circle:before { + content: "\F094" +} + +.van-icon-pause:before { + content: "\F095" +} + +.van-icon-peer-pay:before { + content: "\F096" +} + +.van-icon-pending-payment:before { + content: "\F097" +} + +.van-icon-phone-circle-o:before { + content: "\F098" +} + +.van-icon-phone-circle:before { + content: "\F099" +} + +.van-icon-phone-o:before { + content: "\F09A" +} + +.van-icon-phone:before { + content: "\F09B" +} + +.van-icon-photo-o:before { + content: "\F09C" +} + +.van-icon-photo:before { + content: "\F09D" +} + +.van-icon-photograph:before { + content: "\F09E" +} + +.van-icon-play-circle-o:before { + content: "\F09F" +} + +.van-icon-play-circle:before { + content: "\F0A0" +} + +.van-icon-play:before { + content: "\F0A1" +} + +.van-icon-plus:before { + content: "\F0A2" +} + +.van-icon-point-gift-o:before { + content: "\F0A3" +} + +.van-icon-point-gift:before { + content: "\F0A4" +} + +.van-icon-points:before { + content: "\F0A5" +} + +.van-icon-printer:before { + content: "\F0A6" +} + +.van-icon-qr-invalid:before { + content: "\F0A7" +} + +.van-icon-qr:before { + content: "\F0A8" +} + +.van-icon-question-o:before { + content: "\F0A9" +} + +.van-icon-question:before { + content: "\F0AA" +} + +.van-icon-records:before { + content: "\F0AB" +} + +.van-icon-refund-o:before { + content: "\F0AC" +} + +.van-icon-replay:before { + content: "\F0AD" +} + +.van-icon-scan:before { + content: "\F0AE" +} + +.van-icon-search:before { + content: "\F0AF" +} + +.van-icon-send-gift-o:before { + content: "\F0B0" +} + +.van-icon-send-gift:before { + content: "\F0B1" +} + +.van-icon-service-o:before { + content: "\F0B2" +} + +.van-icon-service:before { + content: "\F0B3" +} + +.van-icon-setting-o:before { + content: "\F0B4" +} + +.van-icon-setting:before { + content: "\F0B5" +} + +.van-icon-share:before { + content: "\F0B6" +} + +.van-icon-shop-collect-o:before { + content: "\F0B7" +} + +.van-icon-shop-collect:before { + content: "\F0B8" +} + +.van-icon-shop-o:before { + content: "\F0B9" +} + +.van-icon-shop:before { + content: "\F0BA" +} + +.van-icon-shopping-cart-o:before { + content: "\F0BB" +} + +.van-icon-shopping-cart:before { + content: "\F0BC" +} + +.van-icon-shrink:before { + content: "\F0BD" +} + +.van-icon-sign:before { + content: "\F0BE" +} + +.van-icon-smile-comment-o:before { + content: "\F0BF" +} + +.van-icon-smile-comment:before { + content: "\F0C0" +} + +.van-icon-smile-o:before { + content: "\F0C1" +} + +.van-icon-smile:before { + content: "\F0C2" +} + +.van-icon-star-o:before { + content: "\F0C3" +} + +.van-icon-star:before { + content: "\F0C4" +} + +.van-icon-stop-circle-o:before { + content: "\F0C5" +} + +.van-icon-stop-circle:before { + content: "\F0C6" +} + +.van-icon-stop:before { + content: "\F0C7" +} + +.van-icon-success:before { + content: "\F0C8" +} + +.van-icon-thumb-circle-o:before { + content: "\F0C9" +} + +.van-icon-thumb-circle:before { + content: "\F0CA" +} + +.van-icon-todo-list-o:before { + content: "\F0CB" +} + +.van-icon-todo-list:before { + content: "\F0CC" +} + +.van-icon-tosend:before { + content: "\F0CD" +} + +.van-icon-tv-o:before { + content: "\F0CE" +} + +.van-icon-umbrella-circle:before { + content: "\F0CF" +} + +.van-icon-underway-o:before { + content: "\F0D0" +} + +.van-icon-underway:before { + content: "\F0D1" +} + +.van-icon-upgrade:before { + content: "\F0D2" +} + +.van-icon-user-circle-o:before { + content: "\F0D3" +} + +.van-icon-user-o:before { + content: "\F0D4" +} + +.van-icon-video-o:before { + content: "\F0D5" +} + +.van-icon-video:before { + content: "\F0D6" +} + +.van-icon-vip-card-o:before { + content: "\F0D7" +} + +.van-icon-vip-card:before { + content: "\F0D8" +} + +.van-icon-volume-o:before { + content: "\F0D9" +} + +.van-icon-volume:before { + content: "\F0DA" +} + +.van-icon-wap-home-o:before { + content: "\F0DB" +} + +.van-icon-wap-home:before { + content: "\F0DC" +} + +.van-icon-wap-nav:before { + content: "\F0DD" +} + +.van-icon-warn-o:before { + content: "\F0DE" +} + +.van-icon-warning-o:before { + content: "\F0DF" +} + +.van-icon-warning:before { + content: "\F0E0" +} + +.van-icon-weapp-nav:before { + content: "\F0E1" +} + +.van-icon-wechat:before { + content: "\F0E2" +} + +.van-icon-youzan-shield:before { + content: "\F0E3" +} + +:host { + display: -webkit-inline-flex; + display: inline-flex; + -webkit-align-items: center; + align-items: center; + -webkit-justify-content: center; + justify-content: center +} + +.van-icon--image { + width: 1em; + height: 1em +} + +.van-icon__image { + width: 100%; + height: 100% +} + +.van-icon__info { + z-index: 1 +} diff --git a/wxcomponents/vant/info/index.d.ts b/wxcomponents/vant/info/index.d.ts new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/wxcomponents/vant/info/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/wxcomponents/vant/info/index.js b/wxcomponents/vant/info/index.js new file mode 100644 index 0000000..7c91e72 --- /dev/null +++ b/wxcomponents/vant/info/index.js @@ -0,0 +1,8 @@ +import { VantComponent } from '../common/component'; +VantComponent({ + props: { + dot: Boolean, + info: null, + customStyle: String + } +}); diff --git a/wxcomponents/vant/info/index.json b/wxcomponents/vant/info/index.json new file mode 100644 index 0000000..efdc3c8 --- /dev/null +++ b/wxcomponents/vant/info/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/wxcomponents/vant/info/index.wxml b/wxcomponents/vant/info/index.wxml new file mode 100644 index 0000000..ea2d23b --- /dev/null +++ b/wxcomponents/vant/info/index.wxml @@ -0,0 +1,7 @@ + + +{{ dot ? '' : info }} diff --git a/wxcomponents/vant/info/index.wxss b/wxcomponents/vant/info/index.wxss new file mode 100644 index 0000000..16e3f32 --- /dev/null +++ b/wxcomponents/vant/info/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-info{position:absolute;top:0;right:0;box-sizing:border-box;white-space:nowrap;text-align:center;-webkit-transform:translate(50%,-50%);transform:translate(50%,-50%);-webkit-transform-origin:100%;transform-origin:100%;min-width:16px;min-width:var(--info-size,16px);padding:0 3px;padding:var(--info-padding,0 3px);color:#fff;color:var(--info-color,#fff);font-weight:500;font-weight:var(--info-font-weight,500);font-size:12px;font-size:var(--info-font-size,12px);font-family:PingFang SC,Helvetica Neue,Arial,sans-serif;font-family:var(--info-font-family,PingFang SC,Helvetica Neue,Arial,sans-serif);line-height:14px;line-height:calc(var(--info-size, 16px) - var(--info-border-width, 1px)*2);background-color:#ee0a24;background-color:var(--info-background-color,#ee0a24);border:1px solid #fff;border:var(--info-border-width,1px) solid var(--white,#fff);border-radius:16px;border-radius:var(--info-size,16px)}.van-info--dot{min-width:0;border-radius:100%;width:8px;width:var(--info-dot-size,8px);height:8px;height:var(--info-dot-size,8px);background-color:#ee0a24;background-color:var(--info-dot-color,#ee0a24)} \ No newline at end of file diff --git a/wxcomponents/vant/loading/index.d.ts b/wxcomponents/vant/loading/index.d.ts new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/wxcomponents/vant/loading/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/wxcomponents/vant/loading/index.js b/wxcomponents/vant/loading/index.js new file mode 100644 index 0000000..e4ff431 --- /dev/null +++ b/wxcomponents/vant/loading/index.js @@ -0,0 +1,32 @@ +import { VantComponent } from '../common/component'; +import { addUnit } from '../common/utils'; +VantComponent({ + props: { + color: String, + vertical: Boolean, + type: { + type: String, + value: 'circular' + }, + size: { + type: String, + observer: 'setSizeWithUnit' + }, + textSize: { + type: String, + observer: 'setTextSizeWithUnit' + } + }, + methods: { + setSizeWithUnit(size) { + this.setData({ + sizeWithUnit: addUnit(size) + }); + }, + setTextSizeWithUnit(size) { + this.set({ + textSizeWithUnit: addUnit(size) + }); + } + } +}); diff --git a/wxcomponents/vant/loading/index.json b/wxcomponents/vant/loading/index.json new file mode 100644 index 0000000..1edff93 --- /dev/null +++ b/wxcomponents/vant/loading/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} \ No newline at end of file diff --git a/wxcomponents/vant/loading/index.wxml b/wxcomponents/vant/loading/index.wxml new file mode 100644 index 0000000..6fac407 --- /dev/null +++ b/wxcomponents/vant/loading/index.wxml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/wxcomponents/vant/loading/index.wxss b/wxcomponents/vant/loading/index.wxss new file mode 100644 index 0000000..f28a6b4 --- /dev/null +++ b/wxcomponents/vant/loading/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';:host{font-size:0;line-height:1}.van-loading{display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;color:#c8c9cc;color:var(--loading-spinner-color,#c8c9cc)}.van-loading__spinner{position:relative;box-sizing:border-box;width:30px;width:var(--loading-spinner-size,30px);max-width:100%;max-height:100%;height:30px;height:var(--loading-spinner-size,30px);-webkit-animation:van-rotate .8s linear infinite;animation:van-rotate .8s linear infinite;-webkit-animation:van-rotate var(--loading-spinner-animation-duration,.8s) linear infinite;animation:van-rotate var(--loading-spinner-animation-duration,.8s) linear infinite}.van-loading__spinner--spinner{-webkit-animation-timing-function:steps(12);animation-timing-function:steps(12)}.van-loading__spinner--circular{border:1px solid transparent;border-top-color:initial;border-radius:100%}.van-loading__text{margin-left:8px;margin-left:var(--padding-xs,8px);color:#969799;color:var(--loading-text-color,#969799);font-size:14px;font-size:var(--loading-text-font-size,14px);line-height:20px;line-height:var(--loading-text-line-height,20px)}.van-loading__text:empty{display:none}.van-loading--vertical{-webkit-flex-direction:column;flex-direction:column}.van-loading--vertical .van-loading__text{margin:8px 0 0;margin:var(--padding-xs,8px) 0 0}.van-loading__dot{position:absolute;top:0;left:0;width:100%;height:100%}.van-loading__dot:before{display:block;width:2px;height:25%;margin:0 auto;background-color:currentColor;border-radius:40%;content:" "}.van-loading__dot:first-of-type{-webkit-transform:rotate(30deg);transform:rotate(30deg);opacity:1}.van-loading__dot:nth-of-type(2){-webkit-transform:rotate(60deg);transform:rotate(60deg);opacity:.9375}.van-loading__dot:nth-of-type(3){-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:.875}.van-loading__dot:nth-of-type(4){-webkit-transform:rotate(120deg);transform:rotate(120deg);opacity:.8125}.van-loading__dot:nth-of-type(5){-webkit-transform:rotate(150deg);transform:rotate(150deg);opacity:.75}.van-loading__dot:nth-of-type(6){-webkit-transform:rotate(180deg);transform:rotate(180deg);opacity:.6875}.van-loading__dot:nth-of-type(7){-webkit-transform:rotate(210deg);transform:rotate(210deg);opacity:.625}.van-loading__dot:nth-of-type(8){-webkit-transform:rotate(240deg);transform:rotate(240deg);opacity:.5625}.van-loading__dot:nth-of-type(9){-webkit-transform:rotate(270deg);transform:rotate(270deg);opacity:.5}.van-loading__dot:nth-of-type(10){-webkit-transform:rotate(300deg);transform:rotate(300deg);opacity:.4375}.van-loading__dot:nth-of-type(11){-webkit-transform:rotate(330deg);transform:rotate(330deg);opacity:.375}.van-loading__dot:nth-of-type(12){-webkit-transform:rotate(1turn);transform:rotate(1turn);opacity:.3125}@-webkit-keyframes van-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes van-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}} \ No newline at end of file diff --git a/wxcomponents/vant/mixins/basic.d.ts b/wxcomponents/vant/mixins/basic.d.ts new file mode 100644 index 0000000..7fd6a7f --- /dev/null +++ b/wxcomponents/vant/mixins/basic.d.ts @@ -0,0 +1 @@ +export declare const basic: string; diff --git a/wxcomponents/vant/mixins/basic.js b/wxcomponents/vant/mixins/basic.js new file mode 100644 index 0000000..aa5ab96 --- /dev/null +++ b/wxcomponents/vant/mixins/basic.js @@ -0,0 +1,22 @@ +export const basic = Behavior({ + methods: { + $emit(...args) { + this.triggerEvent(...args); + }, + getRect(selector, all) { + return new Promise(resolve => { + wx.createSelectorQuery() + .in(this)[all ? 'selectAll' : 'select'](selector) + .boundingClientRect(rect => { + if (all && Array.isArray(rect) && rect.length) { + resolve(rect); + } + if (!all && rect) { + resolve(rect); + } + }) + .exec(); + }); + } + } +}); diff --git a/wxcomponents/vant/mixins/button.d.ts b/wxcomponents/vant/mixins/button.d.ts new file mode 100644 index 0000000..d25c019 --- /dev/null +++ b/wxcomponents/vant/mixins/button.d.ts @@ -0,0 +1 @@ +export declare const button: string; diff --git a/wxcomponents/vant/mixins/button.js b/wxcomponents/vant/mixins/button.js new file mode 100644 index 0000000..94d177e --- /dev/null +++ b/wxcomponents/vant/mixins/button.js @@ -0,0 +1,18 @@ +export const button = Behavior({ + externalClasses: ['hover-class'], + properties: { + id: String, + lang: { + type: String, + value: 'en' + }, + businessId: Number, + sessionFrom: String, + sendMessageTitle: String, + sendMessagePath: String, + sendMessageImg: String, + showMessageCard: Boolean, + appParameter: String, + ariaLabel: String + } +}); diff --git a/wxcomponents/vant/mixins/link.d.ts b/wxcomponents/vant/mixins/link.d.ts new file mode 100644 index 0000000..9c35f7b --- /dev/null +++ b/wxcomponents/vant/mixins/link.d.ts @@ -0,0 +1 @@ +export declare const link: string; diff --git a/wxcomponents/vant/mixins/link.js b/wxcomponents/vant/mixins/link.js new file mode 100644 index 0000000..bcf0f19 --- /dev/null +++ b/wxcomponents/vant/mixins/link.js @@ -0,0 +1,17 @@ +export const link = Behavior({ + properties: { + url: String, + linkType: { + type: String, + value: 'navigateTo' + } + }, + methods: { + jumpLink(urlKey = 'url') { + const url = this.data[urlKey]; + if (url) { + wx[this.data.linkType]({ url }); + } + } + } +}); diff --git a/wxcomponents/vant/mixins/observer/behavior.d.ts b/wxcomponents/vant/mixins/observer/behavior.d.ts new file mode 100644 index 0000000..9743010 --- /dev/null +++ b/wxcomponents/vant/mixins/observer/behavior.d.ts @@ -0,0 +1 @@ +export declare const behavior: string; diff --git a/wxcomponents/vant/mixins/observer/behavior.js b/wxcomponents/vant/mixins/observer/behavior.js new file mode 100644 index 0000000..e60ff4f --- /dev/null +++ b/wxcomponents/vant/mixins/observer/behavior.js @@ -0,0 +1,14 @@ +export const behavior = Behavior({ + methods: { + set(data, callback) { + return new Promise(resolve => { + this.setData(data, () => { + if (callback && typeof callback === 'function') { + callback.call(this); + } + resolve(); + }); + }); + } + } +}); diff --git a/wxcomponents/vant/mixins/observer/index.d.ts b/wxcomponents/vant/mixins/observer/index.d.ts new file mode 100644 index 0000000..355210a --- /dev/null +++ b/wxcomponents/vant/mixins/observer/index.d.ts @@ -0,0 +1 @@ +export declare function observe(vantOptions: any, options: any): void; diff --git a/wxcomponents/vant/mixins/observer/index.js b/wxcomponents/vant/mixins/observer/index.js new file mode 100644 index 0000000..f4ab3f0 --- /dev/null +++ b/wxcomponents/vant/mixins/observer/index.js @@ -0,0 +1,19 @@ +import { behavior } from './behavior'; +export function observe(vantOptions, options) { + const { watch } = vantOptions; + options.behaviors.push(behavior); + if (watch) { + const props = options.properties || {}; + Object.keys(watch).forEach(key => { + if (key in props) { + let prop = props[key]; + if (prop === null || !('type' in prop)) { + prop = { type: prop }; + } + prop.observer = watch[key]; + props[key] = prop; + } + }); + options.properties = props; + } +} diff --git a/wxcomponents/vant/mixins/open-type.d.ts b/wxcomponents/vant/mixins/open-type.d.ts new file mode 100644 index 0000000..4165fd4 --- /dev/null +++ b/wxcomponents/vant/mixins/open-type.d.ts @@ -0,0 +1 @@ +export declare const openType: string; diff --git a/wxcomponents/vant/mixins/open-type.js b/wxcomponents/vant/mixins/open-type.js new file mode 100644 index 0000000..a1ee826 --- /dev/null +++ b/wxcomponents/vant/mixins/open-type.js @@ -0,0 +1,25 @@ +export const openType = Behavior({ + properties: { + openType: String + }, + methods: { + bindGetUserInfo(event) { + this.$emit('getuserinfo', event.detail); + }, + bindContact(event) { + this.$emit('contact', event.detail); + }, + bindGetPhoneNumber(event) { + this.$emit('getphonenumber', event.detail); + }, + bindError(event) { + this.$emit('error', event.detail); + }, + bindLaunchApp(event) { + this.$emit('launchapp', event.detail); + }, + bindOpenSetting(event) { + this.$emit('opensetting', event.detail); + }, + } +}); diff --git a/wxcomponents/vant/mixins/touch.d.ts b/wxcomponents/vant/mixins/touch.d.ts new file mode 100644 index 0000000..8b50d29 --- /dev/null +++ b/wxcomponents/vant/mixins/touch.d.ts @@ -0,0 +1 @@ +export declare const touch: string; diff --git a/wxcomponents/vant/mixins/touch.js b/wxcomponents/vant/mixins/touch.js new file mode 100644 index 0000000..bedb23a --- /dev/null +++ b/wxcomponents/vant/mixins/touch.js @@ -0,0 +1,35 @@ +const MIN_DISTANCE = 10; +function getDirection(x, y) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} +export const touch = Behavior({ + methods: { + resetTouchStatus() { + this.direction = ''; + this.deltaX = 0; + this.deltaY = 0; + this.offsetX = 0; + this.offsetY = 0; + }, + touchStart(event) { + this.resetTouchStatus(); + const touch = event.touches[0]; + this.startX = touch.clientX; + this.startY = touch.clientY; + }, + touchMove(event) { + const touch = event.touches[0]; + this.deltaX = touch.clientX - this.startX; + this.deltaY = touch.clientY - this.startY; + this.offsetX = Math.abs(this.deltaX); + this.offsetY = Math.abs(this.deltaY); + this.direction = this.direction || getDirection(this.offsetX, this.offsetY); + } + } +}); diff --git a/wxcomponents/vant/mixins/transition.d.ts b/wxcomponents/vant/mixins/transition.d.ts new file mode 100644 index 0000000..9306f3e --- /dev/null +++ b/wxcomponents/vant/mixins/transition.d.ts @@ -0,0 +1 @@ +export declare const transition: (showDefaultValue: boolean) => any; diff --git a/wxcomponents/vant/mixins/transition.js b/wxcomponents/vant/mixins/transition.js new file mode 100644 index 0000000..7be0b5a --- /dev/null +++ b/wxcomponents/vant/mixins/transition.js @@ -0,0 +1,120 @@ +import { isObj } from '../common/utils'; +const getClassNames = (name) => ({ + enter: `van-${name}-enter van-${name}-enter-active enter-class enter-active-class`, + 'enter-to': `van-${name}-enter-to van-${name}-enter-active enter-to-class enter-active-class`, + leave: `van-${name}-leave van-${name}-leave-active leave-class leave-active-class`, + 'leave-to': `van-${name}-leave-to van-${name}-leave-active leave-to-class leave-active-class` +}); +const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 30)); +export const transition = function (showDefaultValue) { + return Behavior({ + properties: { + customStyle: String, + // @ts-ignore + show: { + type: Boolean, + value: showDefaultValue, + observer: 'observeShow' + }, + // @ts-ignore + duration: { + type: null, + value: 300, + observer: 'observeDuration' + }, + name: { + type: String, + value: 'fade' + } + }, + data: { + type: '', + inited: false, + display: false + }, + attached() { + if (this.data.show) { + this.enter(); + } + }, + methods: { + observeShow(value) { + value ? this.enter() : this.leave(); + }, + enter() { + const { duration, name } = this.data; + const classNames = getClassNames(name); + const currentDuration = isObj(duration) ? duration.enter : duration; + this.status = 'enter'; + this.$emit('before-enter'); + Promise.resolve() + .then(nextTick) + .then(() => { + this.checkStatus('enter'); + this.$emit('enter'); + this.setData({ + inited: true, + display: true, + classes: classNames.enter, + currentDuration + }); + }) + .then(nextTick) + .then(() => { + this.checkStatus('enter'); + this.transitionEnded = false; + this.setData({ + classes: classNames['enter-to'] + }); + }) + .catch(() => { }); + }, + leave() { + if (!this.data.display) { + return; + } + const { duration, name } = this.data; + const classNames = getClassNames(name); + const currentDuration = isObj(duration) ? duration.leave : duration; + this.status = 'leave'; + this.$emit('before-leave'); + Promise.resolve() + .then(nextTick) + .then(() => { + this.checkStatus('leave'); + this.$emit('leave'); + this.setData({ + classes: classNames.leave, + currentDuration + }); + }) + .then(nextTick) + .then(() => { + this.checkStatus('leave'); + this.transitionEnded = false; + setTimeout(() => this.onTransitionEnd(), currentDuration); + this.setData({ + classes: classNames['leave-to'] + }); + }) + .catch(() => { }); + }, + checkStatus(status) { + if (status !== this.status) { + throw new Error(`incongruent status: ${status}`); + } + }, + onTransitionEnd() { + if (this.transitionEnded) { + return; + } + this.transitionEnded = true; + this.$emit(`after-${this.status}`); + const { show, display } = this.data; + if (!show && display) { + this.setData({ display: false }); + } + } + } + }); +}; diff --git a/wxcomponents/vant/wxs/array.wxs b/wxcomponents/vant/wxs/array.wxs new file mode 100644 index 0000000..1a41dfb --- /dev/null +++ b/wxcomponents/vant/wxs/array.wxs @@ -0,0 +1,5 @@ +function isArray(array) { + return array && (array.constructor === 'Array' || (typeof Array !== 'undefined' && Array.isArray(array))); +} + +module.exports.isArray = isArray; diff --git a/wxcomponents/vant/wxs/bem.wxs b/wxcomponents/vant/wxs/bem.wxs new file mode 100644 index 0000000..870ab24 --- /dev/null +++ b/wxcomponents/vant/wxs/bem.wxs @@ -0,0 +1,38 @@ +var array = require('./array.wxs'); +var object = require('./object.wxs'); +var PREFIX = 'van-'; + +function join(name, mods) { + name = PREFIX + name; + mods = mods.map(function(mod) { + return name + '--' + mod; + }); + mods.unshift(name); + return mods.join(' '); +} + +function traversing(mods, conf) { + if (!conf) { + return; + } + + if (typeof conf === 'string' || typeof conf === 'number') { + mods.push(conf); + } else if (array.isArray(conf)) { + conf.forEach(function(item) { + traversing(mods, item); + }); + } else if (typeof conf === 'object') { + object.keys(conf).forEach(function(key) { + conf[key] && mods.push(key); + }); + } +} + +function bem(name, conf) { + var mods = []; + traversing(mods, conf); + return join(name, mods); +} + +module.exports.bem = bem; diff --git a/wxcomponents/vant/wxs/memoize.wxs b/wxcomponents/vant/wxs/memoize.wxs new file mode 100644 index 0000000..7e119d9 --- /dev/null +++ b/wxcomponents/vant/wxs/memoize.wxs @@ -0,0 +1,54 @@ +/** + * Simple memoize + * wxs doesn't support fn.apply, so this memoize only support up to 2 args + */ + +function isPrimitive(value) { + var type = typeof value; + return ( + type === 'boolean' || + type === 'number' || + type === 'string' || + type === 'undefined' || + value === null + ); +} + +// mock simple fn.call in wxs +function call(fn, args) { + if (args.length === 2) { + return fn(args[0], args[1]); + } + + if (args.length === 1) { + return fn(args[0]); + } + + return fn(); +} + +function serializer(args) { + if (args.length === 1 && isPrimitive(args[0])) { + return args[0]; + } + var obj = {}; + for (var i = 0; i < args.length; i++) { + obj['key' + i] = args[i]; + } + return JSON.stringify(obj); +} + +function memoize(fn) { + var cache = {}; + + return function() { + var key = serializer(arguments); + if (cache[key] === undefined) { + cache[key] = call(fn, arguments); + } + + return cache[key]; + }; +} + +module.exports.memoize = memoize; diff --git a/wxcomponents/vant/wxs/object.wxs b/wxcomponents/vant/wxs/object.wxs new file mode 100644 index 0000000..69f16ea --- /dev/null +++ b/wxcomponents/vant/wxs/object.wxs @@ -0,0 +1,13 @@ +/* eslint-disable */ +var REGEXP = getRegExp('{|}|"', 'g'); + +function keys(obj) { + return JSON.stringify(obj) + .replace(REGEXP, '') + .split(',') + .map(function(item) { + return item.split(':')[0]; + }); +} + +module.exports.keys = keys; diff --git a/wxcomponents/vant/wxs/utils.wxs b/wxcomponents/vant/wxs/utils.wxs new file mode 100644 index 0000000..a0df7ee --- /dev/null +++ b/wxcomponents/vant/wxs/utils.wxs @@ -0,0 +1,7 @@ +var bem = require('./bem.wxs').bem; +var memoize = require('./memoize.wxs').memoize; + +module.exports = { + bem: memoize(bem), + memoize: memoize +};