diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..78df13555fa2898860ecf3ca7fd7762a11bace49
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+unpackage/
+.hbuilderx
+node_modules
+.DS_Store
+uni_modules_tools/copy
+package-lock.json
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..d680f3a8fab20d1ee32074de82995f24141fb7e8
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,8 @@
+unpackage/
+.hbuilderx
+node_modules
+.DS_Store
+uni_modules_tools/copy
+package-lock.json
+uni_modules_tools
+uni_modules.config.json
\ No newline at end of file
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f112766b2fe467674ada5b877819c78ec56423c7
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,57 @@
+
+
+
diff --git a/LICENSE b/LICENSE
index 4470915dccf274f474dd8e4f3894fe0dcb99ad2e..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,201 @@
-MIT License
-
-Copyright (c) 2021 崔红保
-
-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.
+ 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/README.en.md b/README.en.md
deleted file mode 100644
index d2b51efd1f79ee8b1b03427f533ffa29c37d708b..0000000000000000000000000000000000000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# base-app
-
-#### Description
-{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
index 75b7769160ef6de01451814f253085adf8970668..0dfbde60824c22bd06481d487ed9f94e9c7b9978 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,567 @@
-# base-app
+#### 视频介绍
+
+
+
-#### 介绍
-{**以下是 Gitee 平台说明,您可以替换此简介**
-Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
-无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+注:视频会有滞后问题,入门为主。最新的完整功能请看以下文档
-#### 软件架构
-软件架构说明
+#### 简介
+uni-starter是一个集成了大量商用项目常见功能的,云端一体应用快速开发基本项目模版。
+APP有很多通用的功能,比如登录注册、头像、设置、banner、... uni-starter将这些功能都已经集成好。
-#### 安装教程
+直接在`hbuilderx`新建项目选择`uni-starter`模板,即可在此基础上快速开发自己的特色业务。
-1. xxxx
-2. xxxx
-3. xxxx
+有了`uni-starter`,再加上`schema2code`生成前端页面,一个简单应用就可以快速完成。
-#### 使用说明
+如果说[uniCloud admin](https://uniapp.dcloud.io/uniCloud/admin)是管理端项目的基本项目模版,那么uni-starter则是用户端、尤其是移动端的基础项目模板。
-1. xxxx
-2. xxxx
-3. xxxx
+`uni-starter` + `uniCloud admin` 提供了用户端和管理端的基本项目模版,应用开发从未如此简单快捷!
-#### 参与贡献
+##### 扫码体验:h5版演示效果(链接:[https://uni-starter.dcloud.net.cn](https://uni-starter.dcloud.net.cn))
+
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
+### uni-starter集成包括:
+1. 用户管理:
+ - 登录注册(用户名密码登录、手机号验证码登录、APP一键登录、微信登录、Apple登录、微信小程序登录)
+ - 修改密码、忘记密码、头像更换(集成图片裁剪)、昵称修改、积分查看、退出登录
+2. 系统设置:
+ - App更新(整包升级、wgt升级、强制升级,后台搭配uniCloud admin的升级中心插件管理)
+ - 推送开关(app)、清除缓存(app)
+ - 指纹解锁(app)、人脸解锁(app)
+ - 多语言切换
+ - 账号注销(正在完善中...)
+3. 隐私权限:内置Android先弹出隐私协议对话框,然后再向用户申请设备权限
+4. 权限引导:当应用拒绝授权某些权限,但在后续使用中又需要这个权限;此时实现:引导用户可“一键跳转至系统设置”中开启。
+ - 而不是报错让用户自己去找解决方案(更好的用户体验)。
+ - 采用高内聚低耦合的设计结构,直接在应用启动时,应用拦截器中实现。免去在每个业务代码中处理这类问题,更优雅更方便。
+ - 已实现项目:摄像头、相册、获取GPS定位、网络2/3/4/5G和Wi-Fi。你可以参考这些实现,处理更多该类场景的处理。uni-starter也会持续更新完善。
+5. 实用功能
+ - 问题与反馈、关于、隐私政策、用户服务协议
+ - banner(后台搭配uniCloud admin的banner插件管理)
+ - 新闻的搜索、列表、详情、分享。通过clientDB实现,开发者直接修改定义的表名等参数,即可轻松改为自己的业务
+ - 可覆盖原生层的分享菜单
+ - h5版在页面顶部(全局悬浮)引导用户点击下载App
+ - 营销裂变:点击“分销推荐”,生成带用户inviteCode参数的应用下载页(H5),一键分享到微信或微信朋友圈等。被邀请人打开下载页面点击下载,设备剪贴板的内容会被自动设置为邀请者的inviteCode。被邀请人下载app之后通过任何方式登录(含:注册并登录),uni-starter框架会自动获取设备剪切板中的inviteCode提交到服务端绑定关联关系。
+6. 更好的性能:首页采用nvue,fast编译模式,加快App端启动速度
+7. 内置拦截器:
+ - 页面路由拦截,配置需强制登录的页面;打开时自动检测`token`若无效就自动跳转到登录页
+ - 调用云函数(callFunction)拦截器,自动携带必要参数、自动处理响应体。详见9.自动完成1-2
+8. 自动完成:
+ - 分析uniCloud.callfunction和clientDB操作的响应体,判断code执行对应的操作如跳转到登录页,自动续期token
+ - 操作注册/登录操作自动获取客户端设备:push_clientid、imei、oaid、idfa新增/更新到数据表uni-id-device
+ - 异常恢复处理:断网恢复后自动重连“因网络错误导致的”网络请求
+ - 为迎合苹果App Store的规则,登录与分享功能项显示之前自动检测是否安装了对应客户端。比如:设备未安装微信则不显示微信快捷登录和微信分享选项
+* 更多功能模块会不断更新,请持续关注本插件
-#### 特技
+## 快速体验部署流程
+#### 1. 开通uniCloud
+- 开通`uniCloud`:本项目是云端一体的,它的云端代码需要部署在uniCloud云服务空间里,需要开通uniCloud。在[https://unicloud.dcloud.net.cn/](https://unicloud.dcloud.net.cn/)登录,按云厂商要求进行实名认证。
+- 在uniCloud认证通过后,创建一个服务空间给本项目使用。选择阿里云或腾讯云均可,两种服务空间差异[详情](https://uniapp.dcloud.net.cn/uniCloud/price)
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
-5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+#### 2. 运行云服务空间初始化向导
+
+
+
+
+## 功能模块介绍
+### 1.登录模块
+|登录类型 |描述 |
+|-- |-- |
+|smsCode |验证码登录 |
+|univerify |读取手机SIM卡一键登录 |
+|username |账号密码登录 |
+|weixin |微信登录 |
+|apple |苹果登录 |
+
+配置文件:`项目根目录/uni-starter.config.js`
+```js
+{
+ "router":{
+ "login":["username","smsCode"]
+ }
+}
+```
+
+#### 启用登录方式
+如上示例配置为:`["username","smsCode"]` 表示启用:验证码登录、账号密码登录。
+
+同理配置为:`["weixin","username","smsCode"]` 则表示启用:微信登录、验证码登录、账号密码登录。
+
+总结:需要几项列举几项即可。
+
+#### 优先级
+在uni-starter框架中执行`uni.navigateTo({url: "/pages/ucenter/login-page/index/index"})`,会根据配置跳转到相应的登录页面。如果配置内容为:`["username","smsCode"]`会自动切换到"配置的第0项,也就是`username`类型的登录方式对应的页面”,即`账户登录`方式页面,路径:`/pages/ucenter/login-page/pwd-login/pwd-login`
+
+#### 平台差异性配置
+这里支持用[条件编译](https://uniapp.dcloud.io/platform?id=%e6%9d%a1%e4%bb%b6%e7%bc%96%e8%af%91)因此你可以配置在不同平台下拥有的登录方式。
+如下配置,即表示仅在APP端启用“短信验证码登录”
+```js
+"login": [
+ "username","univerify","weixin","apple"
+ // #ifdef APP-PLUS
+ "smsCode",
+ // #endif
+]
+```
+
+#### 生效策略
+登录方式有如上5种,虽然你希望有几种登录方式就在配置中列举几种。但是有的登录方式可能因为设备环境问题而不被支持;
+比如你正确地配置了微信登录,而用户的手机并没有安装微信,这样微信登录功能就无法使用。
+并且如果出现这种情况你的app会被iOS的App Store拒绝上架。
+所以在这里,我们的生效策略在检测:你是否有列举到某个配置项为前提的情况下,增加了检测当前环境是否支持,如果不支持会自动隐藏。
+
+#### 在uni-app框架中配置:
+在应用模块:`manifest.json` App模块配置 --> OAuth(登录鉴权)--> 勾选并配置你所需要的模块
++ 一键登录:
+ [开通配置](https://dev.dcloud.net.cn/uniLogin)
+ [使用指南](https://uniapp.dcloud.io/univerify)
++ [苹果登录集成指南](https://ask.dcloud.net.cn/article/36651)
++ 短信登录:
+ 使用本功能需要在[DCloud开发者中心](https://dev.dcloud.net.cn/uniSms)开通并充值
+ 教程参考[短信服务开通指南](https://ask.dcloud.net.cn/article/37534)
+ 修改短信注册/登录发生验证码的模板id,在文件`/uniCloud-aliyun/cloudfunctions/uni-id-cf/index.js` 搜索 `const templateId = '11753'` 替换为自己申请的模板id
+
+#### 服务端配置
+uni-starter服务端使用[uni-config-center](https://ext.dcloud.net.cn/plugin?id=4425)统一管理这些配置,
+文件路径`/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json`
+详情下文[目录结构](#id=catalogue) 和[uni-id配置说明](https://uniapp.dcloud.io/uniCloud/uni-id?id=configjson%e7%9a%84%e8%af%b4%e6%98%8e)
+
+### 2.路由拦截
+#### 应用场景
+有些页面,限允许已经登录后用户才访问。
+常规的做法是打开这类页面之前,检查(前端校验)uni_id_token的值是否有效,如果无效会自动跳转到登录页面。
+而这样的页面有很多,入口也不少。面向过程的写法会产生大量的代码冗余,且不易维护。
+而uni-starter基于拦截器(`uni.addInterceptor`),提供了仅需简单配置即可实现的路由拦截功能。
+#### 配置方式
+支持两种模式(二选一)
+##### 黑名单模式
+列举需要强制登录的页面完整路径(支持正则)
+##### 白名单模式
+列举不需要强制登录即可访问的页面完整路径(支持正则)
+#### 配置示例
+配置文件:`项目根目录/uni-starter.config.js`
+
+```js
+"router": {
+ "needLogin" : [
+ {pattern:/^\/pages\/list.*/}, //支持正则表达式
+ "/uni_modules/uni-news-favorite/pages/uni-news-favorite/list",
+ "/uni_modules/uni-feedback/pages/uni-feedback/add"
+ ],
+/*
+ 请注意上下,黑名单(needLogin)、白名单(visitor)两种配置模式二选一不可同时使用
+*/
+ "visitor" : [
+ "/",//注意入口页必须直接写 "/"
+ {"pattern":/^\/pages\/list.*/}, //支持正则表达式
+ {"pattern":/^\/pages\/ucenter\/login-page.*/},
+ "/pages/common/webview/webview",
+ "/pages/grid/grid",
+ "/pages/ucenter/ucenter",
+ "/pages/ucenter/guestbook/guestbook",
+ "/pages/ucenter/about/about",
+ "/pages/ucenter/settings/settings"
+ ]
+}
+```
+
+##### 优势:
+传统的路由管理方式是对uni-app框架路由写法的二次封装,自定义的写法不支持ide的代码提示,且不优雅。
+另外不同插件作者封装不同的路由管理方式,这样做出来的插件与用户的项目结合时,路由写法不统一的差异需要去磨平。
+为此`uni-starter`基于`uni.addInterceptor`(拦截器)实现路由管理。
+
+##### 注意:
+- uni-starter的路由拦截,仅在调用路由API(navigateTo、redirectTo、reLaunch、switchTab)时触发。应用的首页是由系统自动打开,不会触发拦截器。首页需要强制登录才能访问的场景,不由路由控制。但不用担心,如果未登录的用户,打开了需要登录才能访问页面,必定会触发需要携带有效token才能访问的API。此时则会返回相应的响应体,uni-starter监测到token无效这类的响应体也会自动跳转到登录页(这种效果需要前后端都开发完成才体验到)。
+- uni-starter框架不能将登录页`/pages/ucenter/login-page/index/index`设置为首页,否则由拦截器实现的路由管理将生效。
+- 拦截器实现的路由控制,是在路由跳转未完成之前触发。路由切换方式(navigateTo、redirectTo、reLaunch、switchTab)URL参数必须使用绝对路径路
+
+### 3.h5版在页面顶部引导用户`点击下载App`
+把h5端用户引流到APP端,是一个非常实用的功能。相对于h5,APP端有更高的用户留存和更好的产品体验。
+uni-starter集成了这个功能,你只需直接在`项目根目录/uni-starter.config.js`的"h5"->"openApp"中配置相关内容,即可开启全局悬浮的下载引导。
+这也是一个演示开发者如何在h5端做全局悬浮块的例子。你也可以在`/common/openApp.js`中修改他的样式等代码等,注意他只支持原生js语法。
+
+### 4.分享模块
+一个可覆盖原生层分享模块
+- 应用配置:`manifest.json` App模块配置 --> Share --> 勾选并配置你所需要的模块
+- 分享功能配置参数,随着应用的业务场景决定,在各场景调用的时候配置。参考uni-starter的`/pages/list/detail.vue`的`methods -> shareClick`
+- 更多`uni-share`的介绍 [详情](https://ext.dcloud.net.cn/plugin?id=4860)
+
+### 5.升级中心相关
+为了解决开发者维护多个 App 升级繁琐,重复逻辑过多,管理不便的问题,升级中心`uni-upgrade-center`应运而生。
+提供了简单、易用、统一的 App 管理、App 版本管理、安装包发布管理,升级检测更新管理。
+- 升级中心分为两个部分:`uni-upgrade-center` Admin管理后台和`uni-upgrade-center - Admin`前台检测更新。
+- `uni-upgrade-center`的介绍 [详情](https://ext.dcloud.net.cn/plugin?id=4542)
+- `uni-upgrade-center - Admin`的介绍 [详情](https://ext.dcloud.net.cn/plugin?id=4470)
+
+### 6.意见反馈
+- 客户端[详情](https://ext.dcloud.net.cn/plugin?id=50)
+- admin端[详情](https://ext.dcloud.net.cn/plugin?id=4992)
+
+### 7.指纹识别模块
+- `manifest.json` App模块配置 --> `Fingerprint`指纹识别
+
+### 8.消息推送模块
+- `manifest.json` App模块配置 --> `push`消息推送
+
+### 9.隐私政策弹框
+根据工业和信息化部关于开展APP侵害用户权益专项整治要求,App提交到应用市场必须满足以下条件:
+- 应用启动运行时需弹出隐私政策协议,说明应用采集用户数据
+- 应用不能强制要求用户授予权限,即不能“不给权限不让用”
++ 如不希望应用启动时申请“读写手机存储”和“访问设备信息”权限,请参考:https://ask.dcloud.net.cn/article/36549
+
+配置弹出“隐私协议和政策”打开项目的manifest.json文件,切换到“源码视图”项
+在`manifest.json` -> `app-plus` -> `privacy` 节点下添加 prompt节点
+```js
+"privacy" : {
+ "prompt" : "template",
+ "template" : {
+ "title" : "服务协议和隐私政策",
+ "message" : " 请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。 你可阅读《服务协议》 和《隐私政策》 了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
+ "buttonAccept" : "同意",
+ "buttonRefuse" : "暂不同意"
+ }
+}
+```
+- prompt
+ 字符串类型,必填,隐私政策提示框配置策略,可取值template、custom、none,默认值为none
+ + template
+ 使用原生提示框模板,可自定义标题、内容已经按钮上的文本
+ + custom
+ 自定义隐私政策提示框,uni-app项目中推荐使用nvue页面进行自定义,5+ APP使用html页面进行自定义
+ + none
+ 不弹出隐私政策提示框
+- template
+ json格式,可选,模板提示框上显示的内容
+ + title
+ 模板提示框上的标题,默认为“服务协议和隐私政策”
+ + message
+ 模板提示框上的内容,richtext类型字符串,支持a/font/br等节点,点击a链接会调用内置页面打开其href属性中链接地址。
+ **注意:务必配置此提示内容,或参考上面示例内容并修改《服务协议》和《隐私政策》链接地址**
+ + buttonAccept
+ 模板提示框上接受按钮的文本,默认值为“我知道了”
+ + buttonRefuse
+ 模板提示框上拒绝按钮的文本,默认不显示此按钮
+ + second
+ HBuilderX3.1.12+版本新增支持隐私提示框二次确认提示,用于配置二次确认提示框显示内容,message属性值不为空时弹出二次确认提示框
+ + title 二次确认提示框上的标题
+ + message 二次确认提示框上的内容,支持richtext类型字符串
+ + buttonAccept 二次确认提示框上接受按钮的文本
+ + buttonRefuse 二次确认提示框上拒绝按钮的文本
+
+> 更多Android平台隐私与政策提示框配置方法,[详情](https://ask.dcloud.net.cn/article/36937)
+
+##### 注意:
+1. 最新的华为应用市场要求,隐私政策提示框上接受按钮的文本,必须为“同意”而不能是其他有歧义的文字。
+2. 配置后提交云端打包后生效。理论上绝大部分和`manifest.json`生效相关的配置均需要提交云打包后生效
+
+### 10.拦截器改造后的uniCloud
+1. Debug,调试期间开启Debug。接口一旦fail就会弹出真实错误信息。否则将弹出,系统错误请稍后再试!
+```js
+ if(Debug){
+ console.log(e);
+ uni.showModal({
+ content: JSON.stringify(e),
+ showCancel: false
+ });
+ }
+```
+2. 断网自动重试,当callFunction为fail时检测是否因断网引起。如果是会提醒用户并且会在恢复网络之后自动重新发起请求
+3. 常规的errCoder自动执行对应程序,如token无效/过期自动跳转到登录页面。
+4. token自动续期。
+
+### 11.举例路由控制原理,深入了解拦截器的使用
+比如你希望在打开用户中心等页面之前,都检查一下该用户是否登录,否则就重定向到登录页面。使用拦截器你可以用以下写法在应用入口定义全局生效:
+
+```js
+ //定义各个页面,这里为了演示uni-starter框架是把该定义写在全局配置uni-starter.config.js中
+ let needLogin = ["/pages/ucenter/userinfo/userinfo", ... ]
+
+ uni.addInterceptor("navigateTo", {
+ invoke(e) { // 调用前拦截
+ //获取用户的token
+ const token = uni.getStorageSync('uni_id_token')
+ //获取当前页面路径(即url去掉"?"和"?"后的参数)
+ const url = e.url.split('?')[0]
+ //判断要打开的页面是否需要验证登录
+ if (needLogin.includes(url) && token == '') {
+ uni.showToast({
+ title: '该页面需要登录才能访问,请先登录',
+ icon: 'none'
+ })
+ uni.navigateTo({
+ url: "/pages/ucenter/login-page/index/index"
+ })
+ return false
+ }
+ },
+ fail(err) { // 失败回调拦截
+ console.log(err);
+ },
+ })
+```
+- 而路由跳转方法不仅有`uni.navigateTo`还有`uni.redirectTo`,`uni.reLaunch`,`uni.switchTab`;
+- 另外我们还希望控制直接跳转至哪种登录类型
+所以在uni-starter框架中我们这样定义:
+uni-starter/common/appInit.js 的第228-280行
+```js
+ const {"router": {needLogin,login} } = uniStarterConfig //需要登录的页面
+ let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"];
+ list.forEach(item => { //用遍历的方式分别为,uni.navigateTo,uni.redirectTo,uni.reLaunch,uni.switchTab这4个路由方法添加拦截器
+ uni.addInterceptor(item, {
+ invoke(e) { // 调用前拦截
+ //获取用户的token
+ const token = uni.getStorageSync('uni_id_token')
+ //获取当前页面路径(即url去掉"?"和"?"后的参数)
+ const url = e.url.split('?')[0]
+ //判断要打开的页面是否需要验证登录
+ if (needLogin.includes(url) && token == '') {
+ uni.showToast({
+ title: '该页面需要登录才能访问,请先登录',
+ icon: 'none'
+ })
+ uni.navigateTo({
+ url: "/pages/ucenter/login-page/index/index"
+ })
+ return false
+ }
+ //控制登录优先级
+ if (url == '/pages/ucenter/login-page/index/index') {
+ //一键登录(univerify)、账号(username)、验证码登录(短信smsCode)
+ if (login[0] == 'univerify') {
+ if(e.url == url) { e.url += '?' } //添加参数之前判断是否带了`?`号如果没有就补上,因为当开发场景本身有参数的情况下是已经带了`?`号
+ e.url += "univerify_first=true"
+ } else if (login[0] == 'username') {
+ e.url = "/pages/ucenter/login-page/pwd-login/pwd-login"
+ }
+ }
+ return true
+ },
+ fail(err) { // 失败回调拦截
+ console.log(err);
+ },
+ })
+ })
+```
+
+### 12.关于升级
+- 项目升级
+
+ uni-starter遵循uni-app的插件模块化规范,即:[uni_modules](https://uniapp.dcloud.io/uni_modules) 。他是个项目类型的插件。在项目的根目录下有一个符合uni_modules规范的package.json文件,在这个文件右键-从插件市场更新即可更新该插件。
+
+- 插件升级
+
+ 非项目类型的uni_modules插件,是项目根目录下的uni_modules目录下。以插件ID为插件文件夹命名,在该目录右键也会看到“从插件市场更新”选项,点击即可更新该插件。
+
+### 13.多语言国际化
+ uni-starter支持多语言国际化。默认开启,可以在`uni-starter.config.js`->`i18n`->`enable`中配置
+ 如果你启用了多语言国际化需要先阅读:[uni-app多语言国际化](https://uniapp.dcloud.io/collocation/i18n?id=%e6%a1%86%e6%9e%b6%e5%86%85%e7%bd%ae%e7%bb%84%e4%bb%b6%e5%92%8capi%e5%9b%bd%e9%99%85%e5%8c%96)
+
+## 应用启动时序介绍
+文件路径: App.vue
+```js
+ import initApp from '@/common/appInit.js';
+ export default {
+ onLaunch: function() {
+ initApp();
+ }
+ }
+```
+onLaunch生命周期执行了
+1. 全局监听clientDB的err事件,
+ - 判断是否为token过期失效等需要重新登录的问题。自动跳转到登录页面
+ - 检测本地的token是否有效(存在且并未过期)否则跳转到登录页面
+2. 预登录一键登录功能
+3. 执行了initApp()包含以下操作
+ 1. 读取uni-starter.config并挂载到globalData的config下
+ 2. 读取应用版本号,并存到globalData下
+ 3. 检查是否有可更新的应用版本,决定是否启动在线更新版本
+ 4. 监听设备的网络变化并以uni.showToast APi的方式提醒用户
+ 5. 使用[拦截器](https://uniapp.dcloud.io/api/interceptor?id=addinterceptor) 实现
+ - 页面路由拦截,配置需强制登录的页面;打开时检测,如果token无效就自动跳转到登录页
+ - 优雅实现:自动引导打开`选择图片`所需要的权限。当调用`uni.chooseImage`时检测到无权限自动开启引导。并不是在每次调用接口时处理这类问题,你可以参考该例子做更多该类场景的处理。uni-starter也会持续完善
+
+
+## 配置文件
+uni-starter提供了`uni-starter.config.js`,可配置选择登录注册方式及优先级等,可指定该应用是否强制登录才能进入某个页面。配置项内容如下:
+```js
+module.exports = {
+ "h5": {
+ "url": "https://static-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e.bspapp.com", // 前端网页托管的域名
+ // 在h5端全局悬浮引导用户下载app的功能 更多自定义要求在/common/openApp.js中修改
+ "openApp": {
+ //点击悬浮下载栏后打开的网页链接
+ "openUrl": 'https://sj.qq.com/myapp/detail.htm?apkName=com.tencent.android.qqdownloader&info=6646FD239A6EBA9E2DEE5DFC7E18D867',
+ //左侧显示的应用名称
+ "appname": 'uni-starter',
+ //应用的图标
+ "logo": './static/logo.png',
+ }
+ },
+ "mp": {
+ "weixin": {
+ //微信小程序原始id,微信小程序分享时
+ "id": "gh_132465798"
+ }
+ },
+ "router": {
+ //配置需要路由拦截的页面地址,在打开这些页面之前会自动检查(无需联网)uni_id_token的值,如果token无效就自动跳转到登录页
+ "needLogin": [
+ "/pages/ucenter/userinfo/userinfo",
+ "/uni_modules/uni-news-favorite/pages/uni-news-favorite/list",
+ ],
+ "login": ["smsCode","univerify", "username", "weixin", "apple"],
+ /*
+ 这里会根据数组的第0项,决定登录方式的第一优先级是哪种登录方式。
+ 所有你希望拥有的登录方式这里都需要一一列举,未列举到的或设备环境不支持的登录方式将被隐藏。
+ 如果你需要在不同平台有不同的配置,直接用条件编译即可。
+ */
+ },
+ //关于应用
+ "about": {
+ //应用名称
+ "appName": "uni-starter",
+ //应用logo
+ "logo": "/static/logo.png",
+ //公司名称
+ "company": "数字天堂(北京)网络技术有限公司",
+ //口号
+ "slogan": "为开发而生",
+ //政策协议
+ "agreements": [{
+ "title": "用户服务协议", //协议名称
+ "url": "https://ask.dcloud.net.cn/protocol.html" //对应的网络链接
+ },
+ {
+ "title": "隐私政策",
+ "url": "https://ask.dcloud.net.cn/protocol.html"
+ }
+ ],
+ //应用的链接,用于分享到第三方平台和生成关于我们页的二维码
+ "download": "https://m3w.cn/uniapp"
+ },
+ //用于打开应用市场评分界面
+ "marketId":{
+ "ios":"id1417078253",
+ "android":"123456"
+ },
+ //配置多语言国际化。i18n为英文单词 internationalization的首末字符i和n,18为中间的字符数 是“国际化”的简称
+ "i18n":{
+ "enable":false //默认启用,国际化。如果你不想使用国际化相关功能,请改为false
+ }
+}
+```
+
+## 目录结构@catalogue
+
+uni-starter
+├─uniCloud-aliyun
+│ ├─cloudfunctions 云函数目录
+│ | ├─common 公共模块
+│ │ | ├─uni-config-center uni-starter的服务端配置中心,项目所有云函数的配置在这里填写 详情
+│ │ | | ├─index.js config-center入口文件
+│ │ | | └─uni-id uni-id模块配置目录
+│ │ | | ├─config.json uni-id对应的配置数据:微信登录、一键登录、短信验证码登录等key都在这里填写详情
+│ │ | | └─file.cert uni-id依赖的配置文件,假如你使用微信发红包功能,需要的证书文件就是放到这里
+│ | | └───uni-id uni-id用户体系 详情
+│ | ├─uni-analyse-searchhot 云端一体搜索模板依赖的云函数 详情
+│ | └─uni-id-cf 用户中心云函数,实现用户注册、修改密码、发送验证码、快捷登录(微信、短信、账户、一键登录)
+│ └──database 云数据目录
+│ ├─db_init.json db_init.json初始化数据库文件,其中不再包含schema 详情
+│ ├─opendb-app-versions.schema.json 应用版本,表结构文件
+│ ├─opendb-banner.schema.json 横幅数据表,表结构文件
+│ ├─opendb-feedback.schema.json 意见反馈表,表结构文件
+│ ├─opendb-news-articles.schema.json 新闻文章表,表结构文件
+│ ├─opendb-news-categories.schema.json 新闻分类表,表结构文件
+│ ├─opendb-news-comments.schema.json 新闻评论表,表结构文件
+│ ├─opendb-news-favorite.schema.json 新闻收藏表,表结构文件
+│ ├─opendb-search-hot.schema.json 热门搜索表,表结构文件
+│ ├─opendb-search-log.schema.json 搜索记录表,表结构文件
+│ ├─opendb-verify-codes.schema.json 验证码表,表结构文件
+│ ├─uni-id-log.schema.json 登录日志表,表结构文件
+│ ├─uni-id-scores.schema.json 用户积分表,表结构文件
+│ └─uni-id-users.schema.json 用户表,表结构文件
+├─pages 业务页面文件存放的目录
+│ ├─common
+│ │ └─webview webview目录
+│ │ └─webview.vue webview页面 用于实现跨端的web页面浏览
+│ ├─grid
+│ │ └─grid.vue 带宫格和banner的示例页面
+│ ├─list
+│ │ ├─list.vue 新闻列表
+│ │ ├─search
+│ │ │ └─search 云端一体搜索插件
+│ │ └─detail.vue 新闻详情
+│ ├─ucenter
+│ │ ├─about 关于我们
+│ │ │ └─about
+│ │ ├─login-page 登录模块
+│ | | ├─common 登录模块公共库
+│ │ │ │ ├─login-page.css 公共样式库
+│ │ │ │ ├─login-page.mixin.js 公共mixin
+│ │ │ │ └─loginSuccess.js 公共登录成功后操作
+│ | | ├─index 短信验证码登录,手机号码输入页面
+│ | | ├─phone-code 短信验证码登录,验证码输入页面
+│ | | ├─pwd-login 账户密码登录
+│ | | ├─pwd-retrieve 密码重置
+│ │ │ └─register 注册账户模块
+│ │ │ ├─validator.js
+│ │ │ └─register.vue
+│ │ ├─read-news-log 新闻阅读记录
+│ │ │ └─read-news-log
+│ │ ├─settings
+│ │ │ ├─dc-push
+│ │ │ │ └─push.js push权限操作SDK
+│ │ │ └─settings.vue app设置
+│ │ ├─userinfo 用户个人信息
+│ │ │ ├─bind-mobile
+│ │ │ │ └─bind-mobile.vue 绑定手机号码
+│ │ │ ├─limeClipper 图片裁剪插件,来源[limeClipper](https://ext.dcloud.net.cn/plugin?id=3594) @作者: 陌上华年
+│ │ │ │ ├─images
+│ │ │ │ │ ├─photo.svg
+│ │ │ │ │ └─rotate.svg
+│ │ │ │ ├─index.css
+│ │ │ │ ├─limeClipper.vue
+│ │ │ │ ├─README.md
+│ │ │ │ └─utils.js
+│ │ │ ├─main.js
+│ │ │ ├─cropImage.vue 引用limeClipper的图片裁剪模块,为了方便二开可能会出现兼容`vue`与`nvue`,所以做成了`页面`而不是`组件`
+│ │ │ └─userinfo.vue
+│ | └─ucenter.vue 用户中心
+│ |
+├─static 存放应用引用的本地静态资源(如图片、视频等)的目录,注意: 静态资源只能存放于此
+├─uni_modules 存放[uni_module](/uni_modules)规范的插件。
+├─uni_modules_tools uni_modules插件上传辅助脚本 详情 。
+├─main.js Vue初始化入口文件
+├─App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
+├─uni-starter.config uni-starter的前端的配置文件,项目所有模块的配置在这里填写。详见该文件的代码注释。
+├─manifest.json 配置应用名称、appid、logo、版本等打包信息,详见
+└─pages.json 配置页面路由、导航条、选项卡等页面类信息,详见
+
+完整的uni-app目录结构[详情](https://uniapp.dcloud.io/frame?id=%e7%9b%ae%e5%bd%95%e7%bb%93%e6%9e%84)
+
+## 常见API示范
+1. 判断当前用户是否拥有某角色`uniIDHasRole` 演示页面:`/pages/grid/grid` [API文档详情:](https://uniapp.dcloud.io/api/global?id=uniidhasrole)
+2. 指纹解锁、人脸解锁 演示页面:`/pages/ucenter/settings/settings` [API文档详情:](https://uniapp.dcloud.io/api/system/authentication)
+
+## 注意事项
+1. 真机运行需要制作自定义基座,制作后选择运行到自定义基座
+2. 苹果登录的图标,需要满足苹果应用市场的审核规范请勿随便修改;如需修改请先阅读:[Sign in with Apple Button](https://appleid.apple.com/signinwithapple/button)
+3. 应用登录功能,默认不勾选同意隐私权限是响应安卓应用市场的规范;请勿修改该逻辑。
+
+## FAQ:常见问题
+1. 提示“公共模块uni-id缺少配置信息”解决方案:在cloudfunctions右键‘上传所有云函数、公共模块及actions’之后,需要在cloudfunctions -> common -> uni-config-center 目录单独上传一次,右键‘上传公共模块’。
+2. 本项目代码可以商用,无需为DCloud付费。但不能把本项目的代码改造用于非uni-app和uniCloud的技术体系。即,不能将后台改成php、java等其他后台,这将违反使用许可协议。
+
+## 相关案例
+[
+ ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/dd4c366f-6165-46c0-8500-5a679d7e5463.jpg)
+](https://ext.dcloud.net.cn/search?q=uni-starter)
+(点击跳转到案例列表)
+
+
+## 第三方插件(感谢插件作者,排名不分前后):
+1. 图片裁剪 [limeClipper](https://ext.dcloud.net.cn/plugin?id=3594) @作者: 陌上华年
+2. 二维码生成 [Sansnn-uQRCode](https://ext.dcloud.net.cn/plugin?id=1287) @作者: 3snn
+3. clipboard.js [clipboard](https://clipboardjs.com/)
\ No newline at end of file
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..e87aa746bf63f83e270bdeac65ff5b99a43bac0e
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,174 @@
+## 1.1.22(2021-11-10)
+删除`common/openApp.js`中可选链操作符,解决vue3版本在hbuilderX内置浏览器不兼容的问题
+## 1.1.21(2021-11-10)
+新增app端列表页面使用原生list下拉刷新
+## 1.1.20(2021-11-08)
+修复vue3版某些情况下i18n报错的问题
+## 1.1.19(2021-11-08)
+配置文件`uni-starter.config.js`默认关闭i18n多语言国际化
+## 1.1.18(2021-10-14)
+使用2.0版`uni-share`。当显示分享窗口时,监听返回操作(如:物理返回,全面屏手机侧滑)关闭分享窗口,而不是关闭当前页面。
+## 1.1.17(2021-10-12)
+- 更新文档
+- 修复list页面where条件中缺少&符,导致的错误
+## 1.1.16(2021-10-05)
+在控制台提示:开启多语言国际化,将获取i18n中配置的tabbar的值覆盖pages.json中配置的tabbar的值
+## 1.1.15(2021-10-02)
+新增,支持配置是否开启i18n多语言国际化。
+配置文件:`uni-starter.config.js`
+`
+"i18n":{
+ "enable":true //默认启用,国际化。如果你不想使用国际化相关功能,请改为false
+}
+`
+## 1.1.14(2021-09-30)
+1. 通过微信小程序登录自动保存`sessionKey`到`uni-id-users`表
+2. 我的-设置-个人资料 点击绑定手机号码,完善账号信息支持以下三种策略:
+ - APP端,(如果支持)使用"通过运营商一键获取手机号码"
+ - 微信小程序端,支持"一键获取微信绑定的手机号"
+ - 其他端,通过手机验证码
+## 1.1.13(2021-09-29)
+修复search页面因多语言国际化导致的白屏问题
+## 1.1.12(2021-09-28)
+1. 改造微信登录逻辑,直接使用`uni.login`参数`"onlyAuthorize":true`实现
+2. 修复,一键登录弹出层,已勾选“同意隐私政策协议”点击自定义登录按钮,报“你未同意隐私政策协议”的bug
+## 1.1.11(2021-09-24)
+优化邀请下载app页(`pages/ucenter/invite`)下载按钮闪烁的问题
+## 1.1.10(2021-09-23)
+修复获取验证码按钮的文字,在中文模式下显示为英文的问题
+## 1.1.9(2021-09-16)
+修复由多语言切换功能引起的隐私政策协议标题链接被重写的问题
+## 1.1.8(2021-09-15)
+更新数据表guestbook的schema中更新权限的配置
+## 1.1.7(2021-09-14)
+更新数据表opendb-news-articles的schema中的权限配置
+## 1.1.6(2021-09-13)
+纠正错误schema权限表达式`doc.uid`为`doc.user_id`
+## 1.1.5(2021-09-01)
+为了更直观理解路由拦截。移除路由拦截器中,默认过滤登录相关页面拦截的逻辑。确保所有白名单页面均在配置文件router.visitor中体现
+## 1.1.4(2021-08-31)
+修改错误的文章表`SChema`的读权限表达式
+## 1.1.3(2021-08-31)
+修复在微信小程序端默认语言为英文的问题
+## 1.1.2(2021-08-30)
+修复在微信小程序下切换语言报`locale`不存在的问题
+## 1.1.1(2021-08-30)
+- 解决3.2.6以下版本hbuilderx,编译的项目报`uni.setLocale`不存在的问题
+## 1.1.0(2021-08-27)
+- APP端支持vue3 (hbuilderx 3.2.5+)
+- 支持国际化 中英文切换
+- 新增留言板示例
+- 修复签到的时区问题
+## 1.0.48(2021-08-10)
+- 修复登录成功后响应体包含`userInfo.password`的问题
+- 修改了`uni-id-users`表的schema中字段username的编辑权限,防止用户通过clientDB绕过用户名不能重复的规则更新用户名的问题
+## 1.0.47(2021-08-09)
+- 更新文档快速体验部署流程
+- 修复一键登录优先时报变量找不到的问题
+## 1.0.46(2021-08-05)
+清理多余文件
+## 1.0.45(2021-08-05)
+默认首页为nvue页面+fast
+## 1.0.44(2021-08-05)
+解决首页为非nvue页面时白屏的问题。
+- 注意:本次在`common/appInit.js`中修改了路由拦截的逻辑,是个兼容方案;当首页为非nvue页面,路由拦截器逻辑会在加载首页时执行。接下来新版本的hx编译的uni-app项目无论首页是否为nvue都不走拦截器,保持各端逻辑一致。
+## 1.0.43(2021-08-02)
+1. 微信小程序端,新增:微信登录成功后,弹出是否"获取微信头像和昵称,完善个人资料"的弹框
+2. APP端,新增逻辑:微信登录成功后,自动获取用户的微信昵称和头像完善用户个人资料
+- 提示:因为微信的头像一旦更换,微信返回的头像url会失效。所以,以上两示例功能将url(客户端:下载到临时目录/服务端:转为Buffer)再上传到uniCloud云存储中再使用。
+## 1.0.42(2021-07-29)
+新增绑定手机号码页面前端校验
+## 1.0.41(2021-07-27)
+1. 支持vue3.0
+2. 去掉App.vue全局样式,避免与非flex布局的页面样式冲突
+## 1.0.40(2021-07-22)
+1. 调整使用正则表达式配置强制登录功能的写法,解决在小程序端的兼容问题。
+2. 新增签到功能(培养用户习惯,提升用户粘性)。支持:每日签到奖励、周期性连续7日签到,奖励翻倍。
+## 1.0.39(2021-07-19)
+1. 强制登录配置,新增白名单模式
+2. 强制登录配置,支持正则表达式
+## 1.0.38(2021-07-17)
+删除多余文件
+## 1.0.37(2021-07-14)
+去掉配置文件:`uni-starter.config.js`,`h5` —> `url`结尾的`/`
+## 1.0.36(2021-07-14)
+剪切板中的邀请码,添加标识性前缀 `uniInvitationCode:`
+## 1.0.35(2021-07-12)
+1. H5端默认不开启,隐私权限协议签署页面。因为网页端没有什么隐私权限能被获取,目前全球仅欧盟有要求;如有需要请手动开启
+2. 在列表页演示,如何在onShow生命周期获取设备位置,并在设备或者应用没有权限时自动引导。设置完毕自动重新获取。[更多点此查看插件介绍](https://ext.dcloud.net.cn/plugin?name=json-gps)
+## 1.0.34(2021-07-08)
+修复,打开登录页时携带参数,导致的快捷登录方式重复的问题
+## 1.0.33(2021-07-06)
+修复,点击短信验证码登录打开的页面不正确的问题
+## 1.0.32(2021-07-06)
+修复,仅配置一种快捷登录时的错误
+## 1.0.31(2021-07-02)
+优化项目文档
+## 1.0.30(2021-07-01)
+1. 简化宫格页面写法,方便理解如何控制不同状态角色的用户是否可见哪些元素。
+2. uni-id-cf发送短信验证码api,默认注释掉:虚拟发送短信验证码的代码块。
+3. uni-id-cf统一action名称为驼峰法
+## 1.0.29(2021-06-29)
+1. 修复在安卓10以下设备,操作登录获取不到oaid会直接导致登录失败的bug
+2. 修复uniCloud版本为阿里云版时删除头像设置失败,腾讯云版删除头像后二次上传失败的问题
+## 1.0.28(2021-06-28)
+修复云函数uni-id-cf的resetPwdBySmsCode接口,未注册过的用户也能调用的问题
+## 1.0.27(2021-06-25)
+修改文档,新增h5版演示示例
+## 1.0.26(2021-06-24)
+升级用户头像上传的裁切功能,app端为原生裁剪其他端保持原来方式。数据表字段改用avatar_file存储file对象方便做图片的回显
+## 1.0.25(2021-06-23)
+预置uniCloud admin依赖的uniCloud文件,方便uniCloud admin与uni-starter配套使用时免做文件迁移
+## 1.0.24(2021-06-23)
+删除callFunction拦截器中多余的代码
+## 1.0.23(2021-06-22)
+更正调试遗留的uni-config-center/uni-id/config.json的tokenExpiresIn=1配置问题,改为默认值7200
+## 1.0.22(2021-06-22)
+1. 新增一键登录授权界面的其他快捷登录按钮
+2. 优化uni-quick-login组件代码
+3. 调整隐私政策协议框勾选逻辑:在登录页面已勾选,同步勾选。如果没勾选需要手动勾选(为符合应用市场上架要求)
+4. 调整登录页隐私政策协议框位置。
+5. 增强路由拦截,新增判断token是否过期。
+## 1.0.21(2021-06-21)
+优化:uni_modules模式使用uni-id-cf,方便uni-starter与uniCloud-admin的uni-id-cf同步更新。
+## 1.0.20(2021-06-18)
+1.H5端新增,强制要求用户同意隐私协议 2.兼容ios端自动设置打开下载页用户的剪切板为邀请者的inviteCode 3.成功注册用户,且请求体含邀请码inviteCode自动关联裂变关系
+## 1.0.19(2021-06-17)
+1.新增获取邀请码接口getUserInviteCode 2.在邀请用户下载应用页面,自动设置被邀请用户的剪切板为邀请者的code(仅支持安卓端) 3.在注册或登录并注册请求时自动添加剪切板中的请求参数 4.统一接口名称为驼峰法
+## 1.0.18(2021-06-15)
+修复,APP端有安装微信客户端但未显示微信登录快捷键的问题
+## 1.0.17(2021-06-09)
+修复,非APP端deviceInfo为空引起的登录失败问题
+## 1.0.16(2021-06-08)
+新增,操作注册/登录操作自动获取客户端设备:push_clientid、imei、oaid、idfa新增/更新到数据表uni-id-device新增,操作注册/登录操作自动获取客户端设备:push_clientid、imei、oaid、idfa新增/更新到数据表uni-id-device
+## 1.0.15(2021-06-07)
+为迎合苹果App Store的规则,登录与分享功能项显示之前自动检测是否安装了对应客户端。比如:设备未安装微信则不显示微信快捷登录和微信分享选项。为迎合苹果App Store的规则,登录与分享功能项显示之前自动检测是否安装了对应客户端。比如:设备未安装微信则不显示微信快捷登录和微信分享选项。
+## 1.0.14(2021-06-07)
+修改错误的表名称uni-verify为opendb-verify-codes
+## 1.0.13(2021-06-04)
+新增一键登录界面的第三方快捷登录按钮
+## 1.0.12(2021-05-28)
+修复拦截器在ios app端会报错:Unhandled promise...的问题
+## 1.0.10(2021-05-27)
+新增callfunction的拦截器废除this.request的写法。为callFunction添加:请求失败是否断网判断并提示、恢复网络自动重新执行、自动处理响应体:token过期自动跳转到登录页面、token自动续期
+## 1.0.9(2021-05-23)
+修复变量被重复定义的问题
+## 1.0.8(2021-05-22)
+宫格页(/pages/grid/grid),新增根据当前用户是否登录、是否为管理员的角色来决定是否显示的示范
+## 1.0.7(2021-05-22)
+删除多余数据
+## 1.0.6(2021-05-22)
+修复当username(用户名&密码)为第一优先级的登录方式时。无法切换到smsCode(短信验证码)登录方式
+## 1.0.5(2021-05-20)
+改用uni_modules方式处理图片选择api时无权限,引导用户快捷打开系统设置
+## 1.0.4(2021-05-19)
+为方便部署,添加空的manifest.json uni-config-center下的uni-id配置
+## 1.0.3(2021-05-18)
+重大调整,原云函数名称:user-center改名叫uni-id-cf
+修复,绑定手机号码场景。因手机未插SIM导致的一键登录失败后未直接跳到获取短信验证码方式绑定
+## 1.0.2(2021-05-17)
+添加 uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 文件
+## 1.0.1(2021-05-17)
+manifest.json 在小程序平台增加了一个配置项 betterScopedSlots,启用新的作用域插槽编译,用于支持作用域插槽内使用复杂表达式。
+## 1.0.0(2021-05-17)
+第一版
\ No newline at end of file
diff --git a/common/appInit.js b/common/appInit.js
new file mode 100644
index 0000000000000000000000000000000000000000..a3d285a963c1c18265e6a8754ac89911474dad72
--- /dev/null
+++ b/common/appInit.js
@@ -0,0 +1,457 @@
+import uniStarterConfig from '@/uni-starter.config.js';
+import store from '@/store'
+//应用初始化页
+// #ifdef APP-PLUS
+import checkUpdate from '@/uni_modules/uni-upgrade-center-app/utils/check-update';
+import callCheckVersion from '@/uni_modules/uni-upgrade-center-app/utils/call-check-version';
+import interceptorChooseImage from '@/uni_modules/json-interceptor-chooseImage/js_sdk/main.js';
+// #endif
+const db = uniCloud.database()
+export default async function() {
+ let loginConfig = uniStarterConfig.router.login
+ //清除有配置但设备环境不支持的登录项
+ // #ifdef APP-PLUS
+ await new Promise((callBack) => {
+ plus.oauth.getServices(oauthServices => {
+ loginConfig = loginConfig.filter(item => {
+ if (["univerify", "weixin", "apple"].includes(item)) {
+ let index = oauthServices.findIndex(e => e.id == item)
+ if (index == -1) {
+ return false
+ } else {
+ return oauthServices[index].nativeClient
+ }
+ } else {
+ return true
+ }
+ })
+ if (loginConfig.includes('univerify')) { //一键登录 功能预登录
+ uni.preLogin({
+ provider: 'univerify',
+ complete: e => {
+ console.log(e);
+ }
+ })
+ }
+ callBack()
+ }, err => {
+ console.error('获取服务供应商失败:' + JSON.stringify(err));
+ })
+ })
+ // #endif
+
+ //非app移除:一键登录、苹果登录;h5移除微信登录,如果你做微信公众号登录需要将此行移除
+ // #ifndef APP-PLUS
+ loginConfig = loginConfig.filter(item => {
+ return ![
+ 'univerify',
+ 'apple',
+ // #ifdef H5
+ 'weixin'
+ // #endif
+ ].includes(item)
+ })
+ // #endif
+
+ uniStarterConfig.router.login = loginConfig
+
+ // uniStarterConfig挂载到getApp().globalData.config
+ setTimeout(() => {
+ getApp({
+ allowDefault: true
+ }).globalData.config = uniStarterConfig;
+ }, 1)
+
+
+ // 初始化appVersion(仅app生效)
+ initAppVersion();
+
+ // #ifdef APP-PLUS
+ // 实现,路由拦截。当应用无访问摄像头/相册权限,引导跳到设置界面
+ interceptorChooseImage()
+ // #endif
+
+
+ //clientDB的错误提示
+ function onDBError({
+ code, // 错误码详见https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=returnvalue
+ message
+ }) {
+ console.log('onDBError', {
+ code,
+ message
+ });
+ // 处理错误
+ console.error(code, message);
+ if ([
+ 'TOKEN_INVALID_INVALID_CLIENTID',
+ 'TOKEN_INVALID',
+ 'TOKEN_INVALID_TOKEN_EXPIRED',
+ 'TOKEN_INVALID_WRONG_TOKEN',
+ 'TOKEN_INVALID_ANONYMOUS_USER',
+
+ ].includes(code)) {
+ uni.navigateTo({
+ url: '/pages/ucenter/login-page/index/index'
+ })
+ }
+ }
+ // 绑定clientDB错误事件
+ db.on('error', onDBError)
+
+ // 解绑clientDB错误事件
+ //db.off('error', onDBError)
+ db.on('refreshToken', function({
+ token,
+ tokenExpired
+ }) {
+ console.log('监听到clientDB的refreshToken', {
+ token,
+ tokenExpired
+ });
+ store.commit('user/login', {
+ token,
+ tokenExpired
+ })
+ })
+
+ const Debug = false;
+ //拦截器封装callFunction
+ let callFunctionOption;
+ uniCloud.addInterceptor('callFunction', {
+ async invoke(option) {
+ // #ifdef APP-PLUS
+ // 判断如果是执行登录(无论是哪种登录方式),就记录用户的相关设备id
+ if (option.name == 'uni-id-cf' &&
+ (option.data.action == 'register' || option.data.action.slice(0, 5) == 'login')
+ ) {
+ let oaid = await new Promise((callBack, fail) => {
+ if (uni.getSystemInfoSync().platform == "android") {
+ plus.device.getOAID({
+ success: function(e) {
+ callBack(e.oaid)
+ // console.log('getOAID success: '+JSON.stringify(e));
+ },
+ fail: function(e) {
+ callBack()
+ console.log('getOAID failed: ' + JSON.stringify(e));
+ }
+ });
+ } else {
+ callBack()
+ }
+ })
+
+ let imei = await new Promise((callBack, fail) => {
+ if (uni.getSystemInfoSync().platform == "android") {
+ plus.device.getInfo({
+ success: function(e) {
+ callBack(e.imei)
+ // console.log('getOAID success: '+JSON.stringify(e));
+ },
+ fail: function(e) {
+ callBack()
+ console.log('getOAID failed: ' + JSON.stringify(e));
+ }
+ });
+ } else {
+ callBack()
+ }
+ })
+
+ let push_clientid = '',
+ idfa = plus.storage.getItem('idfa') || ''; //idfa有需要的用户在应用首次启动时自己获取存储到storage中
+
+ try {
+ push_clientid = plus.push.getClientInfo().clientid
+ } catch (e) {
+ uni.showModal({
+ content: '获取推送标识失败。如果你的应用不需要推送功能,请注释掉本代码块',
+ showCancel: false,
+ confirmText: "好的"
+ });
+ console.log(e)
+ }
+
+ let deviceInfo = {
+ push_clientid, // 获取匿名设备标识符
+ imei,
+ oaid,
+ idfa
+ }
+ console.log("重新登录/注册,获取设备id", deviceInfo);
+ option.data.deviceInfo = deviceInfo
+
+ // #ifndef H5
+ //注册可能不仅仅走register接口,还有登录并注册的接口
+ option.data.inviteCode = await new Promise((callBack) => {
+ uni.getClipboardData({
+ success: function(res) {
+ if (res.data.slice(0, 18) == 'uniInvitationCode:') {
+ let uniInvitationCode = res.data.slice(18, 38)
+ console.log('当前用户是其他用户推荐下载的,推荐者的code是:' +
+ uniInvitationCode);
+ // uni.showModal({
+ // content: '当前用户是其他用户推荐下载的,推荐者的code是:'+uniInvitationCode,
+ // showCancel: false
+ // });
+ callBack(uniInvitationCode)
+ //当前用户是其他用户推荐下载的。这里登记他的推荐者id 为当前用户的myInviteCode。判断如果是注册
+ } else {
+ callBack(false)
+ }
+ },
+ fail() {
+ callBack(false)
+ }
+ });
+ })
+ // #endif
+ }
+ // #endif
+ // console.log(JSON.stringify(option));
+ callFunctionOption = option
+ },
+ complete(e) {
+ // console.log(JSON.stringify(e));
+ },
+ fail(e) { // 失败回调拦截
+ if (Debug) {
+ uni.showModal({
+ content: JSON.stringify(e),
+ showCancel: false
+ });
+ console.error(e);
+ } else {
+ uni.showModal({
+ content: "系统错误请稍后再试!",
+ showCancel: false,
+ confirmText: "知道了"
+ });
+ }
+ //如果执行错误,检查是否断网
+ uni.getNetworkType({
+ complete: res => {
+ // console.log(res);
+ if (res.networkType == 'none') {
+ uni.showToast({
+ title: '手机网络异常',
+ icon: 'none'
+ });
+ console.log('手机网络异常');
+ let callBack = res => {
+ console.log(res);
+ if (res.isConnected) {
+ uni.showToast({
+ title: '恢复联网自动重新执行',
+ icon: 'none'
+ });
+ console.log(res.networkType, "恢复联网自动重新执行");
+ uni.offNetworkStatusChange(e => {
+ console.log("移除监听成功", e);
+ })
+ //恢复联网自动重新执行
+ uniCloud.callFunction(callFunctionOption)
+ uni.offNetworkStatusChange(callBack);
+ }
+ }
+ uni.onNetworkStatusChange(callBack);
+ }
+ }
+ });
+ },
+ success: (e) => {
+ // console.log(e);
+ const {
+ token,
+ tokenExpired
+ } = e.result
+ if (token && tokenExpired) {
+ store.commit('user/login', {
+ token,
+ tokenExpired
+ })
+ }
+ switch (e.result.code) {
+ case 403:
+ uni.navigateTo({
+ url: "/pages/ucenter/login-page/index/index"
+ })
+ break;
+ case 30203:
+ uni.navigateTo({
+ url: "/pages/ucenter/login-page/index/index"
+ })
+ break;
+ case 50101:
+ uni.showToast({
+ title: e.result.msg,
+ icon: 'none',
+ duration: 2000
+ });
+ break;
+ default:
+ console.log('code的值是:' + e.result.code, '可以在上面添加case,自动处理响应体');
+ break;
+ }
+
+ switch (e.result.errCode) {
+ case 'uni-id-token-not-exist':
+ uni.showToast({
+ title: '登录信息失效',
+ icon: 'none'
+ });
+ uni.navigateTo({
+ url: "/pages/ucenter/login-page/index/index"
+ })
+ break;
+ default:
+ break;
+ }
+ }
+ })
+
+ //自定义路由拦截
+ const {
+ "router": {
+ needLogin,
+ visitor,
+ login
+ }
+ } = uniStarterConfig //需要登录的页面
+
+ let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"];
+ list.forEach(item => { //用遍历的方式分别为,uni.navigateTo,uni.redirectTo,uni.reLaunch,uni.switchTab这4个路由方法添加拦截器
+ uni.addInterceptor(item, {
+ invoke(e) { // 调用前拦截
+ //获取用户的token
+ const token = uni.getStorageSync('uni_id_token'),
+ //token是否已失效
+ tokenExpired = uni.getStorageSync('uni_id_token_expired') < Date.now(),
+ //获取要跳转的页面路径(url去掉"?"和"?"后的参数)
+ url = e.url.split('?')[0];
+ //获取要前往的页面路径(即url去掉"?"和"?"后的参数)
+ const pages = getCurrentPages();
+ if (!pages.length) {
+ console.log("首页启动调用了");
+ return e
+ }
+ const fromUrl = pages[pages.length - 1].route;
+
+ let inLoginPage = fromUrl.split('/')[2] == 'login-page'
+
+ //控制登录优先级
+ if ( //判断当前窗口是否为登录页面,如果是则不重定向路由
+ url == '/pages/ucenter/login-page/index/index' &&
+ !inLoginPage
+ ) {
+ //一键登录(univerify)、账号(username)、验证码登录(短信smsCode)
+ if (login[0] == 'username') {
+ e.url = "/pages/ucenter/login-page/pwd-login/pwd-login"
+ } else {
+ if (e.url == url) {
+ e.url += '?'
+ } //添加参数之前判断是否带了`?`号如果没有就补上,因为当开发场景本身有参数的情况下是已经带了`?`号
+ e.url += "type=" + login[0]
+ }
+ } else {
+ //拦截强制登录页面
+ let pass = true
+ //pattern
+ if (needLogin) {
+ pass = needLogin.every((item) => {
+ if (typeof(item) == 'object' && item.pattern) {
+ return !item.pattern.test(url)
+ }
+ return url != item
+ })
+ // console.log({pass})
+ }
+ if (visitor) {
+ pass = visitor.some((item) => {
+ if (typeof(item) == 'object' && item.pattern) {
+ return item.pattern.test(url)
+ }
+ return url == item
+ })
+ // console.log({pass})
+ }
+
+ if (!pass && (token == '' || tokenExpired)) {
+ uni.showToast({
+ title: '请先登录',
+ icon: 'none'
+ })
+ uni.navigateTo({
+ url: "/pages/ucenter/login-page/index/index"
+ })
+ return false
+ }
+ }
+ return e
+ },
+ fail(err) { // 失败回调拦截
+ console.log(err);
+ if (Debug) {
+ console.log(err);
+ uni.showModal({
+ content: JSON.stringify(err),
+ showCancel: false
+ });
+ }
+ }
+ })
+ })
+
+ // #ifdef APP-PLUS
+ // 监听并提示设备网络状态变化
+ uni.onNetworkStatusChange(res => {
+ console.log(res.isConnected);
+ console.log(res.networkType);
+ if (res.networkType != 'none') {
+ uni.showToast({
+ title: '当前网络类型:' + res.networkType,
+ icon: 'none',
+ duration: 3000
+ })
+ } else {
+ uni.showToast({
+ title: '网络类型:' + res.networkType,
+ icon: 'none',
+ duration: 3000
+ })
+ }
+ });
+ // #endif
+
+}
+/**
+ * // 初始化appVersion
+ */
+function initAppVersion() {
+ // #ifdef APP-PLUS
+ let appid = plus.runtime.appid;
+ plus.runtime.getProperty(appid, (wgtInfo) => {
+ let appVersion = plus.runtime;
+ let currentVersion = appVersion.versionCode > wgtInfo.versionCode ? appVersion : wgtInfo;
+ getApp({
+ allowDefault: true
+ }).appVersion = {
+ ...currentVersion,
+ appid,
+ hasNew: false
+ }
+ // 检查更新小红点
+ callCheckVersion().then(res => {
+ // console.log('检查是否有可以更新的版本', res);
+ if (res.result.code > 0) {
+ // 有新版本
+ getApp({
+ allowDefault: true
+ }).appVersion.hasNew = true;
+ }
+ })
+ });
+ // 检查更新
+ // #endif
+}
diff --git a/common/openApp.js b/common/openApp.js
new file mode 100644
index 0000000000000000000000000000000000000000..6fbbbb44df95b8d3fb630083bacaf694718e432d
--- /dev/null
+++ b/common/openApp.js
@@ -0,0 +1,36 @@
+/*
+ 创建在h5端全局悬浮引导用户下载app的功能,
+ 如不需要本功能直接移除配置文件uni-starter.config.js下的h5/openApp即可
+*/
+
+import CONFIG from '../uni-starter.config.js';
+
+const CONFIG_OPEN = CONFIG.h5.openApp || {};
+// 仅H5端添加"打开APP"
+export default function() {
+ // #ifdef H5
+ if (!CONFIG_OPEN.openUrl) return;
+
+ let openLogo = CONFIG_OPEN.logo ?
+ ` ` : '';
+ let openApp = document.createElement("div");
+ openApp.id = 'openApp';
+ openApp.style =
+ 'position: fixed;background:#FFFFFF;box-shadow: #eeeeee 1px 1px 9px; ;top: 0;left: 0;right: 0;z-index: 999;width: 100%;height: 45px;display: flex;flex-direction: row;justify-content: space-between;align-items: center;box-sizing: border-box;padding: 0 0.5rem;'
+ openApp.innerHTML = `
+
+ ${openLogo}
+
${CONFIG_OPEN.appname || ''}
+
+ 下载app
+ `;
+ document.body.insertBefore(openApp, document.body.firstChild);
+ document.body.style = 'height:calc(100% - 45px); margin-top:45px;';
+ openApp.addEventListener('click', e => {
+ var target = e.target || e.srcElement;
+ if (target.className.indexOf('openBtn') >= 0) {
+ window.location.href = CONFIG_OPEN.openUrl;
+ }
+ })
+ //#endif
+}
diff --git a/common/uni-ui.scss b/common/uni-ui.scss
new file mode 100644
index 0000000000000000000000000000000000000000..de868c7fb9f97825a7c34d61d32381c7185bd7ae
--- /dev/null
+++ b/common/uni-ui.scss
@@ -0,0 +1,118 @@
+
+.uni-flex {
+ display: flex;
+}
+
+.uni-flex-row {
+ @extend .uni-flex;
+ flex-direction: row;
+ box-sizing: border-box;
+}
+
+.uni-flex-column {
+ @extend .uni-flex;
+ flex-direction: column;
+}
+
+.uni-color-gary {
+ color: #3b4144;
+}
+
+/* 标题 */
+.uni-title {
+ display: flex;
+ margin-bottom: $uni-spacing-col-base;
+ font-size: $uni-font-size-lg;
+ font-weight: bold;
+ color: #3b4144;
+}
+
+.uni-title-sub {
+ display: flex;
+ font-size: $uni-font-size-base;
+ font-weight: 500;
+ color: #3b4144;
+}
+
+/* 描述 额外文本 */
+.uni-note {
+ margin-top: 10px;
+ color: #999;
+ font-size: $uni-font-size-sm;
+}
+
+/* 列表内容 */
+.uni-list-box {
+ @extend .uni-flex-row;
+ flex: 1;
+ margin-top: 10px;
+}
+
+/* 略缩图 */
+.uni-thumb {
+ flex-shrink: 0;
+ margin-right: $uni-spacing-row-base;
+ width: 125px;
+ height: 75px;
+ border-radius: $uni-border-radius-lg;
+ overflow: hidden;
+ border: 1px #f5f5f5 solid;
+ image {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.uni-media-box {
+ @extend .uni-flex-row;
+ border-radius: $uni-border-radius-lg;
+ overflow: hidden;
+ .uni-thumb {
+ margin: 0;
+ margin-left: 4px;
+ flex-shrink: 1;
+ width: 33%;
+ border-radius:0;
+ &:first-child {
+ margin: 0;
+ }
+ }
+}
+
+/* 内容 */
+.uni-content {
+ @extend .uni-flex-column;
+ justify-content: space-between;
+}
+
+/* 列表footer */
+.uni-footer {
+ @extend .uni-flex-row;
+ justify-content: space-between;
+ margin-top: $uni-spacing-col-lg;
+}
+.uni-footer-text {
+ font-size: $uni-font-size-sm;
+ color: $uni-text-color-grey;
+ margin-left: 5px;
+}
+
+/* 标签 */
+
+.uni-tag {
+ flex-shrink: 0;
+ padding: 0 5px;
+ border: 1px $uni-border-color solid;
+ margin-right: $uni-spacing-row-sm;
+ border-radius: $uni-border-radius-base;
+ background: $uni-bg-color-grey;
+ color: $uni-text-color;
+ font-size: $uni-font-size-sm;
+}
+
+/* 链接 */
+.uni-link {
+ margin-left: 10px;
+ color: $uni-text-color;
+ text-decoration: underline;
+}
diff --git a/components/Sansnn-uQRCode/README.md b/components/Sansnn-uQRCode/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c99382f8549497838761117878d2720d7f44ced1
--- /dev/null
+++ b/components/Sansnn-uQRCode/README.md
@@ -0,0 +1,172 @@
+> 插件来源:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)
+##### 以下是作者写的插件介绍:
+
+# uQRCode
+
+### 云函数版二维码生成插件explain-qrcode现已发布,URL化后一句代码即可生成,有网就有二维码,100%生成成功,不会因为平台差异,设备差异导致生成失败,无需在前端做适配和兼容,极力推荐。插件地址:[explain-qrcode云函数二维码生成](https://ext.dcloud.net.cn/plugin?id=3359)
+
+uQRCode 生成方式简单,可扩展性高,如有复杂需求可通过自定义组件或修改源码完成需求。已测试H5、微信小程序、iPhoneXsMax真机。
+
+本示例项目中的自定义组件旨在抛砖引玉,有其他需求的朋友可自行扩展,自定义组件参考 ``/components/uni-qrcode/uni-qrcode.vue`` ,自定义组件使用案例参考 ``/pages/component/qrcode/qrcode.vue`` 。
+
+联系方式:QQ540000228。
+
+最近一次用于更新代码的 HBuilder X 版本为 2.8.11。
+
+### 二维码
+**什么是QR码**
+
+QR码属于矩阵式二维码中的一个种类,由DENSO(日本电装)公司开发,由JIS和ISO将其标准化。
+
+**QR码的特点**
+
+一是高速读取(QR就是取自“Quick Response”的首字母),通过摄像头从拍摄到解码到显示内容也就三秒左右,对摄像的角度也没有什么要求;
+
+二是高容量、高密度,理论上内容经过压缩处理后可以存7089个数字,4296个字母和数字混合字符,2953个8位字节数据,1817个汉字;
+
+三是支持纠错处理,按照QR码的标准文档说明,QR码的纠错分为4个级别,分别是:
+- level L : 最大 7% 的错误能够被纠正;
+- level M : 最大 15% 的错误能够被纠正;
+- level Q : 最大 25% 的错误能够被纠正;
+- level H : 最大 30% 的错误能够被纠正;
+
+四是结构化,看似无规则的图形,其实对区域有严格的定义。
+
+更多二维码介绍及原理:[https://blog.csdn.net/jason_ldh/article/details/11801355](https://blog.csdn.net/jason_ldh/article/details/11801355)
+
+### 使用方式
+
+在 ``script`` 中引用组件
+
+```javascript
+import uQRCode from '@/common/uqrcode.js'
+```
+
+在 ``template`` 中创建 `` ``
+
+```html
+
+```
+
+在 ``script`` 中调用 ``make()`` 方法
+
+```javascript
+export default {
+ methods: {
+ async make() {
+ // 回调方式
+ uQRCode.make({
+ canvasId: 'qrcode',
+ componentInstance: this,
+ text: 'uQRCode',
+ size: 354,
+ margin: 10,
+ backgroundColor: '#ffffff',
+ foregroundColor: '#000000',
+ fileType: 'jpg',
+ errorCorrectLevel: uQRCode.errorCorrectLevel.H,
+ success: res => {
+ console.log(res)
+ }
+ })
+
+ // Promise
+ uQRCode.make({
+ canvasId: 'qrcode',
+ componentInstance: this,
+ text: 'uQRCode',
+ size: 354,
+ margin: 10,
+ backgroundColor: '#ffffff',
+ foregroundColor: '#000000',
+ fileType: 'jpg',
+ errorCorrectLevel: uQRCode.errorCorrectLevel.H
+ }).then(res => {
+ console.log(res)
+ })
+
+ // 同步等待
+ var res = await uQRCode.make({
+ canvasId: 'qrcode',
+ componentInstance: this,
+ text: 'uQRCode',
+ size: 354,
+ margin: 10,
+ backgroundColor: '#ffffff',
+ foregroundColor: '#000000',
+ fileType: 'jpg',
+ errorCorrectLevel: uQRCode.errorCorrectLevel.H
+ })
+ console.log(res)
+ }
+ }
+}
+```
+
+### 属性说明
+
+|属性名|说明|
+|---|:---|
+|errorCorrectLevel|纠错等级,包含 `errorCorrectLevel.L`、`errorCorrectLevel.M`、`errorCorrectLevel.Q`、`errorCorrectLevel.H` 四个级别,`L`: 最大 7% 的错误能够被纠正;`M`: 最大 15% 的错误能够被纠正;`Q`: 最大 25% 的错误能够被纠正;`H`: 最大 30% 的错误能够被纠正。|
+|defaults|二维码生成参数的默认值。|
+
+### 方法说明
+
+|方法名|说明|
+|---|:---|
+|[make](#makeoptions)|生成二维码。|
+
+### make(options)
+
+生成二维码
+
+**options参数说明:**
+
+|参数|类型|必填|说明|
+|---|---|---|:---|
+|canvasId|String|是|画布标识,传入 ` ` 的 `canvas-id`|
+|componentInstance|Object|否|自定义组件实例 `this` ,表示在这个自定义组件下查找拥有 `canvas-id` 的 ` ` ,如果省略,则不在任何自定义组件内查找|
+|text|String|是|二维码内容|
+|size|Number|否|画布尺寸大小,请与 ` ` 所设 `width` , `height` 保持一致(默认:`354`)|
+|margin|Number|否|边距,二维码实际尺寸会根据所设边距值进行缩放调整(默认:`0`)|
+|backgroundColor|String|否|背景色,若设置为透明背景, `fileType` 需设置为 `'png'` , 然后设置背景色为 `'rgba(255,255,255,0)'` 即可(默认:`'#ffffff'`)|
+|foregroundColor|String|否|前景色(默认:`'#000000'`)|
+|fileType|String|否|输出图片的类型,只支持 `'jpg'` 和 `'png'`(默认:`'png'`)|
+|errorCorrectLevel|Number|否|纠错等级,参考属性说明 `errorCorrectLevel`(默认:`errorCorrectLevel.H`)|
+
+### 使用建议
+canvas在二维码生成中请当做一个生成工具来看待,它的作用仅是绘制出二维码。应把生成回调得到的资源保存并使用,显示用image图片组件,原因是方便操作,例如调整大小,或是H5端长按保存或识别,所以canvas应将它放在看不见的地方。不能用`display:none;overflow:hidden;`隐藏,否则生成空白。这里推荐canvas的隐藏样式代码
+```html
+
+```
+
+### 常见问题
+**二维码生成不完整**
+
+canvas宽高必须和size一致,并且size的单位是px,如果canvas的单位是rpx,那么不同设备屏幕分辨率不一样,rpx转换成px后的画布尺寸不足以放下全部内容,实际绘制图案超出,就会出现不完整的情况。
+
+**如何扫码跳转指定网页**
+
+text参数直接放入完整的网页地址即可,例如:`https://ext.dcloud.net.cn/plugin?id=1287`。微信客户端不能是ip地址。
+
+**小程序、APP报错**
+
+canvas不支持放在 `slot` 插槽,请尽量放在模板根节点,也就是第一个 ` ` 标签里面
+
+**H5长按识别**
+
+canvas无法长按识别,长按识别需要是图片才行,所以只需将回调过来的资源用image组件显示即可。
+
+### Tips
+- 示例项目中的图片采集于互联网,仅作为案例展示,不作为广告/商业,如有侵权,请告知删除。下载使用的用户,请勿把示例项目中的图片应用到你的项目。
\ No newline at end of file
diff --git a/components/Sansnn-uQRCode/Sansnn-uQRCode.vue b/components/Sansnn-uQRCode/Sansnn-uQRCode.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0433faee91742247dc38a4363bb74f5775d04eb4
--- /dev/null
+++ b/components/Sansnn-uQRCode/Sansnn-uQRCode.vue
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
diff --git a/components/Sansnn-uQRCode/uqrcode.js b/components/Sansnn-uQRCode/uqrcode.js
new file mode 100644
index 0000000000000000000000000000000000000000..311ce1dfacd7052ea3459aa1b142ac5fd65f02d9
--- /dev/null
+++ b/components/Sansnn-uQRCode/uqrcode.js
@@ -0,0 +1,1438 @@
+//---------------------------------------------------------------------
+// github https://github.com/Sansnn/uQRCode
+//---------------------------------------------------------------------
+
+let uQRCode = {};
+
+(function() {
+ //---------------------------------------------------------------------
+ // QRCode for JavaScript
+ //
+ // Copyright (c) 2009 Kazuhiko Arase
+ //
+ // URL: http://www.d-project.com/
+ //
+ // Licensed under the MIT license:
+ // http://www.opensource.org/licenses/mit-license.php
+ //
+ // The word "QR Code" is registered trademark of
+ // DENSO WAVE INCORPORATED
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
+ //
+ //---------------------------------------------------------------------
+
+ //---------------------------------------------------------------------
+ // QR8bitByte
+ //---------------------------------------------------------------------
+
+ function QR8bitByte(data) {
+ this.mode = QRMode.MODE_8BIT_BYTE;
+ this.data = data;
+ }
+
+ QR8bitByte.prototype = {
+
+ getLength: function(buffer) {
+ return this.data.length;
+ },
+
+ write: function(buffer) {
+ for (var i = 0; i < this.data.length; i++) {
+ // not JIS ...
+ buffer.put(this.data.charCodeAt(i), 8);
+ }
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRCode
+ //---------------------------------------------------------------------
+
+ function QRCode(typeNumber, errorCorrectLevel) {
+ this.typeNumber = typeNumber;
+ this.errorCorrectLevel = errorCorrectLevel;
+ this.modules = null;
+ this.moduleCount = 0;
+ this.dataCache = null;
+ this.dataList = new Array();
+ }
+
+ QRCode.prototype = {
+
+ addData: function(data) {
+ var newData = new QR8bitByte(data);
+ this.dataList.push(newData);
+ this.dataCache = null;
+ },
+
+ isDark: function(row, col) {
+ if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
+ throw new Error(row + "," + col);
+ }
+ return this.modules[row][col];
+ },
+
+ getModuleCount: function() {
+ return this.moduleCount;
+ },
+
+ make: function() {
+ // Calculate automatically typeNumber if provided is < 1
+ if (this.typeNumber < 1) {
+ var typeNumber = 1;
+ for (typeNumber = 1; typeNumber < 40; typeNumber++) {
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ for (var i = 0; i < this.dataList.length; i++) {
+ var data = this.dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+ if (buffer.getLengthInBits() <= totalDataCount * 8)
+ break;
+ }
+ this.typeNumber = typeNumber;
+ }
+ this.makeImpl(false, this.getBestMaskPattern());
+ },
+
+ makeImpl: function(test, maskPattern) {
+
+ this.moduleCount = this.typeNumber * 4 + 17;
+ this.modules = new Array(this.moduleCount);
+
+ for (var row = 0; row < this.moduleCount; row++) {
+
+ this.modules[row] = new Array(this.moduleCount);
+
+ for (var col = 0; col < this.moduleCount; col++) {
+ this.modules[row][col] = null; //(col + row) % 3;
+ }
+ }
+
+ this.setupPositionProbePattern(0, 0);
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
+ this.setupPositionAdjustPattern();
+ this.setupTimingPattern();
+ this.setupTypeInfo(test, maskPattern);
+
+ if (this.typeNumber >= 7) {
+ this.setupTypeNumber(test);
+ }
+
+ if (this.dataCache == null) {
+ this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
+ }
+
+ this.mapData(this.dataCache, maskPattern);
+ },
+
+ setupPositionProbePattern: function(row, col) {
+
+ for (var r = -1; r <= 7; r++) {
+
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
+
+ for (var c = -1; c <= 7; c++) {
+
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
+
+ if ((0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ },
+
+ getBestMaskPattern: function() {
+
+ var minLostPoint = 0;
+ var pattern = 0;
+
+ for (var i = 0; i < 8; i++) {
+
+ this.makeImpl(true, i);
+
+ var lostPoint = QRUtil.getLostPoint(this);
+
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ },
+
+ createMovieClip: function(target_mc, instance_name, depth) {
+
+ var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
+ var cs = 1;
+
+ this.make();
+
+ for (var row = 0; row < this.modules.length; row++) {
+
+ var y = row * cs;
+
+ for (var col = 0; col < this.modules[row].length; col++) {
+
+ var x = col * cs;
+ var dark = this.modules[row][col];
+
+ if (dark) {
+ qr_mc.beginFill(0, 100);
+ qr_mc.moveTo(x, y);
+ qr_mc.lineTo(x + cs, y);
+ qr_mc.lineTo(x + cs, y + cs);
+ qr_mc.lineTo(x, y + cs);
+ qr_mc.endFill();
+ }
+ }
+ }
+
+ return qr_mc;
+ },
+
+ setupTimingPattern: function() {
+
+ for (var r = 8; r < this.moduleCount - 8; r++) {
+ if (this.modules[r][6] != null) {
+ continue;
+ }
+ this.modules[r][6] = (r % 2 == 0);
+ }
+
+ for (var c = 8; c < this.moduleCount - 8; c++) {
+ if (this.modules[6][c] != null) {
+ continue;
+ }
+ this.modules[6][c] = (c % 2 == 0);
+ }
+ },
+
+ setupPositionAdjustPattern: function() {
+
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
+
+ for (var i = 0; i < pos.length; i++) {
+
+ for (var j = 0; j < pos.length; j++) {
+
+ var row = pos[i];
+ var col = pos[j];
+
+ if (this.modules[row][col] != null) {
+ continue;
+ }
+
+ for (var r = -2; r <= 2; r++) {
+
+ for (var c = -2; c <= 2; c++) {
+
+ if (r == -2 || r == 2 || c == -2 || c == 2 ||
+ (r == 0 && c == 0)) {
+ this.modules[row + r][col + c] = true;
+ } else {
+ this.modules[row + r][col + c] = false;
+ }
+ }
+ }
+ }
+ }
+ },
+
+ setupTypeNumber: function(test) {
+
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+ }
+
+ for (var i = 0; i < 18; i++) {
+ var mod = (!test && ((bits >> i) & 1) == 1);
+ this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+ }
+ },
+
+ setupTypeInfo: function(test, maskPattern) {
+
+ var data = (this.errorCorrectLevel << 3) | maskPattern;
+ var bits = QRUtil.getBCHTypeInfo(data);
+
+ // vertical
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 6) {
+ this.modules[i][8] = mod;
+ } else if (i < 8) {
+ this.modules[i + 1][8] = mod;
+ } else {
+ this.modules[this.moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ // horizontal
+ for (var i = 0; i < 15; i++) {
+
+ var mod = (!test && ((bits >> i) & 1) == 1);
+
+ if (i < 8) {
+ this.modules[8][this.moduleCount - i - 1] = mod;
+ } else if (i < 9) {
+ this.modules[8][15 - i - 1 + 1] = mod;
+ } else {
+ this.modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ // fixed module
+ this.modules[this.moduleCount - 8][8] = (!test);
+
+ },
+
+ mapData: function(data, maskPattern) {
+
+ var inc = -1;
+ var row = this.moduleCount - 1;
+ var bitIndex = 7;
+ var byteIndex = 0;
+
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+
+ if (col == 6) col--;
+
+ while (true) {
+
+ for (var c = 0; c < 2; c++) {
+
+ if (this.modules[row][col - c] == null) {
+
+ var dark = false;
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
+
+ if (mask) {
+ dark = !dark;
+ }
+
+ this.modules[row][col - c] = dark;
+ bitIndex--;
+
+ if (bitIndex == -1) {
+ byteIndex++;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+
+ if (row < 0 || this.moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+
+ }
+
+ };
+
+ QRCode.PAD0 = 0xEC;
+ QRCode.PAD1 = 0x11;
+
+ QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
+
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
+
+ var buffer = new QRBitBuffer();
+
+ for (var i = 0; i < dataList.length; i++) {
+ var data = dataList[i];
+ buffer.put(data.mode, 4);
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
+ data.write(buffer);
+ }
+
+ // calc num max data.
+ var totalDataCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].dataCount;
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new Error("code length overflow. (" +
+ buffer.getLengthInBits() +
+ ">" +
+ totalDataCount * 8 +
+ ")");
+ }
+
+ // end code
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.putBit(false);
+ }
+
+ // padding
+ while (true) {
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(QRCode.PAD1, 8);
+ }
+
+ return QRCode.createBytes(buffer, rsBlocks);
+ }
+
+ QRCode.createBytes = function(buffer, rsBlocks) {
+
+ var offset = 0;
+
+ var maxDcCount = 0;
+ var maxEcCount = 0;
+
+ var dcdata = new Array(rsBlocks.length);
+ var ecdata = new Array(rsBlocks.length);
+
+ for (var r = 0; r < rsBlocks.length; r++) {
+
+ var dcCount = rsBlocks[r].dataCount;
+ var ecCount = rsBlocks[r].totalCount - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new Array(dcCount);
+
+ for (var i = 0; i < dcdata[r].length; i++) {
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+ }
+ offset += dcCount;
+
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ var modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
+ for (var i = 0; i < ecdata[r].length; i++) {
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+ }
+
+ }
+
+ var totalCodeCount = 0;
+ for (var i = 0; i < rsBlocks.length; i++) {
+ totalCodeCount += rsBlocks[i].totalCount;
+ }
+
+ var data = new Array(totalCodeCount);
+ var index = 0;
+
+ for (var i = 0; i < maxDcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < dcdata[r].length) {
+ data[index++] = dcdata[r][i];
+ }
+ }
+ }
+
+ for (var i = 0; i < maxEcCount; i++) {
+ for (var r = 0; r < rsBlocks.length; r++) {
+ if (i < ecdata[r].length) {
+ data[index++] = ecdata[r][i];
+ }
+ }
+ }
+
+ return data;
+
+ }
+
+ //---------------------------------------------------------------------
+ // QRMode
+ //---------------------------------------------------------------------
+
+ var QRMode = {
+ MODE_NUMBER: 1 << 0,
+ MODE_ALPHA_NUM: 1 << 1,
+ MODE_8BIT_BYTE: 1 << 2,
+ MODE_KANJI: 1 << 3
+ };
+
+ //---------------------------------------------------------------------
+ // QRErrorCorrectLevel
+ //---------------------------------------------------------------------
+
+ var QRErrorCorrectLevel = {
+ L: 1,
+ M: 0,
+ Q: 3,
+ H: 2
+ };
+
+ //---------------------------------------------------------------------
+ // QRMaskPattern
+ //---------------------------------------------------------------------
+
+ var QRMaskPattern = {
+ PATTERN000: 0,
+ PATTERN001: 1,
+ PATTERN010: 2,
+ PATTERN011: 3,
+ PATTERN100: 4,
+ PATTERN101: 5,
+ PATTERN110: 6,
+ PATTERN111: 7
+ };
+
+ //---------------------------------------------------------------------
+ // QRUtil
+ //---------------------------------------------------------------------
+
+ var QRUtil = {
+
+ PATTERN_POSITION_TABLE: [
+ [],
+ [6, 18],
+ [6, 22],
+ [6, 26],
+ [6, 30],
+ [6, 34],
+ [6, 22, 38],
+ [6, 24, 42],
+ [6, 26, 46],
+ [6, 28, 50],
+ [6, 30, 54],
+ [6, 32, 58],
+ [6, 34, 62],
+ [6, 26, 46, 66],
+ [6, 26, 48, 70],
+ [6, 26, 50, 74],
+ [6, 30, 54, 78],
+ [6, 30, 56, 82],
+ [6, 30, 58, 86],
+ [6, 34, 62, 90],
+ [6, 28, 50, 72, 94],
+ [6, 26, 50, 74, 98],
+ [6, 30, 54, 78, 102],
+ [6, 28, 54, 80, 106],
+ [6, 32, 58, 84, 110],
+ [6, 30, 58, 86, 114],
+ [6, 34, 62, 90, 118],
+ [6, 26, 50, 74, 98, 122],
+ [6, 30, 54, 78, 102, 126],
+ [6, 26, 52, 78, 104, 130],
+ [6, 30, 56, 82, 108, 134],
+ [6, 34, 60, 86, 112, 138],
+ [6, 30, 58, 86, 114, 142],
+ [6, 34, 62, 90, 118, 146],
+ [6, 30, 54, 78, 102, 126, 150],
+ [6, 24, 50, 76, 102, 128, 154],
+ [6, 28, 54, 80, 106, 132, 158],
+ [6, 32, 58, 84, 110, 136, 162],
+ [6, 26, 54, 82, 110, 138, 166],
+ [6, 30, 58, 86, 114, 142, 170]
+ ],
+
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+
+ getBCHTypeInfo: function(data) {
+ var d = data << 10;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+ d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+ }
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
+ },
+
+ getBCHTypeNumber: function(data) {
+ var d = data << 12;
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+ d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+ }
+ return (data << 12) | d;
+ },
+
+ getBCHDigit: function(data) {
+
+ var digit = 0;
+
+ while (data != 0) {
+ digit++;
+ data >>>= 1;
+ }
+
+ return digit;
+ },
+
+ getPatternPosition: function(typeNumber) {
+ return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+ },
+
+ getMask: function(maskPattern, i, j) {
+
+ switch (maskPattern) {
+
+ case QRMaskPattern.PATTERN000:
+ return (i + j) % 2 == 0;
+ case QRMaskPattern.PATTERN001:
+ return i % 2 == 0;
+ case QRMaskPattern.PATTERN010:
+ return j % 3 == 0;
+ case QRMaskPattern.PATTERN011:
+ return (i + j) % 3 == 0;
+ case QRMaskPattern.PATTERN100:
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+ case QRMaskPattern.PATTERN101:
+ return (i * j) % 2 + (i * j) % 3 == 0;
+ case QRMaskPattern.PATTERN110:
+ return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+ case QRMaskPattern.PATTERN111:
+ return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+ default:
+ throw new Error("bad maskPattern:" + maskPattern);
+ }
+ },
+
+ getErrorCorrectPolynomial: function(errorCorrectLength) {
+
+ var a = new QRPolynomial([1], 0);
+
+ for (var i = 0; i < errorCorrectLength; i++) {
+ a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+ }
+
+ return a;
+ },
+
+ getLengthInBits: function(mode, type) {
+
+ if (1 <= type && type < 10) {
+
+ // 1 - 9
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 10;
+ case QRMode.MODE_ALPHA_NUM:
+ return 9;
+ case QRMode.MODE_8BIT_BYTE:
+ return 8;
+ case QRMode.MODE_KANJI:
+ return 8;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 27) {
+
+ // 10 - 26
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 12;
+ case QRMode.MODE_ALPHA_NUM:
+ return 11;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 10;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else if (type < 41) {
+
+ // 27 - 40
+
+ switch (mode) {
+ case QRMode.MODE_NUMBER:
+ return 14;
+ case QRMode.MODE_ALPHA_NUM:
+ return 13;
+ case QRMode.MODE_8BIT_BYTE:
+ return 16;
+ case QRMode.MODE_KANJI:
+ return 12;
+ default:
+ throw new Error("mode:" + mode);
+ }
+
+ } else {
+ throw new Error("type:" + type);
+ }
+ },
+
+ getLostPoint: function(qrCode) {
+
+ var moduleCount = qrCode.getModuleCount();
+
+ var lostPoint = 0;
+
+ // LEVEL1
+
+ for (var row = 0; row < moduleCount; row++) {
+
+ for (var col = 0; col < moduleCount; col++) {
+
+ var sameCount = 0;
+ var dark = qrCode.isDark(row, col);
+
+ for (var r = -1; r <= 1; r++) {
+
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (var c = -1; c <= 1; c++) {
+
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrCode.isDark(row + r, col + c)) {
+ sameCount++;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ }
+
+ // LEVEL2
+
+ for (var row = 0; row < moduleCount - 1; row++) {
+ for (var col = 0; col < moduleCount - 1; col++) {
+ var count = 0;
+ if (qrCode.isDark(row, col)) count++;
+ if (qrCode.isDark(row + 1, col)) count++;
+ if (qrCode.isDark(row, col + 1)) count++;
+ if (qrCode.isDark(row + 1, col + 1)) count++;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+
+ for (var row = 0; row < moduleCount; row++) {
+ for (var col = 0; col < moduleCount - 6; col++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row, col + 1) &&
+ qrCode.isDark(row, col + 2) &&
+ qrCode.isDark(row, col + 3) &&
+ qrCode.isDark(row, col + 4) &&
+ !qrCode.isDark(row, col + 5) &&
+ qrCode.isDark(row, col + 6)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount - 6; row++) {
+ if (qrCode.isDark(row, col) &&
+ !qrCode.isDark(row + 1, col) &&
+ qrCode.isDark(row + 2, col) &&
+ qrCode.isDark(row + 3, col) &&
+ qrCode.isDark(row + 4, col) &&
+ !qrCode.isDark(row + 5, col) &&
+ qrCode.isDark(row + 6, col)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+
+ var darkCount = 0;
+
+ for (var col = 0; col < moduleCount; col++) {
+ for (var row = 0; row < moduleCount; row++) {
+ if (qrCode.isDark(row, col)) {
+ darkCount++;
+ }
+ }
+ }
+
+ var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ }
+
+ };
+
+
+ //---------------------------------------------------------------------
+ // QRMath
+ //---------------------------------------------------------------------
+
+ var QRMath = {
+
+ glog: function(n) {
+
+ if (n < 1) {
+ throw new Error("glog(" + n + ")");
+ }
+
+ return QRMath.LOG_TABLE[n];
+ },
+
+ gexp: function(n) {
+
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return QRMath.EXP_TABLE[n];
+ },
+
+ EXP_TABLE: new Array(256),
+
+ LOG_TABLE: new Array(256)
+
+ };
+
+ for (var i = 0; i < 8; i++) {
+ QRMath.EXP_TABLE[i] = 1 << i;
+ }
+ for (var i = 8; i < 256; i++) {
+ QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^
+ QRMath.EXP_TABLE[i - 5] ^
+ QRMath.EXP_TABLE[i - 6] ^
+ QRMath.EXP_TABLE[i - 8];
+ }
+ for (var i = 0; i < 255; i++) {
+ QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+ }
+
+ //---------------------------------------------------------------------
+ // QRPolynomial
+ //---------------------------------------------------------------------
+
+ function QRPolynomial(num, shift) {
+
+ if (num.length == undefined) {
+ throw new Error(num.length + "/" + shift);
+ }
+
+ var offset = 0;
+
+ while (offset < num.length && num[offset] == 0) {
+ offset++;
+ }
+
+ this.num = new Array(num.length - offset + shift);
+ for (var i = 0; i < num.length - offset; i++) {
+ this.num[i] = num[i + offset];
+ }
+ }
+
+ QRPolynomial.prototype = {
+
+ get: function(index) {
+ return this.num[index];
+ },
+
+ getLength: function() {
+ return this.num.length;
+ },
+
+ multiply: function(e) {
+
+ var num = new Array(this.getLength() + e.getLength() - 1);
+
+ for (var i = 0; i < this.getLength(); i++) {
+ for (var j = 0; j < e.getLength(); j++) {
+ num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+ }
+ }
+
+ return new QRPolynomial(num, 0);
+ },
+
+ mod: function(e) {
+
+ if (this.getLength() - e.getLength() < 0) {
+ return this;
+ }
+
+ var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
+
+ var num = new Array(this.getLength());
+
+ for (var i = 0; i < this.getLength(); i++) {
+ num[i] = this.get(i);
+ }
+
+ for (var i = 0; i < e.getLength(); i++) {
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+ }
+
+ // recursive call
+ return new QRPolynomial(num, 0).mod(e);
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // QRRSBlock
+ //---------------------------------------------------------------------
+
+ function QRRSBlock(totalCount, dataCount) {
+ this.totalCount = totalCount;
+ this.dataCount = dataCount;
+ }
+
+ QRRSBlock.RS_BLOCK_TABLE = [
+
+ // L
+ // M
+ // Q
+ // H
+
+ // 1
+ [1, 26, 19],
+ [1, 26, 16],
+ [1, 26, 13],
+ [1, 26, 9],
+
+ // 2
+ [1, 44, 34],
+ [1, 44, 28],
+ [1, 44, 22],
+ [1, 44, 16],
+
+ // 3
+ [1, 70, 55],
+ [1, 70, 44],
+ [2, 35, 17],
+ [2, 35, 13],
+
+ // 4
+ [1, 100, 80],
+ [2, 50, 32],
+ [2, 50, 24],
+ [4, 25, 9],
+
+ // 5
+ [1, 134, 108],
+ [2, 67, 43],
+ [2, 33, 15, 2, 34, 16],
+ [2, 33, 11, 2, 34, 12],
+
+ // 6
+ [2, 86, 68],
+ [4, 43, 27],
+ [4, 43, 19],
+ [4, 43, 15],
+
+ // 7
+ [2, 98, 78],
+ [4, 49, 31],
+ [2, 32, 14, 4, 33, 15],
+ [4, 39, 13, 1, 40, 14],
+
+ // 8
+ [2, 121, 97],
+ [2, 60, 38, 2, 61, 39],
+ [4, 40, 18, 2, 41, 19],
+ [4, 40, 14, 2, 41, 15],
+
+ // 9
+ [2, 146, 116],
+ [3, 58, 36, 2, 59, 37],
+ [4, 36, 16, 4, 37, 17],
+ [4, 36, 12, 4, 37, 13],
+
+ // 10
+ [2, 86, 68, 2, 87, 69],
+ [4, 69, 43, 1, 70, 44],
+ [6, 43, 19, 2, 44, 20],
+ [6, 43, 15, 2, 44, 16],
+
+ // 11
+ [4, 101, 81],
+ [1, 80, 50, 4, 81, 51],
+ [4, 50, 22, 4, 51, 23],
+ [3, 36, 12, 8, 37, 13],
+
+ // 12
+ [2, 116, 92, 2, 117, 93],
+ [6, 58, 36, 2, 59, 37],
+ [4, 46, 20, 6, 47, 21],
+ [7, 42, 14, 4, 43, 15],
+
+ // 13
+ [4, 133, 107],
+ [8, 59, 37, 1, 60, 38],
+ [8, 44, 20, 4, 45, 21],
+ [12, 33, 11, 4, 34, 12],
+
+ // 14
+ [3, 145, 115, 1, 146, 116],
+ [4, 64, 40, 5, 65, 41],
+ [11, 36, 16, 5, 37, 17],
+ [11, 36, 12, 5, 37, 13],
+
+ // 15
+ [5, 109, 87, 1, 110, 88],
+ [5, 65, 41, 5, 66, 42],
+ [5, 54, 24, 7, 55, 25],
+ [11, 36, 12],
+
+ // 16
+ [5, 122, 98, 1, 123, 99],
+ [7, 73, 45, 3, 74, 46],
+ [15, 43, 19, 2, 44, 20],
+ [3, 45, 15, 13, 46, 16],
+
+ // 17
+ [1, 135, 107, 5, 136, 108],
+ [10, 74, 46, 1, 75, 47],
+ [1, 50, 22, 15, 51, 23],
+ [2, 42, 14, 17, 43, 15],
+
+ // 18
+ [5, 150, 120, 1, 151, 121],
+ [9, 69, 43, 4, 70, 44],
+ [17, 50, 22, 1, 51, 23],
+ [2, 42, 14, 19, 43, 15],
+
+ // 19
+ [3, 141, 113, 4, 142, 114],
+ [3, 70, 44, 11, 71, 45],
+ [17, 47, 21, 4, 48, 22],
+ [9, 39, 13, 16, 40, 14],
+
+ // 20
+ [3, 135, 107, 5, 136, 108],
+ [3, 67, 41, 13, 68, 42],
+ [15, 54, 24, 5, 55, 25],
+ [15, 43, 15, 10, 44, 16],
+
+ // 21
+ [4, 144, 116, 4, 145, 117],
+ [17, 68, 42],
+ [17, 50, 22, 6, 51, 23],
+ [19, 46, 16, 6, 47, 17],
+
+ // 22
+ [2, 139, 111, 7, 140, 112],
+ [17, 74, 46],
+ [7, 54, 24, 16, 55, 25],
+ [34, 37, 13],
+
+ // 23
+ [4, 151, 121, 5, 152, 122],
+ [4, 75, 47, 14, 76, 48],
+ [11, 54, 24, 14, 55, 25],
+ [16, 45, 15, 14, 46, 16],
+
+ // 24
+ [6, 147, 117, 4, 148, 118],
+ [6, 73, 45, 14, 74, 46],
+ [11, 54, 24, 16, 55, 25],
+ [30, 46, 16, 2, 47, 17],
+
+ // 25
+ [8, 132, 106, 4, 133, 107],
+ [8, 75, 47, 13, 76, 48],
+ [7, 54, 24, 22, 55, 25],
+ [22, 45, 15, 13, 46, 16],
+
+ // 26
+ [10, 142, 114, 2, 143, 115],
+ [19, 74, 46, 4, 75, 47],
+ [28, 50, 22, 6, 51, 23],
+ [33, 46, 16, 4, 47, 17],
+
+ // 27
+ [8, 152, 122, 4, 153, 123],
+ [22, 73, 45, 3, 74, 46],
+ [8, 53, 23, 26, 54, 24],
+ [12, 45, 15, 28, 46, 16],
+
+ // 28
+ [3, 147, 117, 10, 148, 118],
+ [3, 73, 45, 23, 74, 46],
+ [4, 54, 24, 31, 55, 25],
+ [11, 45, 15, 31, 46, 16],
+
+ // 29
+ [7, 146, 116, 7, 147, 117],
+ [21, 73, 45, 7, 74, 46],
+ [1, 53, 23, 37, 54, 24],
+ [19, 45, 15, 26, 46, 16],
+
+ // 30
+ [5, 145, 115, 10, 146, 116],
+ [19, 75, 47, 10, 76, 48],
+ [15, 54, 24, 25, 55, 25],
+ [23, 45, 15, 25, 46, 16],
+
+ // 31
+ [13, 145, 115, 3, 146, 116],
+ [2, 74, 46, 29, 75, 47],
+ [42, 54, 24, 1, 55, 25],
+ [23, 45, 15, 28, 46, 16],
+
+ // 32
+ [17, 145, 115],
+ [10, 74, 46, 23, 75, 47],
+ [10, 54, 24, 35, 55, 25],
+ [19, 45, 15, 35, 46, 16],
+
+ // 33
+ [17, 145, 115, 1, 146, 116],
+ [14, 74, 46, 21, 75, 47],
+ [29, 54, 24, 19, 55, 25],
+ [11, 45, 15, 46, 46, 16],
+
+ // 34
+ [13, 145, 115, 6, 146, 116],
+ [14, 74, 46, 23, 75, 47],
+ [44, 54, 24, 7, 55, 25],
+ [59, 46, 16, 1, 47, 17],
+
+ // 35
+ [12, 151, 121, 7, 152, 122],
+ [12, 75, 47, 26, 76, 48],
+ [39, 54, 24, 14, 55, 25],
+ [22, 45, 15, 41, 46, 16],
+
+ // 36
+ [6, 151, 121, 14, 152, 122],
+ [6, 75, 47, 34, 76, 48],
+ [46, 54, 24, 10, 55, 25],
+ [2, 45, 15, 64, 46, 16],
+
+ // 37
+ [17, 152, 122, 4, 153, 123],
+ [29, 74, 46, 14, 75, 47],
+ [49, 54, 24, 10, 55, 25],
+ [24, 45, 15, 46, 46, 16],
+
+ // 38
+ [4, 152, 122, 18, 153, 123],
+ [13, 74, 46, 32, 75, 47],
+ [48, 54, 24, 14, 55, 25],
+ [42, 45, 15, 32, 46, 16],
+
+ // 39
+ [20, 147, 117, 4, 148, 118],
+ [40, 75, 47, 7, 76, 48],
+ [43, 54, 24, 22, 55, 25],
+ [10, 45, 15, 67, 46, 16],
+
+ // 40
+ [19, 148, 118, 6, 149, 119],
+ [18, 75, 47, 31, 76, 48],
+ [34, 54, 24, 34, 55, 25],
+ [20, 45, 15, 61, 46, 16]
+ ];
+
+ QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
+
+ var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
+
+ if (rsBlock == undefined) {
+ throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
+ }
+
+ var length = rsBlock.length / 3;
+
+ var list = new Array();
+
+ for (var i = 0; i < length; i++) {
+
+ var count = rsBlock[i * 3 + 0];
+ var totalCount = rsBlock[i * 3 + 1];
+ var dataCount = rsBlock[i * 3 + 2];
+
+ for (var j = 0; j < count; j++) {
+ list.push(new QRRSBlock(totalCount, dataCount));
+ }
+ }
+
+ return list;
+ }
+
+ QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
+
+ switch (errorCorrectLevel) {
+ case QRErrorCorrectLevel.L:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
+ case QRErrorCorrectLevel.M:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
+ case QRErrorCorrectLevel.Q:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
+ case QRErrorCorrectLevel.H:
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
+ default:
+ return undefined;
+ }
+ }
+
+ //---------------------------------------------------------------------
+ // QRBitBuffer
+ //---------------------------------------------------------------------
+
+ function QRBitBuffer() {
+ this.buffer = new Array();
+ this.length = 0;
+ }
+
+ QRBitBuffer.prototype = {
+
+ get: function(index) {
+ var bufIndex = Math.floor(index / 8);
+ return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
+ },
+
+ put: function(num, length) {
+ for (var i = 0; i < length; i++) {
+ this.putBit(((num >>> (length - i - 1)) & 1) == 1);
+ }
+ },
+
+ getLengthInBits: function() {
+ return this.length;
+ },
+
+ putBit: function(bit) {
+
+ var bufIndex = Math.floor(this.length / 8);
+ if (this.buffer.length <= bufIndex) {
+ this.buffer.push(0);
+ }
+
+ if (bit) {
+ this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+ }
+
+ this.length++;
+ }
+ };
+
+ //---------------------------------------------------------------------
+ // Support Chinese
+ //---------------------------------------------------------------------
+ function utf16To8(text) {
+ var result = '';
+ var c;
+ for (var i = 0; i < text.length; i++) {
+ c = text.charCodeAt(i);
+ if (c >= 0x0001 && c <= 0x007F) {
+ result += text.charAt(i);
+ } else if (c > 0x07FF) {
+ result += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
+ result += String.fromCharCode(0x80 | c >> 6 & 0x3F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ } else {
+ result += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
+ result += String.fromCharCode(0x80 | c >> 0 & 0x3F);
+ }
+ }
+ return result;
+ }
+
+ uQRCode = {
+
+ errorCorrectLevel: QRErrorCorrectLevel,
+
+ defaults: {
+ size: 354,
+ margin: 0,
+ backgroundColor: '#ffffff',
+ foregroundColor: '#000000',
+ fileType: 'png', // 'jpg', 'png'
+ errorCorrectLevel: QRErrorCorrectLevel.H,
+ typeNumber: -1
+ },
+
+ make: function(options) {
+ return new Promise((reslove, reject) => {
+ var defaultOptions = {
+ canvasId: options.canvasId,
+ componentInstance: options.componentInstance,
+ text: options.text,
+ size: this.defaults.size,
+ margin: this.defaults.margin,
+ backgroundColor: this.defaults.backgroundColor,
+ foregroundColor: this.defaults.foregroundColor,
+ fileType: this.defaults.fileType,
+ errorCorrectLevel: this.defaults.errorCorrectLevel,
+ typeNumber: this.defaults.typeNumber
+ };
+ if (options) {
+ for (var i in options) {
+ defaultOptions[i] = options[i];
+ }
+ }
+ options = defaultOptions;
+ if (!options.canvasId) {
+ console.error('uQRCode: Please set canvasId!');
+ return;
+ }
+
+ function createCanvas() {
+ var qrcode = new QRCode(options.typeNumber, options.errorCorrectLevel);
+ qrcode.addData(utf16To8(options.text));
+ qrcode.make();
+
+ var ctx = uni.createCanvasContext(options.canvasId, options.componentInstance);
+ ctx.setFillStyle(options.backgroundColor);
+ ctx.fillRect(0, 0, options.size, options.size);
+
+ var tileW = (options.size - options.margin * 2) / qrcode.getModuleCount();
+ var tileH = tileW;
+
+ for (var row = 0; row < qrcode.getModuleCount(); row++) {
+ for (var col = 0; col < qrcode.getModuleCount(); col++) {
+ var style = qrcode.isDark(row, col) ? options.foregroundColor : options.backgroundColor;
+ ctx.setFillStyle(style);
+ var x = Math.round(col * tileW) + options.margin;
+ var y = Math.round(row * tileH) + options.margin;
+ var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
+ var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
+ ctx.fillRect(x, y, w, h);
+ }
+ }
+
+ setTimeout(function() {
+ ctx.draw(false, (function() {
+ setTimeout(function() {
+ uni.canvasToTempFilePath({
+ canvasId: options.canvasId,
+ fileType: options.fileType,
+ width: options.size,
+ height: options.size,
+ destWidth: options.size,
+ destHeight: options.size,
+ success: function(res) {
+ let resData; // 将统一为base64格式
+ let tempFilePath = res.tempFilePath; // H5为base64,其他为相对路径
+
+ // #ifdef H5
+ resData = tempFilePath;
+ options.success && options.success(resData);
+ reslove(resData);
+ // #endif
+
+ // #ifdef APP-PLUS
+ const path = plus.io.convertLocalFileSystemURL(tempFilePath) // 绝对路径
+ let fileReader = new plus.io.FileReader();
+ fileReader.readAsDataURL(path);
+ fileReader.onloadend = res => {
+ resData = res.target.result;
+ options.success && options.success(resData);
+ reslove(resData);
+ };
+ // #endif
+
+ // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+ uni.getFileSystemManager().readFile({
+ filePath: tempFilePath,
+ encoding: 'base64',
+ success: res => {
+ resData = 'data:image/png;base64,' + res.data;
+ options.success && options.success(resData);
+ reslove(resData);
+ }
+ })
+ // #endif
+
+ // #ifndef H5 || APP-PLUS || MP-WEIXIN || MP-QQ || MP-TOUTIAO
+ if (plus) {
+ const path = plus.io.convertLocalFileSystemURL(tempFilePath) // 绝对路径
+ let fileReader = new plus.io.FileReader();
+ fileReader.readAsDataURL(path);
+ fileReader.onloadend = res => {
+ resData = res.target.result;
+ options.success && options.success(resData);
+ reslove(resData);
+ };
+ } else {
+ uni.request({
+ url: tempFilePath,
+ method: 'GET',
+ responseType: 'arraybuffer',
+ success: res => {
+ resData = `data:image/png;base64,${uni.arrayBufferToBase64(res.data)}`; // 把arraybuffer转成base64
+ options.success && options.success(resData);
+ reslove(resData);
+ }
+ })
+ }
+ // #endif
+ },
+ fail: function(error) {
+ options.fail && options.fail(error);
+ reject(error);
+ },
+ complete: function(res) {
+ options.complete && options.complete(res);
+ }
+ }, options.componentInstance);
+ }, options.text.length + 100);
+ })());
+ }, 150);
+ }
+
+ createCanvas();
+ });
+ }
+ }
+
+})()
+
+export default uQRCode
diff --git a/components/cloud-image/cloud-image.vue b/components/cloud-image/cloud-image.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3f2815937d591835950b9bb99e159a952bb0eedd
--- /dev/null
+++ b/components/cloud-image/cloud-image.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/refreshBox/refreshBox.nvue b/components/refreshBox/refreshBox.nvue
new file mode 100644
index 0000000000000000000000000000000000000000..f41c25cf49ac5b5fd7ca0c0b1ec58c582d932fd9
--- /dev/null
+++ b/components/refreshBox/refreshBox.nvue
@@ -0,0 +1,95 @@
+
+
+
+
+ {{config[state].text}}
+
+
+
+
+
+
diff --git a/components/uni-agreements/uni-agreements.vue b/components/uni-agreements/uni-agreements.vue
new file mode 100644
index 0000000000000000000000000000000000000000..2c0af79c1e4b5593604e670f1c244a461c09c91d
--- /dev/null
+++ b/components/uni-agreements/uni-agreements.vue
@@ -0,0 +1,77 @@
+
+
+
+
+ {{$t('common.agree')}}
+
+
+ {{agreement.title}}
+ &
+
+
+
+
+
+
+
diff --git a/components/uni-bindMobileByMpWeixin/uni-bindMobileByMpWeixin.vue b/components/uni-bindMobileByMpWeixin/uni-bindMobileByMpWeixin.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bceda443e6b7de3d17a9a43f7be6f0aa525b7e91
--- /dev/null
+++ b/components/uni-bindMobileByMpWeixin/uni-bindMobileByMpWeixin.vue
@@ -0,0 +1,189 @@
+
+
+
+ 绑定资料
+ 将一键获取你的手机号码绑定你的个人资料
+
+ 关闭
+ 获取
+
+
+
+
+
+
+
+
diff --git a/components/uni-load-state/i18n/en.json b/components/uni-load-state/i18n/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..b600ad47c8d868090e2f70ae8472d8eb5bd6e203
--- /dev/null
+++ b/components/uni-load-state/i18n/en.json
@@ -0,0 +1,6 @@
+{
+ "noData": "No Data",
+ "noNetwork": "Network error",
+ "toSet": "Go to settings",
+ "error": "error"
+}
diff --git a/components/uni-load-state/i18n/index.js b/components/uni-load-state/i18n/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..c70a38619a5e2b7f933ec3dda91db5ddc9840231
--- /dev/null
+++ b/components/uni-load-state/i18n/index.js
@@ -0,0 +1,6 @@
+import en from './en.json'
+import zhHans from './zh-Hans.json'
+export default {
+ en,
+ 'zh-Hans': zhHans
+}
diff --git a/components/uni-load-state/i18n/zh-Hans.json b/components/uni-load-state/i18n/zh-Hans.json
new file mode 100644
index 0000000000000000000000000000000000000000..4fa8e1a78267e21eac0fff2c3f52053319fb83f5
--- /dev/null
+++ b/components/uni-load-state/i18n/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "noData": "暂无数据",
+ "noNetwork": "网络异常",
+ "toSet": "前往设置",
+ "error": "错误"
+}
diff --git a/components/uni-load-state/readme.md b/components/uni-load-state/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..07288d69d7a7a687a7d3b5ee6840c5516cdee510
--- /dev/null
+++ b/components/uni-load-state/readme.md
@@ -0,0 +1,3 @@
+新增uni-load-state组件,这是一个封装数据请求状态的组件。根据uniCloud-db组件提供的参数直接响应对应的效果。
+包括加载中、当前页面为空、没有更多数据、上拉加载更多;
+加载错误判断,如果是断网就引导打开系统网络设置页面。恢复联网后自动触发networkResume方法。
\ No newline at end of file
diff --git a/components/uni-load-state/uni-load-state.vue b/components/uni-load-state/uni-load-state.vue
new file mode 100644
index 0000000000000000000000000000000000000000..640f4a7c3d383fb3dc313b3f536d1e8419d55f59
--- /dev/null
+++ b/components/uni-load-state/uni-load-state.vue
@@ -0,0 +1,171 @@
+
+
+
+
+
+ {{noNetwork}}
+
+ {{toSet}}
+
+
+ {{error}}:{{JSON.stringify(state.error)}}
+
+
+
+ {{state.loading?'加载中...':(state.hasMore?'上拉加载更多':'没有更多数据了')}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/uni-quick-login/uni-quick-login.vue b/components/uni-quick-login/uni-quick-login.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bfc75b2b0ca91b90f39a196d0b064b7daa04a398
--- /dev/null
+++ b/components/uni-quick-login/uni-quick-login.vue
@@ -0,0 +1,396 @@
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/uni-section/uni-section.vue b/components/uni-section/uni-section.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b3fc47c559f0cd4ea7f63d0c798ae342c766e57d
--- /dev/null
+++ b/components/uni-section/uni-section.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+ {{ title }}
+ {{ subTitle }}
+
+
+
+
+
+
+
diff --git a/components/uni-send-sms-code/uni-send-sms-code.vue b/components/uni-send-sms-code/uni-send-sms-code.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4b59b75e9a2bd34ca2d6215b7ece14d4310b3d04
--- /dev/null
+++ b/components/uni-send-sms-code/uni-send-sms-code.vue
@@ -0,0 +1,144 @@
+
+
+ {{innerText}}
+
+
+
+
+
+
diff --git a/components/uni-user-profile/uni-user-profile.vue b/components/uni-user-profile/uni-user-profile.vue
new file mode 100644
index 0000000000000000000000000000000000000000..62beb86485fa39557e91887f8408d0d1cd5b3d2f
--- /dev/null
+++ b/components/uni-user-profile/uni-user-profile.vue
@@ -0,0 +1,194 @@
+
+
+
+ 绑定资料
+ 获取你的微信头像和昵称,完善你的个人资料
+
+ 关闭
+ 确定
+
+
+
+
+
+
+
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..bb564510ede52ef9c0dabfd730531233d977de69
--- /dev/null
+++ b/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lang/en.js b/lang/en.js
new file mode 100644
index 0000000000000000000000000000000000000000..43e1bfbcaeb9c0cc3aa28dfaed417ca93c0b81b1
--- /dev/null
+++ b/lang/en.js
@@ -0,0 +1,199 @@
+export default {
+ tabbar:'List,Grid,contacts,Mine',
+ agreementsTitle:'User service agreement,Privacy policy',
+ common: {
+ wechatFriends: "friends",
+ wechatBbs: "bbs",
+ weibo: "weibo",
+ more: "more",
+ agree:"agree",
+ copy: "copy",
+ wechatApplet: "applet",
+ cancelShare: "cancel sharing",
+ updateSucceeded: "update succeeded",
+ phonePlaceholder: "Please enter your mobile phone number",
+ verifyCodePlaceholder: "Please enter the verification code",
+ newPasswordPlaceholder: "Please enter a new password",
+ confirmNewPasswordPlaceholder: "Please confirm the new password",
+ confirmPassword: "Please confirm the password",
+ verifyCodeSend: "Verification code has been sent to via SMS",
+ passwordDigits: "The password is 6 - 20 digits",
+ getVerifyCode: "Get Code",
+ noAgree: "You have not agreed to the privacy policy agreement",
+ gotIt: "got it",
+ login: "sign in",
+ error: "error",
+ complete: "complete",
+ submit: "Submit",
+ formatErr: "Incorrect mobile phone number format",
+ sixDigitCode: "Please enter a 6-digit verification code",
+ resetNavTitle:"Reset password"
+ },
+ list: {
+ inputPlaceholder: "Please enter the search content",
+ },
+ search: {
+ cancelText: "cancel",
+ searchHistory: "search history",
+ searchDiscovery: "search discovery",
+ deleteAll: "delete all",
+ delete: "delete",
+ deleteTip: "Are you sure to clear the search history ?",
+ complete: "complete",
+ searchHiddenTip: "Current search found hidden",
+ },
+ grid: {
+ grid: "Grid Assembly",
+ visibleToAll: "Visible to all",
+ invisibleToTourists: "Invisible to tourists",
+ adminVisible: "Admin visible",
+ clickTip: "Click the",
+ clickTipGrid: "grid",
+ },
+ mine: {
+ showText: "Text",
+ signIn: "Check In Reward",
+ toEvaluate: "To Evaluate",
+ readArticles: "Read Articles",
+ myScore: "My Score",
+ invite: "Invite Friends",
+ guestBook: "Guest Book Example",
+ feedback: "Problems And Feedback",
+ settings: "Settings",
+ about: "About",
+ checkUpdate: "Check for Updates",
+ clicked: "You Clicked",
+ checkScore: "Please check your points after logging in",
+ currentScore: "The current score is ",
+ noScore: "There are currently no points",
+ notLogged: "not logged in",
+ },
+ userinfo: {
+ navigationBarTitle:"My Profile",
+ ProfilePhoto: "Profile Photo",
+ nickname: "Nickname",
+ notSet: "not set",
+ phoneNumber: "Phone Number",
+ notSpecified: "Not Specified",
+ setNickname: "Set Nickname ",
+ setNicknamePlaceholder: "Please enter a nickname to set",
+ bindPhoneNumber: "One click binding of local number",
+ bindOtherLogin: "Other number binding",
+ noChange: "No change",
+ uploading: "uploading",
+ requestFail: "Request for service failed",
+ setting: "setting",
+ deleteSucceeded: "Delete succeeded",
+ setSucceeded: "Set successfully",
+ },
+ smsCode: {
+ resendVerifyCode: "resend",
+ phoneErrTip: "Mobile phone number format error",
+ sendSuccessTip: "SMS verification code sent successfully",
+ },
+ loadMore: {
+ noData: "No Data",
+ noNetwork: "Network error",
+ toSet: "Go to settings",
+ error: "error",
+ },
+ guestbook: {
+ navigationBarTitle:"Message board",
+ msgContent: "post message content",
+ notAvailable: "not available for visitors who are not logged in",
+ send: "send",
+ addSucceeded: "Successfully added",
+ noPermission: "You don't have permission for this operation",
+ },
+ uniFeedback: {
+ navigationBarTitle: "Problems and feedback",
+ msgTitle: "Message content",
+ imgTitle: "Picture list",
+ contacts: "contacts",
+ phone: "contact number",
+ submit: "submit",
+ },
+ settings: {
+ navigationBarTitle:"Settings",
+ userInfo: "Personal Data",
+ changePassword: "change password",
+ clearTmp: "clean cache",
+ pushServer: "push function",
+ fingerPrint: "fingerprint unlock",
+ facial: "face unlock",
+ deactivate: "Deactivate",
+ logOut: "Logout",
+ login: "Login",
+ changeLanguage: "Language",
+ please: "please",
+ successText: "success",
+ failTip: "Authentication failed. Please try again",
+ authFailed: "authentication failed",
+ deviceNoOpen: "The device is not turned on",
+ fail: "fail",
+ tips: "tips",
+ exitLogin: "Do you want to log out?",
+ cancelText: "cancel",
+ confirmText: "confirm",
+ clearing: "clearing",
+ clearedSuccessed: "Cleared successfully",
+ },
+ deactivate: {
+ cancelText: "cancel",
+ nextStep: "next step",
+ navigationBarTitle:"Logout prompt"
+ },
+ about: {
+ sacnQR: "Scan the QR Code and your friends can also download it",
+ client: "applCantion",
+ and: "And",
+ about: "About",
+ },
+ invite: {
+ download: "Download",
+ },
+ login: {
+ phoneLogin: "After logging in, you can show yourself",
+ phoneLoginTip: "Unregistered mobile phone numbers will be automatically registered after verification",
+ getVerifyCode: "Get Code",
+ },
+ uniQuickLogin: {
+ accountLogin: "Account",
+ SMSLogin: "SMS",
+ wechatLogin: "wechat",
+ appleLogin: "Apple",
+ oneClickLogin: "One click login",
+ QQLogin: "QQ",
+ xiaomiLogin: "Xiaomi",
+ getProviderFail: "Failed to get service provider",
+ loginErr: "Login service initialization error",
+ chooseOtherLogin: "Click the third-party login",
+ },
+ pwdLogin: {
+ pwdLogin: "User name password login",
+ placeholder: "Please enter mobile number / user name",
+ passwordPlaceholder: "Please input a password",
+ verifyCodePlaceholder: "Please enter the verification code",
+ login: "sign in",
+ forgetPassword: "Forget password",
+ register: "Registered account",
+ },
+ register: {
+ navigationBarTitle:"register",
+ usernamePlaceholder: "Please enter user name",
+ nicknamePlaceholder: "Please enter user nickname",
+ passwordDigitsPlaceholder: "Please enter a 6-20 digit password",
+ passwordAgain: "Enter the password again",
+ registerAndLogin: "Register and log in",
+ },
+ listDetail: {
+ follow: "Click follow",
+ newsErr: "Error, news ID is empty",
+ },
+ newsLog:{
+ navigationBarTitle:"Reading Log"
+ },
+ bindMobile:{
+ navigationBarTitle:"Bind Mobile"
+ }
+}
diff --git a/lang/i18n.js b/lang/i18n.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a3599046457dccedf51380d55496324fccf717a
--- /dev/null
+++ b/lang/i18n.js
@@ -0,0 +1,102 @@
+import langEn from './en'
+import zhHans from './zh-Hans'
+import uniStarterConfig from '../uni-starter.config.js'
+const {i18n:{enable:i18nEnable} }= uniStarterConfig
+const messages = {
+ 'en': langEn,
+ 'zh-Hans': zhHans
+}
+let currentLang
+if(i18nEnable){
+ currentLang = uni.getStorageSync('CURRENT_LANG')
+}else{
+ currentLang = "zh-Hans"
+}
+// console.log(uni.getStorageSync('CURRENT_LANG'),currentLang);
+if (!currentLang) {
+ if (uni.getLocale) {
+ console.log('获取应用语言:', uni.getLocale());
+ let language = 'en'
+ if (uni.getLocale() != 'en') {
+ language = 'zh-Hans'
+ }
+ uni.setStorageSync('CURRENT_LANG', language)
+ currentLang = language
+ } else {
+ uni.getSystemInfo({
+ success: function(res) {
+ console.log('获取设备信息:', res);
+ let language = 'zh-Hans'
+ if (res.language == 'en') {
+ language = 'en'
+ }
+ uni.setStorageSync('CURRENT_LANG', language)
+ currentLang = language
+ },
+ fail: (err) => {
+ console.error(err)
+ }
+ })
+ }
+}
+let i18nConfig = {
+ locale: currentLang, // set locale
+ messages // set locale messages
+}
+
+// #ifdef VUE2
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+Vue.use(VueI18n)
+const i18n = new VueI18n(i18nConfig)
+// #endif
+
+// #ifdef VUE3
+import {
+ createI18n
+} from 'vue-i18n'
+const i18n = createI18n(i18nConfig)
+// #endif
+
+export default i18n
+
+
+if(i18nEnable){
+console.log(`
+ 你已开启多语言国际化,将自动根据语言获取【lang/en.js】或【lang/en.js】文件中配置的tabbar的值,
+ 覆盖你在pages.json中的tabbar的值
+ 如果你不需要多语言国际化,请打开配置文件uni-starter.config.js找到 -> i18n -> enable把值设置为false
+`);
+ let initLanguageAfter = () => {
+ function $i18n(e){
+ // #ifdef VUE3
+ return i18n.global.messages[i18n.global.locale][e]
+ // #endif
+ return i18n.messages[i18n.locale][e]
+ }
+ setTimeout(function(){
+ //底部tabbar更新
+ $i18n('tabbar').split(',').forEach((text, index) => {
+ // console.log(text);
+ uni.setTabBarItem({
+ index,
+ text,
+ complete: e => {
+ // console.log("e: " + JSON.stringify(e));
+ }
+ })
+ })
+ },1)
+ //更新 uni-starter.config agreements
+ let agreementsTitle = $i18n('agreementsTitle').split(',')
+ let agreements = uniStarterConfig.about.agreements
+ agreements[0].title = agreementsTitle[0]
+ agreements[1].title = agreementsTitle[1]
+ uniStarterConfig.about.agreements = agreements
+ }
+ initLanguageAfter()
+ uni.$on('changeLanguage', e => {
+ console.log('changeLanguage', e);
+ initLanguageAfter(e)
+ })
+}
\ No newline at end of file
diff --git a/lang/zh-Hans.js b/lang/zh-Hans.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cbcb56a1cd76d0ea354f6f19f5b133b925b9c3c
--- /dev/null
+++ b/lang/zh-Hans.js
@@ -0,0 +1,200 @@
+export default {
+ tabbar:'列表,宫格,通讯录,我的',
+ agreementsTitle:'用户服务协议,隐私政策',
+ common:{
+ wechatFriends: "微信好友",
+ wechatBbs: "微信朋友圈",
+ weibo:"微博",
+ more: "更多",
+ agree:"同意",
+ copy: "复制",
+ wechatApplet: "微信小程序",
+ cancelShare: "取消分享",
+ updateSucceeded: "更新成功",
+ phonePlaceholder: "请输入手机号",
+ verifyCodePlaceholder: "请输入验证码",
+ newPasswordPlaceholder: "请输入新密码",
+ confirmNewPasswordPlaceholder: "请确认新密码",
+ confirmPassword: "请确认密码",
+ verifyCodeSend: "验证码已通过短信发送至",
+ passwordDigits: "密码为6 - 20位",
+ getVerifyCode: "获取验证码",
+ noAgree: "你未同意隐私政策协议",
+ gotIt: "知道了",
+ login: "登录",
+ error: "错误",
+ complete: "完成",
+ submit: "提交",
+ formatErr:"手机号码格式不正确",
+ sixDigitCode:"请输入6位验证码",
+ resetNavTitle:"重置密码"
+
+ },
+ list: {
+ inputPlaceholder: "请输入搜索内容",
+ },
+ search:{
+ cancelText: '取消',
+ searchHistory: "搜索历史",
+ searchDiscovery: "搜索发现",
+ deleteAll: "全部删除",
+ delete: "删除",
+ deleteTip: "确认清空搜索历史吗?",
+ complete: "完成",
+ searchHiddenTip: "当前搜索发现已隐藏",
+ },
+ grid:{
+ grid: "宫格组件",
+ visibleToAll: "所有人可见",
+ invisibleToTourists: "游客不可见",
+ adminVisible: "管理员可见",
+ clickTip: "点击第",
+ clickTipGrid: "个宫格",
+ },
+ mine:{
+ showText: "文字",
+ signIn: "签到有奖",
+ toEvaluate: "去评分",
+ readArticles: "阅读过的文章",
+ myScore: "我的积分",
+ invite: "分销推荐",
+ guestBook: "留言板示例",
+ feedback: "问题与反馈",
+ settings: "设置",
+ checkUpdate: "检查更新",
+ about: "关于",
+ clicked: "你点击了",
+ checkScore: "请登录后查看积分",
+ currentScore: "当前积分为",
+ noScore: "当前无积分",
+ notLogged: "未登录",
+ },
+ userinfo:{
+ navigationBarTitle:"个人资料",
+ ProfilePhoto: "头像",
+ nickname: "昵称",
+ notSet: "未设置",
+ phoneNumber: "手机号",
+ notSpecified: "未绑定",
+ setNickname: "设置昵称",
+ setNicknamePlaceholder: "请输入要设置的昵称",
+ bindPhoneNumber: "本机号码一键绑定",
+ bindOtherLogin: "其他号码绑定",
+ noChange: "没有变化",
+ uploading: "正在上传",
+ requestFail: "请求服务失败",
+ setting: "设置中",
+ deleteSucceeded: "删除成功",
+ setSucceeded: "设置成功",
+ },
+ smsCode:{
+ resendVerifyCode: "重新发送",
+ phoneErrTip: "手机号格式错误",
+ sendSuccessTip: "短信验证码发送成功",
+ },
+ loadMore:{
+ noData: "暂无数据",
+ noNetwork: "网络异常",
+ toSet: "前往设置",
+ error: "错误",
+ },
+ guestbook:{
+ navigationBarTitle:"留言板",
+ msgContent: "发表留言内容",
+ notAvailable: "未登录游客不可用",
+ send: "发送",
+ addSucceeded: "新增成功",
+ noPermission: "你没有该操作权限",
+ },
+ uniFeedback:{
+ navigationBarTitle:"问题与反馈",
+ msgTitle: "留言内容",
+ imgTitle: "图片列表",
+ contacts: "联系人",
+ phone: "联系电话",
+ submit: "提交",
+ },
+ settings:{
+ navigationBarTitle:"设置",
+ userInfo: "个人资料",
+ changePassword: "修改密码",
+ clearTmp: "清理缓存",
+ pushServer: "推送功能",
+ fingerPrint: "指纹解锁",
+ facial: "人脸解锁",
+ deactivate: "注销账号",
+ logOut: "退出登录",
+ login: "登录",
+ failTip: "认证失败请重试",
+ authFailed: "认证失败",
+ changeLanguage: "切换语言",
+ please: "请用",
+ successText: "成功",
+ deviceNoOpen: "设备未开启",
+ fail: "失败",
+ tips: "提示",
+ exitLogin: "是否退出登录?",
+ clearing: "清除中",
+ clearedSuccessed: "清除成功",
+ confirmText: "确定",
+ cancelText: '取消',
+ },
+ deactivate:{
+ cancelText: '取消',
+ nextStep: "下一步",
+ navigationBarTitle:"注销提示"
+ },
+ about:{
+ sacnQR: "扫描二维码,您的朋友也可以下载",
+ client: "客户端",
+ and: "和",
+ about: "关于",
+ },
+ invite:{
+ download: "下载",
+ },
+ login:{
+ phoneLogin: "登录后即可展示自己",
+ phoneLoginTip: "未注册的手机号验证通过后将自动注册",
+ getVerifyCode: "获取验证码",
+ },
+ uniQuickLogin:{
+ accountLogin: "账号登录",
+ SMSLogin: "短信验证码",
+ wechatLogin: "微信登录",
+ appleLogin: "苹果登录",
+ oneClickLogin: "一键登录",
+ QQLogin: "QQ登录",
+ xiaomiLogin: "小米登录",
+ getProviderFail: "获取服务供应商失败",
+ loginErr: "登录服务初始化错误",
+ chooseOtherLogin: "点击了第三方登录",
+ },
+ pwdLogin:{
+ pwdLogin: "用户名密码登录",
+ placeholder: "请输入手机号/用户名",
+ passwordPlaceholder: "请输入密码",
+ verifyCodePlaceholder: "请输入验证码",
+ login: "登录",
+ forgetPassword: "忘记密码",
+ register: "注册账号",
+ },
+ register:{
+ navigationBarTitle:"注册",
+ usernamePlaceholder: "请输入用户名",
+ nicknamePlaceholder: "请输入用户昵称",
+ registerAndLogin: "注册并登录",
+ passwordDigitsPlaceholder: "请输入6-20位密码",
+ passwordAgain: "再次输入密码",
+ },
+ listDetail:{
+ follow: "点击关注",
+ newsErr: "出错了,新闻ID为空",
+ },
+ newsLog:{
+ navigationBarTitle:"阅读记录"
+ },
+ bindMobile:{
+ navigationBarTitle:"绑定手机号码"
+ }
+}
diff --git a/main.js b/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0b835c22b61a21a8932abb6c6de7ebef6dbbd13
--- /dev/null
+++ b/main.js
@@ -0,0 +1,29 @@
+import App from './App'
+import store from './store'
+import i18n from './lang/i18n'
+
+
+// #ifndef VUE3
+import Vue from 'vue'
+Vue.config.productionTip = false
+Vue.prototype.$store = store
+App.mpType = 'app'
+const app = new Vue({
+ i18n,
+ store,
+ ...App
+})
+app.$mount()
+// #endif
+
+
+// #ifdef VUE3
+import {createSSRApp} from 'vue'
+
+export function createApp() {
+ const app = createSSRApp(App)
+ app.use(i18n)
+ app.use(store)
+ return {app}
+}
+// #endif
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..0c95e9f1158aac5301218c696f50c11c865476d3
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,229 @@
+{
+ "name": "统一应用基本项目",
+ "appid": "请点击重新获取",
+ "description": "云端一体应用快速开发模版",
+ "versionName": "1.0.0",
+ "versionCode": "100",
+ "transformPx": false,
+ "app-plus": {
+ "locales": {
+ "en": {
+ // 英文
+ "name": "uni-starter", // 应用名称
+ "android": {
+ "strings": {
+ //Android平台自定义字符串
+ "CustomKey": "CustomValue"
+ }
+ },
+ "ios": {
+ "privacyDescription": {
+ //iOS平台隐私访问描述信息
+ "NSPhotoLibraryUsageDescription": "access to the user’s photo library(read)"
+ },
+ "infoPlist": {
+ //iOS平台自定义InfoPlist.strings
+ "CustomKey": "CustomValue"
+ }
+ }
+ },
+ "zh": {
+ // 中文(简体)
+ "name": "统一应用基本项目" // 应用名称
+ }
+ },
+ "privacy": {
+ "prompt": "template",
+ "template": {
+ "title": "服务协议和隐私政策",
+ "message": " 请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。 你可阅读《服务协议》 和《隐私政策》 了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
+ "buttonAccept": "同意",
+ "buttonRefuse": "暂不同意"
+ }
+ },
+ "compatible": {
+ "ignoreVersion": true
+ },
+ "usingComponents": true,
+ "nvueStyleCompiler": "uni-app",
+ "compilerVersion": 3,
+ "splashscreen": {
+ "alwaysShowBeforeRender": false,
+ "waiting": true,
+ "autoclose": true,
+ "delay": 0
+ },
+ "modules": {
+ "Fingerprint": {
+ },
+ "Share": {
+ },
+ "OAuth": {
+ },
+ "FaceID": {
+ },
+ "Geolocation": {
+ },
+ "Push": {
+ },
+ "Bluetooth": {
+ }
+ },
+ "distribute": {
+ "android": {
+ "permissions": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "abiFilters": [
+ "armeabi-v7a",
+ "arm64-v8a",
+ "x86"
+ ]
+ },
+ "ios": {
+ "capabilities": {
+ "entitlements": {
+ "com.apple.developer.associated-domains": [
+ "applinks:static-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e.bspapp.com"
+ ]
+ }
+ }
+ },
+ "sdkConfigs": {
+ "oauth": {
+ "apple": {
+ },
+ "weixin": {
+ "appid": "",
+ "appsecret": "",
+ "UniversalLinks": ""
+ },
+ "univerify": {
+ }
+ },
+ "ad": {
+ },
+ "share": {
+ "weixin": {
+ "appid": "",
+ "UniversalLinks": ""
+ }
+ },
+ "geolocation": {
+ "baidu": {
+ "__platform__": [
+ "ios",
+ "android"
+ ],
+ "appkey_ios": "请填写地图的key",
+ "appkey_android": "请填写地图的key"
+ }
+ },
+ "push": {
+ "unipush": {
+ }
+ },
+ "payment": {
+ }
+ },
+ "icons": {
+ "android": {
+ "hdpi": "",
+ "xhdpi": "",
+ "xxhdpi": "",
+ "xxxhdpi": ""
+ },
+ "ios": {
+ "appstore": "",
+ "ipad": {
+ "app": "",
+ "app@2x": "",
+ "notification": "",
+ "notification@2x": "",
+ "proapp@2x": "",
+ "settings": "",
+ "settings@2x": "",
+ "spotlight": "",
+ "spotlight@2x": ""
+ },
+ "iphone": {
+ "app@2x": "",
+ "app@3x": "",
+ "notification@2x": "",
+ "notification@3x": "",
+ "settings@2x": "",
+ "settings@3x": "",
+ "spotlight@2x": "",
+ "spotlight@3x": ""
+ }
+ }
+ },
+ "splashscreen": {
+ "iosStyle": "common",
+ "androidStyle": "common"
+ }
+ },
+ "nvueLaunchMode": ""
+ },
+ "quickapp": {
+ },
+ "mp-weixin": {
+ "appid": "",
+ "setting": {
+ "urlCheck": false,
+ "es6": false
+ },
+ "usingComponents": true,
+ "betterScopedSlots": true,
+ "permission": {
+ "scope.userLocation": {
+ "desc": "演示在onShow生命周期获取地理位置"
+ }
+ }
+ },
+ "mp-alipay": {
+ "usingComponents": true
+ },
+ "mp-baidu": {
+ "usingComponents": true
+ },
+ "mp-toutiao": {
+ "usingComponents": true
+ },
+ "uniStatistics": {
+ "enable": false
+ },
+ "h5": {
+ "template": "",
+ "sdkConfigs": {
+ "maps": {
+ "qqmap": {
+ "key": ""
+ }
+ }
+ },
+ "router": {
+ "base": ""
+ }
+ },
+ "_spaceID": "",
+ "vueVersion": "2"
+}
+//...
+// 中文(简体)
+// 应用名称
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c0099edbd8f7aa3b393a3ff13ba7b5b81b0cb6d6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,85 @@
+{
+ "id": "uni-starter",
+ "displayName": "uni-starter",
+ "version": "1.1.22",
+ "description": "云端一体应用快速开发基本项目模版",
+ "keywords": [
+ "login",
+ "登录",
+ "搜索",
+ "uni-id例子",
+ "留言板"
+ ],
+ "repository": "https://codechina.csdn.net/dcloud/uni-starter.git",
+ "engines": {
+ "HBuilderX": "^3.2.6"
+ },
+ "dcloudext": {
+ "category": [
+ "uniCloud",
+ "云端一体项目模板"
+ ],
+ "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"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "u",
+ "Android Browser": "u",
+ "微信浏览器(Android)": "u",
+ "QQ浏览器(Android)": "u"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "n",
+ "Edge": "u",
+ "Firefox": "u",
+ "Safari": "u"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ },
+ "dependencies": {}
+}
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..ebd08303990dbcfdb950556618a0575f169a43b6
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,240 @@
+{
+ "pages": [{
+ "path": "pages/list/list",
+ "style": {
+ // #ifndef APP-PLUS
+ "enablePullDownRefresh": true,
+ // #endif
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/grid/grid",
+ "style": {
+ //#ifndef MP
+ "navigationStyle": "custom"
+ //#endif
+ }
+ }, {
+ "path": "pages/ucenter/login-page/index/index",
+ "style": {
+ "navigationBarTitleText": "",
+ "app-plus": {
+ "animationType": "none",
+ "popGesture": "none"
+ }
+ }
+ }, {
+ "path": "pages/list/search/search",
+ "style": {
+ "navigationBarTitleText":"搜索"
+ }
+ }, {
+ "path": "pages/list/detail",
+ "style": {
+ "app-plus": {
+ "titleNView": {
+ "buttons": [{
+ "type": "share"
+ }],
+ "type": "transparent"
+ }
+ },
+ "h5": {
+ "titleNView": {
+ "type": "transparent"
+ }
+ },
+ "navigationBarTitleText": "文章详情"
+ }
+ }, {
+ "path": "pages/ucenter/userinfo/bind-mobile/bind-mobile",
+ "style": {
+ "navigationBarTitleText": "绑定手机号码"
+ }
+ },
+ {
+ "path": "pages/ucenter/ucenter",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/ucenter/about/about",
+ "style": {
+ "navigationBarTitleText": "关于"
+ // #ifdef APP-PLUS
+ ,
+ "app-plus": {
+ "titleNView": {
+ "buttons": [{
+ "type": "share"
+ }]
+ }
+ }
+ // #endif
+ }
+
+ },
+ {
+ "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
+
+ }
+ }
+ }, {
+ "path": "pages/uni-agree/uni-agree",
+ "style": {
+ "navigationStyle": "custom",
+ "app-plus": {
+ "popGesture": "none"
+ }
+ }
+ }, {
+ "path": "pages/ucenter/settings/settings",
+ "style": {
+ "navigationBarTitleText": "设置"
+ }
+
+ }, {
+ "path": "pages/ucenter/userinfo/userinfo",
+ "style": {
+ "navigationBarTitleText": "个人资料"
+ }
+ }, {
+ "path": "pages/ucenter/userinfo/cropImage",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ }, {
+ "path": "pages/ucenter/login-page/pwd-login/pwd-login",
+ "style": {
+ "navigationBarTitleText": ""
+ }
+ }, {
+ "path": "pages/ucenter/login-page/pwd-retrieve/pwd-retrieve",
+ "style": {
+ "navigationBarTitleText": "重置密码"
+ }
+ }, {
+ "path": "pages/ucenter/login-page/phone-code/phone-code",
+ "style": {
+ "navigationBarTitleText": ""
+ }
+
+ }, {
+ "path": "pages/common/webview/webview",
+ "style": {
+ "navigationBarTitleText": "",
+ "enablePullDownRefresh": false
+ }
+
+ }, {
+ "path": "pages/ucenter/login-page/register/register",
+ "style": {
+ "navigationBarTitleText": "注册",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "pages/ucenter/read-news-log/read-news-log",
+ "style": {
+ "navigationBarTitleText": "阅读记录",
+ "enablePullDownRefresh": true
+ }
+ }, {
+ "path": "pages/ucenter/invite/invite",
+ "style": {
+ "navigationStyle": "custom",
+ "enablePullDownRefresh": false
+ }
+
+ }, {
+ "path": "pages/ucenter/settings/deactivate/deactivate",
+ "style": {
+ "navigationBarTitleText": "注销提醒",
+ "enablePullDownRefresh": false
+ }
+ }, {
+ "path": "uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback",
+ "style": {
+ "navigationBarTitleText": "意见反馈",
+ "enablePullDownRefresh": false
+ }
+ }, {
+ "path": "pages/ucenter/guestbook/guestbook",
+ "style": {
+ "navigationBarTitleText": "留言板",
+ "enablePullDownRefresh": false,
+ "app-plus": {
+ "titleNView": {
+ "buttons": [{
+ "text": "切换",
+ "fontSize": "12px"
+ },
+ {
+ "text": "注销",
+ "fontSize": "12px"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ],
+ "globalStyle": {
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "uni-starter",
+ "navigationBarBackgroundColor": "#FFFFFF",
+ "backgroundColor": "#F8F8F8",
+ "enablePullDownRefresh": false
+ },
+ "condition": {
+ "list": [{
+ "path": "pages/list/detail"
+ }, {
+ "path": "pages/list/list"
+ },
+ {
+ "path": "pages/ucenter/login-page/index/index"
+ }, {
+ "path": "pages/ucenter/userinfo/userinfo"
+ },
+ {
+ "path": "pages/ucenter/settings/settings"
+ }
+ ],
+ "current": 1
+ },
+ "tabBar": {
+ "color": "#7A7E83",
+ "selectedColor": "#007AFF",
+ "borderStyle": "black",
+ "backgroundColor": "#FFFFFF",
+ "list": [{
+ "pagePath": "pages/list/list",
+ "iconPath": "static/tabbar/list.png",
+ "selectedIconPath": "static/tabbar/list_active.png",
+ "text": "列表"
+ }, {
+ "pagePath": "pages/grid/grid",
+ "iconPath": "static/tabbar/grid.png",
+ "selectedIconPath": "static/tabbar/grid_active.png",
+ "text": "宫格"
+ }
+ , {
+ "pagePath": "pages/ucenter/ucenter",
+ "iconPath": "static/tabbar/me.png",
+ "selectedIconPath": "static/tabbar/me_active.png",
+ "text": "我的"
+ }]
+ }
+}
diff --git a/pages/common/webview/webview.vue b/pages/common/webview/webview.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5fa64b98d363de76140e0d24fe11ac6e43ce61da
--- /dev/null
+++ b/pages/common/webview/webview.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/grid/grid.vue b/pages/grid/grid.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0358fbc097ff85e1cd16520d12d4d36fcf46a0f0
--- /dev/null
+++ b/pages/grid/grid.vue
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/list/detail.vue b/pages/list/detail.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ee1ca77d803f5aad8c7195ad1589d7bb66213eed
--- /dev/null
+++ b/pages/list/detail.vue
@@ -0,0 +1,368 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{data.excerpt}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/list/list.nvue b/pages/list/list.nvue
new file mode 100644
index 0000000000000000000000000000000000000000..dec5cb44ae2105be3c79802a8685e0bd43c2764f
--- /dev/null
+++ b/pages/list/list.nvue
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.title}}
+
+ {{item.user_id[0].username}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/list/search/search.nvue b/pages/list/search/search.nvue
new file mode 100644
index 0000000000000000000000000000000000000000..12ab77042bec049036e79227fbab7a68bf283d51
--- /dev/null
+++ b/pages/list/search/search.nvue
@@ -0,0 +1,506 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{word}}
+
+
+
+
+
+
+
+
+
+ 正在加载...
+
+
+ {{error.message}}
+
+ {{word.content}}
+
+
+
+ 当前搜索发现已隐藏
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/about/about.vue b/pages/ucenter/about/about.vue
new file mode 100644
index 0000000000000000000000000000000000000000..beab4a57e7ec695940bd94e86ffbda80569356f0
--- /dev/null
+++ b/pages/ucenter/about/about.vue
@@ -0,0 +1,203 @@
+
+
+
+
+ {{about.appName}}
+ Version {{version}}
+
+
+ {{$t('about.sacnQR')}} {{about.appName}} {{$t('about.client')}}
+
+
+
+ 《{{agreement.title}}》
+ {{$t('about.and')}}
+
+ Copyright © {{year}}
+ {{about.company}}
+
+
+
+
+
diff --git a/pages/ucenter/guestbook/guestbook.vue b/pages/ucenter/guestbook/guestbook.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0edc841db09a8c151d1d9fdfa03cea80703d5c92
--- /dev/null
+++ b/pages/ucenter/guestbook/guestbook.vue
@@ -0,0 +1,223 @@
+
+
+
+ {{error.message}}
+
+
+
+
+
+ {{item.user_id[0].nickname}}
+ {{item.text}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{$t('guestbook.send')}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/ucenter/invite/invite.vue b/pages/ucenter/invite/invite.vue
new file mode 100644
index 0000000000000000000000000000000000000000..5bb4df85a7e9dc21a70e183a392fe5fd3d3daeda
--- /dev/null
+++ b/pages/ucenter/invite/invite.vue
@@ -0,0 +1,179 @@
+
+
+
+
+ {{about.appName}}
+ {{about.slogan}}
+
+
+
+ {{$t('invite.download')}}
+
+ version {{about.version}}
+
+
+ {{about.company}}
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/login-page/common/login-page.css b/pages/ucenter/login-page/common/login-page.css
new file mode 100644
index 0000000000000000000000000000000000000000..34ff42ce28f58158db20c7e9736b27922b84a93d
--- /dev/null
+++ b/pages/ucenter/login-page/common/login-page.css
@@ -0,0 +1,61 @@
+/* #ifndef APP-NVUE */
+view {
+ display: flex;
+ box-sizing: border-box;
+ flex-direction: column;
+}
+
+/* #endif */
+
+.content {
+ padding: 0 50rpx;
+ width: 750rpx;
+ flex: 1;
+}
+
+.input-box {
+ padding: 0 15px;
+ margin-bottom: 10px;
+ background-color: #F8F8F8;
+ border-radius: 6px;
+ font-size: 28rpx;
+}
+
+.get-code {
+ margin: 0;
+ margin-top: 15px;
+ background-color: #007aff;
+ color: #FFFFFF;
+}
+
+.input-box,
+.get-code {
+ height: 45px;
+ line-height: 45px;
+}
+
+.title {
+ text-align: center;
+ padding-bottom: 5px;
+}
+
+.tip {
+ color: #666666;
+ font-size: 26rpx;
+ margin: 6px 0;
+}
+
+.easyinput {
+ background-color: #F8F8F8;
+ border-radius: 6rpx;
+}
+
+.send-btn {
+ width: 100%;
+ margin-top: 15px;
+ border-radius: 6rpx;
+}
+
+.link {
+ color: #04498c;
+}
diff --git a/pages/ucenter/login-page/common/login-page.mixin.js b/pages/ucenter/login-page/common/login-page.mixin.js
new file mode 100644
index 0000000000000000000000000000000000000000..6b161253c7fa2ff16062ab1b3577d512b3b00d3c
--- /dev/null
+++ b/pages/ucenter/login-page/common/login-page.mixin.js
@@ -0,0 +1,15 @@
+import {mapMutations} from 'vuex';
+import loginSuccess from './loginSuccess.js';
+let mixin = {
+ methods:{
+ ...mapMutations({
+ setUserInfo: 'user/login'
+ }),
+ loginSuccess(result){
+ loginSuccess(result)
+ delete result.userInfo.token
+ this.setUserInfo(result.userInfo)
+ }
+ }
+}
+export default mixin
\ No newline at end of file
diff --git a/pages/ucenter/login-page/common/loginSuccess.js b/pages/ucenter/login-page/common/loginSuccess.js
new file mode 100644
index 0000000000000000000000000000000000000000..db1540f381ae82913c3a555bd411fb49a1568049
--- /dev/null
+++ b/pages/ucenter/login-page/common/loginSuccess.js
@@ -0,0 +1,20 @@
+export default function(result){
+ uni.showToast({
+ title: '登录成功',
+ icon: 'none'
+ });
+ console.log('登录成功',result);
+
+ var delta = 0//判断需要返回几层
+ let pages = getCurrentPages();
+ // console.log(pages);
+ pages.forEach((page,index)=>{
+ // console.log(pages[pages.length-index-1].route.split('/')[2]);
+ pages[pages.length-index-1].route.split('/')
+ if(pages[pages.length-index-1].route.split('/')[2] == 'login-page'){
+ delta ++
+ }
+ })
+ // console.log('判断需要返回几层',delta);
+ uni.navigateBack({delta})
+}
diff --git a/pages/ucenter/login-page/index/index.vue b/pages/ucenter/login-page/index/index.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f30fdfaac1cee50fb74521fb11641da2ac467516
--- /dev/null
+++ b/pages/ucenter/login-page/index/index.vue
@@ -0,0 +1,133 @@
+
+
+
+ {{$t('login.phoneLogin')}}
+
+
+
+
+
+
+
+
+ {{$t('login.getVerifyCode')}}
+ {{$t('login.phoneLoginTip')}}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/login-page/phone-code/phone-code.vue b/pages/ucenter/login-page/phone-code/phone-code.vue
new file mode 100644
index 0000000000000000000000000000000000000000..8eb43be8513d78cdcfb6b240e03c155c215a5510
--- /dev/null
+++ b/pages/ucenter/login-page/phone-code/phone-code.vue
@@ -0,0 +1,72 @@
+
+
+
+ {{$t('common.verifyCodePlaceholder')}}
+ {{tipText}}
+
+
+
+
+
+
+
+ {{$t('common.login')}}
+
+
+
+
+
+
diff --git a/pages/ucenter/login-page/pwd-login/pwd-login.vue b/pages/ucenter/login-page/pwd-login/pwd-login.vue
new file mode 100644
index 0000000000000000000000000000000000000000..4610d99968ea86b041028a109253af3969cdaf0f
--- /dev/null
+++ b/pages/ucenter/login-page/pwd-login/pwd-login.vue
@@ -0,0 +1,164 @@
+
+
+
+ {{$t('pwdLogin.pwdLogin')}}
+
+
+
+
+
+
+
+ {{$t('pwdLogin.login')}}
+
+
+ {{$t('pwdLogin.forgetPassword')}}
+ {{$t('pwdLogin.register')}}
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/login-page/pwd-retrieve/pwd-retrieve.vue b/pages/ucenter/login-page/pwd-retrieve/pwd-retrieve.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c28ae7db685698851bab69b64cea56bf9338871c
--- /dev/null
+++ b/pages/ucenter/login-page/pwd-retrieve/pwd-retrieve.vue
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{$t('common.complete')}}
+
+
+
+
+
+
+
diff --git a/pages/ucenter/login-page/register/register.vue b/pages/ucenter/login-page/register/register.vue
new file mode 100644
index 0000000000000000000000000000000000000000..81f71d430a07ec986d38f57ee1c6cb24029d97cd
--- /dev/null
+++ b/pages/ucenter/login-page/register/register.vue
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{$t('register.registerAndLogin')}}
+
+
+
+
+
+
+
diff --git a/pages/ucenter/login-page/register/validator.js b/pages/ucenter/login-page/register/validator.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5b4c27c569cd62b36610ddafe97f7f8bfc84b88
--- /dev/null
+++ b/pages/ucenter/login-page/register/validator.js
@@ -0,0 +1,61 @@
+export default {
+ "username": {
+ "rules": [{
+ required: true,
+ errorMessage: '请输入用户名',
+ },
+ {
+ minLength: 3,
+ maxLength: 32,
+ errorMessage: '用户名长度在 {minLength} 到 {maxLength} 个字符',
+ },
+ {
+ validateFunction:function(rule,value,data,callback){
+ console.log(value);
+ if(/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)){
+ callback('用户名不能是:手机号或邮箱')
+ };
+ return true
+ }
+ }
+ ],
+ "label": "用户名"
+ },
+ "password":{
+ "rules": [{
+ required: true,
+ errorMessage: '请输入密码',
+ },
+ {
+ minLength: 6,
+ maxLength: 20,
+ errorMessage: '密码长度在 {minLength} 到 {maxLength} 个字符',
+ }
+ ],
+ "label": "密码"
+ },
+ "pwd2":{
+ "rules": [{
+
+ required: true,
+ errorMessage: '再次输入密码',
+
+ },
+ {
+ minLength: 6,
+ maxLength: 20,
+ errorMessage: '密码长度在 {minLength} 到 {maxLength} 个字符',
+ },
+ {
+ validateFunction:function(rule,value,data,callback){
+ console.log(value);
+ if(value!=data.password){
+ callback('两次输入密码不一致')
+ };
+ return true
+ }
+ }
+ ],
+ "label": "确认密码"
+ }
+}
\ No newline at end of file
diff --git a/pages/ucenter/read-news-log/read-news-log.vue b/pages/ucenter/read-news-log/read-news-log.vue
new file mode 100644
index 0000000000000000000000000000000000000000..137f58a4649edf60459443f025192c836dabcbaa
--- /dev/null
+++ b/pages/ucenter/read-news-log/read-news-log.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+ {{item.title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/settings/dc-push/push.js b/pages/ucenter/settings/dc-push/push.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ad20d42425d57f4830433799ad4132314df72f2
--- /dev/null
+++ b/pages/ucenter/settings/dc-push/push.js
@@ -0,0 +1,118 @@
+/**
+ * 判断Push是否开启
+ */
+function isTurnedOnPush(){
+ var isOn = undefined;
+ try{
+ if('iOS' == plus.os.name){
+ var types = 0;
+ var app = plus.ios.invoke('UIApplication', 'sharedApplication');
+ var settings = plus.ios.invoke(app, 'currentUserNotificationSettings');
+ if(settings){
+ types = settings.plusGetAttribute('types');
+ plus.ios.deleteObject(settings);
+ }else{
+ types = plus.ios.invoke(app, 'enabledRemoteNotificationTypes');
+ }
+ plus.ios.deleteObject(app);
+ isOn = (0!=types);
+ }else{
+ var main = plus.android.runtimeMainActivity();
+ var manager = plus.android.invoke('com.igexin.sdk.PushManager', 'getInstance');
+ isOn = plus.android.invoke(manager, 'isPushTurnedOn', main);
+ }
+ }catch(e){
+ console.error('exception in isTurnedOnPush@dc-push!!');
+ }
+ return isOn;
+}
+
+/**
+ * 打开Push
+ * Android平台 - 打开个推(UniPush)的推送通道
+ * iOS平台 - 如果开启通知功能,则打开应用的设置页面引导用户开启通知
+ */
+function turnOnPush(){
+ try{
+ if('iOS' == plus.os.name){
+ // 如果设置中没有开启通知,则打开应用的设置界面
+ if(!isTurnedOnPush()){
+ settingInIos();
+ }
+ }else{
+ var main = plus.android.runtimeMainActivity();
+ var manager = plus.android.invoke('com.igexin.sdk.PushManager', 'getInstance');
+ plus.android.invoke(manager, 'turnOnPush', main);
+ }
+ }catch(e){
+ console.error('exception in turnOnPush@dc-push!!');
+ }
+}
+
+/**
+ * 关闭Push
+ * Android平台 - 关闭个推(UniPush)的推送通道
+ * iOS平台 - 不做任何操作
+ */
+function trunOffPush(){
+ try{
+ if('iOS' == plus.os.name){
+ // 这里不做任何操作(不引导用户关闭应用的推送能力),应该通知业务服务器不向此用户下发推送消息
+ }else{
+ var main = plus.android.runtimeMainActivity();
+ var manager = plus.android.invoke('com.igexin.sdk.PushManager', 'getInstance');
+ plus.android.invoke(manager, 'turnOffPush', main);
+ }
+ }catch(e){
+ console.error('exception in trunOffPush@dc-push!!');
+ }
+}
+
+/**
+ * iOS平台打开应用设置界面
+ */
+function settingInIos(){
+ try{
+ if('iOS' == plus.os.name){
+ var app = plus.ios.invoke('UIApplication', 'sharedApplication');
+ var setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:');
+ plus.ios.invoke(app, 'openURL:', setting);
+ plus.ios.deleteObject(setting);
+ plus.ios.deleteObject(app);
+ }
+ }catch(e){
+ console.error('exception in settingInIos@dc-push!!');
+ }
+}
+/**
+ * android打开应用设置页面
+ */
+function settingInAndroid(){
+ if (uni.getSystemInfoSync().platform == "android") {
+ var main = plus.android.runtimeMainActivity();
+ var Intent = plus.android.importClass('android.content.Intent');
+ var Settings = plus.android.importClass('android.provider.Settings');
+ var intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ // 安卓跳转设置页面详细查看(https://ask.dcloud.net.cn/question/14732)
+ main.startActivity(intent);
+ }
+}
+/**
+ * 打开应用设置界面
+ */
+function setting(){
+ if (uni.getSystemInfoSync().platform == "ios") {
+ settingInIos();
+ }
+ if (uni.getSystemInfoSync().platform == "android") {
+ settingInAndroid();
+ }
+}
+
+export default {
+ isOn: isTurnedOnPush,
+ iosSetting: settingInIos,
+ on: turnOnPush,
+ off: trunOffPush,
+ setting:setting
+}
diff --git a/pages/ucenter/settings/deactivate/deactivate.vue b/pages/ucenter/settings/deactivate/deactivate.vue
new file mode 100644
index 0000000000000000000000000000000000000000..58fa9c7b0b0d17e9fec2228a74cb71553b97ee31
--- /dev/null
+++ b/pages/ucenter/settings/deactivate/deactivate.vue
@@ -0,0 +1,103 @@
+
+
+
+ 一、注销是不可逆操作,注销后:\n
+ 1.帐号将无法登录、无法找回。\n
+ 2.帐号所有信息都会清除(个人身份信息、粉丝数等;发布的作品、评论、点赞等;交易信息等),你
+ 的朋友将无法通过本应用帐号联系你,请自行备份相关
+ 信息和数据。\n
+
+ 二、重要提示\n
+ 1.封禁帐号(永久封禁、社交封禁、直播权限封禁)不能申请注销。\n
+ 2.注销后,你的身份证、三方帐号(微信、QQ、微博、支付宝)、手机号等绑定关系将解除,解除后可以绑定到其他帐号。\n
+ 3.注销后,手机号可以注册新的帐号,新帐号不会存在之前帐号的任何信息(作品、粉丝、评论、个人信息等)。\n
+ 4.注销本应用帐号前,需尽快处理帐号下的资金问题。\n
+ 5.视具体帐号情况而定,注销最多需要7天。\n
+
+
+ {{$t('deactivate.nextStep')}}
+ {{$t('deactivate.cancelText')}}
+
+
+
+
+
+
+
diff --git a/pages/ucenter/settings/settings.vue b/pages/ucenter/settings/settings.vue
new file mode 100644
index 0000000000000000000000000000000000000000..68ad813ceb7de6c5e88709acd8ceb4b6b73cb93a
--- /dev/null
+++ b/pages/ucenter/settings/settings.vue
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{$t('settings.logOut')}}
+ {{$t('settings.login')}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/ucenter/ucenter.vue b/pages/ucenter/ucenter.vue
new file mode 100644
index 0000000000000000000000000000000000000000..12e1610d27b00947a5cef1b945e2b347e8c58c9e
--- /dev/null
+++ b/pages/ucenter/ucenter.vue
@@ -0,0 +1,449 @@
+
+
+
+
+
+
+
+ {{userInfo.nickname||userInfo.username||userInfo.mobile}}
+ {{$t('mine.notLogged')}}
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/ucenter/userinfo/bind-mobile/bind-mobile.vue b/pages/ucenter/userinfo/bind-mobile/bind-mobile.vue
new file mode 100644
index 0000000000000000000000000000000000000000..29cb05d85f094acd893fe7e7ede6875ecdf7e8dd
--- /dev/null
+++ b/pages/ucenter/userinfo/bind-mobile/bind-mobile.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+ {{$t('common.submit')}}
+
+
+
+
+
diff --git a/pages/ucenter/userinfo/cropImage.vue b/pages/ucenter/userinfo/cropImage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..dbec54d65615aba78c4eb62417606835da945ea6
--- /dev/null
+++ b/pages/ucenter/userinfo/cropImage.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/ucenter/userinfo/limeClipper/README.md b/pages/ucenter/userinfo/limeClipper/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9219f815af48cf5b2c5b999f22af1e608e9970d8
--- /dev/null
+++ b/pages/ucenter/userinfo/limeClipper/README.md
@@ -0,0 +1,227 @@
+> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594)
+##### 以下是作者写的插件介绍:
+
+# Clipper 图片裁剪
+> uniapp 图片裁剪,可用于图片头像等裁剪处理
+> [查看更多](http://liangei.gitee.io/limeui/#/clipper)
+> Q群:458377637
+
+
+## 平台兼容
+
+| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
+| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
+| √ | √ | √ | 未测 | √ | √ | √ |
+
+
+## 代码演示
+### 基本用法
+`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height`
+
+```html
+
+
+裁剪
+```
+
+```js
+// 非uni_modules引入
+import lClipper from '@/components/lime-clipper/'
+// uni_modules引入
+import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/'
+export default {
+ components: {lClipper},
+ data() {
+ return {
+ show: false,
+ url: '',
+ }
+ }
+}
+```
+
+
+### 传入图片
+`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**
+
+* **当为网络地址时**
+* H5:👉 需要解决跨域问题。
+* 小程序:👉 需要配置 downloadFile 域名
+
+
+```html
+
+
+裁剪
+```
+
+```js
+export default {
+ components: {lClipper},
+ data() {
+ return {
+ imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg',
+ show: false,
+ url: '',
+ }
+ }
+}
+```
+
+
+### 确定按钮颜色
+样式变量名:`--l-clipper-confirm-color`
+可放到全局样式的 `page` 里或节点的 `style`
+```html
+
+```
+```css
+// css 中为组件设置 CSS 变量
+.clipper {
+ --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
+}
+// 全局
+page {
+ --l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
+}
+```
+
+
+### 使用插槽
+共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。
+
+```html
+
+
+
+ 取消
+ 选择图片
+ 旋转
+ 确定
+
+
+ 显示取消按钮
+
+
+ 显示选择图片按钮
+
+
+ 显示旋转按钮
+
+
+ 显示确定按钮
+
+
+ 锁定裁剪框宽度
+
+
+ 锁定裁剪框高度
+
+
+ 锁定裁剪框比例
+
+
+ 限制移动范围
+
+
+ 禁止缩放
+
+
+ 禁止旋转
+
+
+
+
+裁剪
+```
+
+```js
+export default {
+ components: {lClipper},
+ data() {
+ return {
+ show: false,
+ url: '',
+ isLockWidth: false,
+ isLockHeight: false,
+ isLockRatio: true,
+ isLimitMove: false,
+ isDisableScale: false,
+ isDisableRotate: false,
+ isShowCancelBtn: true,
+ isShowPhotoBtn: true,
+ isShowRotateBtn: true,
+ isShowConfirmBtn: true
+ }
+ }
+}
+```
+
+
+## API
+
+### Props
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ------------- | ------------ | ---------------- | ------------ |
+| image-url | 图片路径 | string | |
+| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | number | `1` |
+| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | Object | |
+| width | 裁剪框宽度,单位为 `rpx` | number | `400` |
+| height | 裁剪框高度 | number | `400` |
+| min-width | 裁剪框最小宽度 | number | `200` |
+| min-height |裁剪框最小高度 | number | `200` |
+| max-width | 裁剪框最大宽度 | number | `600` |
+| max-height | 裁剪框最大宽度 | number | `600` |
+| min-ratio | 图片最小缩放比 | number | `0.5` |
+| max-ratio | 图片最大缩放比 | number | `2` |
+| rotate-angle | 旋转按钮每次旋转的角度 | number | `90` |
+| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | number | `1` |
+| is-lock-width | 是否锁定裁剪框宽度 | boolean | `false` |
+| is-lock-height | 是否锁定裁剪框高度上 | boolean | `false` |
+| is-lock-ratio | 是否锁定裁剪框比例 | boolean | `true` |
+| is-disable-scale | 是否禁止缩放 | boolean | `false` |
+| is-disable-rotate | 是否禁止旋转 | boolean | `false` |
+| is-limit-move | 是否限制移动范围 | boolean | `false` |
+| is-show-photo-btn | 是否显示选择图片按钮 | boolean | `true` |
+| is-show-rotate-btn | 是否显示转按钮 | boolean | `true` |
+| is-show-confirm-btn | 是否显示确定按钮 | boolean | `true` |
+| is-show-cancel-btn | 是否显示关闭按钮 | boolean | `true` |
+
+
+
+### 事件 Events
+
+| 事件名 | 说明 | 回调 |
+| ------- | ------------ | -------------- |
+| success | 生成图片成功 | {`width`, `height`, `url`} |
+| fail | 生成图片失败 | `error` |
+| cancel | 关闭 | `false` |
+| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} |
+| change | 图片大小改变时触发 | {`width`, `height`} |
+| rotate | 图片旋转时触发 | `angle` |
+
+## 常见问题
+> 1、H5端使用网络图片需要解决跨域问题。
+> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!
+> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签` `
+> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。
+> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。
+
+
+## 打赏
+如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
+![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")
\ No newline at end of file
diff --git a/pages/ucenter/userinfo/limeClipper/images/photo.svg b/pages/ucenter/userinfo/limeClipper/images/photo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7b4b59058376794d6e6a78035f627678102f96ad
--- /dev/null
+++ b/pages/ucenter/userinfo/limeClipper/images/photo.svg
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/userinfo/limeClipper/images/rotate.svg b/pages/ucenter/userinfo/limeClipper/images/rotate.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0143706ca7adea484ed38339980c2cc23559595e
--- /dev/null
+++ b/pages/ucenter/userinfo/limeClipper/images/rotate.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/ucenter/userinfo/limeClipper/index.css b/pages/ucenter/userinfo/limeClipper/index.css
new file mode 100644
index 0000000000000000000000000000000000000000..ce542bf1193799b39f006d08e71b4fb3cbecf1cc
--- /dev/null
+++ b/pages/ucenter/userinfo/limeClipper/index.css
@@ -0,0 +1,160 @@
+.flex-auto {
+ flex: auto;
+}
+.bg-transparent {
+ background-color: rgba(0,0,0,0.9);
+ transition-duration: 0.35s;
+}
+.l-clipper {
+ width: 100vw;
+ height: calc(100vh - var(--window-top));
+ background-color: rgba(0,0,0,0.9);
+ position: fixed;
+ top: var(--window-top);
+ left: 0;
+ z-index: 1;
+}
+.l-clipper-mask {
+ position: relative;
+ z-index: 2;
+ pointer-events: none;
+}
+.l-clipper__content {
+ pointer-events: none;
+ position: absolute;
+ border: 1rpx solid rgba(255,255,255,0.3);
+ box-sizing: border-box;
+ box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh;
+ background: transparent;
+}
+.l-clipper__content::before,
+.l-clipper__content::after {
+ content: '';
+ position: absolute;
+ border: 1rpx dashed rgba(255,255,255,0.3);
+}
+.l-clipper__content::before {
+ width: 100%;
+ top: 33.33%;
+ height: 33.33%;
+ border-left: none;
+ border-right: none;
+}
+.l-clipper__content::after {
+ width: 33.33%;
+ left: 33.33%;
+ height: 100%;
+ border-top: none;
+ border-bottom: none;
+}
+.l-clipper__edge {
+ position: absolute;
+ width: 34rpx;
+ height: 34rpx;
+ border: 6rpx solid #fff;
+ pointer-events: auto;
+}
+.l-clipper__edge::before {
+ content: '';
+ position: absolute;
+ width: 40rpx;
+ height: 40rpx;
+ background-color: transparent;
+}
+.l-clipper__edge:nth-child(1) {
+ left: -6rpx;
+ top: -6rpx;
+ border-bottom-width: 0 !important;
+ border-right-width: 0 !important;
+}
+.l-clipper__edge:nth-child(1):before {
+ top: -50%;
+ left: -50%;
+}
+.l-clipper__edge:nth-child(2) {
+ right: -6rpx;
+ top: -6rpx;
+ border-bottom-width: 0 !important;
+ border-left-width: 0 !important;
+}
+.l-clipper__edge:nth-child(2):before {
+ top: -50%;
+ left: 50%;
+}
+.l-clipper__edge:nth-child(3) {
+ left: -6rpx;
+ bottom: -6rpx;
+ border-top-width: 0 !important;
+ border-right-width: 0 !important;
+}
+.l-clipper__edge:nth-child(3):before {
+ bottom: -50%;
+ left: -50%;
+}
+.l-clipper__edge:nth-child(4) {
+ right: -6rpx;
+ bottom: -6rpx;
+ border-top-width: 0 !important;
+ border-left-width: 0 !important;
+}
+.l-clipper__edge:nth-child(4):before {
+ bottom: -50%;
+ left: 50%;
+}
+.l-clipper-image {
+ width: 100%;
+ border-style: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ transform-origin: center;
+}
+.l-clipper-canvas {
+ position: fixed;
+ z-index: 10;
+ left: -200vw;
+ top: -200vw;
+ pointer-events: none;
+}
+.l-clipper-tools {
+ position: fixed;
+ left: 0;
+ bottom: 10px;
+ width: 100%;
+ z-index: 99;
+ color: #fff;
+}
+.l-clipper-tools__btns {
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: 20rpx 40rpx;
+ box-sizing: border-box;
+}
+.l-clipper-tools__btns .cancel {
+ width: 112rpx;
+ height: 60rpx;
+ text-align: center;
+ line-height: 60rpx;
+}
+.l-clipper-tools__btns .confirm {
+ width: 112rpx;
+ height: 60rpx;
+ line-height: 60rpx;
+ background-color: #07c160;
+ border-radius: 6rpx;
+ text-align: center;
+}
+.l-clipper-tools__btns image {
+ display: block;
+ width: 60rpx;
+ height: 60rpx;
+}
+.l-clipper-tools__btns {
+ flex-direction: row;
+}
diff --git a/pages/ucenter/userinfo/limeClipper/limeClipper.vue b/pages/ucenter/userinfo/limeClipper/limeClipper.vue
new file mode 100644
index 0000000000000000000000000000000000000000..076354b4dc86a069113b23e87f3eb8bd1c947aa8
--- /dev/null
+++ b/pages/ucenter/userinfo/limeClipper/limeClipper.vue
@@ -0,0 +1,816 @@
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+
+
+
+
+
+
+
+
+
+ 确定
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/ucenter/userinfo/limeClipper/utils.js b/pages/ucenter/userinfo/limeClipper/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..980c43915efa8b5664ca42e439e1e0ef2b28cb4b
--- /dev/null
+++ b/pages/ucenter/userinfo/limeClipper/utils.js
@@ -0,0 +1,244 @@
+/**
+ * 判断手指触摸位置
+ */
+export function determineDirection(clipX, clipY, clipWidth, clipHeight, currentX, currentY) {
+ /*
+ * (右下>>1 右上>>2 左上>>3 左下>>4)
+ */
+ let corner;
+ /**
+ * 思路:(利用直角坐标系)
+ * 1.找出裁剪框中心点
+ * 2.如点击坐标在上方点与左方点区域内,则点击为左上角
+ * 3.如点击坐标在下方点与右方点区域内,则点击为右下角
+ * 4.其他角同理
+ */
+ const mainPoint = [clipX + clipWidth / 2, clipY + clipHeight / 2]; // 中心点
+ const currentPoint = [currentX, currentY]; // 触摸点
+
+ if (currentPoint[0] <= mainPoint[0] && currentPoint[1] <= mainPoint[1]) {
+ corner = 3; // 左上
+ } else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] <= mainPoint[1]) {
+ corner = 2; // 右上
+ } else if (currentPoint[0] <= mainPoint[0] && currentPoint[1] >= mainPoint[1]) {
+ corner = 4; // 左下
+ } else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] >= mainPoint[1]) {
+ corner = 1; // 右下
+ }
+
+ return corner;
+}
+
+/**
+ * 图片边缘检测检测时,计算图片偏移量
+ */
+export function calcImageOffset(data, scale) {
+ let left = data.imageLeft;
+ let top = data.imageTop;
+ scale = scale || data.scale;
+
+ let imageWidth = data.imageWidth;
+ let imageHeight = data.imageHeight;
+ if ((data.angle / 90) % 2) {
+ imageWidth = data.imageHeight;
+ imageHeight = data.imageWidth;
+ }
+ const {
+ clipX,
+ clipWidth,
+ clipY,
+ clipHeight
+ } = data;
+
+ // 当前图片宽度/高度
+ const currentImageSize = (size) => (size * scale) / 2;
+ const currentImageWidth = currentImageSize(imageWidth);
+ const currentImageHeight = currentImageSize(imageHeight);
+
+ left = clipX + currentImageWidth >= left ? left : clipX + currentImageWidth;
+ left = clipX + clipWidth - currentImageWidth <= left ? left : clipX + clipWidth - currentImageWidth;
+ top = clipY + currentImageHeight >= top ? top : clipY + currentImageHeight;
+ top = clipY + clipHeight - currentImageHeight <= top ? top : clipY + clipHeight - currentImageHeight;
+ return {
+ left,
+ top,
+ scale
+ };
+}
+
+/**
+ * 图片边缘检测时,计算图片缩放比例
+ */
+export function calcImageScale(data, scale) {
+ scale = scale || data.scale;
+ let {
+ imageWidth,
+ imageHeight,
+ clipWidth,
+ clipHeight,
+ angle
+ } = data
+ if ((angle / 90) % 2) {
+ imageWidth = imageHeight;
+ imageHeight = imageWidth;
+ }
+ if (imageWidth * scale < clipWidth) {
+ scale = clipWidth / imageWidth;
+ }
+ if (imageHeight * scale < clipHeight) {
+ scale = Math.max(scale, clipHeight / imageHeight);
+ }
+ return scale;
+}
+
+/**
+ * 计算图片尺寸
+ */
+export function calcImageSize(width, height, data) {
+ let imageWidth = width,
+ imageHeight = height;
+ let {
+ clipWidth,
+ clipHeight,
+ sysinfo,
+ width: originWidth,
+ height: originHeight
+ } = data
+ if (imageWidth && imageHeight) {
+ if (imageWidth / imageHeight > (clipWidth || originWidth) / (clipWidth || originHeight)) {
+ imageHeight = clipHeight || originHeight;
+ imageWidth = (width / height) * imageHeight;
+ } else {
+ imageWidth = clipWidth || originWidth;
+ imageHeight = (height / width) * imageWidth;
+ }
+ } else {
+ let sys = sysinfo || uni.getSystemInfoSync();
+ imageWidth = sys.windowWidth;
+ imageHeight = 0;
+ }
+ return {
+ imageWidth,
+ imageHeight
+ };
+}
+
+/**
+ * 勾股定理求斜边
+ */
+export function calcPythagoreanTheorem(width, height) {
+ return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+}
+
+/**
+ * 拖动裁剪框时计算
+ */
+export function clipTouchMoveOfCalculate(data, event) {
+ const clientX = event.touches[0].clientX;
+ const clientY = event.touches[0].clientY;
+
+ let {
+ clipWidth,
+ clipHeight,
+ clipY: oldClipY,
+ clipX: oldClipX,
+ clipStart,
+ isLockRatio,
+ maxWidth,
+ minWidth,
+ maxHeight,
+ minHeight
+ } = data;
+ maxWidth = maxWidth / 2;
+ minWidth = minWidth / 2;
+ minHeight = minHeight / 2;
+ maxHeight = maxHeight / 2;
+
+ let width = clipWidth,
+ height = clipHeight,
+ clipY = oldClipY,
+ clipX = oldClipX,
+ // 获取裁剪框实际宽度/高度
+ // 如果大于最大值则使用最大值
+ // 如果小于最小值则使用最小值
+ sizecorrect = () => {
+ width = width <= maxWidth ? (width >= minWidth ? width : minWidth) : maxWidth;
+ height = height <= maxHeight ? (height >= minHeight ? height : minHeight) : maxHeight;
+ },
+ sizeinspect = () => {
+ sizecorrect();
+ if ((width > maxWidth || width < minWidth || height > maxHeight || height < minHeight) && isLockRatio) {
+ return false;
+ } else {
+ return true;
+ }
+ };
+ //if (clipStart.corner) {
+ height = clipStart.height + (clipStart.corner > 1 && clipStart.corner < 4 ? 1 : -1) * (clipStart.y - clientY);
+ //}
+ switch (clipStart.corner) {
+ case 1:
+ width = clipStart.width - clipStart.x + clientX;
+ if (isLockRatio) {
+ height = width / (clipWidth / clipHeight);
+ }
+ if (!sizeinspect()) return;
+ break;
+ case 2:
+ width = clipStart.width - clipStart.x + clientX;
+ if (isLockRatio) {
+ height = width / (clipWidth / clipHeight);
+ }
+ if (!sizeinspect()) {
+ return;
+ } else {
+ clipY = clipStart.clipY - (height - clipStart.height);
+ }
+
+ break;
+ case 3:
+ width = clipStart.width + clipStart.x - clientX;
+ if (isLockRatio) {
+ height = width / (clipWidth / clipHeight);
+ }
+ if (!sizeinspect()) {
+ return;
+ } else {
+ clipY = clipStart.clipY - (height - clipStart.height);
+ clipX = clipStart.clipX - (width - clipStart.width);
+ }
+
+ break;
+ case 4:
+ width = clipStart.width + clipStart.x - clientX;
+ if (isLockRatio) {
+ height = width / (clipWidth / clipHeight);
+ }
+ if (!sizeinspect()) {
+ return;
+ } else {
+ clipX = clipStart.clipX - (width - clipStart.width);
+ }
+ break;
+ default:
+ break;
+ }
+ return {
+ width,
+ height,
+ clipX,
+ clipY
+ };
+}
+
+/**
+ * 单指拖动图片计算偏移
+ */
+export function imageTouchMoveOfCalcOffset(data, clientXForLeft, clientYForLeft) {
+ let left = clientXForLeft - data.touchRelative[0].x,
+ top = clientYForLeft - data.touchRelative[0].y;
+ return {
+ left,
+ top
+ };
+}
diff --git a/pages/ucenter/userinfo/userinfo.vue b/pages/ucenter/userinfo/userinfo.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7e3f42307fde886b001e9b9847ed198c5cf5eded
--- /dev/null
+++ b/pages/ucenter/userinfo/userinfo.vue
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+ {{$t('userinfo.ProfilePhoto')}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/uni-agree/uni-agree.nvue b/pages/uni-agree/uni-agree.nvue
new file mode 100644
index 0000000000000000000000000000000000000000..5befcea554d0b103656b23cf176e3cc895153aa4
--- /dev/null
+++ b/pages/uni-agree/uni-agree.nvue
@@ -0,0 +1,139 @@
+
+
+
+ 个人信息保护指引
+
+
+ 1.在浏览使用时,我们会收集、使用设备标识信息用于推荐。
+
+
+ 2.我们可能会申请位置权限,用于演示 uni-app 的地图、定位能力。
+
+
+ 3.你可以查看完整版
+
+
+ 《用户协议》
+ 和
+ 《隐私政策》
+
+
+ 以便了解我们收集、使用、共享、存储信息的情况,以及对信息的保护措施。
+
+
+ 如果你同意请点击下面的按钮以接受我们的服务
+
+
+ 同意
+ 暂不使用
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/uni-agree/utils/uni-agree.js b/pages/uni-agree/utils/uni-agree.js
new file mode 100644
index 0000000000000000000000000000000000000000..3d1340c729a973d501d3e4f99d288aa1fe36496d
--- /dev/null
+++ b/pages/uni-agree/utils/uni-agree.js
@@ -0,0 +1,11 @@
+export default function(){
+ console.log(uni.getSystemInfoSync().platform)
+ let userprotocol = uni.getStorageSync('userprotocol');
+ console.log('userprotocol',userprotocol);
+ if(!userprotocol){
+ uni.navigateTo({
+ url:'/pages/uni-agree/uni-agree',
+ animationType:"none"
+ })
+ }
+}
\ No newline at end of file
diff --git a/static/app-plus/sharemenu/copyurl.png b/static/app-plus/sharemenu/copyurl.png
new file mode 100644
index 0000000000000000000000000000000000000000..270e6aee210a59d179d67ac3e44d169d030a8721
Binary files /dev/null and b/static/app-plus/sharemenu/copyurl.png differ
diff --git a/static/app-plus/sharemenu/more.png b/static/app-plus/sharemenu/more.png
new file mode 100644
index 0000000000000000000000000000000000000000..bca03ce8015e5317bad3c5fd6cf7d566d6cacea6
Binary files /dev/null and b/static/app-plus/sharemenu/more.png differ
diff --git a/static/app-plus/sharemenu/mp_weixin.png b/static/app-plus/sharemenu/mp_weixin.png
new file mode 100644
index 0000000000000000000000000000000000000000..5ff5908238fca590df862a3475a627d2692c6cb6
Binary files /dev/null and b/static/app-plus/sharemenu/mp_weixin.png differ
diff --git a/static/app-plus/sharemenu/qq.png b/static/app-plus/sharemenu/qq.png
new file mode 100644
index 0000000000000000000000000000000000000000..28e745655ba66f66917144ff8ef4f4eb39395a15
Binary files /dev/null and b/static/app-plus/sharemenu/qq.png differ
diff --git a/static/app-plus/sharemenu/wechatfriend.png b/static/app-plus/sharemenu/wechatfriend.png
new file mode 100644
index 0000000000000000000000000000000000000000..e6af3472fe40c35b6a31e2ceb4a0d64a4f1db3db
Binary files /dev/null and b/static/app-plus/sharemenu/wechatfriend.png differ
diff --git a/static/app-plus/sharemenu/wechatmoments.png b/static/app-plus/sharemenu/wechatmoments.png
new file mode 100644
index 0000000000000000000000000000000000000000..6445df06def179c84852804a4701a5b29efd6e9b
Binary files /dev/null and b/static/app-plus/sharemenu/wechatmoments.png differ
diff --git a/static/app-plus/sharemenu/weibo.png b/static/app-plus/sharemenu/weibo.png
new file mode 100644
index 0000000000000000000000000000000000000000..8affa79cb02b8a2cf880e3df2017c136767f12c7
Binary files /dev/null and b/static/app-plus/sharemenu/weibo.png differ
diff --git a/static/grid/c1.png b/static/grid/c1.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d38fdc45f54393919608143278902961ebfc03e
Binary files /dev/null and b/static/grid/c1.png differ
diff --git a/static/grid/c2.png b/static/grid/c2.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce956d76c7547cc90469647a2a1f6cd34731dbb7
Binary files /dev/null and b/static/grid/c2.png differ
diff --git a/static/grid/c3.png b/static/grid/c3.png
new file mode 100644
index 0000000000000000000000000000000000000000..216202ad01c5d093a15c247cf791bf66759cf54d
Binary files /dev/null and b/static/grid/c3.png differ
diff --git a/static/grid/c4.png b/static/grid/c4.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb8b4770c323cc87544a502c4efcd9792ec6047a
Binary files /dev/null and b/static/grid/c4.png differ
diff --git a/static/grid/c5.png b/static/grid/c5.png
new file mode 100644
index 0000000000000000000000000000000000000000..310bfb123ba811240a23883c589557cced22af97
Binary files /dev/null and b/static/grid/c5.png differ
diff --git a/static/grid/c6.png b/static/grid/c6.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3c45d8814b2657a1c603b1a44c8207da134cb40
Binary files /dev/null and b/static/grid/c6.png differ
diff --git a/static/grid/c7.png b/static/grid/c7.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1e73908c282c8ce053a037a9b0d0ff2bcdb5f28
Binary files /dev/null and b/static/grid/c7.png differ
diff --git a/static/grid/c8.png b/static/grid/c8.png
new file mode 100644
index 0000000000000000000000000000000000000000..c32633c0b399d119fe940b19fb48ee0efd986ca1
Binary files /dev/null and b/static/grid/c8.png differ
diff --git a/static/grid/c9.png b/static/grid/c9.png
new file mode 100644
index 0000000000000000000000000000000000000000..51bcf6a1b39ff986d5e347f16a34c8d3e5dfccec
Binary files /dev/null and b/static/grid/c9.png differ
diff --git a/static/grid/empty.png b/static/grid/empty.png
new file mode 100644
index 0000000000000000000000000000000000000000..c836ffa48680ae45bd5a125f2ca5cd66f5799774
Binary files /dev/null and b/static/grid/empty.png differ
diff --git a/static/h5/download-app/android.png b/static/h5/download-app/android.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc0981584587371ae4471c51ecf7d4bfc307978f
Binary files /dev/null and b/static/h5/download-app/android.png differ
diff --git a/static/h5/download-app/ios.png b/static/h5/download-app/ios.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f3d7593a18eb804b7052e53a48e231dd602c2f7
Binary files /dev/null and b/static/h5/download-app/ios.png differ
diff --git a/static/h5/download-app/openImg.png b/static/h5/download-app/openImg.png
new file mode 100644
index 0000000000000000000000000000000000000000..6de7ef2e3564078cd78f111888a9f0c25d65b2a5
Binary files /dev/null and b/static/h5/download-app/openImg.png differ
diff --git a/static/limeClipper/photo.svg b/static/limeClipper/photo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7b4b59058376794d6e6a78035f627678102f96ad
--- /dev/null
+++ b/static/limeClipper/photo.svg
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
diff --git a/static/limeClipper/rotate.svg b/static/limeClipper/rotate.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0143706ca7adea484ed38339980c2cc23559595e
--- /dev/null
+++ b/static/limeClipper/rotate.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/static/login-index/apple.png b/static/login-index/apple.png
new file mode 100644
index 0000000000000000000000000000000000000000..04a3579cbd143037161da2779fb695f731818d81
Binary files /dev/null and b/static/login-index/apple.png differ
diff --git a/static/login-index/weixin.png b/static/login-index/weixin.png
new file mode 100644
index 0000000000000000000000000000000000000000..913a9d1d6959aef1b0efef8171f74f6878adfd37
Binary files /dev/null and b/static/login-index/weixin.png differ
diff --git a/static/logo.png b/static/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5771e209bb677e2ebd5ff766ad5ee11790f305a
Binary files /dev/null and b/static/logo.png differ
diff --git a/static/tabbar/grid.png b/static/tabbar/grid.png
new file mode 100644
index 0000000000000000000000000000000000000000..6bb1d837bc8a3b37d909746eba22b2e2293fe664
Binary files /dev/null and b/static/tabbar/grid.png differ
diff --git a/static/tabbar/grid_active.png b/static/tabbar/grid_active.png
new file mode 100644
index 0000000000000000000000000000000000000000..81df4c78f5562c303606bd515b928c741e803edf
Binary files /dev/null and b/static/tabbar/grid_active.png differ
diff --git a/static/tabbar/im-contacts.png b/static/tabbar/im-contacts.png
new file mode 100644
index 0000000000000000000000000000000000000000..17bb78fb08cdda17fe1acd7c6c758c33a88f7fa1
Binary files /dev/null and b/static/tabbar/im-contacts.png differ
diff --git a/static/tabbar/im-contacts_active.png b/static/tabbar/im-contacts_active.png
new file mode 100644
index 0000000000000000000000000000000000000000..b86a8c19b70d11255ff39e3ba3056b5dd621dfbf
Binary files /dev/null and b/static/tabbar/im-contacts_active.png differ
diff --git a/static/tabbar/list.png b/static/tabbar/list.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ddda5e31e93694190259410b1e7eec2dcb35186
Binary files /dev/null and b/static/tabbar/list.png differ
diff --git a/static/tabbar/list_active.png b/static/tabbar/list_active.png
new file mode 100644
index 0000000000000000000000000000000000000000..195b149b2fbf4f224d390507954635c9fa2a83e7
Binary files /dev/null and b/static/tabbar/list_active.png differ
diff --git a/static/tabbar/me.png b/static/tabbar/me.png
new file mode 100644
index 0000000000000000000000000000000000000000..1bff84a5047cc57dcb03d76e476bd1fda120c43c
Binary files /dev/null and b/static/tabbar/me.png differ
diff --git a/static/tabbar/me_active.png b/static/tabbar/me_active.png
new file mode 100644
index 0000000000000000000000000000000000000000..c509f7f8ab06f5affa1ea1a8df02def3aedb3035
Binary files /dev/null and b/static/tabbar/me_active.png differ
diff --git a/static/uni-center/defaultAvatarUrl.png b/static/uni-center/defaultAvatarUrl.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3d33188b94e4843e0311836ffb0fd843195ae4e
Binary files /dev/null and b/static/uni-center/defaultAvatarUrl.png differ
diff --git a/static/uni-center/grey.png b/static/uni-center/grey.png
new file mode 100644
index 0000000000000000000000000000000000000000..2aae15a5d0b9eea8451df6395d53775bcc676f78
Binary files /dev/null and b/static/uni-center/grey.png differ
diff --git a/static/uni-center/headers.png b/static/uni-center/headers.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a8a4ad2bd55122db45c0de819b85da87df4f50f
Binary files /dev/null and b/static/uni-center/headers.png differ
diff --git a/static/uni-load-state/disconnection.png b/static/uni-load-state/disconnection.png
new file mode 100644
index 0000000000000000000000000000000000000000..a96f200358f26de619c4d071e469460c8fe178f7
Binary files /dev/null and b/static/uni-load-state/disconnection.png differ
diff --git a/static/uni-quick-login/apple.png b/static/uni-quick-login/apple.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d4b1334ff3c1ee81488d9c8cb05df232ec3b652
Binary files /dev/null and b/static/uni-quick-login/apple.png differ
diff --git a/static/uni-quick-login/sms.png b/static/uni-quick-login/sms.png
new file mode 100644
index 0000000000000000000000000000000000000000..fee8760911f91afc987871b6229af321c7433630
Binary files /dev/null and b/static/uni-quick-login/sms.png differ
diff --git a/static/uni-quick-login/univerify.png b/static/uni-quick-login/univerify.png
new file mode 100644
index 0000000000000000000000000000000000000000..00909a84976e151fdfcb7b000e52ed46dc2c6e33
Binary files /dev/null and b/static/uni-quick-login/univerify.png differ
diff --git a/static/uni-quick-login/user.png b/static/uni-quick-login/user.png
new file mode 100644
index 0000000000000000000000000000000000000000..57153d320f4eec453d8cb7ffe042a95e81347622
Binary files /dev/null and b/static/uni-quick-login/user.png differ
diff --git a/static/uni-quick-login/wechat.png b/static/uni-quick-login/wechat.png
new file mode 100644
index 0000000000000000000000000000000000000000..a16c17dc7156118c7780558a47706cbb7cae45ce
Binary files /dev/null and b/static/uni-quick-login/wechat.png differ
diff --git a/static/uni-sign-in/background.png b/static/uni-sign-in/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d7ba0999a55dea2553a7319e93c8904b51d7810
Binary files /dev/null and b/static/uni-sign-in/background.png differ
diff --git a/static/uni.ttf b/static/uni.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..60a1968d08cc6056c70b5402b2effac43c6f96a3
Binary files /dev/null and b/static/uni.ttf differ
diff --git a/store/index.js b/store/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..0282d1430997be1e01927f85255f098ee0349608
--- /dev/null
+++ b/store/index.js
@@ -0,0 +1,24 @@
+import user from '@/store/modules/user.js'
+
+// #ifndef VUE3
+import Vue from 'vue'
+import Vuex from 'vuex'
+Vue.use(Vuex)
+const store = new Vuex.Store({
+ modules: {
+ user
+ },
+ strict: true
+})
+// #endif
+
+// #ifdef VUE3
+import {createStore} from 'vuex'
+const store = createStore({
+ modules: {
+ user
+ }
+})
+// #endif
+
+export default store
\ No newline at end of file
diff --git a/store/modules/user.js b/store/modules/user.js
new file mode 100644
index 0000000000000000000000000000000000000000..22d12ba7c140ac33294f5475e8acb626395829ef
--- /dev/null
+++ b/store/modules/user.js
@@ -0,0 +1,48 @@
+// 上次启动时的用户信息
+let userInfoHistory = uni.getStorageSync('userInfo') || {};
+let state = {
+ //是否已经登录
+ hasLogin: Boolean(Object.keys(userInfoHistory).length),
+ //用户信息
+ info: userInfoHistory
+ },
+ getters = {
+ info(state) {
+ return state.info;
+ },
+ hasLogin(state){
+ return state.hasLogin;
+ }
+ },
+ mutations = {
+ login(state, info) { //登录成功后的操作
+ //原有的结合传来的参数
+ let _info = state.info;
+ state.info = Object.assign({}, _info, info);
+ //设置为已经登录
+ state.hasLogin = true;
+ console.log('state.info',state.info);
+ //存储最新的用户数据到本地持久化存储
+ uni.setStorageSync('userInfo', state.info);
+ uni.setStorageSync('uni_id_token', state.info.token)
+ uni.setStorageSync('uni_id_token_expired', state.info.tokenExpired)
+
+ },
+ logout(state) {
+ state.info = {};
+ state.hasLogin = false;
+ uni.setStorageSync('userInfo', {});
+ uni.setStorageSync('uni_id_token', '');
+ uni.setStorageSync('uni_id_token_expired', 0)
+ }
+ },
+ actions = {
+
+ }
+export default {
+ namespaced: true,
+ state,
+ getters,
+ mutations,
+ actions
+}
\ No newline at end of file
diff --git a/uni-starter.config.js b/uni-starter.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b2fd222335fee4c7fdf77c40e8011782340290e
--- /dev/null
+++ b/uni-starter.config.js
@@ -0,0 +1,92 @@
+//这是应用的配置页面,App.vue挂载到getApp().globalData.config
+export default {
+ "h5": {
+ "url": "https://uni-starter.dcloud.net.cn", // 前端网页托管的域名
+ // 在h5端全局悬浮引导用户下载app的功能 更多自定义要求在/common/openApp.js中修改
+ // "openApp": { //如不需要本功能直接移除本节点即可
+ // //点击悬浮下载栏后打开的网页链接
+ // "openUrl": '/#/pages/ucenter/invite/invite',
+ // //左侧显示的应用名称
+ // "appname": 'uni-starter',
+ // //应用的图标
+ // "logo": './static/logo.png',
+ // }
+ },
+ "mp": {
+ "weixin": {
+ //微信小程序原始id,微信小程序分享时
+ "id": "gh_33446d7f7a26"
+ }
+ },
+ "router": {
+ /*
+ 名词解释:“强制登录页”
+ 在打开定义的需强制登录的页面之前会自动检查(前端校验)uni_id_token的值是否有效,
+ 如果无效会自动跳转到登录页面
+ 两种模式:
+ 1.needLogin:黑名单模式。枚举游客不可访问的页面。
+ 2.visitor:白名单模式。枚举游客可访问的页面。
+ * 注意:黑名单与白名单模式二选一
+ */
+ // "needLogin" : [
+ // {pattern:/^\/pages\/list.*/}, //支持正则表达式
+ // "/uni_modules/uni-news-favorite/pages/uni-news-favorite/list",
+ // "/uni_modules/uni-feedback/pages/uni-feedback/add"
+ // ],
+ "visitor" : [
+ "/",//注意入口页必须直接写 "/"
+ {"pattern":/^\/pages\/list.*/}, //支持正则表达式
+ {"pattern":/^\/pages\/ucenter\/login-page.*/},
+ "/pages/common/webview/webview",
+ "/pages/grid/grid",
+ "/pages/ucenter/ucenter",
+ "/pages/ucenter/guestbook/guestbook",
+ "/pages/ucenter/about/about",
+ "/pages/ucenter/settings/settings"
+ ],
+ /*
+ login:配置登录类型与优先级
+ 未列举到的,或设备环境不支持的选项,将被隐藏。如果你需要在不同平台有不同的配置,直接用条件编译即可
+ 根据数组的第0项,决定登录方式的第一优先级。
+ */
+ "login": ["weixin","univerify","username", "smsCode", "apple"]
+ },
+ //关于应用
+ "about": {
+ //应用名称
+ "appName": "uni-starter",
+ //应用logo
+ "logo": "/static/logo.png",
+ //公司名称
+ "company": "北京xx网络技术有限公司",
+ //口号
+ "slogan": "云端一体应用快速开发模版",
+ //政策协议
+ "agreements": [{
+ "title": "用户服务协议", //如果开启了多语言国际化,本配置将失效。请在 lang/en.js 和 lang/zh-Hans.js中配置
+ "url": "请填写用户服务协议链接" //对应的网络链接
+ },
+ {
+ "title": "隐私政策", //如果开启了多语言国际化,本配置将失效。请在 lang/en.js 和 lang/zh-Hans.js中配置
+ "url": "请填写隐私政策链接" //对应的网络链接
+ }
+ ],
+ //应用的链接,用于分享到第三方平台和生成关于我们页的二维码
+ "download": "",
+ //version
+ "version":"1.0.0" //用于非app端显示,app端自动获取
+ },
+ "download":{ //用于生成二合一下载页面
+ "ios":"https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8",
+ "android":"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-97fca9f2-41f6-449f-a35e-3f135d4c3875/6d754387-a6c3-48ed-8ad2-e8f39b40fc01.apk"
+ },
+ //用于打开应用市场评分界面
+ "marketId":{
+ "ios":"id1417078253",
+ "android":"123456"
+ },
+ //配置多语言国际化。i18n为英文单词 internationalization的首末字符i和n,18为中间的字符数 是“国际化”的简称
+ "i18n":{
+ "enable":false //默认关闭,国际化。如果你想使用国际化相关功能,请改为true
+ }
+}
\ No newline at end of file
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000000000000000000000000000000000000..45ae737e66433b1d6050e07a62833f7146183de2
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:24rpx;
+$uni-font-size-base:28rpx;
+$uni-font-size-lg:32rpx;
+
+/* 图片尺寸 */
+$uni-img-size-sm:40rpx;
+$uni-img-size-base:52rpx;
+$uni-img-size-lg:80rpx;
+
+/* Border Radius */
+$uni-border-radius-sm: 4rpx;
+$uni-border-radius-base: 6rpx;
+$uni-border-radius-lg: 12rpx;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 10px;
+$uni-spacing-row-base: 20rpx;
+$uni-spacing-row-lg: 30rpx;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 8rpx;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 24rpx;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:40rpx;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:36rpx;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:30rpx;
\ No newline at end of file
diff --git a/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f16dc2fe70cfe7a79f8ce4dece68d49ccf51947
--- /dev/null
+++ b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/index.js
@@ -0,0 +1,49 @@
+'use strict';
+exports.main = async (event, context) => {
+ /**
+ * 根据搜索记录,设定时间间隔来归纳出热搜数据并存储在热搜表中
+ */
+ const SEARCHHOT = 'opendb-search-hot'; // 热搜数据库名称
+ const SEARCHLOG = 'opendb-search-log'; // 搜索记录数据库名称
+ const SEARCHLOG_timeZone = 604800000; // 归纳搜索记录时间间隔,毫秒数,默认为最近7天
+ const SEARCHHOT_size = 10; // 热搜条数
+
+ const DB = uniCloud.database();
+ const DBCmd = DB.command;
+ const $ = DB.command.aggregate;
+ const SEARCHHOT_db = DB.collection(SEARCHHOT);
+ const SEARCHLOG_db = DB.collection(SEARCHLOG);
+ const timeEnd = Date.now() - SEARCHLOG_timeZone;
+
+ let {
+ data: searchHotData
+ } = await SEARCHLOG_db
+ .aggregate()
+ .match({
+ create_date: DBCmd.gt(timeEnd)
+ })
+ .group({
+ _id: {
+ 'content': '$content',
+ },
+ count: $.sum(1)
+ })
+ .replaceRoot({
+ newRoot: $.mergeObjects(['$_id', '$$ROOT'])
+ })
+ .project({
+ _id: false
+ })
+ .sort({
+ count: -1
+ })
+ .end();
+
+ let now = Date.now();
+ searchHotData.map(item => {
+ item.create_date = now;
+ return item;
+ }).slice(0, SEARCHHOT_size);
+ // searchHotData = searchHotData.sort((a, b) => b.count - a.count).slice(0, SEARCHHOT_size);
+ return searchHotData.length ? await SEARCHHOT_db.add(searchHotData) : ''
+};
diff --git a/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..6005add8563ac879001ba7f5fdeb304768ed8486
--- /dev/null
+++ b/uniCloud-aliyun/cloudfunctions/uni-analyse-searchhot/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "uni-analyse-searchhot",
+ "version": "1.0.0",
+ "description": "定时归纳热搜",
+ "main": "index.js",
+ "dependencies": {},
+ "cloudfunction-config": {
+ "triggers": [{
+ "name": "analyse-searchHot",
+ "type": "timer",
+ "config": "0 0 */2 * * * *"
+ }]
+ }
+}
diff --git "a/uniCloud-aliyun/database/JQL\346\225\260\346\215\256\345\272\223\347\256\241\347\220\206.jql" "b/uniCloud-aliyun/database/JQL\346\225\260\346\215\256\345\272\223\347\256\241\347\220\206.jql"
new file mode 100644
index 0000000000000000000000000000000000000000..4903b479c888e928fc113d11322ff3411095ab97
--- /dev/null
+++ "b/uniCloud-aliyun/database/JQL\346\225\260\346\215\256\345\272\223\347\256\241\347\220\206.jql"
@@ -0,0 +1,12 @@
+// 本文件用于,使用JQL语法操作项目关联的uniCloud空间的数据库,方便开发调试和远程数据库管理
+// 编写clientDB的js API(也支持常规js语法,比如var),可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法
+// 可以全部运行,也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码
+// 如果文档中存在多条JQL语句,只有最后一条语句生效
+// 如果混写了普通js,最后一条语句需是数据库操作语句
+// 此处代码运行不受DB Schema的权限控制,移植代码到实际业务中注意在schema中配好permission
+// 不支持clientDB的action
+// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database?id=limit
+// 详细JQL语法,请参考 https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=jsquery
+
+// 下面示例查询uni-id-users表的所有数据
+db.collection('guestbook, uni-id-users').where('user_id._id=="610a6daa506cc7000100c07f"').get();
diff --git "a/uniCloud-aliyun/database/JQL\346\237\245\350\257\242.jql" "b/uniCloud-aliyun/database/JQL\346\237\245\350\257\242.jql"
new file mode 100644
index 0000000000000000000000000000000000000000..680e8987bb99075ab51c0044f4fd659659f877a2
--- /dev/null
+++ "b/uniCloud-aliyun/database/JQL\346\237\245\350\257\242.jql"
@@ -0,0 +1,9 @@
+// 本查询文件用于,使用JQL语法查询项目关联的uniCloud空间的数据库,方便开发调试
+// 选中查询代码,点击工具栏上的运行按钮或者【F5】运行查询语句
+// 如果没有选中代码,直接运行,则会执行整个文档的JQL语句。但如果文档中存在多条JQL语句,只有最后一条语句生效
+// 本文档支持简单js,但不支持clientDB的action
+// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database?id=limit
+// 详细JQL语法,请参考 https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=jsquery
+
+// 下面示例查询uni-id-users表的所有数据
+db.collection('uni-id-users').get();
diff --git a/uniCloud-aliyun/database/db_init.json b/uniCloud-aliyun/database/db_init.json
new file mode 100644
index 0000000000000000000000000000000000000000..6c7d6891cea81a29360b087bf2f4029127174a31
--- /dev/null
+++ b/uniCloud-aliyun/database/db_init.json
@@ -0,0 +1,157 @@
+// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/cf-database?id=db_init
+// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据
+{
+ "opendb-verify-codes": {
+ "data": []
+ },
+ "uni-id-roles": {
+ "data": []
+ },
+ "uni-id-permissions": {
+ "data": []
+ },
+ "uni-id-log": {
+ "data": []
+ },
+ "opendb-admin-menus": {
+ "data": [{
+ "menu_id": "system_management",
+ "name": "系统管理",
+ "icon": "uni-icons-gear",
+ "url": "",
+ "sort": 1000,
+ "parent_id": "",
+ "permission": [],
+ "enable": true,
+ "create_date": 1602662469396
+ }, {
+ "menu_id": "system_user",
+ "name": "用户管理",
+ "icon": "uni-icons-person",
+ "url": "/pages/system/user/list",
+ "sort": 1010,
+ "parent_id": "system_management",
+ "permission": [],
+ "enable": true,
+ "create_date": 1602662469398
+ }, {
+ "menu_id": "system_role",
+ "name": "角色管理",
+ "icon": "uni-icons-personadd",
+ "url": "/pages/system/role/list",
+ "sort": 1020,
+ "parent_id": "system_management",
+ "permission": [],
+ "enable": true,
+ "create_date": 1602662469397
+ }, {
+ "menu_id": "system_permission",
+ "name": "权限管理",
+ "icon": "uni-icons-locked",
+ "url": "/pages/system/permission/list",
+ "sort": 1030,
+ "parent_id": "system_management",
+ "permission": [],
+ "enable": true,
+ "create_date": 1602662469396
+ }, {
+ "menu_id": "system_menu",
+ "name": "菜单管理",
+ "icon": "uni-icons-settings",
+ "url": "/pages/system/menu/list",
+ "sort": 1040,
+ "parent_id": "system_management",
+ "permission": [],
+ "enable": true,
+ "create_date": 1602662469396
+ }]
+ },
+ "opendb-news-articles": {
+ "data": [{
+ "title": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务",
+ "excerpt": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务",
+ "content": "随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。
\n阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。
\n经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。
\n经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!
\n如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。
\n\n 阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable
\n
\n集成uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。
\n这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app的产品确实过硬。
\n很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。
\n自从uni-app推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。
\n本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。
\n后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。
\n使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。
\nDCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。
\n进一步了解uni-app,详见:https://uniapp.dcloud.io
\n欢迎扫码关注DCloud公众号,转发消息到朋友圈。
",
+ "avatar": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-aliyun-gacrhzeynhss7c6d04/249516a0-3941-11eb-899d-733ae62bed2f.jpg",
+ "type": 0,
+ "user_id": "123",
+ "comment_count": 0,
+ "like_count": 0,
+ "comment_status": 0,
+ "article_status": 1,
+ "publish_date": 1616092287006,
+ "last_modify_date": 1616092303031,
+ "create_time": "2021-03-19T08:25:06.109Z"
+ }]
+ },
+ "opendb-app-versions": {
+ "data": [{
+ "is_silently": false,
+ "is_mandatory": false,
+ "appid": "__UNI__03B096E",
+ "name": "uni-starter",
+ "title": "新增升级中心",
+ "contents": "新增升级中心",
+ "platform": [
+ "Android"
+ ],
+ "version": "1.0.1",
+ "url": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-3469aac7-a663-4c5d-8ee8-94275f8c09ab/3128d010-01c5-4121-a1d6-f3f919944a23.apk",
+ "stable_publish": false,
+ "type": "native_app",
+ "create_date": 1616771628150
+ }]
+ },
+ "uni-id-users": {
+ "data": [{
+ "_id": "123",
+ "username": "预置用户",
+ "nickname": "测试",
+ "avatar": "https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/d84c6de0-6080-11eb-bdc1-8bd33eb6adaa.png",
+ "mobile": "18888888888",
+ "mobile_confirmed": 1
+ }]
+ },
+ "opendb-banner": {
+ "data": [{
+ "status": true,
+ "bannerfile": {
+ "name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg",
+ "extname": "jpg",
+ "fileType": "image",
+ "url": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/b88a7e17-35f0-4d0d-bc32-93f8909baf03.jpg",
+ "size": 70880,
+ "image": {
+ "width": 500,
+ "height": 333,
+ "location": "blob:http://localhost:8081/a3bfaab4-7ee6-44d5-a171-dc8225d83598"
+ },
+ "path": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/b88a7e17-35f0-4d0d-bc32-93f8909baf03.jpg"
+ },
+ "open_url": "https://www.dcloud.io/",
+ "title": "测试",
+ "sort": 1,
+ "category_id": "",
+ "description": ""
+ },
+ {
+ "status": true,
+ "bannerfile": {
+ "name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg",
+ "extname": "jpg",
+ "fileType": "image",
+ "url": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/9db94cb4-a5e0-4ed9-b356-b42a392b3112.jpg",
+ "size": 70880,
+ "image": {
+ "width": 500,
+ "height": 333,
+ "location": "blob:http://localhost:8081/1a6f718a-4012-476a-9172-590fef2cc518"
+ },
+ "path": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/9db94cb4-a5e0-4ed9-b356-b42a392b3112.jpg"
+ },
+ "open_url": "https://www.dcloud.io/",
+ "title": "",
+ "category_id": "",
+ "description": ""
+ }]
+ }
+}
\ No newline at end of file
diff --git a/uniCloud-aliyun/database/default.jql b/uniCloud-aliyun/database/default.jql
new file mode 100644
index 0000000000000000000000000000000000000000..465356a46dcc688b3da922ce65ae05b56a04cc45
--- /dev/null
+++ b/uniCloud-aliyun/database/default.jql
@@ -0,0 +1,12 @@
+// 本文件用于,使用JQL语法操作项目关联的uniCloud空间的数据库,方便开发调试和远程数据库管理
+// 编写clientDB的js API(也支持常规js语法,比如var),可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法
+// 可以全部运行,也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码
+// 如果文档中存在多条JQL语句,只有最后一条语句生效
+// 如果混写了普通js,最后一条语句需是数据库操作语句
+// 此处代码运行不受DB Schema的权限控制,移植代码到实际业务中注意在schema中配好permission
+// 不支持clientDB的action
+// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database?id=limit
+// 详细JQL语法,请参考 https://uniapp.dcloud.net.cn/uniCloud/clientdb?id=jsquery
+
+// 下面示例查询uni-id-users表的所有数据
+db.collection('uni-id-users').get();
diff --git a/uniCloud-aliyun/database/guestbook.schema.json b/uniCloud-aliyun/database/guestbook.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..b4e9bb93d59668768053172b7b1537ed61bdb33b
--- /dev/null
+++ b/uniCloud-aliyun/database/guestbook.schema.json
@@ -0,0 +1,57 @@
+// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema
+{
+ "bsonType": "object",
+ "required": [],
+ "permission": {
+ "read": "doc.state || auth.uid == doc.user_id || 'AUDITOR' in auth.role",
+ "create": "auth.uid != null",
+ "update": "'AUDITOR' in auth.role",
+ "delete": "auth.uid == doc.user_id"
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成",
+ "permission":{
+ "write":false
+ }
+ },
+ "text": {
+ "bsonType": "string",
+ "permission":{
+ "write":false
+ }
+ },
+ "user_id": {
+ "forceDefaultValue": {
+ "$env": "uid"
+ },
+ "foreignKey": "uni-id-users._id",
+ "permission":{
+ "write":false
+ }
+ },
+ "ip": {
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ },
+ "permission":{
+ "write":false
+ }
+ },
+ "create_time": {
+ "forceDefaultValue": {
+ "$env": "now"
+ },
+ "permission":{
+ "write":false
+ }
+ },
+ "state": {
+ "bsonType": "bool",
+ "forceDefaultValue":false,
+ "permission":{
+ "write":true
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uniCloud-aliyun/database/opendb-admin-menus.schema.json b/uniCloud-aliyun/database/opendb-admin-menus.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..c6b9de5383e1ee6488f07604e8a34898b546de67
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-admin-menus.schema.json
@@ -0,0 +1,56 @@
+{
+ "bsonType": "object",
+ "required": ["name", "menu_id"],
+ "permission": {
+ "read": true
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID,系统自动生成"
+ },
+ "menu_id": {
+ "bsonType": "string",
+ "description": "菜单项的ID,不可重复",
+ "trim": "both"
+ },
+ "name": {
+ "bsonType": "string",
+ "description": "菜单名称",
+ "trim": "both"
+ },
+ "icon": {
+ "bsonType": "string",
+ "description": "菜单图标",
+ "trim": "both"
+ },
+ "url": {
+ "bsonType": "string",
+ "description": "菜单url",
+ "trim": "both"
+ },
+ "sort": {
+ "bsonType": "int",
+ "description": "菜单序号(越大越靠后)"
+ },
+ "parent_id": {
+ "bsonType": "string",
+ "description": "父级菜单Id",
+ "parentKey": "menu_id"
+ },
+ "permission": {
+ "bsonType": "array",
+ "description": "菜单权限列表"
+ },
+ "enable": {
+ "bsonType": "bool",
+ "description": "是否启用菜单,true启用、false禁用"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "菜单创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-app-versions.schema.json b/uniCloud-aliyun/database/opendb-app-versions.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..a24c2d34d647ce7d19d173c316c152c004764cd1
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-app-versions.schema.json
@@ -0,0 +1,124 @@
+{
+ "bsonType": "object",
+ "required": ["appid", "platform", "version", "url", "contents", "type"],
+ "permission": {
+ "read": false,
+ "create": false,
+ "update": false,
+ "delete": false
+ },
+ "properties": {
+ "_id": {
+ "description": "记录id,自动生成"
+ },
+ "appid": {
+ "bsonType": "string",
+ "trim": "both",
+ "description": "应用的AppID",
+ "label": "AppID",
+ "componentForEdit": {
+ "name": "uni-easyinput",
+ "props": {
+ "disabled": true
+ }
+ }
+ },
+ "name": {
+ "bsonType": "string",
+ "trim": "both",
+ "description": "应用名称",
+ "label": "应用名称",
+ "componentForEdit": {
+ "name": "uni-easyinput",
+ "props": {
+ "disabled": true
+ }
+ }
+ },
+ "title": {
+ "bsonType": "string",
+ "description": "更新标题",
+ "label": "更新标题"
+ },
+ "contents": {
+ "bsonType": "string",
+ "description": "更新内容",
+ "label": "更新内容",
+ "componentForEdit": {
+ "name": "textarea"
+ },
+ "componentForShow": {
+ "name": "textarea",
+ "props": {
+ "disabled": true
+ }
+ }
+ },
+ "platform": {
+ "bsonType": "array",
+ "enum": [{
+ "value": "Android",
+ "text": "安卓"
+ }, {
+ "value": "iOS",
+ "text": "苹果"
+ }],
+ "description": "更新平台,Android || iOS || [Android, iOS]",
+ "label": "平台"
+ },
+ "type": {
+ "bsonType": "string",
+ "enum": [{
+ "value": "native_app",
+ "text": "原生App安装包"
+ }, {
+ "value": "wgt",
+ "text": "Wgt资源包"
+ }],
+ "description": "安装包类型,native_app || wgt",
+ "label": "安装包类型"
+ },
+ "version": {
+ "bsonType": "string",
+ "description": "当前包版本号,必须大于当前线上发行版本号",
+ "label": "版本号"
+ },
+ "min_uni_version": {
+ "bsonType": "string",
+ "description": "原生App最低版本",
+ "label": "原生App最低版本"
+ },
+ "url": {
+ "bsonType": "string",
+ "description": "可下载安装包地址",
+ "label": "包地址"
+ },
+ "stable_publish": {
+ "bsonType": "bool",
+ "description": "是否上线发行",
+ "label": "上线发行"
+ },
+ "is_silently": {
+ "bsonType": "bool",
+ "description": "是否静默更新",
+ "label": "静默更新",
+ "defaultValue": false
+ },
+ "is_mandatory": {
+ "bsonType": "bool",
+ "description": "是否强制更新",
+ "label": "强制更新",
+ "defaultValue": false
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "label": "上传时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ },
+ "componentForEdit": {
+ "name": "uni-dateformat"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-banner.schema.json b/uniCloud-aliyun/database/opendb-banner.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..a027517e79b756cdb0af19666759f54845e1377b
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-banner.schema.json
@@ -0,0 +1,54 @@
+{
+ "bsonType": "object",
+ "required": ["bannerfile"],
+ "permission": {
+ "read": true
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "bannerfile": {
+ "bsonType": "file",
+ "fileMediaType": "image",
+ "title": "图片文件",
+ "description": "图片文件信息,包括文件名、url等"
+ },
+ "open_url": {
+ "bsonType": "string",
+ "description": "点击跳转目标地址。如果是web地址则使用内置web-view打开;如果是本地页面则跳转本地页面;如果是schema地址则打开本地的app",
+ "title": "点击目标地址",
+ "format": "url",
+ "pattern": "^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S",
+ "trim": "both"
+ },
+ "title": {
+ "bsonType": "string",
+ "description": "注意标题文字颜色和背景图靠色导致看不清的问题",
+ "maxLength": 20,
+ "title": "标题",
+ "trim": "both"
+ },
+ "sort": {
+ "bsonType": "int",
+ "description": "数字越小,排序越前",
+ "title": "排序"
+ },
+ "category_id": {
+ "bsonType": "string",
+ "description": "多个栏目的banner都存在一个表里时可用这个字段区分",
+ "title": "分类id"
+ },
+ "status": {
+ "bsonType": "bool",
+ "defaultValue": true,
+ "title": "生效状态"
+ },
+ "description": {
+ "bsonType": "string",
+ "description": "维护者自用描述",
+ "title": "备注",
+ "trim": "both"
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-department.schema.json b/uniCloud-aliyun/database/opendb-department.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..698239b363e88fa4ed2eaa8b199ec1a5edaf7648
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-department.schema.json
@@ -0,0 +1,47 @@
+{
+ "bsonType": "object",
+ "required": ["name"],
+ "permission": {
+ "read": true,
+ "create": false,
+ "update": false,
+ "delete": false
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "parent_id": {
+ "bsonType": "string",
+ "description": "父级部门ID",
+ "parentKey": "_id"
+ },
+ "name": {
+ "bsonType": "string",
+ "description": "部门名称",
+ "title": "部门名称",
+ "trim": "both"
+ },
+ "level": {
+ "bsonType": "int",
+ "description": "部门层级,为提升检索效率而作的冗余设计"
+ },
+ "sort": {
+ "bsonType": "int",
+ "description": "部门在当前层级下的顺序,由小到大",
+ "title": "显示顺序"
+ },
+ "manager_uid": {
+ "bsonType": "string",
+ "description": "部门主管的userid, 参考`uni-id-users` 表",
+ "foreignKey": "uni-id-users._id"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "部门创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-mall-goods.schema.json b/uniCloud-aliyun/database/opendb-mall-goods.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..b3c24cc6506c60543bd011741f599fcfbbd62c50
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-mall-goods.schema.json
@@ -0,0 +1,123 @@
+{
+ "bsonType": "object",
+ "permission": {
+ "create": false,
+ "delete": false,
+ "read": "doc.is_on_sale == true",
+ "update": false
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(商品 ID),系统自动生成"
+ },
+ "add_date": {
+ "bsonType": "timestamp",
+ "defaultValue": {
+ "$env": "now"
+ },
+ "description": "上架时间"
+ },
+ "category_id": {
+ "bsonType": "string",
+ "description": "分类 id,参考`opendb-mall-categories`表",
+ "foreignKey": "opendb-mall-categories._id"
+ },
+ "comment_count": {
+ "bsonType": "int",
+ "description": "累计评论数"
+ },
+ "goods_banner_imgs": {
+ "bsonType": "array",
+ "description": "商品详情页的banner图地址"
+ },
+ "goods_desc": {
+ "bsonType": "string",
+ "description": "商品详细描述",
+ "title": "详细描述",
+ "trim": "both"
+ },
+ "goods_sn": {
+ "bsonType": "string",
+ "description": "商品的唯一货号",
+ "title": "货号",
+ "trim": "both"
+ },
+ "goods_thumb": {
+ "bsonType": "string",
+ "description": "商品缩略图,用于在列表或搜索结果中预览显示",
+ "pattern": "^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S",
+ "title": "缩略图地址",
+ "trim": "both"
+ },
+ "is_alone_sale": {
+ "bsonType": "bool",
+ "description": "是否能单独销售;如果不能单独销售,则只能作为某商品的配件或者赠品销售"
+ },
+ "is_best": {
+ "bsonType": "bool",
+ "description": "是否精品"
+ },
+ "is_hot": {
+ "bsonType": "bool",
+ "description": "是否热销"
+ },
+ "is_new": {
+ "bsonType": "bool",
+ "description": "是否新品",
+ "title": "是否新品"
+ },
+ "is_on_sale": {
+ "bsonType": "bool",
+ "description": "是否上架销售",
+ "title": "是否上架"
+ },
+ "is_real": {
+ "bsonType": "bool",
+ "description": "是否实物",
+ "title": "是否为实物"
+ },
+ "keywords": {
+ "bsonType": "string",
+ "description": "商品关键字,为搜索引擎收录使用",
+ "title": "关键字",
+ "trim": "both"
+ },
+ "last_modify_date": {
+ "bsonType": "timestamp",
+ "defaultValue": {
+ "$env": "now"
+ },
+ "description": "最后修改时间"
+ },
+ "month_sell_count": {
+ "bsonType": "int",
+ "description": "月销量"
+ },
+ "name": {
+ "bsonType": "string",
+ "description": "商品名称",
+ "title": "名称",
+ "trim": "both"
+ },
+ "remain_count": {
+ "bsonType": "int",
+ "description": "库存数量",
+ "title": "库存数量"
+ },
+ "seller_note": {
+ "bsonType": "string",
+ "description": "商家备注,仅商家可见",
+ "permission": {
+ "read": false
+ },
+ "trim": "both"
+ },
+ "total_sell_count": {
+ "bsonType": "int",
+ "description": "总销量"
+ }
+ },
+ "required": ["goods_sn", "name", "remain_count", "month_sell_count", "total_sell_count", "comment_count", "is_real",
+ "is_on_sale", "is_alone_sale", "is_best", "is_new", "is_hot"
+ ]
+}
diff --git a/uniCloud-aliyun/database/opendb-news-articles-detail.schema.json b/uniCloud-aliyun/database/opendb-news-articles-detail.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..325fc9aadd7babd0b8ff08ccbacf848ba633e962
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-news-articles-detail.schema.json
@@ -0,0 +1,122 @@
+{
+ "bsonType": "object",
+ "permission": {
+ "create": "auth.uid != null",
+ "delete": "doc.user_id == auth.uid",
+ "read": true,
+ "update": "doc.user_id == auth.uid"
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(用户 ID),系统自动生成"
+ },
+ "article_status": {
+ "bsonType": "int",
+ "description": "文章状态:0 草稿箱 1 已发布",
+ "maximum": 1,
+ "minimum": 0
+ },
+ "avatar": {
+ "bsonType": "string",
+ "description": "缩略图地址",
+ "label": "封面大图"
+ },
+ "category_id": {
+ "bsonType": "string",
+ "description": "分类 id,参考`uni-news-categories`表"
+ },
+ "comment_count": {
+ "bsonType": "int",
+ "description": "评论数量",
+ "permission": {
+ "write": false
+ }
+ },
+ "comment_status": {
+ "bsonType": "int",
+ "description": "评论状态:0 关闭 1 开放",
+ "maximum": 1,
+ "minimum": 0
+ },
+ "content": {
+ "bsonType": "string",
+ "description": "文章内容",
+ "label": "文章内容"
+ },
+ "excerpt": {
+ "bsonType": "string",
+ "description": "文章摘录",
+ "label": "摘要"
+ },
+ "is_essence": {
+ "bsonType": "bool",
+ "description": "阅读加精",
+ "permission": {
+ "write": false
+ }
+ },
+ "is_sticky": {
+ "bsonType": "bool",
+ "description": "是否置顶",
+ "permission": {
+ "write": false
+ }
+ },
+ "last_comment_user_id": {
+ "bsonType": "string",
+ "description": "最后回复用户 id,参考`uni-id-users` 表"
+ },
+ "last_modify_date": {
+ "bsonType": "timestamp",
+ "description": "最后修改时间"
+ },
+ "last_modify_ip": {
+ "bsonType": "string",
+ "description": "最后修改时 IP 地址"
+ },
+ "like_count": {
+ "bsonType": "int",
+ "description": "喜欢数、点赞数",
+ "permission": {
+ "write": false
+ }
+ },
+ "mode": {
+ "bsonType": "number",
+ "description": "排版显示模式"
+ },
+ "publish_date": {
+ "bsonType": "timestamp",
+ "defaultValue": {
+ "$env": "now"
+ },
+ "description": "发表时间"
+ },
+ "publish_ip": {
+ "bsonType": "string",
+ "description": "发表时 IP 地址",
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ }
+ },
+ "title": {
+ "bsonType": "string",
+ "description": "标题",
+ "label": "标题"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "文章作者ID, 参考`uni-id-users` 表"
+ },
+ "view_count": {
+ "bsonType": "int",
+ "description": "阅读数量",
+ "permission": {
+ "write": false
+ }
+ }
+ },
+ "required": ["user_id", "title", "content", "article_status", "view_count", "like_count", "is_sticky", "is_essence",
+ "comment_status", "comment_count", "mode"
+ ]
+}
diff --git a/uniCloud-aliyun/database/opendb-news-articles.schema.json b/uniCloud-aliyun/database/opendb-news-articles.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..ee4f8cce2c03225b63c9ecd41dfc1b526b7c98ec
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-news-articles.schema.json
@@ -0,0 +1,165 @@
+{
+ "bsonType": "object",
+ "required": ["user_id", "title", "content"],
+ "permission": {
+ "read": "doc.uid == auth.uid && doc.article_status == 0 || doc.article_status == 1",
+ "create": "auth.uid != null",
+ "update": "doc.user_id == auth.uid",
+ "delete": "doc.user_id == auth.uid"
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(用户 ID),系统自动生成"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "文章作者ID, 参考`uni-id-users` 表",
+ "foreignKey": "uni-id-users._id",
+ "defaultValue": {
+ "$env": "uid"
+ }
+ },
+ "category_id": {
+ "bsonType": "string",
+ "title": "分类",
+ "description": "分类 id,参考`uni-news-categories`表",
+ "foreignKey": "opendb-news-categories._id",
+ "enum": {
+ "collection": "opendb-news-categories",
+ "field": "name as text, _id as value"
+ }
+ },
+ "title": {
+ "bsonType": "string",
+ "title": "标题",
+ "description": "标题",
+ "label": "标题",
+ "trim": "both"
+ },
+ "content": {
+ "bsonType": "string",
+ "title": "文章内容",
+ "description": "文章内容",
+ "label": "文章内容",
+ "trim": "right"
+ },
+ "excerpt": {
+ "bsonType": "string",
+ "title": "文章摘录",
+ "description": "文章摘录",
+ "label": "摘要",
+ "trim": "both"
+ },
+ "article_status": {
+ "bsonType": "int",
+ "title": "文章状态",
+ "description": "文章状态:0 草稿箱 1 已发布",
+ "defaultValue": 0,
+ "enum": [{
+ "value": 0,
+ "text": "草稿箱"
+ }, {
+ "value": 1,
+ "text": "已发布"
+ }]
+ },
+ "view_count": {
+ "bsonType": "int",
+ "title": "阅读数量",
+ "description": "阅读数量",
+ "permission": {
+ "write": false
+ }
+ },
+ "like_count": {
+ "bsonType": "int",
+ "description": "喜欢数、点赞数",
+ "permission": {
+ "write": false
+ }
+ },
+ "is_sticky": {
+ "bsonType": "bool",
+ "title": "是否置顶",
+ "description": "是否置顶",
+ "permission": {
+ "write": false
+ }
+ },
+ "is_essence": {
+ "bsonType": "bool",
+ "title": "阅读加精",
+ "description": "阅读加精",
+ "permission": {
+ "write": false
+ }
+ },
+ "comment_status": {
+ "bsonType": "int",
+ "title": "开放评论",
+ "description": "评论状态:0 关闭 1 开放",
+ "enum": [{
+ "value": 0,
+ "text": "关闭"
+ }, {
+ "value": 1,
+ "text": "开放"
+ }]
+ },
+ "comment_count": {
+ "bsonType": "int",
+ "description": "评论数量",
+ "permission": {
+ "write": false
+ }
+ },
+ "last_comment_user_id": {
+ "bsonType": "string",
+ "description": "最后回复用户 id,参考`uni-id-users` 表",
+ "foreignKey": "uni-id-users._id"
+ },
+ "avatar": {
+ "bsonType": "string",
+ "title": "封面大图",
+ "description": "缩略图地址",
+ "label": "封面大图",
+ "trim": "both"
+ },
+ "publish_date": {
+ "bsonType": "timestamp",
+ "title": "发表时间",
+ "description": "发表时间",
+ "defaultValue": {
+ "$env": "now"
+ }
+ },
+ "publish_ip": {
+ "bsonType": "string",
+ "title": "发布文章时IP地址",
+ "description": "发表时 IP 地址",
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ }
+ },
+ "last_modify_date": {
+ "bsonType": "timestamp",
+ "title": "最后修改时间",
+ "description": "最后修改时间",
+ "defaultValue": {
+ "$env": "now"
+ }
+ },
+ "last_modify_ip": {
+ "bsonType": "string",
+ "description": "最后修改时 IP 地址",
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ }
+ },
+ "mode": {
+ "bsonType": "number",
+ "title": "排版显示模式",
+ "description": "排版显示模式,如左图右文、上图下文等"
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-news-categories.schema.json b/uniCloud-aliyun/database/opendb-news-categories.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..976c8a8f4fd0d89c87a28365b8cacafb641b1a95
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-news-categories.schema.json
@@ -0,0 +1,50 @@
+{
+ "bsonType": "object",
+ "required": ["name"],
+ "permission": {
+ "read": true,
+ "create": false,
+ "update": false,
+ "delete": false
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(文章 ID),系统自动生成"
+ },
+ "name": {
+ "bsonType": "string",
+ "description": "类别名称",
+ "label": "名称",
+ "trim": "both"
+ },
+ "description": {
+ "bsonType": "string",
+ "description": "类别描述",
+ "label": "描述",
+ "trim": "both"
+ },
+ "icon": {
+ "bsonType": "string",
+ "description": "类别图标地址",
+ "label": "图标地址",
+ "pattern": "^(http:\/\/|https:\/\/|\/|.\/|@\/)\\S",
+ "trim": "both"
+ },
+ "sort": {
+ "bsonType": "int",
+ "description": "类别显示顺序",
+ "label": "排序"
+ },
+ "article_count": {
+ "bsonType": "int",
+ "description": "该类别下文章数量"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-news-comments.schema.json b/uniCloud-aliyun/database/opendb-news-comments.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..1c0b197f6ba56b59970e3cd4da0baa9a7a73c76a
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-news-comments.schema.json
@@ -0,0 +1,68 @@
+{
+ "bsonType": "object",
+ "required": ["article_id", "user_id", "comment_content", "like_count", "comment_type", "reply_user_id",
+ "reply_comment_id"
+ ],
+ "permission": {
+ "read": true,
+ "create": "auth.uid != null && get(`database.opendb-news-article.${doc.article_id}`).comment_status == 1",
+ "update": "doc.user_id == auth.uid",
+ "delete": "doc.user_id == auth.uid"
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(文章 ID),系统自动生成"
+ },
+ "article_id": {
+ "bsonType": "string",
+ "description": "文章ID,opendb-news-posts 表中的`_id`字段",
+ "foreignKey": "opendb-news-articles._id"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "评论者ID,参考`uni-id-users` 表",
+ "forceDefaultValue": {
+ "$env": "uid"
+ },
+ "foreignKey": "uni-id-users._id"
+ },
+ "comment_content": {
+ "bsonType": "string",
+ "description": "评论内容",
+ "title": "评论内容",
+ "trim": "right"
+ },
+ "like_count": {
+ "bsonType": "int",
+ "description": "评论喜欢数、点赞数"
+ },
+ "comment_type": {
+ "bsonType": "int",
+ "description": "回复类型: 0 针对文章的回复 1 针对评论的回复"
+ },
+ "reply_user_id": {
+ "bsonType": "string",
+ "description": "被回复的评论用户ID,comment_type为1时有效",
+ "foreignKey": "uni-id-users._id"
+ },
+ "reply_comment_id": {
+ "bsonType": "string",
+ "description": "被回复的评论ID,comment_type为1时有效",
+ "foreignKey": "opendb-news-comments._id"
+ },
+ "comment_date": {
+ "bsonType": "timestamp",
+ "description": "评论发表时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ },
+ "comment_ip": {
+ "bsonType": "string",
+ "description": "评论发表时 IP 地址",
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-news-favorite.schema.json b/uniCloud-aliyun/database/opendb-news-favorite.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..a4034f17042a1d855c256dab5761e4b34f59f007
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-news-favorite.schema.json
@@ -0,0 +1,46 @@
+{
+ "bsonType": "object",
+ "required": ["user_id", "article_id"],
+ "permission": {
+ "read": "doc.user_id == auth.uid",
+ "create": "auth.uid != null",
+ "update": "doc.user_id == auth.uid",
+ "delete": "doc.user_id == auth.uid"
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "article_id": {
+ "bsonType": "string",
+ "description": "文章id,参考opendb-news-articles表",
+ "foreignKey": "opendb-news-articles._id"
+ },
+ "article_title": {
+ "bsonType": "string",
+ "description": "文章标题"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "收藏者id,参考uni-id-users表",
+ "forceDefaultValue": {
+ "$env": "uid"
+ },
+ "foreignKey": "uni-id-users._id"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "收藏时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ },
+ "update_date": {
+ "bsonType": "timestamp",
+ "description": "更新\/修改时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/opendb-search-hot.schema.json b/uniCloud-aliyun/database/opendb-search-hot.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..1230be4c8bd443f26ab8136c69854dfe47d27e03
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-search-hot.schema.json
@@ -0,0 +1,27 @@
+{
+ "bsonType": "object",
+ "permission": {
+ "create": false,
+ "delete": false,
+ "read": true,
+ "update": false
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "content": {
+ "bsonType": "string",
+ "description": "搜索内容"
+ },
+ "count": {
+ "bsonType": "long",
+ "description": "搜索次数"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "统计时间"
+ }
+ },
+ "required": ["content", "count"]
+}
diff --git a/uniCloud-aliyun/database/opendb-search-log.schema.json b/uniCloud-aliyun/database/opendb-search-log.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..421ee8c0aa01062fcd3cc86ccffe00bbb2b32cab
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-search-log.schema.json
@@ -0,0 +1,31 @@
+{
+ "bsonType": "object",
+ "permission": {
+ "create": true,
+ "delete": false,
+ "read": false,
+ "update": false
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "content": {
+ "bsonType": "string",
+ "description": "搜索内容"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "统计时间"
+ },
+ "device_id": {
+ "bsonType": "string",
+ "description": "设备id"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "收藏者id,参考uni-id-users表"
+ }
+ },
+ "required": ["content"]
+}
diff --git a/uniCloud-aliyun/database/opendb-verify-codes.schema.json b/uniCloud-aliyun/database/opendb-verify-codes.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..50c27c6ae3cc4e90e90eede4d9ea1cd02385c8e9
--- /dev/null
+++ b/uniCloud-aliyun/database/opendb-verify-codes.schema.json
@@ -0,0 +1,45 @@
+{
+ "bsonType": "object",
+ "required": [],
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "mobile": {
+ "bsonType": "string",
+ "description": "手机号码"
+ },
+ "email": {
+ "bsonType": "string",
+ "description": "邮箱"
+ },
+ "device_uuid": {
+ "bsonType": "string",
+ "description": "设备UUID,常用于图片验证码"
+ },
+ "code": {
+ "bsonType": "string",
+ "description": "验证码"
+ },
+ "scene": {
+ "bsonType": "string",
+ "description": "使用验证码的场景,如:login, bind, unbind, pay"
+ },
+ "state": {
+ "bsonType": "int",
+ "description": "验证状态:0 未验证、1 已验证、2 已作废"
+ },
+ "ip": {
+ "bsonType": "string",
+ "description": "请求时客户端IP地址"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间"
+ },
+ "expired_date": {
+ "bsonType": "timestamp",
+ "description": "过期时间"
+ }
+ }
+}
\ No newline at end of file
diff --git a/uniCloud-aliyun/database/read-news-log.schema.json b/uniCloud-aliyun/database/read-news-log.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..1cbd342af01ef11e4c2a4fec86e8da5e7e2385c6
--- /dev/null
+++ b/uniCloud-aliyun/database/read-news-log.schema.json
@@ -0,0 +1,35 @@
+{
+ "bsonType": "object",
+ "required": ["user_id", "article_id"],
+ "permission": {
+ "read": "doc.user_id == auth.uid",
+ "create": "auth.uid != null",
+ "update": "doc.user_id == auth.uid"
+ //"delete": "doc.user_id == auth.uid"
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "article_id": {
+ "bsonType": "string",
+ "description": "文章id,参考opendb-news-articles表",
+ "foreignKey": "opendb-news-articles._id"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "收藏者id,参考uni-id-users表",
+ "forceDefaultValue": {
+ "$env": "uid"
+ },
+ "foreignKey": "uni-id-users._id"
+ },
+ "last_time": { //设计策略是多次看同一个文章只做一次记录,重复看的文章时间更新为当前时间
+ "bsonType": "timestamp",
+ "description": "最后一次看的时间",
+ "defaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/uni-id-device.schema.json b/uniCloud-aliyun/database/uni-id-device.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..483a7852ddd886366a2640e18e778044b677158b
--- /dev/null
+++ b/uniCloud-aliyun/database/uni-id-device.schema.json
@@ -0,0 +1,64 @@
+{
+ "bsonType": "object",
+ "required": ["user_id"],
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "用户id,参考uni-id-users表"
+ },
+ "ua": {
+ "bsonType": "string",
+ "description": "userAgent"
+ },
+ "uuid": {
+ "bsonType": "string",
+ "description": "设备唯一标识(需要加密存储)"
+ },
+ "vendor": {
+ "bsonType": "string",
+ "description": "设备厂商"
+ },
+ "push_clientid": {
+ "bsonType": "string",
+ "description": "推送设备客户端标识"
+ },
+ "imei": {
+ "bsonType": "string",
+ "description": "国际移动设备识别码IMEI(International Mobile Equipment Identity)"
+ },
+ "oaid": {
+ "bsonType": "string",
+ "description": "移动智能设备标识公共服务平台提供的匿名设备标识符(OAID)"
+ },
+ "idfa": {
+ "bsonType": "string",
+ "description": "iOS平台配置应用使用广告标识(IDFA)"
+ },
+ "model": {
+ "bsonType": "string",
+ "description": "设备型号"
+ },
+ "platform": {
+ "bsonType": "string",
+ "description": "平台类型"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ },
+ "last_active_date": {
+ "bsonType": "timestamp",
+ "description": "最后登录时间"
+ },
+ "last_active_ip": {
+ "bsonType": "string",
+ "description": "最后登录IP"
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/uni-id-log.schema.json b/uniCloud-aliyun/database/uni-id-log.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..086432acee206583e54003c22eef62d377a510c5
--- /dev/null
+++ b/uniCloud-aliyun/database/uni-id-log.schema.json
@@ -0,0 +1,41 @@
+{
+ "bsonType": "object",
+ "required": ["user_id"],
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "用户id,参考uni-id-users表"
+ },
+ "ua": {
+ "bsonType": "string",
+ "description": "userAgent"
+ },
+ "device_uuid": {
+ "bsonType": "string",
+ "description": "设备唯一标识(需要加密存储)"
+ },
+ "type": {
+ "bsonType": "string",
+ "enum": ["login", "logout"],
+ "description": "登录类型"
+ },
+ "state": {
+ "bsonType": "int",
+ "description": "结果:0 失败、1 成功"
+ },
+ "ip": {
+ "bsonType": "string",
+ "description": "ip地址"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/uni-id-permissions.schema.json b/uniCloud-aliyun/database/uni-id-permissions.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..f0ddc99de8928df2446b125155406c4f86f043f1
--- /dev/null
+++ b/uniCloud-aliyun/database/uni-id-permissions.schema.json
@@ -0,0 +1,46 @@
+{
+ "bsonType": "object",
+ "required": ["permission_id", "permission_name"],
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID,系统自动生成"
+ },
+ "permission_id": {
+ "bsonType": "string",
+ "description": "权限唯一标识,不可修改,不允许重复",
+ "label": "权限标识",
+ "trim": "both",
+ "title": "权限ID",
+ "component": {
+ "name": "input"
+ }
+ },
+ "permission_name": {
+ "bsonType": "string",
+ "description": "权限名称",
+ "label": "权限名称",
+ "title": "权限名称",
+ "trim": "both",
+ "component": {
+ "name": "input"
+ }
+ },
+ "comment": {
+ "bsonType": "string",
+ "description": "备注",
+ "label": "备注",
+ "title": "备注",
+ "trim": "both",
+ "component": {
+ "name": "textarea"
+ }
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/uni-id-roles.schema.json b/uniCloud-aliyun/database/uni-id-roles.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..9802441517783dbd906fafa8e01c3c5a607184c5
--- /dev/null
+++ b/uniCloud-aliyun/database/uni-id-roles.schema.json
@@ -0,0 +1,46 @@
+{
+ "bsonType": "object",
+ "required": ["role_id"],
+ "permission": {
+ "read": false,
+ "create": false,
+ "update": false,
+ "delete": false
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID,系统自动生成"
+ },
+ "role_id": {
+ "title": "唯一ID",
+ "bsonType": "string",
+ "description": "角色唯一标识,不可修改,不允许重复",
+ "trim": "both"
+ },
+ "role_name": {
+ "title": "名称",
+ "bsonType": "string",
+ "description": "角色名称",
+ "trim": "both"
+ },
+ "permission": {
+ "title": "权限",
+ "bsonType": "array",
+ "foreignKey": "uni-id-permissions.permission_id",
+ "description": "角色拥有的权限列表"
+ },
+ "comment": {
+ "title": "备注",
+ "bsonType": "string",
+ "description": "备注",
+ "trim": "both"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/uni-id-scores.schema.json b/uniCloud-aliyun/database/uni-id-scores.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..0e2a7f6587fe90bde952a7dc5565593d96661689
--- /dev/null
+++ b/uniCloud-aliyun/database/uni-id-scores.schema.json
@@ -0,0 +1,44 @@
+{
+ "bsonType": "object",
+ "required": ["user_id", "score", "balance"],
+ "permission": {
+ "read": "doc.user_id == auth.uid",
+ "create": false,
+ "update": false,
+ "delete": false
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "用户id,参考uni-id-users表"
+ },
+ "score": {
+ "bsonType": "int",
+ "description": "本次变化的积分"
+ },
+ "type": {
+ "bsonType": "int",
+ "enum": [1, 2],
+ "description": "积分类型 1:收入 2:支出"
+ },
+ "balance": {
+ "bsonType": "int",
+ "description": "变化后的积分余额"
+ },
+ "comment": {
+ "bsonType": "string",
+ "description": "备注,说明积分新增、消费的缘由",
+ "trim": "both"
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "description": "创建时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ }
+ }
+}
diff --git a/uniCloud-aliyun/database/uni-id-users.schema.json b/uniCloud-aliyun/database/uni-id-users.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..a75e9cb9eaf852d4bd5974a2566e0195216028ea
--- /dev/null
+++ b/uniCloud-aliyun/database/uni-id-users.schema.json
@@ -0,0 +1,366 @@
+{
+ "bsonType": "object",
+ "permission":{
+ "read":true,
+ "update":"doc._id == auth.uid"
+ },
+ "required": [],
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(用户 ID),系统自动生成"
+ },
+ "username": {
+ "bsonType": "string",
+ "title": "用户名",
+ "description": "用户名,不允许重复",
+ "trim": "both",
+ "permission":{
+ "write":false
+ }
+ },
+ "password": {
+ "bsonType": "password",
+ "title": "密码",
+ "description": "密码,加密存储",
+ "trim": "both",
+ "permission":{
+ "write":false
+ }
+ },
+ "password_secret_version": {
+ "bsonType": "int",
+ "title": "passwordSecret",
+ "description": "密码使用的passwordSecret版本",
+ "permission":{
+ "write":false
+ }
+ },
+ "nickname": {
+ "bsonType": "string",
+ "title": "昵称",
+ "description": "用户昵称",
+ "trim": "both"
+ },
+ "gender": {
+ "bsonType": "int",
+ "title": "性别",
+ "description": "用户性别:0 未知 1 男性 2 女性",
+ "defaultValue": 0,
+ "enum": [{
+ "text": "未知",
+ "value": 0
+ },
+ {
+ "text": "男",
+ "value": 1
+ },
+ {
+ "text": "女",
+ "value": 2
+ }
+ ]
+ },
+ "status": {
+ "bsonType": "int",
+ "description": "用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝",
+ "title": "用户状态",
+ "defaultValue": 0,
+ "permission":{
+ "write":false
+ },
+ "enum": [{
+ "text": "正常",
+ "value": 0
+ },
+ {
+ "text": "禁用",
+ "value": 1
+ },
+ {
+ "text": "审核中",
+ "value": 2
+ },
+ {
+ "text": "审核拒绝",
+ "value": 3
+ }
+ ]
+ },
+ "mobile": {
+ "bsonType": "string",
+ "title": "手机号码",
+ "description": "手机号码",
+ "pattern": "^\\+?[0-9-]{3,20}$",
+ "trim": "both",
+ "permission":{
+ "write":false
+ }
+ },
+ "mobile_confirmed": {
+ "bsonType": "int",
+ "description": "手机号验证状态:0 未验证 1 已验证",
+ "title": "手机号验证状态",
+ "defaultValue": 0,
+ "enum": [{
+ "text": "未验证",
+ "value": 0
+ },
+ {
+ "text": "已验证",
+ "value": 1
+ }
+ ],
+ "permission":{
+ "write":false
+ }
+ },
+ "email": {
+ "bsonType": "string",
+ "format": "email",
+ "title": "邮箱",
+ "description": "邮箱地址",
+ "trim": "both",
+ "permission":{
+ "write":false
+ }
+ },
+ "email_confirmed": {
+ "bsonType": "int",
+ "description": "邮箱验证状态:0 未验证 1 已验证",
+ "title": "邮箱验证状态",
+ "defaultValue": 0,
+ "enum": [{
+ "text": "未验证",
+ "value": 0
+ },
+ {
+ "text": "已验证",
+ "value": 1
+ }
+ ],
+ "permission":{
+ "write":false
+ }
+ },
+ "avatar": {
+ "bsonType": "string",
+ "title": "头像地址",
+ "description": "头像地址",
+ "trim": "both"
+ },
+ "avatar_file": {
+ "bsonType": "file",
+ "title": "头像文件",
+ "description": "用file类型方便使用uni-file-picker组件"
+ },
+ "department_id": {
+ "bsonType": "array",
+ "description": "部门ID",
+ "permission":{
+ "write":false
+ },
+ "title": "部门",
+ "enumType": "tree",
+ "enum": {
+ "collection": "opendb-department",
+ "orderby": "name asc",
+ "field": "_id as value, name as text"
+ }
+ },
+ "role": {
+ "bsonType": "array",
+ "title": "角色",
+ "description": "用户角色",
+ "enum": {
+ "collection": "uni-id-roles",
+ "field": "role_id as value, role_name as text"
+ },
+ "foreignKey": "uni-id-roles.role_id",
+ "permission": {
+ "write": false
+ }
+ },
+ "wx_unionid": {
+ "bsonType": "string",
+ "description": "微信unionid",
+ "permission":{
+ "write":false
+ }
+ },
+ "wx_openid": {
+ "bsonType": "object",
+ "description": "微信各个平台openid",
+ "properties": {
+ "app-plus": {
+ "bsonType": "string",
+ "description": "app平台微信openid"
+ },
+ "mp-weixin": {
+ "bsonType": "string",
+ "description": "微信小程序平台openid"
+ }
+ },
+ "permission":{
+ "write":false
+ }
+ },
+ "ali_openid": {
+ "bsonType": "string",
+ "description": "支付宝平台openid",
+ "permission":{
+ "write":false
+ }
+ },
+ "apple_openid": {
+ "bsonType": "string",
+ "description": "苹果登录openid",
+ "permission":{
+ "write":false
+ }
+ },
+ "comment": {
+ "bsonType": "string",
+ "title": "备注",
+ "description": "备注",
+ "trim": "both",
+ "permission":{
+ "write":false
+ }
+ },
+ "realname_auth": {
+ "bsonType": "object",
+ "description": "实名认证信息",
+ "required": [
+ "type",
+ "auth_status"
+ ],
+ "permission":{
+ "write":false
+ },
+ "properties": {
+ "type": {
+ "bsonType": "int",
+ "minimum": 0,
+ "maximum": 1,
+ "description": "用户类型:0 个人用户 1 企业用户"
+ },
+ "auth_status": {
+ "bsonType": "int",
+ "minimum": 0,
+ "maximum": 3,
+ "description": "认证状态:0 未认证 1 等待认证 2 认证通过 3 认证失败"
+ },
+ "auth_date": {
+ "bsonType": "timestamp",
+ "description": "认证通过时间"
+ },
+ "real_name": {
+ "bsonType": "string",
+ "description": "真实姓名/企业名称"
+ },
+ "identity": {
+ "bsonType": "string",
+ "description": "身份证号码/营业执照号码"
+ },
+ "id_card_front": {
+ "bsonType": "string",
+ "description": "身份证正面照 URL"
+ },
+ "id_card_back": {
+ "bsonType": "string",
+ "description": "身份证反面照 URL"
+ },
+ "in_hand": {
+ "bsonType": "string",
+ "description": "手持身份证照片 URL"
+ },
+ "license": {
+ "bsonType": "string",
+ "description": "营业执照 URL"
+ },
+ "contact_person": {
+ "bsonType": "string",
+ "description": "联系人姓名"
+ },
+ "contact_mobile": {
+ "bsonType": "string",
+ "description": "联系人手机号码"
+ },
+ "contact_email": {
+ "bsonType": "string",
+ "description": "联系人邮箱"
+ }
+ }
+ },
+ "score": {
+ "bsonType": "int",
+ "description": "用户积分,积分变更记录可参考:uni-id-scores表定义",
+ "permission":{
+ "write":false
+ }
+ },
+ "register_date": {
+ "bsonType": "timestamp",
+ "description": "注册时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ },
+ "permission":{
+ "write":false
+ }
+ },
+ "register_ip": {
+ "bsonType": "string",
+ "description": "注册时 IP 地址",
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ },
+ "permission":{
+ "write":false
+ }
+ },
+ "last_login_date": {
+ "bsonType": "timestamp",
+ "description": "最后登录时间",
+ "permission":{
+ "write":false
+ }
+ },
+ "last_login_ip": {
+ "bsonType": "string",
+ "description": "最后登录时 IP 地址",
+ "permission":{
+ "write":false
+ }
+ },
+ "token": {
+ "bsonType": "array",
+ "description": "用户token",
+ "permission":{
+ "write":false
+ }
+ },
+ "inviter_uid": {
+ "bsonType": "array",
+ "description": "用户全部上级邀请者",
+ "trim": "both",
+ "permission":{
+ "write":false
+ }
+ },
+ "invite_time": {
+ "bsonType": "timestamp",
+ "description": "受邀时间",
+ "permission":{
+ "write":false
+ }
+ },
+ "my_invite_code": {
+ "bsonType": "string",
+ "description": "用户自身邀请码",
+ "permission":{
+ "write":false
+ }
+ }
+ }
+}
diff --git a/uni_modules.config.json b/uni_modules.config.json
new file mode 100644
index 0000000000000000000000000000000000000000..ebabb75f3953edb8ebb2b78a440765f627301409
--- /dev/null
+++ b/uni_modules.config.json
@@ -0,0 +1,6 @@
+{
+ "scripts": {
+ "preupload": "node uni_modules_tools/main.js change",
+ "postupload": "node uni_modules_tools/main.js recovery"
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/json-gps/changelog.md b/uni_modules/json-gps/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..d9847e2e43455e00468d589f6414667bc097c4c4
--- /dev/null
+++ b/uni_modules/json-gps/changelog.md
@@ -0,0 +1,2 @@
+## 1.0.0(2021-07-12)
+第一版发布
diff --git a/uni_modules/json-gps/js_sdk/gps.js b/uni_modules/json-gps/js_sdk/gps.js
new file mode 100644
index 0000000000000000000000000000000000000000..34bd0e819f86465066099a7f1688fbc4ff0394d9
--- /dev/null
+++ b/uni_modules/json-gps/js_sdk/gps.js
@@ -0,0 +1,133 @@
+// #ifdef APP-PLUS
+import permision from "./wa-permission/permission.js"
+// #endif
+class Gps {
+ constructor(arg) {
+ this.lock = false //锁防止重复请求
+ }
+ async getLocation(param = {
+ type: 'wgs84'
+ }) {
+ return new Promise(async (callback) => {
+ if (this.lock) {
+ // console.log('已锁,已有另一个请求正在执行。无需重复请求');
+ callback(false);
+ return false
+ }
+ this.lock = true //加锁防止重复的请求
+ uni.getLocation({
+ ...param,
+ success: res => {
+ this.lock = false //成功后解锁
+ //console.log(res);
+ callback(res)
+ },
+ fail: async (err) => {
+ uni.showToast({
+ title: '定位获取失败',
+ icon: 'none'
+ });
+ console.error(err)
+ callback(false)
+
+ // #ifdef APP-PLUS
+ await this.checkGpsIsOpen()
+ // #endif
+
+
+ // #ifdef MP-WEIXIN
+ if (err.errMsg == 'getLocation:fail auth deny') {
+ uni.showModal({
+ content: '应用无定位权限',
+ confirmText: '前往设置',
+ complete: (e) => {
+ if (e.confirm) {
+ uni.openSetting({
+ success(res) {
+ console.log(res.authSetting)
+ }
+ });
+ }
+ this.lock = false //解锁让回到界面重新获取
+ }
+ });
+ }
+ if (err.errMsg == 'getLocation:fail:ERROR_NOCELL&WIFI_LOCATIONSWITCHOFF') {
+ uni.showModal({
+ content: '未开启定位权限,请前往手机系统设置中开启',
+ showCancel: false,
+ confirmText:"知道了"
+ });
+ }
+ // #endif
+ }
+ });
+ })
+ }
+ // #ifdef APP-PLUS
+ async checkGpsIsOpen() {
+ this.lock = true //加锁防止重复的请求
+ console.log('检查定位设置开启问题', permision.checkSystemEnableLocation());
+ if (!permision.checkSystemEnableLocation()) {
+ plus.nativeUI.confirm("手机定位权限没有开启,是否去开启?", (e) => {
+ this.lock = false
+ if (e.index == 0) {
+ if (uni.getSystemInfoSync().platform == "ios") {
+ plus.runtime.openURL("app-settings://");
+ } else {
+ var main = plus.android.runtimeMainActivity(); //获取activity
+ var Intent = plus.android.importClass('android.content.Intent');
+ var Settings = plus.android.importClass('android.provider.Settings');
+ var intent = new Intent(Settings
+ .ACTION_LOCATION_SOURCE_SETTINGS); //可设置表中所有Action字段
+ main.startActivity(intent);
+ }
+ } else {
+ uni.showToast({
+ title: '设备无定位权限',
+ icon: 'none'
+ });
+ callback(false)
+ }
+ }, {
+ "buttons": ["去设置", "不开启"],
+ "verticalAlign": "center"
+ });
+ return false
+ }
+ let checkAppGpsRes = await this.checkAppGps()
+ console.log(checkAppGpsRes, 'checkAppGpsRes');
+ if (!checkAppGpsRes) {
+ plus.nativeUI.confirm("应用定位权限没有开启,是否去开启?", (e) => {
+ this.lock = false
+ if (e.index == 0) {
+ permision.gotoAppPermissionSetting()
+ callback(false)
+ } else {
+ uni.showToast({
+ title: '应用无定位权限',
+ icon: 'none'
+ });
+ return false
+ }
+ }, {
+ "buttons": ["去设置", "不开启"],
+ "verticalAlign": "center"
+ });
+ } else {
+ this.lock = false
+ }
+ }
+ async checkAppGps() {
+ if (uni.getSystemInfoSync().platform == "ios" && !permision.judgeIosPermission("location")) {
+ return false
+ }
+ if (uni.getSystemInfoSync().platform != "ios" && await permision.requestAndroidPermission(
+ "android.permission.ACCESS_FINE_LOCATION") != 1) {
+ return false
+ }
+ return true
+ }
+ // #endif
+}
+export default Gps
diff --git a/uni_modules/json-gps/js_sdk/wa-permission/permission.js b/uni_modules/json-gps/js_sdk/wa-permission/permission.js
new file mode 100644
index 0000000000000000000000000000000000000000..501cab45618434cca3c4597682bc9c404d8e18bc
--- /dev/null
+++ b/uni_modules/json-gps/js_sdk/wa-permission/permission.js
@@ -0,0 +1,272 @@
+/**
+ * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
+ */
+
+var isIos
+// #ifdef APP-PLUS
+isIos = (plus.os.name == "iOS")
+// #endif
+
+// 判断推送权限是否开启
+function judgeIosPermissionPush() {
+ var result = false;
+ var UIApplication = plus.ios.import("UIApplication");
+ var app = UIApplication.sharedApplication();
+ var enabledTypes = 0;
+ if (app.currentUserNotificationSettings) {
+ var settings = app.currentUserNotificationSettings();
+ enabledTypes = settings.plusGetAttribute("types");
+ console.log("enabledTypes1:" + enabledTypes);
+ if (enabledTypes == 0) {
+ console.log("推送权限没有开启");
+ } else {
+ result = true;
+ console.log("已经开启推送功能!")
+ }
+ plus.ios.deleteObject(settings);
+ } else {
+ enabledTypes = app.enabledRemoteNotificationTypes();
+ if (enabledTypes == 0) {
+ console.log("推送权限没有开启!");
+ } else {
+ result = true;
+ console.log("已经开启推送功能!")
+ }
+ console.log("enabledTypes2:" + enabledTypes);
+ }
+ plus.ios.deleteObject(app);
+ plus.ios.deleteObject(UIApplication);
+ return result;
+}
+
+// 判断定位权限是否开启
+function judgeIosPermissionLocation() {
+ var result = false;
+ var cllocationManger = plus.ios.import("CLLocationManager");
+ var status = cllocationManger.authorizationStatus();
+ result = (status != 2)
+ console.log("定位权限开启:" + result);
+ // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
+ /* var enable = cllocationManger.locationServicesEnabled();
+ var status = cllocationManger.authorizationStatus();
+ console.log("enable:" + enable);
+ console.log("status:" + status);
+ if (enable && status != 2) {
+ result = true;
+ console.log("手机定位服务已开启且已授予定位权限");
+ } else {
+ console.log("手机系统的定位没有打开或未给予定位权限");
+ } */
+ plus.ios.deleteObject(cllocationManger);
+ return result;
+}
+
+// 判断麦克风权限是否开启
+function judgeIosPermissionRecord() {
+ var result = false;
+ var avaudiosession = plus.ios.import("AVAudioSession");
+ var avaudio = avaudiosession.sharedInstance();
+ var permissionStatus = avaudio.recordPermission();
+ console.log("permissionStatus:" + permissionStatus);
+ if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
+ console.log("麦克风权限没有开启");
+ } else {
+ result = true;
+ console.log("麦克风权限已经开启");
+ }
+ plus.ios.deleteObject(avaudiosession);
+ return result;
+}
+
+// 判断相机权限是否开启
+function judgeIosPermissionCamera() {
+ var result = false;
+ var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
+ var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
+ console.log("authStatus:" + authStatus);
+ if (authStatus == 3) {
+ result = true;
+ console.log("相机权限已经开启");
+ } else {
+ console.log("相机权限没有开启");
+ }
+ plus.ios.deleteObject(AVCaptureDevice);
+ return result;
+}
+
+// 判断相册权限是否开启
+function judgeIosPermissionPhotoLibrary() {
+ var result = false;
+ var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
+ var authStatus = PHPhotoLibrary.authorizationStatus();
+ console.log("authStatus:" + authStatus);
+ if (authStatus == 3) {
+ result = true;
+ console.log("相册权限已经开启");
+ } else {
+ console.log("相册权限没有开启");
+ }
+ plus.ios.deleteObject(PHPhotoLibrary);
+ return result;
+}
+
+// 判断通讯录权限是否开启
+function judgeIosPermissionContact() {
+ var result = false;
+ var CNContactStore = plus.ios.import("CNContactStore");
+ var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
+ if (cnAuthStatus == 3) {
+ result = true;
+ console.log("通讯录权限已经开启");
+ } else {
+ console.log("通讯录权限没有开启");
+ }
+ plus.ios.deleteObject(CNContactStore);
+ return result;
+}
+
+// 判断日历权限是否开启
+function judgeIosPermissionCalendar() {
+ var result = false;
+ var EKEventStore = plus.ios.import("EKEventStore");
+ var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
+ if (ekAuthStatus == 3) {
+ result = true;
+ console.log("日历权限已经开启");
+ } else {
+ console.log("日历权限没有开启");
+ }
+ plus.ios.deleteObject(EKEventStore);
+ return result;
+}
+
+// 判断备忘录权限是否开启
+function judgeIosPermissionMemo() {
+ var result = false;
+ var EKEventStore = plus.ios.import("EKEventStore");
+ var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
+ if (ekAuthStatus == 3) {
+ result = true;
+ console.log("备忘录权限已经开启");
+ } else {
+ console.log("备忘录权限没有开启");
+ }
+ plus.ios.deleteObject(EKEventStore);
+ return result;
+}
+
+// Android权限查询
+function requestAndroidPermission(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);
+ // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
+ // if (result != 1) {
+ // gotoAppPermissionSetting()
+ // }
+ },
+ function(error) {
+ console.log('申请权限错误:' + error.code + " = " + error.message);
+ resolve({
+ code: error.code,
+ message: error.message
+ });
+ }
+ );
+ });
+}
+
+// 使用一个方法,根据参数判断权限
+function judgeIosPermission(permissionID) {
+ if (permissionID == "location") {
+ return judgeIosPermissionLocation()
+ } else if (permissionID == "camera") {
+ return judgeIosPermissionCamera()
+ } else if (permissionID == "photoLibrary") {
+ return judgeIosPermissionPhotoLibrary()
+ } else if (permissionID == "record") {
+ return judgeIosPermissionRecord()
+ } else if (permissionID == "push") {
+ return judgeIosPermissionPush()
+ } else if (permissionID == "contact") {
+ return judgeIosPermissionContact()
+ } else if (permissionID == "calendar") {
+ return judgeIosPermissionCalendar()
+ } else if (permissionID == "memo") {
+ return judgeIosPermissionMemo()
+ }
+ return false;
+}
+
+// 跳转到**应用**的权限页面
+function gotoAppPermissionSetting() {
+ if (isIos) {
+ var UIApplication = plus.ios.import("UIApplication");
+ var application2 = UIApplication.sharedApplication();
+ var NSURL2 = plus.ios.import("NSURL");
+ // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");
+ var setting2 = NSURL2.URLWithString("app-settings:");
+ application2.openURL(setting2);
+
+ plus.ios.deleteObject(setting2);
+ plus.ios.deleteObject(NSURL2);
+ plus.ios.deleteObject(application2);
+ } else {
+ // console.log(plus.device.vendor);
+ 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);
+ }
+}
+
+// 检查系统的设备服务是否开启
+// var checkSystemEnableLocation = async function () {
+function checkSystemEnableLocation() {
+ if (isIos) {
+ var result = false;
+ var cllocationManger = plus.ios.import("CLLocationManager");
+ var result = cllocationManger.locationServicesEnabled();
+ console.log("系统定位开启:" + result);
+ plus.ios.deleteObject(cllocationManger);
+ return result;
+ } else {
+ var context = plus.android.importClass("android.content.Context");
+ var locationManager = plus.android.importClass("android.location.LocationManager");
+ var main = plus.android.runtimeMainActivity();
+ var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
+ var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
+ console.log("系统定位开启:" + result);
+ return result
+ }
+}
+
+export default {
+ judgeIosPermission: judgeIosPermission,
+ requestAndroidPermission: requestAndroidPermission,
+ checkSystemEnableLocation: checkSystemEnableLocation,
+ gotoAppPermissionSetting: gotoAppPermissionSetting
+}
diff --git a/uni_modules/json-gps/package.json b/uni_modules/json-gps/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..3689121274d939b689de3d8e841da4b65fdb83fe
--- /dev/null
+++ b/uni_modules/json-gps/package.json
@@ -0,0 +1,76 @@
+{
+ "id": "json-gps",
+ "displayName": "地理位置获取方法,支持在onShow生命周期使用集成权限判断和引导开启(包括设备权限和应用权限)",
+ "version": "1.0.0",
+ "description": "支持在onShow生命周期使用集成权限判断和引导开启(包括设备权限和应用权限)的地理位置获取方法",
+ "keywords": [
+ "权限引导"
+],
+ "repository": "",
+ "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": ""
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "u",
+ "Android Browser": "u",
+ "微信浏览器(Android)": "u",
+ "QQ浏览器(Android)": "u"
+ },
+ "H5-pc": {
+ "Chrome": "u",
+ "IE": "u",
+ "Edge": "u",
+ "Firefox": "u",
+ "Safari": "u"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/json-gps/readme.md b/uni_modules/json-gps/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..739335fc233a750753ffc013ab9a96688de68c42
--- /dev/null
+++ b/uni_modules/json-gps/readme.md
@@ -0,0 +1,30 @@
+### 插件简介:
+支持在onShow生命周期,使用的集成权限判断和引导开启(包括设备权限和应用权限)的地理位置获取方法
+
+### 插件背景:
+实现获取用户地理位置,当手机未开启定位模块或应用无定位权限时,引导用户前往手机系统或应用权限设置页面。设置完回到应用界面自动重新获取。
+为了实现该效果,开发者把获取定位权限放在onShow生命周期,然而即使是原生开发,调用判断设备权限操作也会触发onShow生命周期,直接使用会导致死循环。因此本插件,二次封装用锁的方式控制该问题。
+
+### 使用方式
+```js
+import Gps from '@/uni_modules/json-gps/js_sdk/gps.js';
+const gps = new Gps()
+export default {
+ async onShow() {
+ uni.showLoading({
+ title:"获取定位中"
+ });
+ let location = await gps.getLocation()
+ console.log(location);
+ if(location){
+ uni.showToast({
+ title: JSON.stringify(location),
+ icon: 'none'
+ });
+ }
+ uni.hideLoading()
+ }
+}
+```
+
+>本插件基于第三方插件:[App权限判断和提示](https://ext.dcloud.net.cn/plugin?id=594)二次封装而成
\ No newline at end of file
diff --git a/uni_modules/json-interceptor-chooseImage/changelog.md b/uni_modules/json-interceptor-chooseImage/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..512bce81867403f5638af728a1d30982e9537e7f
--- /dev/null
+++ b/uni_modules/json-interceptor-chooseImage/changelog.md
@@ -0,0 +1,6 @@
+## 1.0.2(2021-05-20)
+修复IOS提示不准确,无摄像头权限提示了无法访问相册
+## 1.0.1(2021-05-20)
+新增文档和示例代码
+## 1.0.0(2021-05-20)
+第一版本发布
diff --git a/uni_modules/json-interceptor-chooseImage/js_sdk/main.js b/uni_modules/json-interceptor-chooseImage/js_sdk/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cf7bc605d189d68764b0b4251bed83e76496e1a
--- /dev/null
+++ b/uni_modules/json-interceptor-chooseImage/js_sdk/main.js
@@ -0,0 +1,70 @@
+export default function(){
+ //当应用无访问摄像头/相册权限,引导跳到设置界面
+ uni.addInterceptor('chooseImage', {
+ fail(e) { // 失败回调拦截 更多拦截器用法 [详情](https://uniapp.dcloud.io/api/interceptor?id=addinterceptor)
+ console.log(e);
+ if (uni.getSystemInfoSync().platform == "android" && e.errMsg == 'chooseImage:fail No Permission') {
+ if (e.code === 11) {
+ uni.showModal({
+ title: "无法访问摄像头",
+ content: "当前无摄像头访问权限,建议前往设置",
+ confirmText: "前往设置",
+ success(e) {
+ if (e.confirm) {
+ gotoAppPermissionSetting()
+ }
+ }
+ });
+ } else {
+ uni.showModal({
+ title: "无法访问相册",
+ content: "当前无系统相册访问权限,建议前往设置",
+ confirmText: "前往设置",
+ success(e) {
+ if (e.confirm) {
+ gotoAppPermissionSetting()
+ }
+ }
+ });
+ }
+ } else if (e.errCode === 2&&e.errMsg == "chooseImage:fail No filming permission") {
+ console.log('e.errMsg === 2 ios无法拍照权限 ');
+ // 注:e.errCode === 8 ios无从相册选择图片的权限 api已内置无需自己用拦截器实现
+ uni.showModal({
+ title: "无法访问摄像头",
+ content: "当前无摄像头访问权限,建议前往设置",
+ confirmText: "前往设置",
+ success(e) {
+ if (e.confirm) {
+ gotoAppPermissionSetting()
+ }
+ }
+ });
+ }
+ }
+ })
+
+ //跳转到**应用**的权限页面 参考来源:https://ext.dcloud.net.cn/plugin?id=594
+ function gotoAppPermissionSetting() {
+ if (uni.getSystemInfoSync().platform == "ios") {
+ 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/json-interceptor-chooseImage/package.json b/uni_modules/json-interceptor-chooseImage/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9b81e6a1209db4fe0c6f32e101f0ee124cf83367
--- /dev/null
+++ b/uni_modules/json-interceptor-chooseImage/package.json
@@ -0,0 +1,76 @@
+{
+ "id": "json-interceptor-chooseImage",
+ "displayName": "拦截器应用示例 — 图片选择",
+ "version": "1.0.2",
+ "description": "当选择图片遇到权限问题时引导用户快捷打开系统设置",
+ "keywords": [
+ "interceptor,拦截器,相册权限"
+],
+ "repository": "",
+ "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": ""
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "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"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/json-interceptor-chooseImage/readme.md b/uni_modules/json-interceptor-chooseImage/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..e9d98fb956397d004d17975bd05fd64d00624f85
--- /dev/null
+++ b/uni_modules/json-interceptor-chooseImage/readme.md
@@ -0,0 +1,30 @@
+拦截器顾名思义,是在框架方法执行的各个环节(包含:拦截前触发、成功回调拦截、失败回调拦截、完成回调拦截)
+插入逻辑,篡改参数或终止运行。
+#### 优势
+- 这种方式相当于改写了api的内部逻辑,相比语法糖他更加直观,不影响ide的代码提示。
+- 将常规固定的逻辑封装到框架的api内,且支持个性化设计。如你可以在本插件路径:`/uni_modules/json-interceptor-chooseImage/js_sdk/main.js`修改弹出框元素,绘制更漂亮的样式和文字说明。
+
+#### 使用示例,App.vue页代码如下:
+```
+
+```
+
+> 跳转到**应用**的权限页面 参考来源:[https://ext.dcloud.net.cn/plugin?id=594](https://ext.dcloud.net.cn/plugin?id=594) 感谢作者@DCloud_heavensoft
diff --git a/uni_modules/uni-badge/changelog.md b/uni_modules/uni-badge/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..4ca8c5b477a3f996a515460a986c96c6bf63d4ef
--- /dev/null
+++ b/uni_modules/uni-badge/changelog.md
@@ -0,0 +1,22 @@
+## 1.1.6(2021-09-22)
+- 修复 在字节小程序上样式不生效的 bug
+## 1.1.5(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.4(2021-07-29)
+- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
+## 1.1.3(2021-06-24)
+- 优化 示例项目
+## 1.1.1(2021-05-12)
+- 新增 组件示例地址
+## 1.1.0(2021-05-12)
+- 新增 uni-badge 的 absolute 属性,支持定位
+- 新增 uni-badge 的 offset 属性,支持定位偏移
+- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
+- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
+- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
+## 1.0.7(2021-05-07)
+- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
+- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
+- 新增 uni-badge 属性 custom-style, 支持自定义样式
+## 1.0.6(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-badge/components/uni-badge/uni-badge.vue b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f3869c481ec5f1547e41d3cf3d2dc1c9ce5b0f22
--- /dev/null
+++ b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue
@@ -0,0 +1,253 @@
+
+
+
+ {{displayValue}}
+
+
+
+
+
+
diff --git a/uni_modules/uni-badge/package.json b/uni_modules/uni-badge/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4efafd509b3489e15a5081e838f51456acfbb9a4
--- /dev/null
+++ b/uni_modules/uni-badge/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-badge",
+ "displayName": "uni-badge 数字角标",
+ "version": "1.1.6",
+ "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
+ "keywords": [
+ "",
+ "badge",
+ "uni-ui",
+ "uniui",
+ "数字角标",
+ "徽章"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-badge/readme.md b/uni_modules/uni-badge/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..d29680be1c2da3d0e6ad943e41568f7d1161fc84
--- /dev/null
+++ b/uni_modules/uni-badge/readme.md
@@ -0,0 +1,58 @@
+
+
+## Badge 数字角标
+> **组件名:uni-badge**
+> 代码块: `uBadge`
+
+
+数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+ 右上
+
+
+
+
+
+```
+
+
+## API
+
+### Badge Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|text |String |- |角标内容 |
+|type |String |default|颜色类型,可选值:default(灰色)、primary(蓝色)、success(绿色)、warning(黄色)、error(红色)|
+|size |String |normal |Badge 大小,可取值:normal、small |
+|is-dot |Boolean|false |不展示数字,只有一个小点 |
+|max-num |String/Numbuer|99 |展示封顶的数字值,超过 99 显示99+ |
+|custom-style |Object | {} |自定义 Badge 样式, 样式对象语法 |
+|inverted |Boolean|false |是否无需背景颜色,为 true 时,背景颜色将变为文字的字体颜色 |
+|absolute (不支持 nvue) |String| rightTop|开启绝对定位, 角标将定位到其包裹的标签的四个角上,可选值: rightTop(右上角)、rightBottom(右下角)、leftBottom(左下角) 、leftTop(左上角) |
+|offset |Array[number]| [0, 0]|距定位角中心点的偏移量,[-10, -10] 表示向 absolute 指定的方向偏移 10px,[10, 10] 表示向 absolute 指定的反方向偏移 10px,只有存在 absolute 属性时有效,与absolute 的值一一对应(例如:值为rightTop, 对应 offset 为 [right, Top])|
+
+### Badge Events
+
+|事件名 |事件说明 |返回参数 |
+|:-: |:-: |:-: |
+|@click |点击 Badge 触发事件| - |
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge](https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge)
\ No newline at end of file
diff --git a/uni_modules/uni-calendar/changelog.md b/uni_modules/uni-calendar/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..bd8974992c1e97a734e1c3ae9d251d9025f483e0
--- /dev/null
+++ b/uni_modules/uni-calendar/changelog.md
@@ -0,0 +1,10 @@
+## 1.4.2(2021-08-24)
+- 新增 支持国际化
+## 1.4.1(2021-08-05)
+- 修复 弹出层被 tabbar 遮盖 bug
+## 1.4.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.3.16(2021-05-12)
+- 新增 组件示例地址
+## 1.3.15(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-calendar/components/uni-calendar/calendar.js b/uni_modules/uni-calendar/components/uni-calendar/calendar.js
new file mode 100644
index 0000000000000000000000000000000000000000..b8d7d6fc44038901fe7a47def32b53764575c1a8
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/calendar.js
@@ -0,0 +1,546 @@
+/**
+* @1900-2100区间内的公历、农历互转
+* @charset UTF-8
+* @github https://github.com/jjonline/calendar.js
+* @Author Jea杨(JJonline@JJonline.Cn)
+* @Time 2014-7-21
+* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
+* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
+* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
+* @Version 1.0.3
+* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
+* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
+*/
+/* eslint-disable */
+var calendar = {
+
+ /**
+ * 农历1900-2100的润大小信息表
+ * @Array Of Property
+ * @return Hex
+ */
+ lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
+ 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
+ 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
+ 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
+ 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
+ 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
+ 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
+ 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
+ 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
+ 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
+ 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
+ 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
+ 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
+ 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
+ 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
+ /** Add By JJonline@JJonline.Cn**/
+ 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
+ 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
+ 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
+ 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
+ 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
+ 0x0d520], // 2100
+
+ /**
+ * 公历每个月份的天数普通表
+ * @Array Of Property
+ * @return Number
+ */
+ solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+ /**
+ * 天干地支之天干速查表
+ * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
+ * @return Cn string
+ */
+ Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
+
+ /**
+ * 天干地支之地支速查表
+ * @Array Of Property
+ * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
+ * @return Cn string
+ */
+ Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
+
+ /**
+ * 天干地支之地支速查表<=>生肖
+ * @Array Of Property
+ * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
+ * @return Cn string
+ */
+ Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
+
+ /**
+ * 24节气速查表
+ * @Array Of Property
+ * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
+ * @return Cn string
+ */
+ solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
+
+ /**
+ * 1900-2100各年的24节气日期速查表
+ * @Array Of Property
+ * @return 0x string For splice
+ */
+ sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
+ '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
+ 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
+ '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
+ '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
+ '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
+ '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
+ '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+ '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
+ '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+ '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
+ '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
+ '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
+ '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
+ '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
+ '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
+ '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
+ '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
+
+ /**
+ * 数字转中文速查表
+ * @Array Of Property
+ * @trans ['日','一','二','三','四','五','六','七','八','九','十']
+ * @return Cn string
+ */
+ nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
+
+ /**
+ * 日期转农历称呼速查表
+ * @Array Of Property
+ * @trans ['初','十','廿','卅']
+ * @return Cn string
+ */
+ nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
+
+ /**
+ * 月份转农历称呼速查表
+ * @Array Of Property
+ * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
+ * @return Cn string
+ */
+ nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
+
+ /**
+ * 返回农历y年一整年的总天数
+ * @param lunar Year
+ * @return Number
+ * @eg:var count = calendar.lYearDays(1987) ;//count=387
+ */
+ lYearDays: function (y) {
+ var i; var sum = 348
+ for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
+ return (sum + this.leapDays(y))
+ },
+
+ /**
+ * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
+ * @param lunar Year
+ * @return Number (0-12)
+ * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
+ */
+ leapMonth: function (y) { // 闰字编码 \u95f0
+ return (this.lunarInfo[y - 1900] & 0xf)
+ },
+
+ /**
+ * 返回农历y年闰月的天数 若该年没有闰月则返回0
+ * @param lunar Year
+ * @return Number (0、29、30)
+ * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
+ */
+ leapDays: function (y) {
+ if (this.leapMonth(y)) {
+ return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
+ }
+ return (0)
+ },
+
+ /**
+ * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
+ * @param lunar Year
+ * @return Number (-1、29、30)
+ * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
+ */
+ monthDays: function (y, m) {
+ if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
+ return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
+ },
+
+ /**
+ * 返回公历(!)y年m月的天数
+ * @param solar Year
+ * @return Number (-1、28、29、30、31)
+ * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
+ */
+ solarDays: function (y, m) {
+ if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+ var ms = m - 1
+ if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
+ return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
+ } else {
+ return (this.solarMonth[ms])
+ }
+ },
+
+ /**
+ * 农历年份转换为干支纪年
+ * @param lYear 农历年的年份数
+ * @return Cn string
+ */
+ toGanZhiYear: function (lYear) {
+ var ganKey = (lYear - 3) % 10
+ var zhiKey = (lYear - 3) % 12
+ if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
+ if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
+ return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
+ },
+
+ /**
+ * 公历月、日判断所属星座
+ * @param cMonth [description]
+ * @param cDay [description]
+ * @return Cn string
+ */
+ toAstro: function (cMonth, cDay) {
+ var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
+ var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
+ return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
+ },
+
+ /**
+ * 传入offset偏移量返回干支
+ * @param offset 相对甲子的偏移量
+ * @return Cn string
+ */
+ toGanZhi: function (offset) {
+ return this.Gan[offset % 10] + this.Zhi[offset % 12]
+ },
+
+ /**
+ * 传入公历(!)y年获得该年第n个节气的公历日期
+ * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
+ * @return day Number
+ * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
+ */
+ getTerm: function (y, n) {
+ if (y < 1900 || y > 2100) { return -1 }
+ if (n < 1 || n > 24) { return -1 }
+ var _table = this.sTermInfo[y - 1900]
+ var _info = [
+ parseInt('0x' + _table.substr(0, 5)).toString(),
+ parseInt('0x' + _table.substr(5, 5)).toString(),
+ parseInt('0x' + _table.substr(10, 5)).toString(),
+ parseInt('0x' + _table.substr(15, 5)).toString(),
+ parseInt('0x' + _table.substr(20, 5)).toString(),
+ parseInt('0x' + _table.substr(25, 5)).toString()
+ ]
+ var _calday = [
+ _info[0].substr(0, 1),
+ _info[0].substr(1, 2),
+ _info[0].substr(3, 1),
+ _info[0].substr(4, 2),
+
+ _info[1].substr(0, 1),
+ _info[1].substr(1, 2),
+ _info[1].substr(3, 1),
+ _info[1].substr(4, 2),
+
+ _info[2].substr(0, 1),
+ _info[2].substr(1, 2),
+ _info[2].substr(3, 1),
+ _info[2].substr(4, 2),
+
+ _info[3].substr(0, 1),
+ _info[3].substr(1, 2),
+ _info[3].substr(3, 1),
+ _info[3].substr(4, 2),
+
+ _info[4].substr(0, 1),
+ _info[4].substr(1, 2),
+ _info[4].substr(3, 1),
+ _info[4].substr(4, 2),
+
+ _info[5].substr(0, 1),
+ _info[5].substr(1, 2),
+ _info[5].substr(3, 1),
+ _info[5].substr(4, 2)
+ ]
+ return parseInt(_calday[n - 1])
+ },
+
+ /**
+ * 传入农历数字月份返回汉语通俗表示法
+ * @param lunar month
+ * @return Cn string
+ * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
+ */
+ toChinaMonth: function (m) { // 月 => \u6708
+ if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+ var s = this.nStr3[m - 1]
+ s += '\u6708'// 加上月字
+ return s
+ },
+
+ /**
+ * 传入农历日期数字返回汉字表示法
+ * @param lunar day
+ * @return Cn string
+ * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
+ */
+ toChinaDay: function (d) { // 日 => \u65e5
+ var s
+ switch (d) {
+ case 10:
+ s = '\u521d\u5341'; break
+ case 20:
+ s = '\u4e8c\u5341'; break
+ break
+ case 30:
+ s = '\u4e09\u5341'; break
+ break
+ default :
+ s = this.nStr2[Math.floor(d / 10)]
+ s += this.nStr1[d % 10]
+ }
+ return (s)
+ },
+
+ /**
+ * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
+ * @param y year
+ * @return Cn string
+ * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
+ */
+ getAnimal: function (y) {
+ return this.Animals[(y - 4) % 12]
+ },
+
+ /**
+ * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
+ * @param y solar year
+ * @param m solar month
+ * @param d solar day
+ * @return JSON object
+ * @eg:console.log(calendar.solar2lunar(1987,11,01));
+ */
+ solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
+ // 年份限定、上限
+ if (y < 1900 || y > 2100) {
+ return -1// undefined转换为数字变为NaN
+ }
+ // 公历传参最下限
+ if (y == 1900 && m == 1 && d < 31) {
+ return -1
+ }
+ // 未传参 获得当天
+ if (!y) {
+ var objDate = new Date()
+ } else {
+ var objDate = new Date(y, parseInt(m) - 1, d)
+ }
+ var i; var leap = 0; var temp = 0
+ // 修正ymd参数
+ var y = objDate.getFullYear()
+ var m = objDate.getMonth() + 1
+ var d = objDate.getDate()
+ var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
+ for (i = 1900; i < 2101 && offset > 0; i++) {
+ temp = this.lYearDays(i)
+ offset -= temp
+ }
+ if (offset < 0) {
+ offset += temp; i--
+ }
+
+ // 是否今天
+ var isTodayObj = new Date()
+ var isToday = false
+ if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
+ isToday = true
+ }
+ // 星期几
+ var nWeek = objDate.getDay()
+ var cWeek = this.nStr1[nWeek]
+ // 数字表示周几顺应天朝周一开始的惯例
+ if (nWeek == 0) {
+ nWeek = 7
+ }
+ // 农历年
+ var year = i
+ var leap = this.leapMonth(i) // 闰哪个月
+ var isLeap = false
+
+ // 效验闰月
+ for (i = 1; i < 13 && offset > 0; i++) {
+ // 闰月
+ if (leap > 0 && i == (leap + 1) && isLeap == false) {
+ --i
+ isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
+ } else {
+ temp = this.monthDays(year, i)// 计算农历普通月天数
+ }
+ // 解除闰月
+ if (isLeap == true && i == (leap + 1)) { isLeap = false }
+ offset -= temp
+ }
+ // 闰月导致数组下标重叠取反
+ if (offset == 0 && leap > 0 && i == leap + 1) {
+ if (isLeap) {
+ isLeap = false
+ } else {
+ isLeap = true; --i
+ }
+ }
+ if (offset < 0) {
+ offset += temp; --i
+ }
+ // 农历月
+ var month = i
+ // 农历日
+ var day = offset + 1
+ // 天干地支处理
+ var sm = m - 1
+ var gzY = this.toGanZhiYear(year)
+
+ // 当月的两个节气
+ // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
+ var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
+ var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
+
+ // 依据12节气修正干支月
+ var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
+ if (d >= firstNode) {
+ gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
+ }
+
+ // 传入的日期的节气与否
+ var isTerm = false
+ var Term = null
+ if (firstNode == d) {
+ isTerm = true
+ Term = this.solarTerm[m * 2 - 2]
+ }
+ if (secondNode == d) {
+ isTerm = true
+ Term = this.solarTerm[m * 2 - 1]
+ }
+ // 日柱 当月一日与 1900/1/1 相差天数
+ var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
+ var gzD = this.toGanZhi(dayCyclical + d - 1)
+ // 该日期所属的星座
+ var astro = this.toAstro(m, d)
+
+ return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
+ },
+
+ /**
+ * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
+ * @param y lunar year
+ * @param m lunar month
+ * @param d lunar day
+ * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
+ * @return JSON object
+ * @eg:console.log(calendar.lunar2solar(1987,9,10));
+ */
+ lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
+ var isLeapMonth = !!isLeapMonth
+ var leapOffset = 0
+ var leapMonth = this.leapMonth(y)
+ var leapDay = this.leapDays(y)
+ if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
+ if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
+ var day = this.monthDays(y, m)
+ var _day = day
+ // bugFix 2016-9-25
+ // if month is leap, _day use leapDays method
+ if (isLeapMonth) {
+ _day = this.leapDays(y, m)
+ }
+ if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
+
+ // 计算农历的时间差
+ var offset = 0
+ for (var i = 1900; i < y; i++) {
+ offset += this.lYearDays(i)
+ }
+ var leap = 0; var isAdd = false
+ for (var i = 1; i < m; i++) {
+ leap = this.leapMonth(y)
+ if (!isAdd) { // 处理闰月
+ if (leap <= i && leap > 0) {
+ offset += this.leapDays(y); isAdd = true
+ }
+ }
+ offset += this.monthDays(y, i)
+ }
+ // 转换闰月农历 需补充该年闰月的前一个月的时差
+ if (isLeapMonth) { offset += day }
+ // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
+ var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
+ var calObj = new Date((offset + d - 31) * 86400000 + stmap)
+ var cY = calObj.getUTCFullYear()
+ var cM = calObj.getUTCMonth() + 1
+ var cD = calObj.getUTCDate()
+
+ return this.solar2lunar(cY, cM, cD)
+ }
+}
+
+export default calendar
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..fcbd13cfc08064e801531332625f0fdacbb7c509
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/en.json
@@ -0,0 +1,12 @@
+{
+ "uni-calender.ok": "ok",
+ "uni-calender.cancel": "cancel",
+ "uni-calender.today": "today",
+ "uni-calender.MON": "MON",
+ "uni-calender.TUE": "TUE",
+ "uni-calender.WED": "WED",
+ "uni-calender.THU": "THU",
+ "uni-calender.FRI": "FRI",
+ "uni-calender.SAT": "SAT",
+ "uni-calender.SUN": "SUN"
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js b/uni_modules/uni-calendar/components/uni-calendar/i18n/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..de7509c87ba5197b9f5d20ca94a0558c7a8e08a9
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/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-calendar/components/uni-calendar/i18n/zh-Hans.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
new file mode 100644
index 0000000000000000000000000000000000000000..1ca43de010911bfec3405d84de46530f6de1a03e
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json
@@ -0,0 +1,12 @@
+{
+ "uni-calender.ok": "确定",
+ "uni-calender.cancel": "取消",
+ "uni-calender.today": "今日",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
new file mode 100644
index 0000000000000000000000000000000000000000..e0fe33b958f8ee991a4de2d1b370c8ca81e0dbb9
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json
@@ -0,0 +1,12 @@
+{
+ "uni-calender.ok": "確定",
+ "uni-calender.cancel": "取消",
+ "uni-calender.today": "今日",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0353011e99ec6f362fba732ce5ca62c490288f23
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue
@@ -0,0 +1,181 @@
+
+
+
+
+ {{weeks.date}}
+ {{todayText}}
+ {{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}
+ {{weeks.extraInfo.info}}
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
new file mode 100644
index 0000000000000000000000000000000000000000..401a2de6d5d5d1ea583d562dd67d0711e94f2ce3
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
@@ -0,0 +1,547 @@
+
+
+
+
+
+
+
+
+ {{nowDate.month}}
+
+
+
+ {{SUNText}}
+
+
+ {{monText}}
+
+
+ {{TUEText}}
+
+
+ {{WEDText}}
+
+
+ {{THUText}}
+
+
+ {{FRIText}}
+
+
+ {{SATText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-calendar/components/uni-calendar/util.js b/uni_modules/uni-calendar/components/uni-calendar/util.js
new file mode 100644
index 0000000000000000000000000000000000000000..37f44321ebc299212eea8646c9e7e63e9b2ed6f8
--- /dev/null
+++ b/uni_modules/uni-calendar/components/uni-calendar/util.js
@@ -0,0 +1,352 @@
+import CALENDAR from './calendar.js'
+
+class Calendar {
+ constructor({
+ date,
+ selected,
+ startDate,
+ endDate,
+ range
+ } = {}) {
+ // 当前日期
+ this.date = this.getDate(new Date()) // 当前初入日期
+ // 打点信息
+ this.selected = selected || [];
+ // 范围开始
+ this.startDate = startDate
+ // 范围结束
+ this.endDate = endDate
+ this.range = range
+ // 多选状态
+ this.cleanMultipleStatus()
+ // 每周日期
+ this.weeks = {}
+ // this._getWeek(this.date.fullDate)
+ }
+ /**
+ * 设置日期
+ * @param {Object} date
+ */
+ setDate(date) {
+ this.selectDate = this.getDate(date)
+ this._getWeek(this.selectDate.fullDate)
+ }
+
+ /**
+ * 清理多选状态
+ */
+ cleanMultipleStatus() {
+ this.multipleStatus = {
+ before: '',
+ after: '',
+ data: []
+ }
+ }
+
+ /**
+ * 重置开始日期
+ */
+ resetSatrtDate(startDate) {
+ // 范围开始
+ this.startDate = startDate
+
+ }
+
+ /**
+ * 重置结束日期
+ */
+ resetEndDate(endDate) {
+ // 范围结束
+ this.endDate = endDate
+ }
+
+ /**
+ * 获取任意时间
+ */
+ getDate(date, AddDayCount = 0, str = 'day') {
+ if (!date) {
+ date = new Date()
+ }
+ if (typeof date !== 'object') {
+ date = date.replace(/-/g, '/')
+ }
+ const dd = new Date(date)
+ switch (str) {
+ case 'day':
+ dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ case 'month':
+ if (dd.getDate() === 31) {
+ dd.setDate(dd.getDate() + AddDayCount)
+ } else {
+ dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
+ }
+ break
+ case 'year':
+ dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ }
+ const y = dd.getFullYear()
+ const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+ const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+ return {
+ fullDate: y + '-' + m + '-' + d,
+ year: y,
+ month: m,
+ date: d,
+ day: dd.getDay()
+ }
+ }
+
+
+ /**
+ * 获取上月剩余天数
+ */
+ _getLastMonthDays(firstDay, full) {
+ let dateArr = []
+ for (let i = firstDay; i > 0; i--) {
+ const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+ dateArr.push({
+ date: beforeDate,
+ month: full.month - 1,
+ lunar: this.getlunar(full.year, full.month - 1, beforeDate),
+ disable: true
+ })
+ }
+ return dateArr
+ }
+ /**
+ * 获取本月天数
+ */
+ _currentMonthDys(dateData, full) {
+ let dateArr = []
+ let fullDate = this.date.fullDate
+ for (let i = 1; i <= dateData; i++) {
+ let isinfo = false
+ let nowDate = full.year + '-' + (full.month < 10 ?
+ full.month : full.month) + '-' + (i < 10 ?
+ '0' + i : i)
+ // 是否今天
+ let isDay = fullDate === nowDate
+ // 获取打点信息
+ let info = this.selected && this.selected.find((item) => {
+ if (this.dateEqual(nowDate, item.date)) {
+ return item
+ }
+ })
+
+ // 日期禁用
+ let disableBefore = true
+ let disableAfter = true
+ if (this.startDate) {
+ let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+ disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+ }
+
+ if (this.endDate) {
+ let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+ disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+ }
+ let multiples = this.multipleStatus.data
+ let checked = false
+ let multiplesStatus = -1
+ if (this.range) {
+ if (multiples) {
+ multiplesStatus = multiples.findIndex((item) => {
+ return this.dateEqual(item, nowDate)
+ })
+ }
+ if (multiplesStatus !== -1) {
+ checked = true
+ }
+ }
+ let data = {
+ fullDate: nowDate,
+ year: full.year,
+ date: i,
+ multiple: this.range ? checked : false,
+ beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
+ afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
+ month: full.month,
+ lunar: this.getlunar(full.year, full.month, i),
+ disable: !disableBefore || !disableAfter,
+ isDay
+ }
+ if (info) {
+ data.extraInfo = info
+ }
+
+ dateArr.push(data)
+ }
+ return dateArr
+ }
+ /**
+ * 获取下月天数
+ */
+ _getNextMonthDays(surplus, full) {
+ let dateArr = []
+ for (let i = 1; i < surplus + 1; i++) {
+ dateArr.push({
+ date: i,
+ month: Number(full.month) + 1,
+ lunar: this.getlunar(full.year, Number(full.month) + 1, i),
+ disable: true
+ })
+ }
+ return dateArr
+ }
+
+ /**
+ * 获取当前日期详情
+ * @param {Object} date
+ */
+ getInfo(date) {
+ if (!date) {
+ date = new Date()
+ }
+ const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+ return dateInfo
+ }
+
+ /**
+ * 比较时间大小
+ */
+ dateCompare(startDate, endDate) {
+ // 计算截止时间
+ startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+ if (startDate <= endDate) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ /**
+ * 比较时间是否相等
+ */
+ dateEqual(before, after) {
+ // 计算截止时间
+ before = new Date(before.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ after = new Date(after.replace('-', '/').replace('-', '/'))
+ if (before.getTime() - after.getTime() === 0) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+
+ /**
+ * 获取日期范围内所有日期
+ * @param {Object} begin
+ * @param {Object} end
+ */
+ geDateAll(begin, end) {
+ var arr = []
+ var ab = begin.split('-')
+ var ae = end.split('-')
+ var db = new Date()
+ db.setFullYear(ab[0], ab[1] - 1, ab[2])
+ var de = new Date()
+ de.setFullYear(ae[0], ae[1] - 1, ae[2])
+ var unixDb = db.getTime() - 24 * 60 * 60 * 1000
+ var unixDe = de.getTime() - 24 * 60 * 60 * 1000
+ for (var k = unixDb; k <= unixDe;) {
+ k = k + 24 * 60 * 60 * 1000
+ arr.push(this.getDate(new Date(parseInt(k))).fullDate)
+ }
+ return arr
+ }
+ /**
+ * 计算阴历日期显示
+ */
+ getlunar(year, month, date) {
+ return CALENDAR.solar2lunar(year, month, date)
+ }
+ /**
+ * 设置打点
+ */
+ setSelectInfo(data, value) {
+ this.selected = value
+ this._getWeek(data)
+ }
+
+ /**
+ * 获取多选状态
+ */
+ setMultiple(fullDate) {
+ let {
+ before,
+ after
+ } = this.multipleStatus
+
+ if (!this.range) return
+ if (before && after) {
+ this.multipleStatus.before = ''
+ this.multipleStatus.after = ''
+ this.multipleStatus.data = []
+ } else {
+ if (!before) {
+ this.multipleStatus.before = fullDate
+ } else {
+ this.multipleStatus.after = fullDate
+ if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
+ } else {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
+ }
+ }
+ }
+ this._getWeek(fullDate)
+ }
+
+ /**
+ * 获取每周数据
+ * @param {Object} dateData
+ */
+ _getWeek(dateData) {
+ const {
+ fullDate,
+ year,
+ month,
+ date,
+ day
+ } = this.getDate(dateData)
+ let firstDay = new Date(year, month - 1, 1).getDay()
+ let currentDay = new Date(year, month, 0).getDate()
+ let dates = {
+ lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+ currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+ nextMonthDays: [], // 下个月开始几天
+ weeks: []
+ }
+ let canlender = []
+ const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+ dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+ canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+ let weeks = {}
+ // 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
+ for (let i = 0; i < canlender.length; i++) {
+ if (i % 7 === 0) {
+ weeks[parseInt(i / 7)] = new Array(7)
+ }
+ weeks[parseInt(i / 7)][i % 7] = canlender[i]
+ }
+ this.canlender = canlender
+ this.weeks = weeks
+ }
+
+ //静态方法
+ // static init(date) {
+ // if (!this.instance) {
+ // this.instance = new Calendar(date);
+ // }
+ // return this.instance;
+ // }
+}
+
+
+export default Calendar
diff --git a/uni_modules/uni-calendar/package.json b/uni_modules/uni-calendar/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..8a5023b2807c5935b209dd88602a448e5a6a95ca
--- /dev/null
+++ b/uni_modules/uni-calendar/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-calendar",
+ "displayName": "uni-calendar 日历",
+ "version": "1.4.2",
+ "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": [],
+ "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-calendar/readme.md b/uni_modules/uni-calendar/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..4f3ca0e84117a03d4f3630b92880894b81bb45f0
--- /dev/null
+++ b/uni_modules/uni-calendar/readme.md
@@ -0,0 +1,103 @@
+
+
+## Calendar 日历
+> **组件名:uni-calendar**
+> 代码块: `uCalendar`
+
+
+日历组件
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)
+> - 仅支持自定义组件模式
+> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
+> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
+> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+```
+
+### 通过方法打开日历
+
+需要设置 `insert` 为 `false`
+
+```html
+
+
+ 打开日历
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {};
+ },
+ methods: {
+ open(){
+ this.$refs.calendar.open();
+ },
+ confirm(e) {
+ console.log(e);
+ }
+ }
+};
+
+```
+
+
+## API
+
+### Calendar Props
+
+| 属性名 | 类型 | 默认值| 说明 |
+| | |
+| date | String |- | 自定义当前时间,默认为今天 |
+| lunar | Boolean | false | 显示农历 |
+| startDate | String |- | 日期选择范围-开始日期 |
+| endDate | String |- | 日期选择范围-结束日期 |
+| range | Boolean | false | 范围选择 |
+| insert | Boolean | false | 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式 |
+|clearDate |Boolean |true |弹窗模式是否清空上次选择内容 |
+| selected | Array |- | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] |
+|showMonth | Boolean | true | 是否显示月份为背景 |
+
+### Calendar Events
+
+| 事件名 | 说明 |返回值|
+| | | |
+| open | 弹出日历组件,`insert :false` 时生效|- |
+
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)
\ No newline at end of file
diff --git a/uni_modules/uni-captcha/changelog.md b/uni_modules/uni-captcha/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..a710020dbc70b575fc9b169f02a83fa61347edfd
--- /dev/null
+++ b/uni_modules/uni-captcha/changelog.md
@@ -0,0 +1,4 @@
+## 0.1.1(2021-03-04)
+- refresh不再读取上一条验证码状态
+## 0.1.0(2021-03-01)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-captcha/package.json b/uni_modules/uni-captcha/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..7245ea0fc88f8725eace8210063c393e6d373961
--- /dev/null
+++ b/uni_modules/uni-captcha/package.json
@@ -0,0 +1,80 @@
+{
+ "id": "uni-captcha",
+ "displayName": "uni-captcha",
+ "version": "0.1.1",
+ "description": "简洁、高效、灵活可配置的云端验证码模块",
+ "keywords": [
+ "uniCloud",
+ "captcha",
+ "验证码",
+ "图形验证码",
+ "人机验证"
+],
+ "repository": "https://gitee.com/dcloud/uni-captcha",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "uniCloud",
+ "云函数模板"
+ ],
+ "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"
+ },
+ "client": {
+ "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"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-captcha/readme.md b/uni_modules/uni-captcha/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..b23de182a8d172171104510b5d09bdf280536730
--- /dev/null
+++ b/uni_modules/uni-captcha/readme.md
@@ -0,0 +1,92 @@
+## uni 验证码验证文档
+
+> 用途:主要使用在登录、需要人机校验或其他限制调用的场景
+
+> 验证码生成、校验都在服务端。页面使用返回的 base64 显示。[云端一体登录模板](https://ext.dcloud.net.cn/plugin?id=13)已集成,可下载体验。
+
+> 数据表使用[opendb-verify-codes](https://gitee.com/dcloud/opendb/blob/master/collection/opendb-verify-codes/collection.json)
+
+### 获取验证码@create
+
+用法:`uniCaptcha.create(Object params);`
+
+**参数说明**
+
+| 字段 | 类型 | 必填 | 默认值 | 说明 |
+| --------------- | ------ | ---- | ------- | ----------------------------------------------- |
+| scene | String | 是 | 4 | 使用场景值,用于防止不同功能的验证码混用 |
+| deviceId | String | - | - | 设备 id,如果不传,将自动从 uniCloud 上下文获取 |
+| width | Number | - | 100 | 图片宽度 |
+| height | Number | - | 40 | 图片高度 |
+| backgroundColor | String | - | #FFFAE8 | 验证码背景色 |
+| size | Number | - | 4 | 验证码长度,最多 6 个字符 |
+| noise | Number | - | 4 | 验证码干扰线条数 |
+| expiresDate | Number | - | 180 | 验证码过期时间(s) |
+
+**响应参数**
+
+| 字段 | 类型 | 说明 |
+| ------------- | ------ | ------------------- |
+| code | Number | 错误码,0 表示成功 |
+| message | String | 详细信息 |
+| captchaBase64 | String | 验证码:base64 格式 |
+
+`注意:`
+
+- 重新生成后,上条验证码作废
+
+### 校验验证码@verify
+
+用法:`uniCaptcha.verify(Object params);`
+
+**参数说明**
+
+| 字段 | 类型 | 必填 | 默认值 | 说明 |
+| -------- | ------ | ---- | ------ | ----------------------------------------------- |
+| scene | String | 是 | - | 类型,用于防止不同功能的验证码混用 |
+| captcha | String | 是 | - | 验证码 |
+| deviceId | String | - | - | 设备 id,如果不传,将自动从 uniCloud 上下文获取 |
+
+**响应参数**
+
+| 字段 | 类型 | 说明 |
+| ------- | ------ | ------------------ |
+| code | Number | 错误码,0 表示成功 |
+| message | String | 详细信息 |
+
+`注意:`
+
+- 若提示验证码失效,请重新获取
+
+### 刷新验证码@refresh
+
+用法:`uniCaptcha.refresh(Object params);`
+
+**参数说明**
+
+| 字段 | 类型 | 必填 | 默认值 | 说明 |
+| -------- | ------ | ---- | ------ | ----------------------------------------------- |
+| scene | String | 是 | - | 类型,用于防止不同功能的验证码混用 |
+| deviceId | String | - | - | 设备 id,如果不传,将自动从 uniCloud 上下文获取 |
+
+**响应参数**
+
+| 字段 | 类型 | 说明 |
+| ------------- | ------ | ------------------- |
+| code | Number | 错误码,0 表示成功 |
+| message | String | 详细信息 |
+| captchaBase64 | String | 验证码:base64 格式 |
+
+`注意:`
+
+- 支持传入 create 方法的所有参数,如果不传,则自动按照 deviceId 匹配上次生成时的配置生成新的验证码
+
+## 错误码
+
+_详细信息请查看 message 中查看_
+
+| 模块 | 模块码 | 错误代码 | 错误信息 |
+| :----: | :----: | :------: | :---------------------: |
+| 验证码 | 100 | 01 | (10001)验证码生成失败 |
+| | | 02 | (10002)验证码校验失败 |
+| | | 03 | (10003)验证码刷新失败 |
diff --git a/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/LICENSE.md b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/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-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..3bc88f4e1c501200d1d9fc04417eb2a04d93e99d
--- /dev/null
+++ b/uni_modules/uni-captcha/uniCloud/cloudfunctions/common/uni-captcha/index.js
@@ -0,0 +1 @@
+"use strict";var t,e=(t=require("fs"))&&"object"==typeof t&&"default"in t?t.default:t,n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function r(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function o(t,e){return t(e={exports:{}},e.exports),e.exports}var i=o((function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.font16x32=e.font12x24=e.font8x16=void 0;var n="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";e.font8x16={w:8,h:16,fonts:n,data:[[0,0,0,0,0,0,0,60,66,30,34,66,66,63,0,0],[0,0,0,192,64,64,64,88,100,66,66,66,100,88,0,0],[0,0,0,0,0,0,0,28,34,64,64,64,34,28,0,0],[0,0,0,6,2,2,2,30,34,66,66,66,38,27,0,0],[0,0,0,0,0,0,0,60,66,126,64,64,66,60,0,0],[0,0,0,15,17,16,16,126,16,16,16,16,16,124,0,0],[0,0,0,0,0,0,0,62,68,68,56,64,60,66,66,60],[0,0,0,192,64,64,64,92,98,66,66,66,66,231,0,0],[0,0,0,48,48,0,0,112,16,16,16,16,16,124,0,0],[0,0,0,12,12,0,0,28,4,4,4,4,4,4,68,120],[0,0,0,192,64,64,64,78,72,80,104,72,68,238,0,0],[0,0,0,112,16,16,16,16,16,16,16,16,16,124,0,0],[0,0,0,0,0,0,0,254,73,73,73,73,73,237,0,0],[0,0,0,0,0,0,0,220,98,66,66,66,66,231,0,0],[0,0,0,0,0,0,0,60,66,66,66,66,66,60,0,0],[0,0,0,0,0,0,0,216,100,66,66,66,68,120,64,224],[0,0,0,0,0,0,0,30,34,66,66,66,34,30,2,7],[0,0,0,0,0,0,0,238,50,32,32,32,32,248,0,0],[0,0,0,0,0,0,0,62,66,64,60,2,66,124,0,0],[0,0,0,0,0,16,16,124,16,16,16,16,16,12,0,0],[0,0,0,0,0,0,0,198,66,66,66,66,70,59,0,0],[0,0,0,0,0,0,0,231,66,36,36,40,16,16,0,0],[0,0,0,0,0,0,0,215,146,146,170,170,68,68,0,0],[0,0,0,0,0,0,0,110,36,24,24,24,36,118,0,0],[0,0,0,0,0,0,0,231,66,36,36,40,24,16,16,224],[0,0,0,0,0,0,0,126,68,8,16,16,34,126,0,0],[0,0,0,16,16,24,40,40,36,60,68,66,66,231,0,0],[0,0,0,248,68,68,68,120,68,66,66,66,68,248,0,0],[0,0,0,62,66,66,128,128,128,128,128,66,68,56,0,0],[0,0,0,248,68,66,66,66,66,66,66,66,68,248,0,0],[0,0,0,252,66,72,72,120,72,72,64,66,66,252,0,0],[0,0,0,252,66,72,72,120,72,72,64,64,64,224,0,0],[0,0,0,60,68,68,128,128,128,142,132,68,68,56,0,0],[0,0,0,231,66,66,66,66,126,66,66,66,66,231,0,0],[0,0,0,124,16,16,16,16,16,16,16,16,16,124,0,0],[0,0,0,62,8,8,8,8,8,8,8,8,8,8,136,240],[0,0,0,238,68,72,80,112,80,72,72,68,68,238,0,0],[0,0,0,224,64,64,64,64,64,64,64,64,66,254,0,0],[0,0,0,238,108,108,108,108,84,84,84,84,84,214,0,0],[0,0,0,199,98,98,82,82,74,74,74,70,70,226,0,0],[0,0,0,56,68,130,130,130,130,130,130,130,68,56,0,0],[0,0,0,252,66,66,66,66,124,64,64,64,64,224,0,0],[0,0,0,56,68,130,130,130,130,130,178,202,76,56,6,0],[0,0,0,252,66,66,66,124,72,72,68,68,66,227,0,0],[0,0,0,62,66,66,64,32,24,4,2,66,66,124,0,0],[0,0,0,254,146,16,16,16,16,16,16,16,16,56,0,0],[0,0,0,231,66,66,66,66,66,66,66,66,66,60,0,0],[0,0,0,231,66,66,68,36,36,40,40,24,16,16,0,0],[0,0,0,214,146,146,146,146,170,170,108,68,68,68,0,0],[0,0,0,231,66,36,36,24,24,24,36,36,66,231,0,0],[0,0,0,238,68,68,40,40,16,16,16,16,16,56,0,0],[0,0,0,126,132,4,8,8,16,32,32,66,66,252,0,0],[0,0,0,24,36,66,66,66,66,66,66,66,36,24,0,0],[0,0,0,16,112,16,16,16,16,16,16,16,16,124,0,0],[0,0,0,60,66,66,66,4,4,8,16,32,66,126,0,0],[0,0,0,60,66,66,4,24,4,2,2,66,68,56,0,0],[0,0,0,4,12,20,36,36,68,68,126,4,4,30,0,0],[0,0,0,126,64,64,64,88,100,2,2,66,68,56,0,0],[0,0,0,28,36,64,64,88,100,66,66,66,36,24,0,0],[0,0,0,126,68,68,8,8,16,16,16,16,16,16,0,0],[0,0,0,60,66,66,66,36,24,36,66,66,66,60,0,0],[0,0,0,24,36,66,66,66,38,26,2,2,36,56,0,0]]},e.font12x24={w:12,h:24,fonts:n,data:[[0,0,0,0,0,0,0,0,0,0,15,48,48,7,28,48,96,96,96,113,62,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,192,192,192,192,192,192,192,208,240,0,0,0],[0,0,0,0,16,112,48,48,48,48,51,60,56,48,48,48,48,48,48,56,47,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,96,96,96,96,96,96,64,192,128,0,0,0],[0,0,0,0,0,0,0,0,0,0,15,49,49,97,96,96,96,96,48,48,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,128,0,0,0,64,64,128,0,0,0,0],[0,0,0,0,0,1,0,0,0,0,30,49,48,96,96,96,96,96,32,49,30,0,0,0,0,0,0,0,64,192,192,192,192,192,192,192,192,192,192,192,192,192,192,224,128,0,0,0],[0,0,0,0,0,0,0,0,0,0,7,24,16,48,63,48,48,48,24,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,96,96,224,0,0,0,32,64,128,0,0,0],[0,0,0,0,0,3,6,12,12,12,127,12,12,12,12,12,12,12,12,12,63,0,0,0,0,0,0,0,0,192,96,96,0,0,192,0,0,0,0,0,0,0,0,0,128,0,0,0],[0,0,0,0,0,0,0,0,0,0,15,25,48,48,48,25,31,48,62,31,96,96,112,31,0,0,0,0,0,0,0,0,0,0,112,144,192,192,192,128,0,0,0,192,96,96,224,128],[0,0,0,0,16,112,48,48,48,48,55,56,48,48,48,48,48,48,48,48,121,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,192,192,192,192,192,192,192,192,224,0,0,0],[0,0,0,0,0,6,6,0,0,0,62,6,6,6,6,6,6,6,6,6,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0],[0,0,0,0,0,1,1,0,0,0,15,1,1,1,1,1,1,1,1,1,1,1,51,62,0,0,0,0,0,128,128,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,0,0],[0,0,0,0,16,112,48,48,48,48,51,49,51,50,54,62,59,51,49,49,121,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,128,128,224,0,0,0],[0,0,0,0,2,62,6,6,6,6,6,6,6,6,6,6,6,6,6,6,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0],[0,0,0,0,0,0,0,0,0,0,238,119,102,102,102,102,102,102,102,102,247,0,0,0,0,0,0,0,0,0,0,0,0,0,224,96,96,96,96,96,96,96,96,96,112,0,0,0],[0,0,0,0,0,0,0,0,0,0,115,60,48,48,48,48,48,48,48,48,121,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,192,192,192,192,192,192,192,192,224,0,0,0],[0,0,0,0,0,0,0,0,0,0,15,25,48,96,96,96,96,96,48,48,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,192,96,96,96,96,96,192,192,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,119,56,48,48,48,48,48,48,48,56,55,48,48,124,0,0,0,0,0,0,0,0,0,0,128,192,96,96,96,96,96,96,192,192,128,0,0,0],[0,0,0,0,0,0,0,0,0,0,30,49,48,96,96,96,96,96,32,49,30,0,0,3,0,0,0,0,0,0,0,0,0,0,64,192,192,192,192,192,192,192,192,192,192,192,192,224],[0,0,0,0,0,0,0,0,0,0,249,26,28,24,24,24,24,24,24,24,255,0,0,0,0,0,0,0,0,0,0,0,0,0,224,96,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,15,24,48,48,28,15,1,32,32,48,63,0,0,0,0,0,0,0,0,0,0,0,0,0,224,96,32,0,0,128,192,96,96,192,128,0,0,0],[0,0,0,0,0,0,4,4,12,12,127,12,12,12,12,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,64,64,128,0,0,0],[0,0,0,0,0,0,0,0,0,16,113,48,48,48,48,48,48,48,48,57,30,0,0,0,0,0,0,0,0,0,0,0,0,64,192,192,192,192,192,192,192,192,192,224,128,0,0,0],[0,0,0,0,0,0,0,0,0,0,124,56,24,24,12,12,12,7,7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,240,96,64,64,128,128,128,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,247,99,99,103,55,53,57,57,57,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,176,32,32,32,32,192,192,192,192,128,128,0,0,0],[0,0,0,0,0,0,0,0,0,0,125,24,25,13,14,6,7,11,25,17,123,0,0,0,0,0,0,0,0,0,0,0,0,0,224,128,128,0,0,0,0,0,128,192,224,0,0,0],[0,0,0,0,0,0,0,0,0,0,125,56,24,24,13,13,13,6,6,2,4,4,40,56,0,0,0,0,0,0,0,0,0,0,224,128,128,128,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,63,33,35,3,7,6,14,12,28,24,63,0,0,0,0,0,0,0,0,0,0,0,0,0,192,128,128,0,0,0,0,32,32,96,192,0,0,0],[0,0,0,0,0,6,6,14,11,11,19,17,17,17,31,32,32,32,32,96,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,128,128,192,192,192,96,96,240,0,0,0],[0,0,0,0,0,255,97,96,96,96,96,97,127,96,96,96,96,96,96,96,255,0,0,0,0,0,0,0,0,0,128,192,192,192,192,128,0,192,64,96,96,96,96,192,128,0,0,0],[0,0,0,0,0,7,24,48,48,32,96,96,96,96,96,96,96,48,48,24,15,0,0,0,0,0,0,0,0,224,96,32,32,0,0,0,0,0,0,0,32,32,64,128,0,0,0,0],[0,0,0,0,0,254,97,96,96,96,96,96,96,96,96,96,96,96,96,99,254,0,0,0,0,0,0,0,0,0,128,192,192,96,96,96,96,96,96,96,96,192,192,128,0,0,0,0],[0,0,0,0,0,255,96,96,96,96,97,97,127,97,97,96,96,96,96,96,255,0,0,0,0,0,0,0,0,192,64,32,0,0,0,0,0,0,0,0,0,32,32,64,192,0,0,0],[0,0,0,0,0,255,96,96,96,96,97,97,127,97,97,96,96,96,96,96,240,0,0,0,0,0,0,0,0,192,192,32,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,15,24,48,48,32,96,96,96,96,99,96,96,48,48,24,15,0,0,0,0,0,0,0,0,64,192,64,64,0,0,0,0,0,240,192,192,192,192,192,0,0,0,0],[0,0,0,0,0,240,96,96,96,96,96,96,127,96,96,96,96,96,96,96,240,0,0,0,0,0,0,0,0,240,96,96,96,96,96,96,224,96,96,96,96,96,96,96,240,0,0,0],[0,0,0,0,0,63,6,6,6,6,6,6,6,6,6,6,6,6,6,6,63,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0],[0,0,0,0,0,15,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,97,99,62,0,0,0,0,0,240,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0],[0,0,0,0,0,243,96,97,98,98,100,108,124,118,103,99,99,97,96,96,241,0,0,0,0,0,0,0,0,224,128,0,0,0,0,0,0,0,0,0,128,128,192,224,240,0,0,0],[0,0,0,0,0,240,96,96,96,96,96,96,96,96,96,96,96,96,96,96,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,32,64,192,0,0,0],[0,0,0,0,0,240,112,112,112,89,89,89,89,90,78,78,78,78,68,68,228,0,0,0,0,0,0,0,0,240,224,224,224,96,96,96,96,96,96,96,96,96,96,96,240,0,0,0],[0,0,0,0,0,224,112,112,88,88,76,70,70,67,67,65,64,64,64,64,224,0,0,0,0,0,0,0,0,112,32,32,32,32,32,32,32,32,32,160,224,224,96,96,32,0,0,0],[0,0,0,0,0,15,25,48,48,96,96,96,96,96,96,96,96,48,48,25,15,0,0,0,0,0,0,0,0,0,128,192,64,96,96,96,96,96,96,96,96,64,192,128,0,0,0,0],[0,0,0,0,0,255,96,96,96,96,96,96,96,127,96,96,96,96,96,96,240,0,0,0,0,0,0,0,0,128,192,96,96,96,96,96,192,128,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,15,25,48,48,96,96,96,96,96,96,96,110,50,49,17,15,1,0,0,0,0,0,0,0,0,128,192,64,96,96,96,96,96,96,96,96,64,192,128,128,224,192,0],[0,0,0,0,0,255,96,96,96,96,96,96,127,102,99,99,97,97,96,96,240,0,0,0,0,0,0,0,0,128,192,96,96,96,96,192,0,0,0,0,128,128,192,192,112,0,0,0],[0,0,0,0,0,31,48,96,96,96,112,60,15,3,0,0,64,64,96,112,79,0,0,0,0,0,0,0,0,32,224,32,32,0,0,0,0,192,192,96,96,96,96,192,128,0,0,0],[0,0,0,0,0,127,70,134,134,6,6,6,6,6,6,6,6,6,6,6,15,0,0,0,0,0,0,0,0,224,32,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,240,96,96,96,96,96,96,96,96,96,96,96,96,96,48,31,0,0,0,0,0,0,0,0,112,32,32,32,32,32,32,32,32,32,32,32,32,32,64,128,0,0,0],[0,0,0,0,0,248,112,48,48,48,48,24,24,24,24,13,13,13,15,6,6,0,0,0,0,0,0,0,0,240,96,64,64,64,128,128,128,128,128,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,247,102,102,102,102,103,55,55,59,59,59,59,57,17,17,17,0,0,0,0,0,0,0,0,112,32,32,64,64,64,64,64,128,128,128,128,128,0,0,0,0,0,0],[0,0,0,0,0,121,48,24,24,25,13,14,6,6,7,11,11,25,17,48,121,0,0,0,0,0,0,0,0,224,192,128,128,0,0,0,0,0,0,0,128,128,128,192,224,0,0,0],[0,0,0,0,0,248,112,48,48,24,24,13,13,14,6,6,6,6,6,6,31,0,0,0,0,0,0,0,0,240,96,64,128,128,128,0,0,0,0,0,0,0,0,0,128,0,0,0],[0,0,0,0,0,63,32,65,1,3,3,3,6,6,12,12,24,24,56,48,127,0,0,0,0,0,0,0,0,224,192,192,128,128,0,0,0,0,0,0,0,32,32,64,192,0,0,0],[0,0,0,0,0,15,25,48,48,96,96,96,96,96,96,96,96,48,48,25,15,0,0,0,0,0,0,0,0,0,128,192,192,96,96,96,96,96,96,96,96,192,192,128,0,0,0,0],[0,0,0,0,0,2,6,62,6,6,6,6,6,6,6,6,6,6,6,6,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0],[0,0,0,0,0,31,33,64,96,96,0,1,1,3,4,8,16,32,64,127,127,0,0,0,0,0,0,0,0,0,128,192,192,192,192,128,128,0,0,0,64,64,64,192,192,0,0,0],[0,0,0,0,0,30,35,97,97,97,1,3,14,1,0,0,96,96,96,33,31,0,0,0,0,0,0,0,0,0,0,128,128,128,128,0,0,128,128,192,192,192,192,128,0,0,0,0],[0,0,0,0,0,1,3,3,5,9,9,17,33,33,65,127,1,1,1,1,7,0,0,0,0,0,0,0,128,128,128,128,128,128,128,128,128,128,128,224,128,128,128,128,224,0,0,0],[0,0,0,0,0,63,63,32,32,32,32,47,49,32,0,0,96,96,65,33,31,0,0,0,0,0,0,0,0,192,192,0,0,0,0,0,128,192,192,192,192,192,128,128,0,0,0,0],[0,0,0,0,0,7,24,48,48,32,96,103,104,112,96,96,96,32,48,24,15,0,0,0,0,0,0,0,0,128,192,192,0,0,0,128,192,96,96,96,96,96,64,192,0,0,0,0],[0,0,0,0,0,31,63,48,32,32,0,1,1,2,2,2,6,6,6,6,6,0,0,0,0,0,0,0,0,224,224,64,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,31,48,96,96,96,112,60,15,51,32,96,96,96,96,48,15,0,0,0,0,0,0,0,0,128,192,96,96,96,64,192,0,128,192,96,96,96,96,192,128,0,0,0],[0,0,0,0,0,15,48,48,96,96,96,96,96,49,30,0,0,0,48,49,30,0,0,0,0,0,0,0,0,0,128,192,64,96,96,96,224,96,96,96,192,192,128,128,0,0,0,0]]},e.font16x32={w:16,h:32,fonts:n,data:[[0,0,0,0,0,0,0,0,0,0,0,0,0,15,24,48,48,0,1,14,56,48,96,96,96,48,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,96,48,48,48,240,48,48,48,48,48,50,242,28,0,0,0,0,0],[0,0,0,0,0,8,120,24,24,24,24,24,24,24,27,28,28,24,24,24,24,24,24,24,28,30,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,24,12,6,6,6,6,6,6,6,4,12,24,224,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,3,14,24,24,48,48,48,48,48,48,24,24,12,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,48,24,24,24,0,0,0,0,4,4,8,16,224,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,24,24,48,48,48,48,48,48,16,24,12,7,0,0,0,0,0,0,0,0,0,0,8,120,24,24,24,24,24,24,216,56,24,24,24,24,24,24,24,24,24,56,94,144,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,3,12,24,16,48,48,63,48,48,48,24,24,14,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,48,24,8,12,12,252,0,0,0,4,8,24,224,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,3,3,3,3,63,3,3,3,3,3,3,3,3,3,3,3,3,31,0,0,0,0,0,0,0,0,0,0,0,124,195,3,3,0,0,0,248,0,0,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,3,12,8,24,24,24,8,12,15,24,24,15,15,16,48,48,48,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,238,54,24,24,24,24,24,48,224,0,0,240,252,14,6,6,6,28,240],[0,0,0,0,0,8,120,24,24,24,24,24,24,25,27,28,24,24,24,24,24,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,24,12,12,12,12,12,12,12,12,12,12,12,63,0,0,0,0,0],[0,0,0,0,0,0,1,1,1,0,0,0,0,31,1,1,1,1,1,1,1,1,1,1,1,1,31,0,0,0,0,0,0,0,0,0,0,0,192,192,192,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,128,128,248,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,15,0,0,0,0,0,0,28,28,28,0,0,0,8,248,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,48,96,192],[0,0,0,0,0,8,120,24,24,24,24,24,24,24,24,24,24,24,25,27,28,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,48,96,192,128,128,128,192,224,96,48,56,24,62,0,0,0,0,0],[0,0,0,0,0,0,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,31,0,0,0,0,0,0,0,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,248,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,16,119,57,49,49,49,49,49,49,49,49,49,49,49,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,204,140,140,140,140,140,140,140,140,140,140,140,222,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,8,120,27,28,24,24,24,24,24,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,24,12,12,12,12,12,12,12,12,12,12,12,63,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,3,14,8,24,48,48,48,48,48,48,24,24,12,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,56,12,12,6,6,6,6,6,6,12,12,24,224,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,8,121,26,28,24,24,24,24,24,24,24,24,28,30,25,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,0,0,240,24,12,4,6,6,6,6,6,6,12,12,24,224,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,3,12,24,24,48,48,48,48,48,48,16,24,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,196,60,28,12,12,12,12,12,12,12,12,28,60,204,12,12,12,12,63],[0,0,0,0,0,0,0,0,0,0,0,0,6,126,6,6,7,7,6,6,6,6,6,6,6,6,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,102,134,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,24,24,24,14,7,1,0,32,32,48,56,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,228,28,12,4,0,0,192,240,56,12,12,12,24,240,0,0,0,0,0],[0,0,0,0,0,0,0,0,1,1,1,3,7,63,3,3,3,3,3,3,3,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,0,0,0,0,0,0,0,0,0,4,4,136,240,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,8,120,24,24,24,24,24,24,24,24,24,24,24,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,60,12,12,12,12,12,12,12,12,12,12,28,47,200,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,126,24,24,28,12,12,14,6,6,7,3,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,24,16,16,32,32,64,64,64,128,128,128,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,251,113,48,49,49,25,25,26,26,14,14,14,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,239,198,196,196,196,200,200,104,104,112,112,112,32,32,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,63,14,14,7,3,3,1,1,2,6,4,8,24,124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,16,32,32,64,128,192,192,224,96,48,48,24,126,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,126,24,24,12,12,12,6,6,3,3,3,1,1,1,1,1,1,50,60,0,0,0,0,0,0,0,0,0,0,0,0,0,62,24,16,16,16,32,32,32,64,64,64,128,128,128,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,63,48,32,32,0,1,1,3,7,14,12,28,56,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,48,112,96,192,192,128,0,0,4,4,12,24,248,0,0,0,0,0],[0,0,0,0,0,0,3,3,3,2,6,4,4,4,12,8,8,8,31,16,16,16,48,32,32,96,248,0,0,0,0,0,0,0,0,0,0,128,128,128,128,128,192,192,192,192,96,96,96,96,240,48,48,48,48,24,24,24,62,0,0,0,0,0],[0,0,0,0,0,0,127,24,24,24,24,24,24,24,24,31,24,24,24,24,24,24,24,24,24,24,127,0,0,0,0,0,0,0,0,0,0,0,224,56,28,12,12,12,12,24,48,224,24,12,4,6,6,6,6,6,12,24,240,0,0,0,0,0],[0,0,0,0,0,0,3,6,8,24,48,48,32,96,96,96,96,96,96,96,96,48,48,48,24,12,3,0,0,0,0,0,0,0,0,0,0,0,228,28,12,4,2,2,0,0,0,0,0,0,0,0,0,2,2,4,12,24,224,0,0,0,0,0],[0,0,0,0,0,0,127,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,127,0,0,0,0,0,0,0,0,0,0,0,192,112,24,12,12,12,6,6,6,6,6,6,6,6,6,12,12,8,24,112,192,0,0,0,0,0],[0,0,0,0,0,0,127,24,24,24,24,24,24,24,24,31,24,24,24,24,24,24,24,24,24,24,127,0,0,0,0,0,0,0,0,0,0,0,252,12,4,6,2,0,16,16,48,240,48,16,16,0,0,0,2,2,4,12,252,0,0,0,0,0],[0,0,0,0,0,0,127,24,24,24,24,24,24,24,24,31,24,24,24,24,24,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,254,14,2,3,1,0,8,8,24,248,24,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,3,14,8,24,48,48,32,96,96,96,96,96,96,96,96,48,48,24,24,12,3,0,0,0,0,0,0,0,0,0,0,0,200,56,8,8,4,4,0,0,0,0,0,0,63,12,12,12,12,12,12,16,224,0,0,0,0,0],[0,0,0,0,0,0,252,48,48,48,48,48,48,48,48,48,63,48,48,48,48,48,48,48,48,48,252,0,0,0,0,0,0,0,0,0,0,0,126,24,24,24,24,24,24,24,24,24,248,24,24,24,24,24,24,24,24,24,126,0,0,0,0,0],[0,0,0,0,0,0,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,31,0,0,0,0,0,0,0,0,0,0,0,248,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,248,0,0,0,0,0],[0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,112,112,113,63,0,0,0,0,0,0,254,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,192,128,0],[0,0,0,0,0,0,126,24,24,24,24,24,24,25,25,27,29,28,24,24,24,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,62,24,16,32,96,64,128,128,128,128,192,192,224,96,112,48,56,24,12,12,63,0,0,0,0,0],[0,0,0,0,0,0,126,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,4,12,252,0,0,0,0,0],[0,0,0,0,0,0,248,56,56,56,56,44,44,44,44,46,38,38,38,38,35,35,35,35,35,33,249,0,0,0,0,0,0,0,0,0,0,0,31,28,28,28,60,44,44,44,108,76,76,76,76,140,140,140,140,12,12,12,63,0,0,0,0,0],[0,0,0,0,0,0,248,56,60,44,44,46,38,39,35,35,33,33,32,32,32,32,32,32,32,32,248,0,0,0,0,0,0,0,0,0,0,0,62,8,8,8,8,8,8,8,8,136,136,200,200,232,104,120,56,56,56,24,24,0,0,0,0,0],[0,0,0,0,0,0,3,12,24,16,48,48,96,96,96,96,96,96,96,96,96,48,48,16,24,12,3,0,0,0,0,0,0,0,0,0,0,0,192,48,24,8,12,12,6,6,6,6,6,6,6,6,6,4,12,8,24,48,192,0,0,0,0,0],[0,0,0,0,0,0,127,24,24,24,24,24,24,24,24,24,31,24,24,24,24,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,240,24,12,6,6,6,6,6,12,24,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,3,12,24,48,48,48,96,96,96,96,96,96,96,96,96,39,52,56,24,12,3,0,0,0,0,0,0,0,0,0,0,0,192,48,24,8,12,4,6,6,6,6,6,6,6,6,6,134,204,76,104,112,224,50,62,28,0,0],[0,0,0,0,0,0,127,24,24,24,24,24,24,24,24,31,25,24,24,24,24,24,24,24,24,24,126,0,0,0,0,0,0,0,0,0,0,0,224,56,28,12,12,12,12,24,48,224,192,192,224,96,96,112,48,48,56,24,30,0,0,0,0,0],[0,0,0,0,0,0,7,12,24,48,48,48,48,24,30,7,1,0,0,0,0,32,32,16,24,28,19,0,0,0,0,0,0,0,0,0,0,0,228,28,12,4,4,0,0,0,0,192,240,120,28,14,6,6,6,6,12,24,240,0,0,0,0,0],[0,0,0,0,0,0,63,49,33,65,65,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,7,0,0,0,0,0,0,0,0,0,0,0,252,132,134,130,130,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,224,0,0,0,0,0],[0,0,0,0,0,0,252,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,16,28,7,0,0,0,0,0,0,0,0,0,0,0,62,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,16,32,192,0,0,0,0,0],[0,0,0,0,0,0,124,24,24,24,12,12,12,12,6,6,6,7,3,3,3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,31,4,4,4,8,8,8,8,16,16,16,48,32,32,32,192,192,192,192,128,128,0,0,0,0,0],[0,0,0,0,0,0,251,97,97,97,49,48,49,49,49,49,50,26,26,26,28,28,28,12,8,8,8,0,0,0,0,0,0,0,0,0,0,0,207,134,132,132,132,132,196,200,200,200,200,72,104,112,112,112,112,48,32,32,32,0,0,0,0,0],[0,0,0,0,0,0,126,24,28,12,12,14,6,7,3,3,1,1,2,2,4,4,8,8,16,16,124,0,0,0,0,0,0,0,0,0,0,0,124,16,16,32,32,64,64,128,128,128,128,192,192,224,96,96,48,48,24,24,62,0,0,0,0,0],[0,0,0,0,0,0,126,56,24,24,12,12,14,6,6,3,3,3,1,1,1,1,1,1,1,1,7,0,0,0,0,0,0,0,0,0,0,0,62,8,8,16,16,48,32,32,64,64,64,128,128,128,128,128,128,128,128,128,224,0,0,0,0,0],[0,0,0,0,0,0,31,24,16,32,32,0,0,0,1,1,3,3,7,6,14,12,28,24,56,48,127,0,0,0,0,0,0,0,0,0,0,0,252,24,24,48,112,96,224,192,192,128,128,0,0,0,0,0,4,4,8,24,248,0,0,0,0,0],[0,0,0,0,0,0,3,6,12,24,24,24,48,48,48,48,48,48,48,48,48,24,24,24,12,6,3,0,0,0,0,0,0,0,0,0,0,0,224,48,24,12,12,4,6,6,6,6,6,6,6,6,6,4,12,12,24,48,224,0,0,0,0,0],[0,0,0,0,0,0,0,1,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,31,0,0,0,0,0,0,0,0,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,192,248,0,0,0,0,0],[0,0,0,0,0,0,7,8,16,32,32,48,48,0,0,0,0,0,0,1,2,4,8,16,32,63,63,0,0,0,0,0,0,0,0,0,0,0,224,56,24,12,12,12,12,12,24,16,32,64,128,0,0,4,4,4,12,248,248,0,0,0,0,0],[0,0,0,0,0,0,7,24,48,48,48,48,0,0,0,3,0,0,0,0,0,48,48,48,48,24,7,0,0,0,0,0,0,0,0,0,0,0,192,112,48,24,24,24,24,48,96,192,112,24,8,12,12,12,12,8,24,48,192,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,1,1,2,6,4,8,8,16,32,32,127,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,48,112,112,240,112,112,112,112,112,112,112,112,112,112,254,112,112,112,112,112,112,254,0,0,0,0],[0,0,0,0,0,0,15,15,8,8,8,16,16,19,20,24,16,0,0,0,0,48,48,32,32,16,15,0,0,0,0,0,0,0,0,0,0,0,252,252,0,0,0,0,0,224,48,24,8,12,12,12,12,12,12,24,24,48,192,0,0,0,0,0],[0,0,0,0,0,0,1,3,4,8,24,24,16,48,49,54,60,56,48,48,48,48,24,24,12,6,3,0,0,0,0,0,0,0,0,0,0,0,240,8,12,12,0,0,0,0,240,24,12,6,6,6,6,6,6,4,12,24,224,0,0,0,0,0],[0,0,0,0,0,0,31,31,56,48,32,32,0,0,0,0,0,0,1,1,1,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,252,252,8,16,16,32,32,64,64,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,7,12,24,48,48,48,56,28,14,7,13,24,48,96,96,96,96,96,48,24,7,0,0,0,0,0,0,0,0,0,0,0,224,48,24,12,12,12,12,24,16,224,224,112,56,28,12,12,12,12,24,48,192,0,0,0,0,0],[0,0,0,0,0,0,7,24,48,48,96,96,96,96,96,96,48,24,15,0,0,0,0,48,48,48,15,0,0,0,0,0,0,0,0,0,0,0,192,32,16,24,8,12,12,12,12,28,60,108,140,12,24,24,24,48,96,192,128,0,0,0,0,0]]}}));r(i);i.font16x32,i.font12x24,i.font8x16;var a=o((function(t,r){var o=n&&n.__awaiter||function(t,e,n,r){return new(n||(n=Promise))((function(o,i){function a(t){try{s(r.next(t))}catch(t){i(t)}}function c(t){try{s(r.throw(t))}catch(t){i(t)}}function s(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(a,c)}s((r=r.apply(t,e||[])).next())}))},a=n&&n.__generator||function(t,e){var n,r,o,i,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function c(i){return function(c){return function(i){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&i[0]?r.return:i[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,i[1])).done)return o;switch(r=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,r=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]>16&255,green:n>>8&255,blue:255&n})},t.prototype.drawPointRGB=function(t,e,n){if(!(t>=this.w||e>=this.h||t<0||e<0)){var r=this.h-e-1,o=54+3*t+this._lineByteNum*r;this._data.writeUInt8(n.blue,o),this._data.writeUInt8(n.green,o+1),this._data.writeUInt8(n.red,o+2)}},t.prototype.getPointRGB=function(t,e){if(t>=this.w||e>=this.h||t<0||e<0)throw new Error("out of range");var n=this.h-e-1,r=54+3*t+this._lineByteNum*n;return{blue:this._data.readUInt8(r),green:this._data.readUInt8(r+1),red:this._data.readUInt8(r+2)}},t.prototype.drawLineH=function(t,e,n,r){if(t>e){var o=e;e=t,t=o}for(;t<=e;t++)this.drawPoint(t,n,r)},t.prototype.drawLineV=function(t,e,n,r){if(t>e){var o=e;e=t,t=o}for(;t<=e;t++)this.drawPoint(n,t,r)},t.prototype.drawLine=function(t,e,n,r,o){var i=t,a=e,c=n>t?n-t:t-n,s=r>e?r-e:e-r,d=!1,f=n>t?1:-1,u=r>e?1:-1;if(s>c){var h=c;c=s,s=h,d=!0}for(var l=(s<<1)-c,w=0;w<=c;w++)this.drawPoint(i,a,o),l>=0&&(d?i+=f:a+=u,l-=c<<1),d?a+=u:i+=f,l+=s<<1},t.prototype.drawRect=function(t,e,n,r,o){var i=t+n-1,a=e+r-1;this.drawLineH(t,i,e,o),this.drawLineH(t,i,a,o),this.drawLineV(e,a,t,o),this.drawLineV(e,a,i,o)},t.prototype.fillRect=function(t,e,n,r,o){var i=t+n-1,a=e+r-1;if(t>i){var c=i;i=t,t=c}if(e>a){c=a;a=e,e=c}for(;e<=a;e++)for(var s=t;s<=i;s++)this.drawPoint(s,e,o)},t.prototype.drawCircle=function(t,e,n,r){for(var o=0,i=n,a=3-2*n;o0;f<<=1)128&f&&this.drawPoint(c,a,o),c++;++a-n>=r.h&&(a=n,e+=8)}},t.prototype.drawString=function(t,e,n,r,o){for(var i=0,a=t;i(t.includes(r)&&n.push(e[r]),n),[]);return n[Math.random()*n.length|0]}function u(t={}){const e=["small","medium","big"],n={backgroundColor:16775912,size:4,noise:4,width:100,height:40,fontSize:["medium","big"]};let{backgroundColor:r,size:o,noise:i,width:a,height:s,fontSize:f}=Object.assign({},n,t);"string"==typeof r&&(r=r.replace("#","0x")),f instanceof Array||(f=[]),f.filter(t=>e.includes(t)),f.length||(f=n.fontSize),o=o>6?6:o;const u=new c(a,s);u.fillRect(0,0,a,s,r),function(t,e){for(let n=1;n>16,r=e>>8&255,o=255&e,i=Math.max(n,r,o),a=Math.min(n,r,o);return(i+a)/510}(t):1;let o,i;r>=.5?(o=Math.round(100*r)-45,i=Math.round(100*r)-25):(o=Math.round(100*r)+25,i=Math.round(100*r)+45);const a=h(o,i)/100,c=a<.5?a*(a+n):a+n-a*n,s=2*a-c,d=Math.floor(255*w(s,c,e+1/3)),f=Math.floor(255*w(s,c,e));return"#"+(Math.floor(255*w(s,c,e-1/3))|f<<8|d<<16|1<<24).toString(16).slice(1)};function w(t,e,n){return 6*(n=(n+1)%1)<1?t+(e-t)*n*6:2*n<1?e:3*n<2?t+(e-t)*(2/3-n)*6:t}const p=Object.prototype.toString;function g(t){return"[object Object]"===p.call(t)}function y(){"development"===process.env.NODE_ENV&&console.log(...arguments)}const v=async function(){};function m(t){return v.constructor===t.constructor?async function(){const e=await t.apply(this,arguments);return g(e)&&e.msg&&(e.message=e.msg),e}:function(){const e=t.apply(this,arguments);return g(e)&&e.msg&&(e.message=e.msg),e}}const b=uniCloud.database().collection("opendb-verify-codes"),_={};var I=Object.freeze({__proto__:null,create:async function(t={}){let{scene:e,expiresDate:n,deviceId:r,...o}=t;if(r=r||__ctx__.DEVICEID,!r)throw new Error("deviceId不可为空");if(!e)throw new Error("scene验证码场景不可为空");try{const{text:i,base64:a}=u(o),c=await this.setVerifyCode({deviceId:r,code:i,expiresDate:n,scene:e});return c.code>0?{...c,code:10001}:(_[r]=t,{code:0,msg:"验证码获取成功",captchaBase64:a})}catch(t){return{code:10001,msg:"验证码生成失败:"+t.message}}},verify:async function({deviceId:t,captcha:e,scene:n}){if(!(t=t||__ctx__.DEVICEID))throw new Error("deviceId不可为空");if(!n)throw new Error("scene验证码场景不可为空");try{const r=await this.verifyCode({deviceId:t,code:e,scene:n});return r.code>0?{...r,code:10002}:{code:0,msg:"验证码通过"}}catch(t){return{code:10002,msg:"验证码校验失败:"+t.message}}},refresh:async function(t={}){let{scene:e,expiresDate:n,deviceId:r,...o}=t;if(r=r||__ctx__.DEVICEID,!r)throw new Error("deviceId不可为空");if(!e)throw new Error("scene验证码场景不可为空");const i=await b.where({deviceId:r,scene:e,state:0}).orderBy("created_date","desc").limit(1).get();if(i&&i.data&&i.data.length>0){const t=i.data[0];await b.doc(t._id).update({state:2});let a={};Object.keys(o).length>0&&(_[r]=Object.assign({},_[r],o)),a=_[r];let c={};try{c=await this.create(Object.assign({},a,{deviceId:r,scene:e,expiresDate:n}))}catch(t){return{code:50403,msg:t.message}}return c.code>0?{...c,code:10003}:{code:0,msg:"验证码刷新成功",captchaBase64:c.captchaBase64}}return{code:10003,msg:"验证码刷新失败:无此设备信息,请重新获取"}},setVerifyCode:async function({deviceId:t,code:e,expiresDate:n,scene:r}){if(!t)return{code:10101,msg:"deviceId不可为空"};if(!e)return{code:10102,msg:"验证码不可为空"};n||(n=180);const o=Date.now(),i={deviceId:t,scene:r,code:e.toLocaleLowerCase(),state:0,ip:__ctx__.CLIENTIP,created_date:o,expired_date:o+1e3*n};return y("addRes",await b.add(i)),{code:0,deviceId:t}},verifyCode:async function({deviceId:t,code:e,scene:n}){if(!t)return{code:10101,msg:"deviceId不可为空"};if(!e)return{code:10102,msg:"验证码不可为空"};const r=Date.now(),o={deviceId:t,scene:n,code:e.toLocaleLowerCase(),state:0},i=await b.where(o).orderBy("created_date","desc").limit(1).get();if(y("verifyRecord:",i),i&&i.data&&i.data.length>0){const t=i.data[0];if(t.expired_date
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-card/package.json b/uni_modules/uni-card/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..507273c1f11d146f34c4bf180ffa21d30a535b6c
--- /dev/null
+++ b/uni_modules/uni-card/package.json
@@ -0,0 +1,85 @@
+{
+ "id": "uni-card",
+ "displayName": "uni-card 卡片",
+ "version": "1.2.1",
+ "description": "Card 组件,提供常见的卡片样式。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "card",
+ "",
+ "卡片"
+],
+ "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-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"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-card/readme.md b/uni_modules/uni-card/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..6f72c837d0df7a5022e84c11257a47e79992f12a
--- /dev/null
+++ b/uni_modules/uni-card/readme.md
@@ -0,0 +1,104 @@
+
+
+## Card 卡片
+> **组件名:uni-card**
+> 代码块: `uCard`
+
+
+卡片视图组件。
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 因为平台兼容问题 , 目前 APP-NVUE 安卓平台下不支持阴影
+
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+ 内容主体,可自定义内容及样式
+
+
+
+
+
+
+
+
+
+ uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可编译到iOS、Android、H5、以及各种小程序等多个平台。即使不跨端,uni-app同时也是更好的小程序开发框架。
+
+
+
+
+ uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可编译到iOS、Android、H5、以及各种小程序等多个平台。即使不跨端,uni-app同时也是更好的小程序开发框架。
+
+
+
+
+ 默认内容
+
+
+
+
+```
+
+## API
+
+### Card Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|title |String |- |标题文字 |
+|extra |String |- |标题额外信息 |
+|note |String |- |底部信息 |
+|thumbnail |String |- |标题左侧缩略图,支持网络图片,本地图片,本图片需要传入一个绝对路径,如:`/static/xxx.png` |
+|mode |String |basic |卡片模式 ,可选值, basic:基础卡片 ;style :图文卡片 ; title :标题卡片 |
+|isFull |Boolean|false |卡片内容是否通栏,为true时将去除padding值 |
+|isShadow |Boolean|false |卡片内容是否开启阴影 |
+
+
+### Card Events
+
+|事件称名 |事件说明 |返回参数 |
+|:-: |:-: |:-: |
+|@click |点击 Card 触发事件 |- |
+
+
+### Card Slots
+
+|插槽称名 |说明 |
+|:-: |:-: |
+|header |卡片头部插槽( 图文卡片 mode="style" 时,不支持)|
+|footer |卡片底部插槽 |
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/card/card](https://hellouniapp.dcloud.net.cn/pages/extUI/card/card)
\ No newline at end of file
diff --git a/uni_modules/uni-collapse/changelog.md b/uni_modules/uni-collapse/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..9fb4b5c1b1cc1c89ff1be7a1456f0121e3736fbd
--- /dev/null
+++ b/uni_modules/uni-collapse/changelog.md
@@ -0,0 +1,27 @@
+## 1.3.3(2021-08-17)
+- 优化 show-arrow 属性默认为true
+## 1.3.2(2021-08-17)
+- 新增 show-arrow 属性,控制是否显示右侧箭头
+## 1.3.1(2021-07-30)
+- 优化 vue3下小程序事件警告的问题
+## 1.3.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.2.2(2021-07-21)
+- 修复 由1.2.0版本引起的 change 事件返回 undefined 的Bug
+## 1.2.1(2021-07-21)
+- 优化 组件示例
+## 1.2.0(2021-07-21)
+- 新增 组件折叠动画
+- 新增 value\v-model 属性 ,动态修改面板折叠状态
+- 新增 title 插槽 ,可定义面板标题
+- 新增 border 属性 ,显示隐藏面板内容分隔线
+- 新增 title-border 属性 ,显示隐藏面板标题分隔线
+- 修复 resize 方法失效的Bug
+- 修复 change 事件返回参数不正确的Bug
+- 优化 H5、App 平台自动更具内容更新高度,无需调用 reszie() 方法
+## 1.1.7(2021-05-12)
+- 新增 组件示例地址
+## 1.1.6(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.1.5(2021-02-05)
+- 调整为uni_modules目录规范
\ No newline at end of file
diff --git a/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue b/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e962a9f1a30f0c052c826c01128758c3195e67a5
--- /dev/null
+++ b/uni_modules/uni-collapse/components/uni-collapse-item/uni-collapse-item.vue
@@ -0,0 +1,402 @@
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue b/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b7360d47f03d31f38d931c43620b060bd7b5846d
--- /dev/null
+++ b/uni_modules/uni-collapse/components/uni-collapse/uni-collapse.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-collapse/package.json b/uni_modules/uni-collapse/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..965814fb4c8447cdcbdd8223ca4403303bc84cdb
--- /dev/null
+++ b/uni_modules/uni-collapse/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-collapse",
+ "displayName": "uni-collapse 折叠面板",
+ "version": "1.3.3",
+ "description": "Collapse 组件,可以折叠 / 展开的内容区域。",
+ "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-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": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-collapse/readme.md b/uni_modules/uni-collapse/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..12e872fb1d6f51bdb6fb8259043b1fa3c04b47a2
--- /dev/null
+++ b/uni_modules/uni-collapse/readme.md
@@ -0,0 +1,276 @@
+
+
+## Collapse 折叠面板
+> **组件名:uni-collapse**
+> 代码块: `uCollapse`
+> 关联组件:`uni-collapse-item`、`uni-icons`。
+
+
+折叠面板用来折叠/显示过长的内容或者是列表。通常是在多内容分类项使用,折叠不重要的内容,显示重要内容。点击可以展开折叠部分。
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - `App` 端默认关闭组件动画 ,因为 `height` 动画开销比较大,会导致页面卡顿,请酌情使用动画
+> - 如在使用组件过程从发现卡顿严重,请尝试停用组件动画,问题原因如上
+> - 在小程序端组件内容发生变化,需要手动调用 resize() 方法,手动更新几点信息,避免出现内容错位
+> - 如需自定义组件默认边框颜色等,请使用插槽自定义内容并合理使用 `border ` 和 `title-border` 属性
+> - 折叠面板仅支持嵌套使用,请勿单独使用
+> - 组件支持 nvue ,需要在 `manifest.json > app-plus` 节点下配置 `"nvueStyleCompiler" : "uni-app"`
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+
+### 基本用法
+
+使用 `title` 属性指定面板显示内容
+
+使用 `open` 属性默认打开当前面板
+
+使用 `disabled` 属性禁用面板
+
+
+```html
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+```
+
+### 手风琴效果
+
+使用 `accordion` 属性,可以仅打开一个面板并关闭其他已经打开的面板,效果类似手风琴
+
+设置 `accordion` 属性时,`open` 属性则生效在最后一个组件
+
+```html
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+```
+
+### 动态设置折叠面板打开状态
+
+使用 `v-model` 属性,动态设置面板的显示状态
+
+使用 `name` 属性设置每个面板的唯一标识,如不设置使用默认索引,从字符串 `"0"` 开始记数
+
+**注意**
+
+- 如果 `accordion` 属性为 `true` 则 `v-model` 类型为 `String`
+- 如果 `accordion` 属性为 `false` 则 `v-model` 类型为 `Array`
+- 请注意 `v-model` 属性与 `open` 属性请勿一起使用 ,建议只使用 `v-model`
+
+```html
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+```
+
+```javascript
+export default {
+ data(){
+ return {
+ value:['key1','key2'],
+ // 如果设置了 accordion 属性,则使用 string 类型
+ // value:'key1'
+ }
+ }
+}
+```
+
+### 使用动画
+
+使用 `show-animation` 属性开启或关闭面板折叠动画,默认动画开启
+
+**注意**
+
+- `App` 端默认关闭组件动画 ,因为 height 动画开销比较大,会导致页面卡顿,请酌情使用动画,如出现明显卡顿,尝试关闭动画
+
+
+```html
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+ 折叠内容
+
+
+```
+
+### 配置图片
+
+使用 `thumb` 配置图片地址, 可在面板左侧显示一个图片
+
+如需显示更多内容,如图标等,请见下方自定义插槽的说明
+
+```html
+
+
+
+ 折叠内容主体,可自定义内容及样式
+
+
+
+```
+
+### 自定义插槽
+
+如果需要自定义面板显示,可以使用 `title` 插槽达成完全自定义。下面是一个使用 `uni-list` 的列表示例,需要引入 `uni-list` 组件
+
+```html
+
+
+
+
+
+
+
+
+
+
+ 折叠内容主体,可自定义内容及样式
+
+
+
+```
+
+**注意**
+
+- 在折叠面板组件中使用list时,在 App-Nvue 下请勿单独使用 uni-list-item,会导致组件无法正常显示,其他平台不做限制
+- 在默认插槽里使用 uni-list 组件与上方示例一样,直接写在默认插槽里即可
+
+## API
+
+### Collapse Props
+
+|属性名|类型|默认值|说明|
+|:-:|:-:|:-:|:-:|
+|value/v-model|String/Array|-|当前激活面板改变时触发(如果是手风琴模式,参数类型为string,否则为array)|
+|accordion|Boolean|false|是否开启手风琴效果 |
+
+### Collapse Event
+
+|事件称名|说明|返回值|
+|:-:|:-:|:-:|
+|@change|切换面板时触发 |切换面板时触发,如果是手风琴模式,返回类型为string,否则为array|
+
+### Collapse Methods
+
+|方法名称|说明|
+|:-:|:-:|
+|resize |更新当前列表高度|
+
+> **提示**
+> - resize 方法解决动态添加数据,带动画的折叠面板高度不更新的问题
+> - 需要在数据渲染完毕之后使用 `resize` 方法。推荐在 `this.$nextTick()` 中使用
+> - 当前只有小程序端需要调用此方法,H5\App 端已经做了处理,不需要手动更新高度
+> ```html
+>
+>
+>
+>
+> {{content}}
+>
+>
+>
+>
+> 折叠内容主体,这是一段比较长内容。默认折叠主要内容,只显示当前项标题。点击标题展开,才能看到这段文字。再次点击标题,折叠内容。
+>
+>
+>
+> 动态修改内容
+>
+> ```
+> ```javascript
+> export default {
+> data() {
+> return {
+> value:['0'],
+> content: '折叠内容主体,可自定义内容及样式,点击按钮修改内容使高度发生变化。',
+> }
+> },
+> methods: {
+> add() {
+> if (this.content.length > 35) {
+> this.content = '折叠内容主体,可自定义内容及样式,点击按钮修改内容使高度发生变化。'
+> } else {
+> this.content = '折叠内容主体,这是一段比较长内容。通过点击按钮修改后内容后,使组件高度发生变化,在次点击按钮恢复之前的内容和高度。'
+> }
+> // TODO 小程序中不支持自动更新 ,需要手动resize 更新组件高度
+> // #ifdef MP
+> this.$nextTick(() => {
+> this.$refs.collapse.resize()
+> })
+> // #endif
+> }
+> }
+> }
+> ```
+
+
+### CollapseItem Props
+
+|属性名|类型|默认值|说明|
+|:-:|:-:|:-:|:-:|
+|title|String|-|标题文字|
+|thumb|String|-|标题左侧缩略图|
+|disabled|Boolean|false|是否禁用|
+|open|Boolean|false|是否展开面板|
+|show-animation|Boolean|false|开启动画|
+|border|Boolean|true|折叠面板内容分隔线|
+|title-border|String|auto|折叠面板标题分隔线可选值见下方 **TitleBorder Params**|
+|show-arrow|Boolean|true|是否显示右侧箭头|
+
+#### TitleBorder Params
+
+|参数名|说明|
+|:-:|:-:|
+|auto|分隔线自动显示|
+|none|不显示分隔线|
+|show|一直显示分隔线|
+
+### Collapse Slots
+
+|插槽名|说明|
+|:-:| :-:|
+|default|默认插槽|
+|title|面板标题插槽,如使用此插槽禁用样式效果将失效|
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/collapse/collapse](https://hellouniapp.dcloud.net.cn/pages/extUI/collapse/collapse)
\ No newline at end of file
diff --git a/uni_modules/uni-combox/changelog.md b/uni_modules/uni-combox/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..39e8a055d5e6d6bb1e7beffa6db32196b224a230
--- /dev/null
+++ b/uni_modules/uni-combox/changelog.md
@@ -0,0 +1,10 @@
+## 0.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.0.6(2021-05-12)
+- 新增 组件示例地址
+## 0.0.5(2021-04-21)
+- 优化 添加依赖 uni-icons, 导入后自动下载依赖
+## 0.0.4(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 0.0.3(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-combox/components/uni-combox/uni-combox.vue b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue
new file mode 100644
index 0000000000000000000000000000000000000000..fef61111447a01d928d623d144e6c2700873eb5e
--- /dev/null
+++ b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue
@@ -0,0 +1,239 @@
+
+
+
+ {{label}}
+
+
+
+
+
+
+
+ {{emptyTips}}
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-combox/package.json b/uni_modules/uni-combox/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1254459e9936ca6a53fa08206b75f6e12e945708
--- /dev/null
+++ b/uni_modules/uni-combox/package.json
@@ -0,0 +1,85 @@
+{
+ "id": "uni-combox",
+ "displayName": "uni-combox 组合框",
+ "version": "0.1.0",
+ "description": "可以选择也可以输入的表单项 ",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "combox",
+ "组合框",
+ "select"
+],
+ "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-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "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"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-combox/readme.md b/uni_modules/uni-combox/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..edab4d409d273103f364792c5b891f9da57644bf
--- /dev/null
+++ b/uni_modules/uni-combox/readme.md
@@ -0,0 +1,52 @@
+
+
+## Combox 组合框
+> **组件名:uni-combox**
+> 代码块: `uCombox`
+
+
+组合框组件。
+
+### 平台兼容性说明
+
+**暂不支持nvue**
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+```html
+
+```
+
+## API
+
+### Combox Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|label |String |- |标签文字 |
+|value |String |- |combox的值 |
+|labelWidth |String |auto |标签宽度,有单位字符串,如:'100px' |
+|placeholder|String |- |输入框占位符 |
+|candidates |Array/String |[] |候选字段 |
+|emptyTips |String |无匹配项 |无匹配项时的提示语 |
+
+### Combox Events
+
+|事件称名 |说明 |返回值 |
+|:-: |:-: |:-: |
+|@input |combox输入事件 |返回combox值|
+
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/combox/combox](https://hellouniapp.dcloud.net.cn/pages/extUI/combox/combox)
\ No newline at end of file
diff --git a/uni_modules/uni-config-center/changelog.md b/uni_modules/uni-config-center/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..4d2eb92f668fd9c35d56f525fde7244b7b38972d
--- /dev/null
+++ b/uni_modules/uni-config-center/changelog.md
@@ -0,0 +1,4 @@
+## 0.0.2(2021-04-16)
+- 修改插件package信息
+## 0.0.1(2021-03-15)
+- 初始化项目
diff --git a/uni_modules/uni-config-center/package.json b/uni_modules/uni-config-center/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c5dec93b1299d7881b5f80f95960b8024f41772b
--- /dev/null
+++ b/uni_modules/uni-config-center/package.json
@@ -0,0 +1,80 @@
+{
+ "id": "uni-config-center",
+ "displayName": "uni-config-center",
+ "version": "0.0.2",
+ "description": "uniCloud 配置中心",
+ "keywords": [
+ "配置",
+ "配置中心"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "uniCloud",
+ "云函数模板"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "directories": {
+ "example": "../../../scripts/dist"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "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"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-config-center/readme.md b/uni_modules/uni-config-center/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..03f7fc27964d93a6c16cc2671d777faa52e079a4
--- /dev/null
+++ b/uni_modules/uni-config-center/readme.md
@@ -0,0 +1,93 @@
+# 为什么使用uni-config-center
+
+实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构
+
+```bash
+cloudfunctions
+└─────common 公共模块
+ ├─plugin-a // 插件A对应的目录
+ │ ├─index.js
+ │ ├─config.json // plugin-a对应的配置文件
+ │ └─other-file.cert // plugin-a依赖的其他文件
+ └─plugin-b // plugin-b对应的目录
+ ├─index.js
+ └─config.json // plugin-b对应的配置文件
+```
+
+假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。
+
+uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下
+
+```bash
+cloudfunctions
+└─────common 公共模块
+ ├─plugin-a // 插件A对应的目录
+ │ └─index.js
+ ├─plugin-b // plugin-b对应的目录
+ │ └─index.js
+ └─uni-config-center
+ ├─index.js // config-center入口文件
+ ├─plugin-a
+ │ ├─config.json // plugin-a对应的配置文件
+ │ └─other-file.cert // plugin-a依赖的其他文件
+ └─plugin-b
+ └─config.json // plugin-b对应的配置文件
+```
+
+使用uni-config-center后的优势
+
+- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便
+- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持)
+
+# 用法
+
+在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common)
+
+```js
+const createConfig = require('uni-config-center')
+
+const uniIdConfig = createConfig({
+ pluginId: 'uni-id', // 插件id
+ defaultConfig: { // 默认配置
+ tokenExpiresIn: 7200,
+ tokenExpiresThreshold: 600,
+ },
+ customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并
+ // defaudltConfig 默认配置
+ // userConfig 用户配置
+ return Object.assign(defaultConfig, userConfig)
+ }
+})
+
+
+// 以如下配置为例
+// {
+// "tokenExpiresIn": 7200,
+// "passwordErrorLimit": 6,
+// "bindTokenToDevice": false,
+// "passwordErrorRetryTime": 3600,
+// "app-plus": {
+// "tokenExpiresIn": 2592000
+// },
+// "service": {
+// "sms": {
+// "codeExpiresIn": 300
+// }
+// }
+// }
+
+// 获取配置
+uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象
+uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200
+uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300
+uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600
+
+// 获取文件绝对路径
+uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径
+
+// 引用文件(require)
+uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。
+
+// 判断是否包含某文件
+uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在
+```
\ No newline at end of file
diff --git a/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e14fb3b0a213443d5c51cb3fcb763d322c21c97f
--- /dev/null
+++ b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js
@@ -0,0 +1 @@
+"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t
+
+ {{ d }}
+ {{dayText}}
+ {{ h }}
+ {{ showColon ? ':' : hourText }}
+ {{ i }}
+ {{ showColon ? ':' : minuteText }}
+ {{ s }}
+ {{secondText}}
+
+
+
+
diff --git a/uni_modules/uni-countdown/package.json b/uni_modules/uni-countdown/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..7960b62e9ff41de8976a2f4e3ba1d2ea00f06668
--- /dev/null
+++ b/uni_modules/uni-countdown/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "uni-countdown",
+ "displayName": "uni-countdown 倒计时",
+ "version": "1.1.2",
+ "description": "CountDown 倒计时组件",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "countdown",
+ "倒计时"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-countdown/readme.md b/uni_modules/uni-countdown/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..25c2a3a2756009668fe23208a4aab6048f088d10
--- /dev/null
+++ b/uni_modules/uni-countdown/readme.md
@@ -0,0 +1,57 @@
+
+
+## CountDown 倒计时
+> **组件名:uni-countdown**
+> 代码块: `uCountDown`
+
+
+倒计时组件。
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+
+
+
+
+
+```
+
+## API
+
+### Countdown Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|backgroundColor |String |#FFFFFF|背景色 |
+|color |String |#000000|文字颜色 |
+|splitorColor |String |#000000|分割符号颜色 |
+|day |Number |0 |天数 |
+|hour |Number |0 |小时 |
+|minute |Number |0 |分钟 |
+|second |Number |0 |秒 |
+|showDay |Boolean|true |是否显示天数 |
+|showColon |Boolean|true |是否以冒号为分隔符 |
+|start |Boolean|true |是否初始化组件后就开始倒计时|
+
+### Countdown Events
+
+|事件称名 |说明 |返回值 |
+|:-: |:-: |:-: |
+|@timeup|倒计时时间到触发事件 |- |
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/countdown/countdown](https://hellouniapp.dcloud.net.cn/pages/extUI/countdown/countdown)
\ No newline at end of file
diff --git a/uni_modules/uni-data-checkbox/changelog.md b/uni_modules/uni-data-checkbox/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..cda4c3bb86d5c1c6d9fcbef053aba73d1710c369
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/changelog.md
@@ -0,0 +1,36 @@
+## 0.2.5(2021-08-23)
+- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
+## 0.2.4(2021-08-17)
+- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
+## 0.2.3(2021-08-11)
+- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
+## 0.2.2(2021-07-30)
+- 优化 在uni-forms组件,与label不对齐的问题
+## 0.2.1(2021-07-27)
+- 修复 单选默认值为0不能选中的Bug
+## 0.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.1.11(2021-07-06)
+- 优化 删除无用日志
+## 0.1.10(2021-07-05)
+- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
+## 0.1.9(2021-07-05)
+- 修复 nvue 黑框样式问题
+## 0.1.8(2021-06-28)
+- 修复 selectedTextColor 属性不生效的Bug
+## 0.1.7(2021-06-02)
+- 新增 map 属性,可以方便映射text/value属性
+## 0.1.6(2021-05-26)
+- 修复 不关联服务空间的情况下组件报错的Bug
+## 0.1.5(2021-05-12)
+- 新增 组件示例地址
+## 0.1.4(2021-04-09)
+- 修复 nvue 下无法选中的问题
+## 0.1.3(2021-03-22)
+- 新增 disabled属性
+## 0.1.2(2021-02-24)
+- 优化 默认颜色显示
+## 0.1.1(2021-02-24)
+- 新增 支持nvue
+## 0.1.0(2021-02-18)
+- “暂无数据”显示居中
diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
new file mode 100644
index 0000000000000000000000000000000000000000..71dd59b1565ef1af6f3e7f471b29d2a9b7a5e1b7
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue
@@ -0,0 +1,823 @@
+
+
+
+
+
+ {{mixinDatacomErrorMessage}}
+
+
+
+
+
+
+
+
+
+
+ {{item[map.text]}}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item[map.text]}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-data-checkbox/package.json b/uni_modules/uni-data-checkbox/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e978c4ef01fb640948e16c975851c3ba92aa8ff2
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/package.json
@@ -0,0 +1,87 @@
+{
+ "id": "uni-data-checkbox",
+ "displayName": "uni-data-checkbox 数据选择器",
+ "version": "0.2.5",
+ "description": "通过数据驱动的单选框和复选框",
+ "keywords": [
+ "uni-ui",
+ "checkbox",
+ "单选",
+ "多选",
+ "单选多选"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": "^3.1.1"
+ },
+ "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-load-more"],
+ "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"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-data-checkbox/readme.md b/uni_modules/uni-data-checkbox/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..485008580fc12ce343f67025ba60fec0a60b36f3
--- /dev/null
+++ b/uni_modules/uni-data-checkbox/readme.md
@@ -0,0 +1,299 @@
+
+
+## DataCheckbox 数据驱动的单选复选框
+> **组件名:uni-data-checkbox**
+> 代码块: `uDataCheckbox`
+
+
+本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
+
+1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
+2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
+3. 本组件合并了单选多选
+4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
+
+在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - 本组件为数据驱动,目的是快速投入使用,只可通过 style 覆盖有限样式,不支持自定义更多样式
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+> - 组件支持 nvue ,需要在 `manifest.json > app-plus` 节点下配置 `"nvueStyleCompiler" : "uni-app"`
+> - 如组件显示有问题 ,请升级 `HBuilderX` 为 `v3.1.0` 以上
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另行文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+设置 `localdata` 属性后,组件会通过数据渲染出对应的内容,默认显示的是单选框
+
+需要注意 `:multiple="false"` 时(单选) , `value/v-model` 的值是 `String|Number` 类型
+
+```html
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {
+ value: 0,
+ range: [{"value": 0,"text": "篮球" },{"value": 1,"text": "足球"},{"value": 2,"text": "游泳"}]
+ }
+ },
+ methods: {
+ change(e){
+ console.log('e:',e);
+ }
+ }
+}
+```
+
+### 多选框
+
+设置 `multiple` 属性,组件显示为多选框
+
+需要注意 `:multiple="true"` 时(多选) , `value/v-model` 的值是 `Array` 类型
+
+```html
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {
+ value: [0,2],
+ range: [{"value": 0,"text": "篮球" },{"value": 1,"text": "足球"},{"value": 2,"text": "游泳"}]
+ }
+ },
+ methods: {
+ change(e){
+ console.log('e:',e);
+ }
+ }
+}
+```
+
+### 设置最大最小值
+
+设置 `:multiple="true"` 时(多选) ,可以设置 `min`、`max` 属性
+
+如果选中个数小于 `min` 属性设置的值,那么选中内容将不可取消,只有当选中个数大于等于 `min`且小于 `max` 时,才可取消选中
+
+如果选中个数大于等于 `max` 属性设置的值,那么其他未选中内容将不可选
+
+```html
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {
+ value: [0,2],
+ range: [{"value": 0,"text": "篮球" },{"value": 1,"text": "足球"},{"value": 2,"text": "游泳"}]
+ }
+ },
+ methods: {
+ change(e){
+ console.log('e:',e);
+ }
+ }
+}
+```
+
+### 设置禁用
+
+如果需要禁用某项,需要在 `localdata` 属性的数据源中添加 `disable` 属性,而不是在组件中添加 `disable` 属性
+
+```html
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {
+ value: 0,
+ range: [{
+ "value": 0,
+ "text": "篮球"
+ },
+ {
+ "value": 1,
+ "text": "足球",
+ // 禁用当前项
+ "disable":true
+ },
+ {
+ "value": 2,
+ "text": "游泳"
+ }
+ ]
+ }
+ },
+ methods: {
+ change(e){
+ console.log('e:',e);
+ }
+ }
+}
+```
+
+
+### 自定义选中颜色
+
+设置 `selectedColor` 属性,可以修改组件选中后的图标及边框颜色
+
+设置 `selectedTextColor` 属性,可以修改组件选中后的文字颜色,如不填写默认同 `selectedColor` 属性 ,`mode` 属性为 `tag` 时,默认为白色
+
+```html
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {
+ value: [0,2],
+ range: [{"value": 0,"text": "篮球" },{"value": 1,"text": "足球"},{"value": 2,"text": "游泳"}]
+ }
+ },
+ methods: {
+ change(e){
+ console.log('e:',e);
+ }
+ }
+}
+```
+
+### 更多模式
+
+设置 `mode` 属性,可以设置更多显示样式,目前内置样式有四种 `default/list/button/tag`
+
+如果需要禁用某项,需要在 `localdata` 属性的数据源中添加 `disable` 属性,而不是在组件中添加 `disable` 属性
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ data() {
+ return {
+ value: 0,
+ range: [{"value": 0,"text": "篮球" },{"value": 1,"text": "足球"},{"value": 2,"text": "游泳"}]
+ }
+ },
+ methods: {
+ change(e){
+ console.log('e:',e);
+ }
+ }
+}
+```
+
+
+## API
+
+### DataCheckbox Props
+
+| 属性名 | 类型 |可选值 | 默认值| 说明 |
+| :-: | :-: |:-: |:-: | :-: |
+|value/v-model|Array/String/Number|- |- |默认值,multiple=true时为 Array类型,否则为 String或Number类型 |
+|localdata |Array |- |- |本地渲染数据, |
+|mode | String |default/list/button/tag|default|显示模式 |
+|multiple |Boolean |- |false |是否多选 |
+|min |String/Number |- |- |最小选择个数 ,multiple为true时生效 |
+|max |String/Number |- |- |最大选择个数 ,multiple为true时生效 |
+|wrap |Boolean |- |- |是否换行显示 |
+|icon |String |left/right |left |list 列表模式下 icon 显示的位置 |
+|selectedColor|String |- |#007aff|选中颜色|
+|selectedTextColor|String |- |#333 |选中文本颜色,如不填写则自动显示|
+|emptyText |String |- |暂无数据 |没有数据时显示的文字 ,本地数据无效|
+|map |Object |- |{text:'text',value:'value'} |字段映射,将text/value映射到数据中的其他字段|
+
+#### Localdata Options
+
+`localdata` 属性的格式为数组,数组内每项是对象,需要严格遵循如下格式
+
+|属性名 | 说明 |
+|:-: | :-: |
+|text |显示文本 |
+|value |选中后的值 |
+|disable |是否禁用 |
+
+#### Mode Options
+
+|属性名 | 说明 |
+|:-: | :-: |
+|default |默认值,横向显示 |
+|list |列表 |
+|button |按钮 |
+|tag |标签 |
+
+
+### DataCheckbox Events
+
+| 事件名 | 事件说明 | 返回参数|
+| :-: | :-: | :-: |
+| @change| 选中状态改变时触发事件 | - |
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/data-checkbox/data-checkbox](https://hellouniapp.dcloud.net.cn/pages/extUI/data-checkbox/data-checkbox)
\ No newline at end of file
diff --git a/uni_modules/uni-data-picker/changelog.md b/uni_modules/uni-data-picker/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..269cedcf404c41523691bb7cfeaba22730bcc736
--- /dev/null
+++ b/uni_modules/uni-data-picker/changelog.md
@@ -0,0 +1,25 @@
+## 0.4.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.3.5(2021-06-04)
+- 修复 无法加载云端数据的问题
+## 0.3.4(2021-05-28)
+- 修复 v-model无效问题
+- 修复 loaddata 为空数据组时加载时间过长问题
+- 修复 上个版本引出的本地数据无法选择带有children的2级节点
+## 0.3.3(2021-05-12)
+- 新增 组件示例地址
+## 0.3.2(2021-04-22)
+- 修复 非树形数据有 where 属性查询报错的问题
+## 0.3.1(2021-04-15)
+- 修复 本地数据概率无法回显时问题
+## 0.3.0(2021-04-07)
+- 新增 支持云端非树形表结构数据
+- 修复 根节点 parent_field 字段等于null时选择界面错乱问题
+## 0.2.0(2021-03-15)
+- 修复 nodeclick、popupopened、popupclosed事件无法触发的问题
+## 0.1.9(2021-03-09)
+- 修复 微信小程序某些情况下无法选择的问题
+## 0.1.8(2021-02-05)
+- 优化 部分样式在nvue上的兼容表现
+## 0.1.7(2021-02-05)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/config.json b/uni_modules/uni-data-picker/components/uni-data-picker/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc6b403974e5b00c4bc44de7334de52448cff076
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-picker/config.json
@@ -0,0 +1,12 @@
+{
+ "id": "3796",
+ "name": "DataPicker",
+ "desc": "数据驱动的picker选择器",
+ "url": "data-picker",
+ "type": "表单组件",
+ "edition": "0.0.8",
+ "suffix": "vue",
+ "module": ["uni-data-picker","uni-data-pickerview","uni-load-more"],
+ "path": "https://ext.dcloud.net.cn/plugin?id=3796",
+ "update_log": ["- 优化 增加下拉箭头"]
+}
diff --git a/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js b/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ef26a26211ff28976e6fc835fbef5d2ea5b5b1e
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-picker/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-data-picker/components/uni-data-picker/uni-data-picker.vue b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..fced5ecd14dd65cb4797444d337056f93514b60a
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue
@@ -0,0 +1,472 @@
+
+
+
+
+
+ {{errorMessage}}
+
+
+
+
+
+
+ {{item.text}} {{split}}
+
+
+
+ {{placeholder}}
+
+
+
+
+
+
+
+
+
+
+ {{popupTitle}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb285009fc728adbb77ee0efb4f8fe65cf0a50a4
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js
@@ -0,0 +1,545 @@
+export default {
+ props: {
+ localdata: {
+ type: [Array, Object],
+ default () {
+ return []
+ }
+ },
+ collection: {
+ type: String,
+ default: ''
+ },
+ action: {
+ type: String,
+ default: ''
+ },
+ field: {
+ type: String,
+ default: ''
+ },
+ orderby: {
+ type: String,
+ default: ''
+ },
+ where: {
+ type: [String, Object],
+ default: ''
+ },
+ pageData: {
+ type: String,
+ default: 'add'
+ },
+ pageCurrent: {
+ type: Number,
+ default: 1
+ },
+ pageSize: {
+ type: Number,
+ default: 20
+ },
+ getcount: {
+ type: [Boolean, String],
+ default: false
+ },
+ getone: {
+ type: [Boolean, String],
+ default: false
+ },
+ gettree: {
+ type: [Boolean, String],
+ default: false
+ },
+ manual: {
+ type: Boolean,
+ default: false
+ },
+ value: {
+ type: [Array, String, Number],
+ default () {
+ return []
+ }
+ },
+ modelValue: {
+ type: [Array, String, Number],
+ default () {
+ return []
+ }
+ },
+ preload: {
+ type: Boolean,
+ default: false
+ },
+ stepSearh: {
+ type: Boolean,
+ default: true
+ },
+ selfField: {
+ type: String,
+ default: ''
+ },
+ parentField: {
+ type: String,
+ default: ''
+ },
+ multiple: {
+ type: Boolean,
+ default: false
+ }
+ },
+ data() {
+ return {
+ loading: false,
+ errorMessage: '',
+ loadMore: {
+ contentdown: '',
+ contentrefresh: '',
+ contentnomore: ''
+ },
+ dataList: [],
+ selected: [],
+ selectedIndex: 0,
+ page: {
+ current: this.pageCurrent,
+ size: this.pageSize,
+ count: 0
+ }
+ }
+ },
+ computed: {
+ isLocaldata() {
+ return !this.collection.length
+ },
+ postField() {
+ let fields = [this.field];
+ if (this.parentField) {
+ fields.push(`${this.parentField} as parent_value`);
+ }
+ return fields.join(',');
+ },
+ dataValue(){
+ let isarr = Array.isArray(this.value) && this.value.length === 0
+ let isstr = typeof this.value === 'string' && !this.value
+ let isnum = typeof this.value === 'number' && !this.value
+
+ if(isarr || isstr || isnum){
+ return this.modelValue
+ }
+
+ return this.value
+ }
+ },
+ created() {
+ this.$watch(() => {
+ var al = [];
+ ['pageCurrent',
+ 'pageSize',
+ 'value',
+ 'modelValue',
+ 'localdata',
+ 'collection',
+ 'action',
+ 'field',
+ 'orderby',
+ 'where',
+ 'getont',
+ 'getcount',
+ 'gettree'
+ ].forEach(key => {
+ al.push(this[key])
+ });
+ return al
+ }, (newValue, oldValue) => {
+ let needReset = false
+ for (let i = 2; i < newValue.length; i++) {
+ if (newValue[i] != oldValue[i]) {
+ needReset = true
+ break
+ }
+ }
+ if (newValue[0] != oldValue[0]) {
+ this.page.current = this.pageCurrent
+ }
+ this.page.size = this.pageSize
+
+ this.onPropsChange()
+ })
+ this._treeData = []
+ },
+ methods: {
+ onPropsChange() {
+ this._treeData = []
+ },
+ getCommand(options = {}) {
+ /* eslint-disable no-undef */
+ let db = uniCloud.database()
+
+ const action = options.action || this.action
+ if (action) {
+ db = db.action(action)
+ }
+
+ const collection = options.collection || this.collection
+ db = db.collection(collection)
+
+ const where = options.where || this.where
+ if (!(!where || !Object.keys(where).length)) {
+ db = db.where(where)
+ }
+
+ const field = options.field || this.field
+ if (field) {
+ db = db.field(field)
+ }
+
+ const orderby = options.orderby || this.orderby
+ if (orderby) {
+ db = db.orderBy(orderby)
+ }
+
+ const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
+ const size = options.pageSize !== undefined ? options.pageSize : this.page.size
+ const getCount = options.getcount !== undefined ? options.getcount : this.getcount
+ const getTree = options.gettree !== undefined ? options.gettree : this.gettree
+
+ const getOptions = {
+ getCount,
+ getTree
+ }
+ if (options.getTreePath) {
+ getOptions.getTreePath = options.getTreePath
+ }
+
+ db = db.skip(size * (current - 1)).limit(size).get(getOptions)
+
+ return db
+ },
+ getNodeData(callback) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+ this.getCommand({
+ field: this.postField,
+ where: this._pathWhere()
+ }).then((res) => {
+ this.loading = false
+ this.selected = res.result.data
+ callback && callback()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ getTreePath(callback) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+
+ this.getCommand({
+ field: this.postField,
+ getTreePath: {
+ startWith: `${this.selfField}=='${this.dataValue}'`
+ }
+ }).then((res) => {
+ this.loading = false
+ let treePath = []
+ this._extractTreePath(res.result.data, treePath)
+ this.selected = treePath
+ callback && callback()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ loadData() {
+ if (this.isLocaldata) {
+ this._processLocalData()
+ return
+ }
+
+ if (this.dataValue.length) {
+ this._loadNodeData((data) => {
+ this._treeData = data
+ this._updateBindData()
+ this._updateSelected()
+ })
+ return
+ }
+
+ if (this.stepSearh) {
+ this._loadNodeData((data) => {
+ this._treeData = data
+ this._updateBindData()
+ })
+ } else {
+ this._loadAllData((data) => {
+ this._treeData = []
+ this._extractTree(data, this._treeData, null)
+ this._updateBindData()
+ })
+ }
+ },
+ _loadAllData(callback) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+
+ this.getCommand({
+ field: this.postField,
+ gettree: true,
+ startwith: `${this.selfField}=='${this.dataValue}'`
+ }).then((res) => {
+ this.loading = false
+ callback(res.result.data)
+ this.onDataChange()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ _loadNodeData(callback, pw) {
+ if (this.loading) {
+ return
+ }
+ this.loading = true
+
+ this.getCommand({
+ field: this.postField,
+ where: pw || this._postWhere(),
+ pageSize: 500
+ }).then((res) => {
+ this.loading = false
+ callback(res.result.data)
+ this.onDataChange()
+ }).catch((err) => {
+ this.loading = false
+ this.errorMessage = err
+ })
+ },
+ _pathWhere() {
+ let result = []
+ let where_field = this._getParentNameByField();
+ if (where_field) {
+ result.push(`${where_field} == '${this.dataValue}'`)
+ }
+
+ if (this.where) {
+ return `(${this.where}) && (${result.join(' || ')})`
+ }
+
+ return result.join(' || ')
+ },
+ _postWhere() {
+ let result = []
+ let selected = this.selected
+ let parentField = this.parentField
+ if (parentField) {
+ result.push(`${parentField} == null || ${parentField} == ""`)
+ }
+ if (selected.length) {
+ for (var i = 0; i < selected.length - 1; i++) {
+ result.push(`${parentField} == '${selected[i].value}'`)
+ }
+ }
+
+ let where = []
+ if (this.where) {
+ where.push(`(${this.where})`)
+ }
+ if (result.length) {
+ where.push(`(${result.join(' || ')})`)
+ }
+
+ return where.join(' && ')
+ },
+ _nodeWhere() {
+ let result = []
+ let selected = this.selected
+ if (selected.length) {
+ result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
+ }
+
+ if (this.where) {
+ return `(${this.where}) && (${result.join(' || ')})`
+ }
+
+ return result.join(' || ')
+ },
+ _getParentNameByField() {
+ const fields = this.field.split(',');
+ let where_field = null;
+ for (let i = 0; i < fields.length; i++) {
+ const items = fields[i].split('as');
+ if (items.length < 2) {
+ continue;
+ }
+ if (items[1].trim() === 'value') {
+ where_field = items[0].trim();
+ break;
+ }
+ }
+ return where_field
+ },
+ _isTreeView() {
+ return (this.parentField && this.selfField)
+ },
+ _updateSelected() {
+ var dl = this.dataList
+ var sl = this.selected
+ for (var i = 0; i < sl.length; i++) {
+ var value = sl[i].value
+ var dl2 = dl[i]
+ for (var j = 0; j < dl2.length; j++) {
+ var item2 = dl2[j]
+ if (item2.value === value) {
+ sl[i].text = item2.text
+ break
+ }
+ }
+ }
+ },
+ _updateBindData(node) {
+ const {
+ dataList,
+ hasNodes
+ } = this._filterData(this._treeData, this.selected)
+
+ let isleaf = this._stepSearh === false && !hasNodes
+
+ if (node) {
+ node.isleaf = isleaf
+ }
+
+ this.dataList = dataList
+ this.selectedIndex = dataList.length - 1
+
+ if (!isleaf && this.selected.length < dataList.length) {
+ this.selected.push({
+ value: null,
+ text: "请选择"
+ })
+ }
+
+ return {
+ isleaf,
+ hasNodes
+ }
+ },
+ _filterData(data, paths) {
+ let dataList = []
+
+ let hasNodes = true
+
+ dataList.push(data.filter((item) => {
+ return item.parent_value === undefined
+ }))
+ for (let i = 0; i < paths.length; i++) {
+ var value = paths[i].value
+ var nodes = data.filter((item) => {
+ return item.parent_value === value
+ })
+
+ if (nodes.length) {
+ dataList.push(nodes)
+ } else {
+ hasNodes = false
+ }
+ }
+
+ return {
+ dataList,
+ hasNodes
+ }
+ },
+ _extractTree(nodes, result, parent_value) {
+ let list = result || []
+ for (let i = 0; i < nodes.length; i++) {
+ let node = nodes[i]
+
+ let child = {}
+ for (let key in node) {
+ if (key !== 'children') {
+ child[key] = node[key]
+ }
+ }
+ if (parent_value !== undefined) {
+ child.parent_value = parent_value
+ }
+ result.push(child)
+
+ let children = node.children
+ if (children) {
+ this._extractTree(children, result, node.value)
+ }
+ }
+ },
+ _extractTreePath(nodes, result) {
+ let list = result || []
+ for (let i = 0; i < nodes.length; i++) {
+ let node = nodes[i]
+
+ let child = {}
+ for (let key in node) {
+ if (key !== 'children') {
+ child[key] = node[key]
+ }
+ }
+ result.push(child)
+
+ let children = node.children
+ if (children) {
+ this._extractTreePath(children, result)
+ }
+ }
+ },
+ _findNodePath(key, nodes, path = []) {
+ for (let i = 0; i < nodes.length; i++) {
+ let {
+ value,
+ text,
+ children
+ } = nodes[i]
+
+ path.push({
+ value,
+ text
+ })
+
+ if (value === key) {
+ return path
+ }
+
+ if (children) {
+ const p = this._findNodePath(key, children, path)
+ if (p.length) {
+ return p
+ }
+ }
+
+ path.pop()
+ }
+ return []
+ },
+ _processLocalData() {
+ this._treeData = []
+ this._extractTree(this.localdata, this._treeData)
+
+ var inputValue = this.dataValue
+ if (inputValue === undefined) {
+ return
+ }
+
+ if (Array.isArray(inputValue)) {
+ inputValue = inputValue[inputValue.length - 1]
+ if (typeof inputValue === 'object' && inputValue.value) {
+ inputValue = inputValue.value
+ }
+ }
+
+ this.selected = this._findNodePath(inputValue, this.localdata)
+ }
+ }
+}
diff --git a/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7b5952965b31469d9c1f6b23166491d5135fa0ad
--- /dev/null
+++ b/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+
+
+
+ {{errorMessage}}
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-data-picker/package.json b/uni_modules/uni-data-picker/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..469b06583e3c2f0e31c35689cd899f3b5b3e3eeb
--- /dev/null
+++ b/uni_modules/uni-data-picker/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "uni-data-picker",
+ "displayName": "uni-data-picker 数据驱动的picker选择器",
+ "version": "0.4.0",
+ "description": "Picker选择器",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "picker",
+ "级联",
+ "省市区",
+ ""
+],
+ "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-load-more"
+ ],
+ "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"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-data-picker/readme.md b/uni_modules/uni-data-picker/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..70eed230caef370d15a0511884374d5b4b7ae988
--- /dev/null
+++ b/uni_modules/uni-data-picker/readme.md
@@ -0,0 +1,270 @@
+## DataPicker 级联选择
+> **组件名:uni-data-picker**
+> 代码块: `uDataPicker`
+> 关联组件:`uni-data-pickerview`、`uni-load-more`。
+
+
+`` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
+
+支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
+
+候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
+
+`` 组件尤其适用于地址选择、分类选择等选择类。
+
+`` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
+
+`` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
+
+在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
+
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+> - `` 内部包含了弹出层组件 `` 外层的布局可能会影响弹出层,[详情](https://developer.mozilla.org/zh-Hans/docs/Web/CSS/Common_CSS_Questions)
+
+
+
+### 平台差异说明
+
+暂不支持在nvue页面中使用
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`componets`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+## API
+
+### DataPicker Props
+
+|属性名 | 类型 | 可选值 | 默认值 | 说明|
+|:-: | :-: |:-: | :-: | :-: |
+|v-model |String/ Number | - | - |绑定数据|
+|localdata |Array | | |数据,[详情](https://gitee.com/dcloud/datacom)|
+|preload |Boolean | true/false | false |预加载数据|
+|readonly |Boolean | true/false | false |是否禁用|
+|step-searh |Boolean | true/false | true |分步查询时,点击节点请求数据|
+|step-search-url |String | | |分步查询时,动态加载云端数据url格式,`https://xxx.com/{parentValue}`(当前版本暂不支持,下版支持)|
+|self-field |String | | |分步查询时当前字段名称|
+|parent-field |String | | |分步查询时父字段名称|
+|collection |String | | |表名。支持输入多个表名,用 `,` 分割|
+|field |String | | |查询字段,多个字段用 `,` 分割|
+|where |String | | |查询条件,内容较多,另见jql文档:[详情](https://uniapp.dcloud.net.cn/uniCloud/uni-clientDB?id=jsquery)|
+|orderby |String | | |排序字段及正序倒叙设置|
+|popup-title |String | | |弹出层标题|
+
+
+> ****
+> `collection/where/orderby` 和 `` 的用法一致,[详情](https://uniapp.dcloud.net.cn/uniCloud/unicloud-db)
+
+
+
+### DataPicker Events
+
+|事件称名 | 类型 | 说明 |
+|:-: | :-: | :-: |
+|@change |EventHandle | 选择完成时触发 {detail: {value}} |
+|@nodeclick |EventHandle | 节点被点击时触发 |
+|@stepsearch |EventHandle | 动态加载节点数据前触发(当前版本暂不支持,下版支持) |
+|@popupopened |EventHandle | 弹出层弹出时触发 |
+|@popupclosed |EventHandle | 弹出层关闭时触发 |
+
+
+
+### 基本用法
+
+#### 云端数据
+
+> **注意事项**
+> - 云端数据需要关联服务空间
+> - 下面示例中使用的表 `opendb-city-china`(中国城市省市区数据,含港澳台), 在[uniCloud控制台](https://unicloud.dcloud.net.cn/)使用opendb创建,[详情](https://gitee.com/dcloud/opendb)
+
+
+```html
+
+
+
+
+
+
+```
+
+```js
+
+
+```
+
+
+
+
+
+#### 本地数据
+
+```html
+
+
+
+
+
+```
+
+```js
+
+
+```
+
+
+#### 自定义solt
+
+```html
+
+
+ {{error}}
+
+
+
+ {{item.text}}
+
+
+
+ 请选择
+
+
+```
+
+
+> **注意事项**
+> `localdata` 和 `collection` 同时配置时,`localdata` 优先
+
+
+
+#### 完整示例
+
+```html
+
+
+
+
+
+
+```
+
+```js
+
+
+```
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/data-picker/data-picker](https://hellouniapp.dcloud.net.cn/pages/extUI/data-picker/data-picker)
\ No newline at end of file
diff --git a/uni_modules/uni-dateformat/changelog.md b/uni_modules/uni-dateformat/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..7006d13a0854c4f636bef64670a4de41526789db
--- /dev/null
+++ b/uni_modules/uni-dateformat/changelog.md
@@ -0,0 +1,7 @@
+## 0.0.5(2021-07-08)
+- 调整 默认时间不再是当前时间,而是显示'-'字符
+## 0.0.4(2021-05-12)
+- 新增 组件示例地址
+## 0.0.3(2021-02-04)
+- 调整为uni_modules目录规范
+- 修复 iOS 平台日期格式化出错的问题
diff --git a/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js b/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
new file mode 100644
index 0000000000000000000000000000000000000000..e00d5597e7a0b8dcdea64ef0c1c3f4d69e9522f8
--- /dev/null
+++ b/uni_modules/uni-dateformat/components/uni-dateformat/date-format.js
@@ -0,0 +1,200 @@
+// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型
+function pad(str, length = 2) {
+ str += ''
+ while (str.length < length) {
+ str = '0' + str
+ }
+ return str.slice(-length)
+}
+
+const parser = {
+ yyyy: (dateObj) => {
+ return pad(dateObj.year, 4)
+ },
+ yy: (dateObj) => {
+ return pad(dateObj.year)
+ },
+ MM: (dateObj) => {
+ return pad(dateObj.month)
+ },
+ M: (dateObj) => {
+ return dateObj.month
+ },
+ dd: (dateObj) => {
+ return pad(dateObj.day)
+ },
+ d: (dateObj) => {
+ return dateObj.day
+ },
+ hh: (dateObj) => {
+ return pad(dateObj.hour)
+ },
+ h: (dateObj) => {
+ return dateObj.hour
+ },
+ mm: (dateObj) => {
+ return pad(dateObj.minute)
+ },
+ m: (dateObj) => {
+ return dateObj.minute
+ },
+ ss: (dateObj) => {
+ return pad(dateObj.second)
+ },
+ s: (dateObj) => {
+ return dateObj.second
+ },
+ SSS: (dateObj) => {
+ return pad(dateObj.millisecond, 3)
+ },
+ S: (dateObj) => {
+ return dateObj.millisecond
+ },
+}
+
+// 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12
+function getDate(time) {
+ if (time instanceof Date) {
+ return time
+ }
+ switch (typeof time) {
+ case 'string':
+ {
+ // 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000
+ if (time.indexOf('T') > -1) {
+ return new Date(time)
+ }
+ return new Date(time.replace(/-/g, '/'))
+ }
+ default:
+ return new Date(time)
+ }
+}
+
+export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') {
+ if (!date && date !== 0) {
+ return ''
+ }
+ date = getDate(date)
+ const dateObj = {
+ year: date.getFullYear(),
+ month: date.getMonth() + 1,
+ day: date.getDate(),
+ hour: date.getHours(),
+ minute: date.getMinutes(),
+ second: date.getSeconds(),
+ millisecond: date.getMilliseconds()
+ }
+ const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/
+ let flag = true
+ let result = format
+ while (flag) {
+ flag = false
+ result = result.replace(tokenRegExp, function(matched) {
+ flag = true
+ return parser[matched](dateObj)
+ })
+ }
+ return result
+}
+
+export function friendlyDate(time, {
+ locale = 'zh',
+ threshold = [60000, 3600000],
+ format = 'yyyy/MM/dd hh:mm:ss'
+}) {
+ if (time === '-') {
+ return time
+ }
+ if (!time && time !== 0) {
+ return ''
+ }
+ const localeText = {
+ zh: {
+ year: '年',
+ month: '月',
+ day: '天',
+ hour: '小时',
+ minute: '分钟',
+ second: '秒',
+ ago: '前',
+ later: '后',
+ justNow: '刚刚',
+ soon: '马上',
+ template: '{num}{unit}{suffix}'
+ },
+ en: {
+ year: 'year',
+ month: 'month',
+ day: 'day',
+ hour: 'hour',
+ minute: 'minute',
+ second: 'second',
+ ago: 'ago',
+ later: 'later',
+ justNow: 'just now',
+ soon: 'soon',
+ template: '{num} {unit} {suffix}'
+ }
+ }
+ const text = localeText[locale] || localeText.zh
+ let date = getDate(time)
+ let ms = date.getTime() - Date.now()
+ let absMs = Math.abs(ms)
+ if (absMs < threshold[0]) {
+ return ms < 0 ? text.justNow : text.soon
+ }
+ if (absMs >= threshold[1]) {
+ return formatDate(date, format)
+ }
+ let num
+ let unit
+ let suffix = text.later
+ if (ms < 0) {
+ suffix = text.ago
+ ms = -ms
+ }
+ const seconds = Math.floor((ms) / 1000)
+ const minutes = Math.floor(seconds / 60)
+ const hours = Math.floor(minutes / 60)
+ const days = Math.floor(hours / 24)
+ const months = Math.floor(days / 30)
+ const years = Math.floor(months / 12)
+ switch (true) {
+ case years > 0:
+ num = years
+ unit = text.year
+ break
+ case months > 0:
+ num = months
+ unit = text.month
+ break
+ case days > 0:
+ num = days
+ unit = text.day
+ break
+ case hours > 0:
+ num = hours
+ unit = text.hour
+ break
+ case minutes > 0:
+ num = minutes
+ unit = text.minute
+ break
+ default:
+ num = seconds
+ unit = text.second
+ break
+ }
+
+ if (locale === 'en') {
+ if (num === 1) {
+ num = 'a'
+ } else {
+ unit += 's'
+ }
+ }
+
+ return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g,
+ suffix)
+}
diff --git a/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue b/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c5ed03078b25ab149f531e86385dfef4c9d7f4cc
--- /dev/null
+++ b/uni_modules/uni-dateformat/components/uni-dateformat/uni-dateformat.vue
@@ -0,0 +1,88 @@
+
+ {{dateShow}}
+
+
+
+
+
diff --git a/uni_modules/uni-dateformat/package.json b/uni_modules/uni-dateformat/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..64ec8cf13521394f42e6d954957c2b19dfc6ad1a
--- /dev/null
+++ b/uni_modules/uni-dateformat/package.json
@@ -0,0 +1,84 @@
+{
+ "id": "uni-dateformat",
+ "displayName": "uni-dateformat 日期格式化",
+ "version": "0.0.5",
+ "description": "日期格式化组件,可以将日期格式化为1分钟前、刚刚等形式",
+ "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": [],
+ "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"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-dateformat/readme.md b/uni_modules/uni-dateformat/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..7d2da4aa033e718269d8d3d662ce98b4e788c234
--- /dev/null
+++ b/uni_modules/uni-dateformat/readme.md
@@ -0,0 +1,77 @@
+
+
+### DateFormat 日期格式化
+> **组件名:uni-dateformat**
+> 代码块: `uDateformat`
+
+
+日期格式化组件。
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+
+
+```
+
+## API
+
+### Dateformat Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|date |Object|String|Number |Date.now() |要格式化的日期对象/日期字符串/时间戳 |
+|threshold |Array |[0, 0] |转化类型阈值 |
+|format |String |'yyyy/MM/dd hh:mm:ss' |格式字符串 |
+|locale |String |zh |格式化使用的语言,目前支持zh(中文)、en(英文) |
+
+
+#### Threshold Options
+
+格式化组件会对时间进行用户友好转化,threshold就是用来控制转化的时间阈值的。
+
+以`[60000, 3600000]`为例,将传入时间与当前时间差的绝对值记为delta(单位毫秒)
+
+- `delta < 60000`时,时间会被转化为“刚刚|马上”
+- `delta >= 60000 && delta < 3600000`时,时间会被转化为“xx分钟前|xx分钟后”,如果超过1小时会显示成“xx小时前|xx小时后”,以此类推
+- `delta >= 3600000`时,会按照format参数传入的格式进行格式化
+
+如果不想转化为“马上|刚刚”可以传入`:threshold = "[0,3600000]"`。默认值`[0,0]`既不会转换为“马上|刚刚”也不会转化为“xx分钟前|xx分钟后”
+
+#### Format Options
+
+format接收字符以及含义如下:
+
+|字符 |说明 |
+|:-: |:-: |
+|yyyy |四位年份 |
+|yy |两位年份 |
+|MM |两位月份(不足两位在前面补0) |
+|M |月份,不自动补0 |
+|dd |两位天(不足两位在前面补0) |
+|d |天,不自动补0 |
+|hh |两位小时(不足两位在前面补0) |
+|h |小时,不自动补0 |
+|mm |两位分钟(不足两位在前面补0) |
+|m |分钟,不自动补0 |
+|ss |两位秒(不足两位在前面补0) |
+|s |秒,不自动补0 |
+|SSS |三位毫秒(不足三位在前面补0) |
+|S |毫秒,不自动补0 |
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/dateformat/dateformat](https://hellouniapp.dcloud.net.cn/pages/extUI/dateformat/dateformat)
\ No newline at end of file
diff --git a/uni_modules/uni-datetime-picker/changelog.md b/uni_modules/uni-datetime-picker/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..1011ada56a1c5b1cbfe3d1ac0e47f4539a185c90
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/changelog.md
@@ -0,0 +1,65 @@
+## 2.1.1(2021-08-24)
+- 新增 支持国际化
+- 优化 范围选择器在 pc 端过宽的问题
+## 2.1.0(2021-08-09)
+- 新增 适配 vue3
+## 2.0.19(2021-08-09)
+- 新增 支持作为 uni-forms 子组件相关功能
+- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug
+## 2.0.18(2021-08-05)
+- 修复 type 属性动态赋值无效的 bug
+- 修复 ‘确认’按钮被 tabbar 遮盖 bug
+- 修复 组件未赋值时范围选左、右日历相同的 bug
+## 2.0.17(2021-08-04)
+- 修复 范围选未正确显示当前值的 bug
+- 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug
+## 2.0.16(2021-07-21)
+- 新增 return-type 属性支持返回 date 日期对象
+## 2.0.15(2021-07-14)
+- 修复 单选日期类型,初始赋值后不在当前日历的 bug
+- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
+- 优化 移动端移除显示框的清空按钮,无实际用途
+## 2.0.14(2021-07-14)
+- 修复 组件赋值为空,界面未更新的 bug
+- 修复 start 和 end 不能动态赋值的 bug
+- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的 bug
+## 2.0.13(2021-07-08)
+- 修复 范围选择不能动态赋值的 bug
+## 2.0.12(2021-07-08)
+- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
+## 2.0.11(2021-07-08)
+- 优化 弹出层在超出视窗边缘定位不准确的问题
+## 2.0.10(2021-07-08)
+- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的 bug
+- 优化 弹出层在超出视窗边缘被遮盖的问题
+## 2.0.9(2021-07-07)
+- 新增 maskClick 事件
+- 修复 特殊情况日历 rpx 布局错误的 bug,rpx -> px
+- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
+## 2.0.8(2021-07-07)
+- 新增 日期时间显示框支持插槽
+## 2.0.7(2021-07-01)
+- 优化 添加 uni-icons 依赖
+## 2.0.6(2021-05-22)
+- 修复 图标在小程序上不显示的 bug
+- 优化 重命名引用组件,避免潜在组件命名冲突
+## 2.0.5(2021-05-20)
+- 优化 代码目录扁平化
+## 2.0.4(2021-05-12)
+- 新增 组件示例地址
+## 2.0.3(2021-05-10)
+- 修复 ios 下不识别 '-' 日期格式的 bug
+- 优化 pc 下弹出层添加边框和阴影
+## 2.0.2(2021-05-08)
+- 修复 在 admin 中获取弹出层定位错误的bug
+## 2.0.1(2021-05-08)
+- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
+## 2.0.0(2021-04-30)
+- 支持日历形式的日期+时间的范围选择
+ > 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
+## 1.0.6(2021-03-18)
+- 新增 hide-second 属性,时间支持仅选择时、分
+- 修复 选择跟显示的日期不一样的 bug
+- 修复 chang事件触发2次的 bug
+- 修复 分、秒 end 范围错误的 bug
+- 优化 更好的 nvue 适配
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
new file mode 100644
index 0000000000000000000000000000000000000000..608dd7853dc016d241b0890cb6f19ee923ee9031
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
@@ -0,0 +1,183 @@
+
+
+
+
+ {{weeks.date}}
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js
new file mode 100644
index 0000000000000000000000000000000000000000..b8d7d6fc44038901fe7a47def32b53764575c1a8
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.js
@@ -0,0 +1,546 @@
+/**
+* @1900-2100区间内的公历、农历互转
+* @charset UTF-8
+* @github https://github.com/jjonline/calendar.js
+* @Author Jea杨(JJonline@JJonline.Cn)
+* @Time 2014-7-21
+* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
+* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
+* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
+* @Version 1.0.3
+* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
+* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
+*/
+/* eslint-disable */
+var calendar = {
+
+ /**
+ * 农历1900-2100的润大小信息表
+ * @Array Of Property
+ * @return Hex
+ */
+ lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
+ 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
+ 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
+ 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
+ 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
+ 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
+ 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
+ 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
+ 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
+ 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
+ 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
+ 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
+ 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
+ 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
+ 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
+ /** Add By JJonline@JJonline.Cn**/
+ 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
+ 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
+ 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
+ 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
+ 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
+ 0x0d520], // 2100
+
+ /**
+ * 公历每个月份的天数普通表
+ * @Array Of Property
+ * @return Number
+ */
+ solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+ /**
+ * 天干地支之天干速查表
+ * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
+ * @return Cn string
+ */
+ Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
+
+ /**
+ * 天干地支之地支速查表
+ * @Array Of Property
+ * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
+ * @return Cn string
+ */
+ Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
+
+ /**
+ * 天干地支之地支速查表<=>生肖
+ * @Array Of Property
+ * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
+ * @return Cn string
+ */
+ Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
+
+ /**
+ * 24节气速查表
+ * @Array Of Property
+ * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
+ * @return Cn string
+ */
+ solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
+
+ /**
+ * 1900-2100各年的24节气日期速查表
+ * @Array Of Property
+ * @return 0x string For splice
+ */
+ sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
+ '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
+ 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
+ '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
+ '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
+ '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
+ '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
+ '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+ '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
+ '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+ '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+ '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+ '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+ '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
+ '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+ '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+ '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+ '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
+ '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
+ '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+ '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
+ '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
+ '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
+ '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+ '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
+ '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
+ '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
+ '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+ '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+ '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
+ '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
+
+ /**
+ * 数字转中文速查表
+ * @Array Of Property
+ * @trans ['日','一','二','三','四','五','六','七','八','九','十']
+ * @return Cn string
+ */
+ nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
+
+ /**
+ * 日期转农历称呼速查表
+ * @Array Of Property
+ * @trans ['初','十','廿','卅']
+ * @return Cn string
+ */
+ nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
+
+ /**
+ * 月份转农历称呼速查表
+ * @Array Of Property
+ * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
+ * @return Cn string
+ */
+ nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
+
+ /**
+ * 返回农历y年一整年的总天数
+ * @param lunar Year
+ * @return Number
+ * @eg:var count = calendar.lYearDays(1987) ;//count=387
+ */
+ lYearDays: function (y) {
+ var i; var sum = 348
+ for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
+ return (sum + this.leapDays(y))
+ },
+
+ /**
+ * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
+ * @param lunar Year
+ * @return Number (0-12)
+ * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
+ */
+ leapMonth: function (y) { // 闰字编码 \u95f0
+ return (this.lunarInfo[y - 1900] & 0xf)
+ },
+
+ /**
+ * 返回农历y年闰月的天数 若该年没有闰月则返回0
+ * @param lunar Year
+ * @return Number (0、29、30)
+ * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
+ */
+ leapDays: function (y) {
+ if (this.leapMonth(y)) {
+ return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
+ }
+ return (0)
+ },
+
+ /**
+ * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
+ * @param lunar Year
+ * @return Number (-1、29、30)
+ * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
+ */
+ monthDays: function (y, m) {
+ if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
+ return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
+ },
+
+ /**
+ * 返回公历(!)y年m月的天数
+ * @param solar Year
+ * @return Number (-1、28、29、30、31)
+ * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
+ */
+ solarDays: function (y, m) {
+ if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+ var ms = m - 1
+ if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
+ return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
+ } else {
+ return (this.solarMonth[ms])
+ }
+ },
+
+ /**
+ * 农历年份转换为干支纪年
+ * @param lYear 农历年的年份数
+ * @return Cn string
+ */
+ toGanZhiYear: function (lYear) {
+ var ganKey = (lYear - 3) % 10
+ var zhiKey = (lYear - 3) % 12
+ if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
+ if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
+ return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
+ },
+
+ /**
+ * 公历月、日判断所属星座
+ * @param cMonth [description]
+ * @param cDay [description]
+ * @return Cn string
+ */
+ toAstro: function (cMonth, cDay) {
+ var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
+ var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
+ return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
+ },
+
+ /**
+ * 传入offset偏移量返回干支
+ * @param offset 相对甲子的偏移量
+ * @return Cn string
+ */
+ toGanZhi: function (offset) {
+ return this.Gan[offset % 10] + this.Zhi[offset % 12]
+ },
+
+ /**
+ * 传入公历(!)y年获得该年第n个节气的公历日期
+ * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
+ * @return day Number
+ * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
+ */
+ getTerm: function (y, n) {
+ if (y < 1900 || y > 2100) { return -1 }
+ if (n < 1 || n > 24) { return -1 }
+ var _table = this.sTermInfo[y - 1900]
+ var _info = [
+ parseInt('0x' + _table.substr(0, 5)).toString(),
+ parseInt('0x' + _table.substr(5, 5)).toString(),
+ parseInt('0x' + _table.substr(10, 5)).toString(),
+ parseInt('0x' + _table.substr(15, 5)).toString(),
+ parseInt('0x' + _table.substr(20, 5)).toString(),
+ parseInt('0x' + _table.substr(25, 5)).toString()
+ ]
+ var _calday = [
+ _info[0].substr(0, 1),
+ _info[0].substr(1, 2),
+ _info[0].substr(3, 1),
+ _info[0].substr(4, 2),
+
+ _info[1].substr(0, 1),
+ _info[1].substr(1, 2),
+ _info[1].substr(3, 1),
+ _info[1].substr(4, 2),
+
+ _info[2].substr(0, 1),
+ _info[2].substr(1, 2),
+ _info[2].substr(3, 1),
+ _info[2].substr(4, 2),
+
+ _info[3].substr(0, 1),
+ _info[3].substr(1, 2),
+ _info[3].substr(3, 1),
+ _info[3].substr(4, 2),
+
+ _info[4].substr(0, 1),
+ _info[4].substr(1, 2),
+ _info[4].substr(3, 1),
+ _info[4].substr(4, 2),
+
+ _info[5].substr(0, 1),
+ _info[5].substr(1, 2),
+ _info[5].substr(3, 1),
+ _info[5].substr(4, 2)
+ ]
+ return parseInt(_calday[n - 1])
+ },
+
+ /**
+ * 传入农历数字月份返回汉语通俗表示法
+ * @param lunar month
+ * @return Cn string
+ * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
+ */
+ toChinaMonth: function (m) { // 月 => \u6708
+ if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+ var s = this.nStr3[m - 1]
+ s += '\u6708'// 加上月字
+ return s
+ },
+
+ /**
+ * 传入农历日期数字返回汉字表示法
+ * @param lunar day
+ * @return Cn string
+ * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
+ */
+ toChinaDay: function (d) { // 日 => \u65e5
+ var s
+ switch (d) {
+ case 10:
+ s = '\u521d\u5341'; break
+ case 20:
+ s = '\u4e8c\u5341'; break
+ break
+ case 30:
+ s = '\u4e09\u5341'; break
+ break
+ default :
+ s = this.nStr2[Math.floor(d / 10)]
+ s += this.nStr1[d % 10]
+ }
+ return (s)
+ },
+
+ /**
+ * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
+ * @param y year
+ * @return Cn string
+ * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
+ */
+ getAnimal: function (y) {
+ return this.Animals[(y - 4) % 12]
+ },
+
+ /**
+ * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
+ * @param y solar year
+ * @param m solar month
+ * @param d solar day
+ * @return JSON object
+ * @eg:console.log(calendar.solar2lunar(1987,11,01));
+ */
+ solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
+ // 年份限定、上限
+ if (y < 1900 || y > 2100) {
+ return -1// undefined转换为数字变为NaN
+ }
+ // 公历传参最下限
+ if (y == 1900 && m == 1 && d < 31) {
+ return -1
+ }
+ // 未传参 获得当天
+ if (!y) {
+ var objDate = new Date()
+ } else {
+ var objDate = new Date(y, parseInt(m) - 1, d)
+ }
+ var i; var leap = 0; var temp = 0
+ // 修正ymd参数
+ var y = objDate.getFullYear()
+ var m = objDate.getMonth() + 1
+ var d = objDate.getDate()
+ var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
+ for (i = 1900; i < 2101 && offset > 0; i++) {
+ temp = this.lYearDays(i)
+ offset -= temp
+ }
+ if (offset < 0) {
+ offset += temp; i--
+ }
+
+ // 是否今天
+ var isTodayObj = new Date()
+ var isToday = false
+ if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
+ isToday = true
+ }
+ // 星期几
+ var nWeek = objDate.getDay()
+ var cWeek = this.nStr1[nWeek]
+ // 数字表示周几顺应天朝周一开始的惯例
+ if (nWeek == 0) {
+ nWeek = 7
+ }
+ // 农历年
+ var year = i
+ var leap = this.leapMonth(i) // 闰哪个月
+ var isLeap = false
+
+ // 效验闰月
+ for (i = 1; i < 13 && offset > 0; i++) {
+ // 闰月
+ if (leap > 0 && i == (leap + 1) && isLeap == false) {
+ --i
+ isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
+ } else {
+ temp = this.monthDays(year, i)// 计算农历普通月天数
+ }
+ // 解除闰月
+ if (isLeap == true && i == (leap + 1)) { isLeap = false }
+ offset -= temp
+ }
+ // 闰月导致数组下标重叠取反
+ if (offset == 0 && leap > 0 && i == leap + 1) {
+ if (isLeap) {
+ isLeap = false
+ } else {
+ isLeap = true; --i
+ }
+ }
+ if (offset < 0) {
+ offset += temp; --i
+ }
+ // 农历月
+ var month = i
+ // 农历日
+ var day = offset + 1
+ // 天干地支处理
+ var sm = m - 1
+ var gzY = this.toGanZhiYear(year)
+
+ // 当月的两个节气
+ // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
+ var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
+ var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
+
+ // 依据12节气修正干支月
+ var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
+ if (d >= firstNode) {
+ gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
+ }
+
+ // 传入的日期的节气与否
+ var isTerm = false
+ var Term = null
+ if (firstNode == d) {
+ isTerm = true
+ Term = this.solarTerm[m * 2 - 2]
+ }
+ if (secondNode == d) {
+ isTerm = true
+ Term = this.solarTerm[m * 2 - 1]
+ }
+ // 日柱 当月一日与 1900/1/1 相差天数
+ var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
+ var gzD = this.toGanZhi(dayCyclical + d - 1)
+ // 该日期所属的星座
+ var astro = this.toAstro(m, d)
+
+ return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
+ },
+
+ /**
+ * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
+ * @param y lunar year
+ * @param m lunar month
+ * @param d lunar day
+ * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
+ * @return JSON object
+ * @eg:console.log(calendar.lunar2solar(1987,9,10));
+ */
+ lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
+ var isLeapMonth = !!isLeapMonth
+ var leapOffset = 0
+ var leapMonth = this.leapMonth(y)
+ var leapDay = this.leapDays(y)
+ if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
+ if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
+ var day = this.monthDays(y, m)
+ var _day = day
+ // bugFix 2016-9-25
+ // if month is leap, _day use leapDays method
+ if (isLeapMonth) {
+ _day = this.leapDays(y, m)
+ }
+ if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
+
+ // 计算农历的时间差
+ var offset = 0
+ for (var i = 1900; i < y; i++) {
+ offset += this.lYearDays(i)
+ }
+ var leap = 0; var isAdd = false
+ for (var i = 1; i < m; i++) {
+ leap = this.leapMonth(y)
+ if (!isAdd) { // 处理闰月
+ if (leap <= i && leap > 0) {
+ offset += this.leapDays(y); isAdd = true
+ }
+ }
+ offset += this.monthDays(y, i)
+ }
+ // 转换闰月农历 需补充该年闰月的前一个月的时差
+ if (isLeapMonth) { offset += day }
+ // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
+ var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
+ var calObj = new Date((offset + d - 31) * 86400000 + stmap)
+ var cY = calObj.getUTCFullYear()
+ var cM = calObj.getUTCMonth() + 1
+ var cD = calObj.getUTCDate()
+
+ return this.solar2lunar(cY, cM, cD)
+ }
+}
+
+export default calendar
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
new file mode 100644
index 0000000000000000000000000000000000000000..73e949336b1b87beff08e43e119c45e14ca88442
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
@@ -0,0 +1,801 @@
+
+
+
+
+
+
+
+
+ {{nowDate.month}}
+
+
+
+ {{SUNText}}
+
+
+ {{monText}}
+
+
+ {{TUEText}}
+
+
+ {{WEDText}}
+
+
+ {{THUText}}
+
+
+ {{FRIText}}
+
+
+ {{SATText}}
+
+
+
+
+
+
+
+
+
+
+ {{tempSingleDate ? tempSingleDate : selectDateText}}
+
+
+
+
+
+
+ {{tempRange.before ? tempRange.before : startDateText}}
+
+
+
+
+
+ {{tempRange.after ? tempRange.after : endDateText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..cc76311be5be4de856623efaa10e42e7f7fa0b8d
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/en.json
@@ -0,0 +1,19 @@
+{
+ "uni-datetime-picker.selectDate": "select date",
+ "uni-datetime-picker.selectTime": "select time",
+ "uni-datetime-picker.selectDateTime": "select datetime",
+ "uni-datetime-picker.startDate": "start date",
+ "uni-datetime-picker.endDate": "end date",
+ "uni-datetime-picker.startTime": "start time",
+ "uni-datetime-picker.endTime": "end time",
+ "uni-datetime-picker.ok": "ok",
+ "uni-datetime-picker.clear": "clear",
+ "uni-datetime-picker.cancel": "cancel",
+ "uni-calender.MON": "MON",
+ "uni-calender.TUE": "TUE",
+ "uni-calender.WED": "WED",
+ "uni-calender.THU": "THU",
+ "uni-calender.FRI": "FRI",
+ "uni-calender.SAT": "SAT",
+ "uni-calender.SUN": "SUN"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..de7509c87ba5197b9f5d20ca94a0558c7a8e08a9
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/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-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
new file mode 100644
index 0000000000000000000000000000000000000000..7bc7405f553cff1a0a7f1ec4855747e2011b331c
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hans.json
@@ -0,0 +1,19 @@
+{
+ "uni-datetime-picker.selectDate": "选择日期",
+ "uni-datetime-picker.selectTime": "选择时间",
+ "uni-datetime-picker.selectDateTime": "选择日期时间",
+ "uni-datetime-picker.startDate": "开始日期",
+ "uni-datetime-picker.endDate": "结束日期",
+ "uni-datetime-picker.startTime": "开始时间",
+ "uni-datetime-picker.endTime": "结束时间",
+ "uni-datetime-picker.ok": "确定",
+ "uni-datetime-picker.clear": "清除",
+ "uni-datetime-picker.cancel": "取消",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
new file mode 100644
index 0000000000000000000000000000000000000000..7d370432ebf316bdd7bd1442fbefcf94169e6d09
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/i18n/zh-Hant.json
@@ -0,0 +1,19 @@
+{
+ "uni-datetime-picker.selectDate": "選擇日期",
+ "uni-datetime-picker.selectTime": "選擇時間",
+ "uni-datetime-picker.selectDateTime": "選擇日期時間",
+ "uni-datetime-picker.startDate": "開始日期",
+ "uni-datetime-picker.endDate": "結束日期",
+ "uni-datetime-picker.startTime": "開始时间",
+ "uni-datetime-picker.endTime": "結束时间",
+ "uni-datetime-picker.ok": "確定",
+ "uni-datetime-picker.clear": "清除",
+ "uni-datetime-picker.cancel": "取消",
+ "uni-calender.SUN": "日",
+ "uni-calender.MON": "一",
+ "uni-calender.TUE": "二",
+ "uni-calender.WED": "三",
+ "uni-calender.THU": "四",
+ "uni-calender.FRI": "五",
+ "uni-calender.SAT": "六"
+}
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/keypress.js
new file mode 100644
index 0000000000000000000000000000000000000000..9601abae31babfc7ce5892085b07dab20ae355b0
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/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
\ No newline at end of file
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1748de582172d5c1af138e8b16304e6056ddece5
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/time-picker.vue
@@ -0,0 +1,924 @@
+
+
+
+
+
+ {{time}}
+
+ {{selectTimeText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7d75ebf4160c40dfc0a3b6ea6d167a6e733e7b47
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
@@ -0,0 +1,951 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{rangeSeparator}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f9f97793282d8e534352bb4a36047bd02caad00
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/components/uni-datetime-picker/util.js
@@ -0,0 +1,408 @@
+import CALENDAR from './calendar.js'
+
+class Calendar {
+ constructor({
+ date,
+ selected,
+ startDate,
+ endDate,
+ range,
+ // multipleStatus
+ } = {}) {
+ // 当前日期
+ this.date = this.getDate(new Date()) // 当前初入日期
+ // 打点信息
+ this.selected = selected || [];
+ // 范围开始
+ this.startDate = startDate
+ // 范围结束
+ this.endDate = endDate
+ this.range = range
+ // 多选状态
+ this.cleanMultipleStatus()
+ // 每周日期
+ this.weeks = {}
+ // this._getWeek(this.date.fullDate)
+ // this.multipleStatus = multipleStatus
+ this.lastHover = false
+ }
+ /**
+ * 设置日期
+ * @param {Object} date
+ */
+ setDate(date) {
+ this.selectDate = this.getDate(date)
+ this._getWeek(this.selectDate.fullDate)
+ }
+
+ /**
+ * 清理多选状态
+ */
+ cleanMultipleStatus() {
+ this.multipleStatus = {
+ before: '',
+ after: '',
+ data: []
+ }
+ }
+
+ /**
+ * 重置开始日期
+ */
+ resetSatrtDate(startDate) {
+ // 范围开始
+ this.startDate = startDate
+
+ }
+
+ /**
+ * 重置结束日期
+ */
+ resetEndDate(endDate) {
+ // 范围结束
+ this.endDate = endDate
+ }
+
+ /**
+ * 获取任意时间
+ */
+ getDate(date, AddDayCount = 0, str = 'day') {
+ if (!date) {
+ date = new Date()
+ }
+ if (typeof date !== 'object') {
+ date = date.replace(/-/g, '/')
+ }
+ const dd = new Date(date)
+ switch (str) {
+ case 'day':
+ dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ case 'month':
+ if (dd.getDate() === 31) {
+ dd.setDate(dd.getDate() + AddDayCount)
+ } else {
+ dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
+ }
+ break
+ case 'year':
+ dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+ break
+ }
+ const y = dd.getFullYear()
+ const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+ const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+ return {
+ fullDate: y + '-' + m + '-' + d,
+ year: y,
+ month: m,
+ date: d,
+ day: dd.getDay()
+ }
+ }
+
+
+ /**
+ * 获取上月剩余天数
+ */
+ _getLastMonthDays(firstDay, full) {
+ let dateArr = []
+ for (let i = firstDay; i > 0; i--) {
+ const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+ dateArr.push({
+ date: beforeDate,
+ month: full.month - 1,
+ lunar: this.getlunar(full.year, full.month - 1, beforeDate),
+ disable: true
+ })
+ }
+ return dateArr
+ }
+ /**
+ * 获取本月天数
+ */
+ _currentMonthDys(dateData, full) {
+ let dateArr = []
+ let fullDate = this.date.fullDate
+ for (let i = 1; i <= dateData; i++) {
+ let isinfo = false
+ let nowDate = full.year + '-' + (full.month < 10 ?
+ full.month : full.month) + '-' + (i < 10 ?
+ '0' + i : i)
+ // 是否今天
+ let isDay = fullDate === nowDate
+ // 获取打点信息
+ let info = this.selected && this.selected.find((item) => {
+ if (this.dateEqual(nowDate, item.date)) {
+ return item
+ }
+ })
+
+ // 日期禁用
+ let disableBefore = true
+ let disableAfter = true
+ if (this.startDate) {
+ // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+ // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+ disableBefore = this.dateCompare(this.startDate, nowDate)
+ }
+
+ if (this.endDate) {
+ // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+ // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+ disableAfter = this.dateCompare(nowDate, this.endDate)
+ }
+ let multiples = this.multipleStatus.data
+ let checked = false
+ let multiplesStatus = -1
+ if (this.range) {
+ if (multiples) {
+ multiplesStatus = multiples.findIndex((item) => {
+ return this.dateEqual(item, nowDate)
+ })
+ }
+ if (multiplesStatus !== -1) {
+ checked = true
+ }
+ }
+ let data = {
+ fullDate: nowDate,
+ year: full.year,
+ date: i,
+ multiple: this.range ? checked : false,
+ beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
+ afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
+ month: full.month,
+ lunar: this.getlunar(full.year, full.month, i),
+ disable: !(disableBefore && disableAfter),
+ isDay
+ }
+ if (info) {
+ data.extraInfo = info
+ }
+
+ dateArr.push(data)
+ }
+ return dateArr
+ }
+ /**
+ * 获取下月天数
+ */
+ _getNextMonthDays(surplus, full) {
+ let dateArr = []
+ for (let i = 1; i < surplus + 1; i++) {
+ dateArr.push({
+ date: i,
+ month: Number(full.month) + 1,
+ lunar: this.getlunar(full.year, Number(full.month) + 1, i),
+ disable: true
+ })
+ }
+ return dateArr
+ }
+
+ /**
+ * 获取当前日期详情
+ * @param {Object} date
+ */
+ getInfo(date) {
+ if (!date) {
+ date = new Date()
+ }
+ const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+ return dateInfo
+ }
+
+ /**
+ * 比较时间大小
+ */
+ dateCompare(startDate, endDate) {
+ // 计算截止时间
+ startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+ if (startDate <= endDate) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ /**
+ * 比较时间是否相等
+ */
+ dateEqual(before, after) {
+ // 计算截止时间
+ before = new Date(before.replace('-', '/').replace('-', '/'))
+ // 计算详细项的截止时间
+ after = new Date(after.replace('-', '/').replace('-', '/'))
+ if (before.getTime() - after.getTime() === 0) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+
+ /**
+ * 获取日期范围内所有日期
+ * @param {Object} begin
+ * @param {Object} end
+ */
+ geDateAll(begin, end) {
+ var arr = []
+ var ab = begin.split('-')
+ var ae = end.split('-')
+ var db = new Date()
+ db.setFullYear(ab[0], ab[1] - 1, ab[2])
+ var de = new Date()
+ de.setFullYear(ae[0], ae[1] - 1, ae[2])
+ var unixDb = db.getTime() - 24 * 60 * 60 * 1000
+ var unixDe = de.getTime() - 24 * 60 * 60 * 1000
+ for (var k = unixDb; k <= unixDe;) {
+ k = k + 24 * 60 * 60 * 1000
+ arr.push(this.getDate(new Date(parseInt(k))).fullDate)
+ }
+ return arr
+ }
+ /**
+ * 计算阴历日期显示
+ */
+ getlunar(year, month, date) {
+ return CALENDAR.solar2lunar(year, month, date)
+ }
+ /**
+ * 设置打点
+ */
+ setSelectInfo(data, value) {
+ this.selected = value
+ this._getWeek(data)
+ }
+
+ /**
+ * 获取多选状态
+ */
+ setMultiple(fullDate) {
+ let {
+ before,
+ after
+ } = this.multipleStatus
+
+ if (!this.range) return
+ if (before && after) {
+ if (!this.lastHover) {
+ this.lastHover = true
+ return
+ }
+ this.multipleStatus.before = ''
+ this.multipleStatus.after = ''
+ this.multipleStatus.data = []
+ this.multipleStatus.fulldate = ''
+ this.lastHover = false
+ } else {
+ this.lastHover = false
+ if (!before) {
+ this.multipleStatus.before = fullDate
+ } else {
+ this.multipleStatus.after = fullDate
+ if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
+ .after);
+ } else {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
+ .before);
+ }
+ }
+ }
+ this._getWeek(fullDate)
+ }
+
+ /**
+ * 鼠标 hover 更新多选状态
+ */
+ setHoverMultiple(fullDate) {
+ let {
+ before,
+ after
+ } = this.multipleStatus
+
+ if (!this.range) return
+ if (this.lastHover) return
+
+ if (!before) {
+ this.multipleStatus.before = fullDate
+ } else {
+ this.multipleStatus.after = fullDate
+ if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
+ } else {
+ this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
+ }
+ }
+ this._getWeek(fullDate)
+ }
+
+ /**
+ * 更新默认值多选状态
+ */
+ setDefaultMultiple(before, after) {
+ this.multipleStatus.before = before
+ this.multipleStatus.after = after
+ if (before && after) {
+ if (this.dateCompare(before, after)) {
+ this.multipleStatus.data = this.geDateAll(before, after);
+ this._getWeek(after)
+ } else {
+ this.multipleStatus.data = this.geDateAll(after, before);
+ this._getWeek(before)
+ }
+ }
+ }
+
+ /**
+ * 获取每周数据
+ * @param {Object} dateData
+ */
+ _getWeek(dateData) {
+ const {
+ fullDate,
+ year,
+ month,
+ date,
+ day
+ } = this.getDate(dateData)
+ let firstDay = new Date(year, month - 1, 1).getDay()
+ let currentDay = new Date(year, month, 0).getDate()
+ let dates = {
+ lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+ currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+ nextMonthDays: [], // 下个月开始几天
+ weeks: []
+ }
+ let canlender = []
+ const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+ dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+ canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+ let weeks = {}
+ // 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
+ for (let i = 0; i < canlender.length; i++) {
+ if (i % 7 === 0) {
+ weeks[parseInt(i / 7)] = new Array(7)
+ }
+ weeks[parseInt(i / 7)][i % 7] = canlender[i]
+ }
+ this.canlender = canlender
+ this.weeks = weeks
+ }
+
+ //静态方法
+ // static init(date) {
+ // if (!this.instance) {
+ // this.instance = new Calendar(date);
+ // }
+ // return this.instance;
+ // }
+}
+
+
+export default Calendar
diff --git a/uni_modules/uni-datetime-picker/package.json b/uni_modules/uni-datetime-picker/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..ad0b2b00587e0e7784c0698a980c97e5064b78f9
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/package.json
@@ -0,0 +1,89 @@
+{
+ "id": "uni-datetime-picker",
+ "displayName": "uni-datetime-picker 日期选择器",
+ "version": "2.1.1",
+ "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
+ "keywords": [
+ "uni-datetime-picker",
+ "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-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "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": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-datetime-picker/readme.md b/uni_modules/uni-datetime-picker/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..1902ae1a60789e1398e5033b423603b40a2db860
--- /dev/null
+++ b/uni_modules/uni-datetime-picker/readme.md
@@ -0,0 +1,155 @@
+
+> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
+## DatetimePicker 时间选择器
+> **组件名:uni-datetime-picker**
+> 代码块: `uDatetimePicker`
+
+
+该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
+
+若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
+
+
+___点击 picker 默认值规则:___
+
+- 若设置初始值 value, 会显示在 picker 显示框中
+- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+ 可以同时选择日期和时间的选择器
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 我是一个插槽,点击我
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## API
+
+### DatetimePicker Props
+
+|属性名 |类型 |默认值 |值域 |说明 |
+|:-: |:-: |:-: | |:-: |
+|type |String |datetime |date/daterange/datetime/datetimerange|选择器类型 |
+|value |String、Number、Array(范围选择)、Date|- |- |输入框当前值 |
+|start |String、Number |- |- |最小值,可以使用日期的字符串(String)、时间戳(Number) |
+|end |String、Number |- |- |最大值,可以使用日期的字符串(String)、时间戳(Number) |
+|return-type |String |string |timestamp 、string、date |返回值格式 |
+|border |Boolean、String |true | |是否有边框 |
+|rangeSeparator |String |'-' |- |选择范围时的分隔符 |
+|placeholder |String |- |- |非范围选择时的占位内容 |
+|start-placeholder|String |- |- |范围选择时开始日期的占位内容 |
+|end-placeholder |String |- |- |范围选择时结束日期的占位内容 |
+|disabled |Boolean、String |false | |是否不可选择 |
+|clearIcon |Boolean、String |true | |是否显示清除按钮(仅PC端适用) |
+
+
+
+
+### DatetimePicker Events
+
+|事件名称 |说明 |返回值 |
+|:-: |:-: |:-: |
+|change |确定日期时间时触发的事件,参数为当前选择的日期对象 |单选返回日期字符串,如:'2010-02-3';范围选返回日期字符串数组,如:['2020-10-1', '2021-4-1'] |
+|maskClick|点击遮罩层触发 |- |
+
+### Popup Methods
+
+|方法称名 |说明|参数|
+|:-:|:-:|:-:|
+|show|打开弹出层|-|
+|close|关闭弹出层 |-|
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/datetime-picker/datetime-picker](https://hellouniapp.dcloud.net.cn/pages/extUI/datetime-picker/datetime-picker)
\ No newline at end of file
diff --git a/uni_modules/uni-drawer/changelog.md b/uni_modules/uni-drawer/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..c8eed01969f6b14644b452e0c3b28f7ad2ecd3ff
--- /dev/null
+++ b/uni_modules/uni-drawer/changelog.md
@@ -0,0 +1,8 @@
+## 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-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-drawer/components/uni-drawer/keypress.js b/uni_modules/uni-drawer/components/uni-drawer/keypress.js
new file mode 100644
index 0000000000000000000000000000000000000000..62dda461bd5d5923a173e541f2cf049d816d612b
--- /dev/null
+++ b/uni_modules/uni-drawer/components/uni-drawer/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-drawer/components/uni-drawer/uni-drawer.vue b/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c3cb00bb43e7a7025526b825bb3794b874a44653
--- /dev/null
+++ b/uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-drawer/package.json b/uni_modules/uni-drawer/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..0fad43f6303f91845bcbad3d97e72c9018c1c79d
--- /dev/null
+++ b/uni_modules/uni-drawer/package.json
@@ -0,0 +1,83 @@
+{
+ "id": "uni-drawer",
+ "displayName": "uni-drawer 抽屉",
+ "version": "1.1.1",
+ "description": "抽屉式导航,用于展示侧滑菜单,侧滑导航。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "drawer",
+ "抽屉",
+ "侧滑导航"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-drawer/readme.md b/uni_modules/uni-drawer/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..d4a8b15bbb2c60d89d18ac2a0cea09e87fc161c7
--- /dev/null
+++ b/uni_modules/uni-drawer/readme.md
@@ -0,0 +1,86 @@
+
+
+## Drawer 抽屉
+> **组件名:uni-drawer**
+> 代码块: `uDrawer`
+
+
+抽屉侧滑菜单。
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - `width` 属性仅在 `vue` 页面生效,`nvue` 页面因性能问题,不支持动态设置宽度,如需修改,请下载组件修改源码
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+
+在 ``template`` 中使用组件
+
+```html
+
+
+ 右侧弹出 显示Drawer
+
+
+ 关闭Drawer
+ 可滚动内容 {{ item }}
+
+
+
+
+
+ {
+ timer = null;
+ }, wait);
+ if (callNow) func.apply(context, args);
+ } else {
+ timer = setTimeout(() => {
+ func.apply(context, args);
+ }, wait)
+ }
+ }
+}
+/**
+ * @desc 函数节流
+ * @param func 函数
+ * @param wait 延迟执行毫秒数
+ * @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
+ */
+export const throttle = (func, wait = 1000, type = 1) => {
+ let previous = 0;
+ let timeout;
+ return function() {
+ let context = this;
+ let args = arguments;
+ if (type === 1) {
+ let now = Date.now();
+
+ if (now - previous > wait) {
+ func.apply(context, args);
+ previous = now;
+ }
+ } else if (type === 2) {
+ if (!timeout) {
+ timeout = setTimeout(() => {
+ timeout = null;
+ func.apply(context, args)
+ }, wait)
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
new file mode 100644
index 0000000000000000000000000000000000000000..16911f247bbe9c1437682587ffba6006ebe20653
--- /dev/null
+++ b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue
@@ -0,0 +1,461 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-easyinput/package.json b/uni_modules/uni-easyinput/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..cb436acb9391929557096a95741ecfba9f3d1956
--- /dev/null
+++ b/uni_modules/uni-easyinput/package.json
@@ -0,0 +1,89 @@
+{
+ "id": "uni-easyinput",
+ "displayName": "uni-easyinput 增强输入框",
+ "version": "0.1.4",
+ "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": {
+ "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-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": "u"
+ }
+ }
+ }
+ }
+}
\ 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 0000000000000000000000000000000000000000..ab6c50bf4107aff9cff2e01c44e1f89b949657e1
--- /dev/null
+++ b/uni_modules/uni-easyinput/readme.md
@@ -0,0 +1,198 @@
+
+
+### Easyinput 增强输入框
+> **组件名:uni-easyinput**
+> 代码块: `uEasyinput`
+
+
+easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的,easyinput 内置了边框,图标等,同时包含 input 所有功能
+
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+### 平台差异说明
+
+暂不支持在nvue页面中使用
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+输入内容后,输入框尾部会显示清除按钮,点击可清除内容,如不需要展示图标,`clearable` 属性设置为 `false` 即可
+
+`clearable` 属性设置为 `true` ,输入框聚焦且内容不为空时,才会显示内容
+
+```html
+
+```
+
+
+### 输入框带左右图标
+
+设置 `prefixIcon` 属性来显示输入框的头部图标
+
+设置 `suffixIcon` 属性来显示输入框的尾部图标
+
+注意图标当前只支持 `uni-icons` 内置的图标,当配置 `suffixIcon` 属性后,会覆盖 `:clearable="true"` 和 `type="password"` 时的原有图标
+
+绑定 `@iconClick` 事件可以触发图标的点击 ,返回 `prefix` 表示点击左侧图标,返回 `suffix` 表示点击右侧图标
+
+```html
+
+
+
+
+
+```
+
+### 输入框禁用
+
+设置 `disable` 属性可以禁用输入框,此时输入框不可编辑
+
+```html
+
+```
+
+### 密码框
+
+设置 `type="password"` 时,输入框内容将会不可见,由实心点代替,同时输入框尾部会显示眼睛图标,点击可切换内容显示状态
+
+```html
+
+```
+
+### 输入框聚焦
+
+设置 `focus` 属性可以使输入框聚焦
+
+如果页面存在多个设置 `focus` 属性的输入框,只有最后一个输入框的 `focus` 属性会生效
+
+```html
+
+```
+
+
+### 多行文本
+
+设置 `type="textarea"` 时可输入多行文本
+
+```html
+
+```
+
+### 多行文本自动高度
+
+设置 `type="textarea"` 时且设置 `autoHeight` 属性,可使用多行文本的自动高度,会跟随内容调整输入框的显示高度
+
+```html
+
+```
+
+### 取消边框
+
+设置 `:inputBorder="false"` 时可取消输入框的边框显示,同时搭配 `uni-forms` 的 `:border="true"` 有较好的效果
+
+```html
+
+
+
+
+
+
+
+
+```
+
+
+## API
+
+### Easyinput Props
+
+|属性名| 类型| 可选值|默认值|说明|
+|:-:|:-:|:-:|:-:|:-:|
+|value|String/ Number|-|-|输入内容|
+|type|String|见 type Options|text|输入框的类型(默认text)|
+|clearable|Boolean|-|true| 是否显示右侧清空内容的图标控件(输入框有内容且不禁用时显示),点击可清空输入框内容|
+|autoHeight|Boolean|-|false| 是否自动增高输入区域,type为textarea时有效|
+|placeholder|String |-| - | 输入框的提示文字|
+|placeholderStyle|String| - | - | placeholder的样式(内联样式,字符串),如"color: #ddd"|
+|focus|Boolean|-|false|是否自动获得焦点|
+|disabled|Boolean|-|false|是否不可输入|
+|maxlength|Number|-|140|最大输入长度,设置为 -1 的时候不限制最大长度|
+|confirmType|String|-|done|设置键盘右下角按钮的文字,仅在type="text"时生效|
+|clearSize|Number|-|15|清除图标的大小,单位px|
+|prefixIcon|String|-|-|输入框头部图标 |
+|suffixIcon|String|-|-|输入框尾部图标|
+|trim|Boolean/String|见 trim Options | false | 是否自动去除空格,传入类型为 Boolean 时,自动去除前后空格|
+|inputBorder|Boolean|-|true|是否显示input输入框的边框|
+|styles|Object|-|-| 样式自定义|
+|passwordIcon|Boolean|-| true | type=password 时,是否显示小眼睛图标|
+
+
+#### Type Options
+
+|属性名| 说明|
+|:-:| :-:|
+|text|文本输入键盘|
+|textarea |多行文本输入键盘|
+|password |密码输入键盘|
+|number|数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式 |
+|idcard|身份证输入键盘,仅支持微信、支付宝、百度、QQ小程序|
+|digit|带小数点的数字键盘,仅支持微信、支付宝、百度、头条、QQ小程序 |
+
+#### ConfirmType Options
+
+平台差异与 [input](https://uniapp.dcloud.io/component/input) 相同
+
+|属性名 | 说明|
+|:-:| :-:|
+|send|右下角按钮为“发送” |
+|search |右下角按钮为“搜索” |
+|next|右下角按钮为“下一个”|
+|go|右下角按钮为“前往” |
+|done|右下角按钮为“完成” |
+
+
+#### Styles Options
+
+|属性名| 默认值 |说明|
+|:-:| :-:| :-:|
+|color| #333| 输入文字颜色|
+|disableColor |#eee| 输入框禁用背景色|
+|borderColor |#e5e5e5 | 边框颜色|
+
+#### Trim Options
+
+传入类型为 `Boolean` 时,自动去除前后空格,传入类型为 `String` 时,可以单独控制,下面是可选值
+
+|属性名|说明|
+|:-:| :-:|
+|both|去除两端空格|
+|left|去除左侧空格|
+|right|去除右侧空格|
+|all|去除所有空格|
+|none|不去除空格|
+
+
+### Easyinput Events
+
+|事件称名| 说明|返回值|
+|:-:| :-:|:-:|
+|@input|输入框内容发生变化时触发| -|
+|@focus|输入框获得焦点时触发| -|
+|@blur|输入框失去焦点时触发| -|
+|@confirm|点击完成按钮时触发| -|
+|@iconClick |点击图标时触发| prefix/suffix |
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/easyinput/easyinput](https://hellouniapp.dcloud.net.cn/pages/extUI/easyinput/easyinput)
\ 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 0000000000000000000000000000000000000000..cbf69d6a572103f2046e3c25adabe0b353b74fd0
--- /dev/null
+++ b/uni_modules/uni-fab/changelog.md
@@ -0,0 +1,8 @@
+## 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 0000000000000000000000000000000000000000..0afab66ee8185475dc2618e8db85175b5a3a856c
--- /dev/null
+++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue
@@ -0,0 +1,448 @@
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 0000000000000000000000000000000000000000..9df4dcd7f5958b17b962e9d37c52c298d549ad00
--- /dev/null
+++ b/uni_modules/uni-fab/components/uni-fab/uni-fab.vue.bak
@@ -0,0 +1,383 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-fab/package.json b/uni_modules/uni-fab/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..84cb81408a8e9439ae57447dad27aa6bab8e4ad6
--- /dev/null
+++ b/uni_modules/uni-fab/package.json
@@ -0,0 +1,83 @@
+{
+ "id": "uni-fab",
+ "displayName": "uni-fab 悬浮按钮",
+ "version": "1.1.0",
+ "description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "按钮",
+ "悬浮按钮",
+ "fab"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-fab/readme.md b/uni_modules/uni-fab/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..0ed6ce815e18c9df82034c4318051ab34ce72902
--- /dev/null
+++ b/uni_modules/uni-fab/readme.md
@@ -0,0 +1,91 @@
+
+
+## Fab 悬浮按钮
+> **组件名:uni-fab**
+> 代码块: `uFab`
+
+
+点击可展开一个图形按钮菜单
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 不建议动态修改属性,可能会耗损部分性能。
+> - 展开菜单暂不支持字体图标,使用图片路径时建议使用绝对路径,相对路径可能会有问题。
+> - 选中状态要通过自己控制,如果不希望有选中状态,不处理 `active` 即可。
+> - 展开菜单建议最多显示四个,如果过多对于小屏手机可能会超出屏幕。
+
+
+### 基本用法
+
+在 `template` 中使用组件
+
+```html
+
+
+
+
+
+```
+
+
+## API
+
+### Fab Props
+
+| 属性名 | 类型 | 默认值 | 说明 |
+| :-: | :-: | :-: | :-: |
+| pattern | Object | - | 可选样式配置项 |
+| horizontal| String | 'left' | 水平对齐方式。`left`:左对齐,`right`:右对齐 |
+| vertical | String | 'bottom' | 垂直对齐方式。`bottom`:下对齐,`top`:上对齐 |
+| direction | String | 'horizontal' | 展开菜单显示方式。`horizontal`:水平显示,`vertical`:垂直显示 |
+| popMenu | Boolean | true | 是否使用弹出菜单 |
+| content | Array | - | 展开菜单内容配置项 |
+
+
+
+**pattern配置项:**
+
+| 参数 | 类型 | 默认值 | 说明 |
+| :-: | :-: | :-: | :-: |
+| color | String | #3c3e49 | 文字默认颜色 |
+| selectedColor | String | #007AFF | 文字选中时的颜色 |
+| backgroundColor | String | #ffffff | 背景色 |
+| buttonColor | String | #3c3e49 | 按钮背景色 |
+
+**content配置项:**
+
+| 参数 | 类型 | 说明 |
+| :-: | :-: | :-: | :-: |
+| iconPath | String | 图片路径 |
+| selectedIconPath | String | 选中后图片路径|
+| text | String | 文字 |
+| active | Boolean | 是否选中当前 |
+
+### Fab Events
+
+| 参数 | 类型 | 说明 |
+| :-: | :-: | :-: |
+| @trigger | Function | 展开菜单点击事件,返回点击信息|
+| @fabClick | Function | 悬浮按钮点击事件 |
+
+
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/fab/fab](https://hellouniapp.dcloud.net.cn/pages/extUI/fab/fab)
\ 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 0000000000000000000000000000000000000000..f35b81748e84866247f8d42fd67e10fbf59584da
--- /dev/null
+++ b/uni_modules/uni-fav/changelog.md
@@ -0,0 +1,14 @@
+## 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 0000000000000000000000000000000000000000..9a0759e0214562df0a0e69aca7760e288b68366b
--- /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 0000000000000000000000000000000000000000..de7509c87ba5197b9f5d20ca94a0558c7a8e08a9
--- /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 0000000000000000000000000000000000000000..67c89bfc7e5b57a51a04aa655d39c895325e8308
--- /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 0000000000000000000000000000000000000000..67c89bfc7e5b57a51a04aa655d39c895325e8308
--- /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 0000000000000000000000000000000000000000..d82864bb9249847d6fe68600dd5d96fb1512cc5a
--- /dev/null
+++ b/uni_modules/uni-fav/components/uni-fav/uni-fav.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+ {{ checked ? contentFav : contentDefault }}
+
+
+
+
+
+
diff --git a/uni_modules/uni-fav/package.json b/uni_modules/uni-fav/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..0556086716f4f1f4035bdfdb781d0ed1d5712939
--- /dev/null
+++ b/uni_modules/uni-fav/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-fav",
+ "displayName": "uni-fav 收藏按钮",
+ "version": "1.1.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-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": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-fav/readme.md b/uni_modules/uni-fav/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..83a01fca35e333c3f942680915632fa0c99a5a8b
--- /dev/null
+++ b/uni_modules/uni-fav/readme.md
@@ -0,0 +1,50 @@
+
+
+## Fav 收藏按钮
+> **组件名:uni-fav**
+> 代码块: `uFav`
+
+
+用于收藏功能,可点击切换选中、不选中的状态。
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+```
+
+## API
+
+### Fav Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|star |Boolean|true |按钮是否带星星 |
+|bgColor |String |#eeeeee |未收藏时的背景色 |
+|bgColorChecked |String |#007aff |已收藏时的背景色 |
+|fgColor |String |#666666 |未收藏时的文字颜色 |
+|fgColorChecked |String |#FFFFFF |已收藏时的文字颜色 |
+|circle |Boolean|false |是否为圆角 |
+|checked |Boolean|false |是否为已收藏 |
+|contentText |Object |```{contentDefault: '收藏',contentFav: '已收藏'}```|收藏按钮文字 |
+
+
+### Fav Events
+
+|事件称名 |说明 |返回值 |
+|:-: |:-: |:-: |
+|click |点击 fav按钮 触发事件 |- |
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/fav/fav](https://hellouniapp.dcloud.net.cn/pages/extUI/fav/fav)
\ No newline at end of file
diff --git a/uni_modules/uni-feedback/changelog.md b/uni_modules/uni-feedback/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..57c13b89d8bcfe95c907caaef24304a6624980bf
--- /dev/null
+++ b/uni_modules/uni-feedback/changelog.md
@@ -0,0 +1,2 @@
+## 1.0.3(2021-08-26)
+删除多余的云函数test2
diff --git a/uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js b/uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js
new file mode 100644
index 0000000000000000000000000000000000000000..be3d330f45a52e0f78e632809f57e20f9c5c5b88
--- /dev/null
+++ b/uni_modules/uni-feedback/js_sdk/validator/opendb-feedback.js
@@ -0,0 +1,98 @@
+// 表单校验规则由 schema2code 生成,不建议直接修改校验规则,而建议通过 schema2code 生成, 详情: https://uniapp.dcloud.net.cn/uniCloud/schema
+
+
+const validator = {
+ "content": {
+ "rules": [
+ {
+ "required": true
+ },
+ {
+ "format": "string"
+ }
+ ],
+ "label": "留言内容/回复内容"
+ },
+ "imgs": {
+ "rules": [
+ {
+ "format": "array"
+ },
+ {
+ "arrayType": "file"
+ },
+ {
+ "maxLength": 6
+ }
+ ],
+ "label": "图片列表"
+ },
+ "contact": {
+ "rules": [
+ {
+ "format": "string"
+ }
+ ],
+ "label": "联系人"
+ },
+ "mobile": {
+ "rules": [
+ {
+ "format": "string"
+ },
+ {
+ "pattern": "^\\+?[0-9-]{3,20}$"
+ }
+ ],
+ "label": "联系电话"
+ }
+}
+
+const enumConverter = {}
+
+function filterToWhere(filter, command) {
+ let where = {}
+ for (let field in filter) {
+ let { type, value } = filter[field]
+ switch (type) {
+ case "search":
+ if (typeof value === 'string' && value.length) {
+ where[field] = new RegExp(value)
+ }
+ break;
+ case "select":
+ if (value.length) {
+ let selectValue = []
+ for (let s of value) {
+ selectValue.push(command.eq(s))
+ }
+ where[field] = command.or(selectValue)
+ }
+ break;
+ case "range":
+ if (value.length) {
+ let gt = value[0]
+ let lt = value[1]
+ where[field] = command.and([command.gte(gt), command.lte(lt)])
+ }
+ break;
+ case "date":
+ if (value.length) {
+ let [s, e] = value
+ let startDate = new Date(s)
+ let endDate = new Date(e)
+ where[field] = command.and([command.gte(startDate), command.lte(endDate)])
+ }
+ break;
+ case "timestamp":
+ if (value.length) {
+ let [startDate, endDate] = value
+ where[field] = command.and([command.gte(startDate), command.lte(endDate)])
+ }
+ break;
+ }
+ }
+ return where
+}
+
+export { validator, enumConverter, filterToWhere }
diff --git a/uni_modules/uni-feedback/package.json b/uni_modules/uni-feedback/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb20e7a1bfc276d8de38e66bc21912e430295d7c
--- /dev/null
+++ b/uni_modules/uni-feedback/package.json
@@ -0,0 +1,88 @@
+{
+ "id": "uni-feedback",
+ "displayName": "问题反馈用户端页面模板",
+ "version": "1.0.3",
+ "description": "问题反馈用户端页面模板,方便开发者快速搭建问题反馈界面",
+ "keywords": [
+ "问题反馈用户端页面模板"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "uniCloud",
+ "云端一体页面模板"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-forms",
+ "uni-file-picker",
+ "uni-easyinput",
+ "uni-load-more",
+ "uni-list",
+ "uni-fab",
+ "uni-link"
+ ],
+ "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": "u",
+ "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-feedback/pages/opendb-feedback/detail.vue b/uni_modules/uni-feedback/pages/opendb-feedback/detail.vue
new file mode 100644
index 0000000000000000000000000000000000000000..fa28fca65965679627691445b2bd86e43d7a62da
--- /dev/null
+++ b/uni_modules/uni-feedback/pages/opendb-feedback/detail.vue
@@ -0,0 +1,113 @@
+
+
+
+ {{error.message}}
+
+
+
+
+
+ 留言内容/回复内容
+ {{data.content}}
+
+
+ 图片列表
+
+
+
+
+
+
+ 联系人
+ {{data.contact}}
+
+
+ 联系电话
+ {{data.mobile}}
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/edit.vue b/uni_modules/uni-feedback/pages/opendb-feedback/edit.vue
new file mode 100644
index 0000000000000000000000000000000000000000..bd65125da9dcde706bb90f4ccb80ca2e3ce472d7
--- /dev/null
+++ b/uni_modules/uni-feedback/pages/opendb-feedback/edit.vue
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 提交
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/list.vue b/uni_modules/uni-feedback/pages/opendb-feedback/list.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d075eb33cae8394539d0d8b61dd368d26fadec2f
--- /dev/null
+++ b/uni_modules/uni-feedback/pages/opendb-feedback/list.vue
@@ -0,0 +1,70 @@
+
+
+
+ {{error.message}}
+
+
+
+
+
+
+
+ {{item._id}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue b/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1978c7214009b4b7a6077e78134452ed279d8c14
--- /dev/null
+++ b/uni_modules/uni-feedback/pages/opendb-feedback/opendb-feedback.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 提交
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-feedback/readme.md b/uni_modules/uni-feedback/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..aa0ede5e64cc25f1fab0f667d2e2bf5522571d01
--- /dev/null
+++ b/uni_modules/uni-feedback/readme.md
@@ -0,0 +1,2 @@
+这是一个问题反馈客户端插件,admin端插件:[https://ext.dcloud.net.cn/plugin?id=4992](https://ext.dcloud.net.cn/plugin?id=4992)
+> 参考案例 [uni-starter](https://ext.dcloud.net.cn/plugin?id=5057)
\ No newline at end of file
diff --git a/uni_modules/uni-feedback/uniCloud/database/opendb-feedback.schema.json b/uni_modules/uni-feedback/uniCloud/database/opendb-feedback.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..e13d8742204b53ad3632925152228e28de4354e6
--- /dev/null
+++ b/uni_modules/uni-feedback/uniCloud/database/opendb-feedback.schema.json
@@ -0,0 +1,72 @@
+{
+ "bsonType": "object",
+ "required": ["content"],
+ "permission": {
+ "create": "auth.uid != null",
+ "read": true,
+ "delete": false,
+ "update": false
+ },
+ "properties": {
+ "_id": {
+ "description": "ID,系统自动生成"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "留言反馈用户ID\/回复留言用户ID,参考uni-id-users表",
+ "foreignKey": "uni-id-users._id",
+ "forceDefaultValue": {
+ "$env": "uid"
+ }
+ },
+ "create_date": {
+ "bsonType": "timestamp",
+ "title": "留言时间\/回复留言时间",
+ "forceDefaultValue": {
+ "$env": "now"
+ }
+ },
+ "content": {
+ "bsonType": "string",
+ "title": "留言内容\/回复内容",
+ "componentForEdit": {
+ "name": "textarea"
+ },
+ "trim": "right"
+ },
+ "imgs": {
+ "bsonType": "array",
+ "arrayType": "file",
+ "maxLength": 6,
+ "fileMediaType": "image",
+ "title": "图片列表"
+ },
+ "is_reply": {
+ "bsonType": "bool",
+ "title": "是否是回复类型"
+ },
+ "feedback_id": {
+ "bsonType": "string",
+ "title": "被回复留言ID"
+ },
+ "contact": {
+ "bsonType": "string",
+ "title": "联系人",
+ "trim": "both"
+ },
+ "mobile": {
+ "bsonType": "string",
+ "title": "联系电话",
+ "pattern": "^\\+?[0-9-]{3,20}$",
+ "trim": "both"
+ },
+ "reply_count": {
+ "permission": {
+ "write": false
+ },
+ "bsonType": "int",
+ "title": "被回复条数",
+ "defaultValue": 0
+ }
+ }
+}
diff --git a/uni_modules/uni-file-picker/changelog.md b/uni_modules/uni-file-picker/changelog.md
new file mode 100644
index 0000000000000000000000000000000000000000..df26c52345e85eea3500e547715ac26b25ed9fc9
--- /dev/null
+++ b/uni_modules/uni-file-picker/changelog.md
@@ -0,0 +1,52 @@
+## 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 0000000000000000000000000000000000000000..24a07f5787f23688cb233546644c28ee0ca7ee29
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js
@@ -0,0 +1,224 @@
+'use strict';
+
+const ERR_MSG_OK = 'chooseAndUploadFile:ok';
+const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
+
+function chooseImage(opts) {
+ const {
+ count,
+ sizeType = ['original', 'compressed'],
+ sourceType = ['album', 'camera'],
+ extension
+ } = opts
+ return new Promise((resolve, reject) => {
+ uni.chooseImage({
+ count,
+ sizeType,
+ sourceType,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res, 'image'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function chooseVideo(opts) {
+ const {
+ camera,
+ compressed,
+ maxDuration,
+ sourceType = ['album', 'camera'],
+ extension
+ } = opts;
+ return new Promise((resolve, reject) => {
+ 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),
+ });
+ },
+ });
+ });
+}
+
+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 0000000000000000000000000000000000000000..ddf1c93b5fb43c1ab38cc8b5412ef5e73de09a34
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
@@ -0,0 +1,652 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择文件
+
+
+
+
+
+
+
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 0000000000000000000000000000000000000000..625d92ec72822c33e50deb5cda45304ff76a59fb
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
+
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 0000000000000000000000000000000000000000..6d6cdc0785164e0d9043280df5fdda6e163d4fa8
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
@@ -0,0 +1,290 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 0000000000000000000000000000000000000000..60aaa3e4ebccc9cf9f456feb3cd6fa5a87a1f5ca
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js
@@ -0,0 +1,109 @@
+/**
+ * 获取文件名和后缀
+ * @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,
+ 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 0000000000000000000000000000000000000000..0a02dda64ff59b26b0a1eb51a31ebeeed9802fa3
--- /dev/null
+++ b/uni_modules/uni-file-picker/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "uni-file-picker",
+ "displayName": "uni-file-picker 文件选择上传",
+ "version": "0.2.14",
+ "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": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "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": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-file-picker/readme.md b/uni_modules/uni-file-picker/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..496327b7f2e9961d2333a315ca7af8a4bf743c75
--- /dev/null
+++ b/uni_modules/uni-file-picker/readme.md
@@ -0,0 +1,305 @@
+
+## FilePicker 文件选择上传
+
+> **组件名:uni-file-picker**
+> 代码块: `uFilePicker`
+
+
+文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - 如不绑定服务空间,`autoUpload`默认为`false`且不可更改
+> - 选择文件目前只支持 `H5` 和 `微信小程序平台` ,且 `微信小程序平台` 使用 `wx.chooseMessageFile()`
+> - v-model 值需要自动上传成功后才会绑定值,一般只用来回显数据
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+
+## API
+
+### FilePicker Props
+
+| 属性名 | 类型 | 默认值 | 可选值 | 说明 |
+| :-: | :-: | :-: | :-: | :-: |
+| v-model/value | Array\Object | - | - | 组件数据,通常用来回显 ,类型由`return-type`属性决定 ,**格式见下文** |
+| disabled | Boolean | false | - | 组件禁用 |
+| readonly | Boolean | false | - | 组件只读,不可选择,不显示进度,不显示删除按钮 |
+| return-type | String | array | array/object | 限制 `value` 格式,当为 `object` 时 ,组件只能单选,且会覆盖 |
+| disable-preview| Boolean | false | - | 禁用图片预览,仅 `mode:grid`生效 |
+| del-icon | Boolean | true | - | 是否显示删除按钮 |
+| auto-upload | Boolean | true | - | 是否自动上传,值为`true`则只触发@select,可自行上传|
+| limit | Number\String | 9 | - | 最大选择个数 ,h5 会自动忽略多选的部分 |
+| title | String | - | - | 组件标题,右侧显示上传计数 |
+| mode | String | list | list/grid | 选择文件后的文件列表样式 |
+| file-mediatype| String | image | image/video/all | 选择文件类型,all 只支持 H5 和微信小程序平台 |
+| file-extname | Array\String | - | - | 选择文件后缀,字符串的情况下需要用逗号分隔(推荐使用字符串),根据 `file-mediatype` 属性而不同|
+| list-styles | Object | - | - | `mode:list` 时的样式 |
+| image-styles | Object | - | - | `mode:grid` 时的样式 |
+
+
+### value 格式
+
+三个属性必填,否则影响组件显示
+
+```json
+[
+ {
+ "name":"file.txt",
+ "extname":"txt",
+ "url":"https://xxxx",
+ // ...
+ }
+]
+
+```
+
+### list-styles 格式
+
+```json
+{
+ "borderStyle":{
+ "color":"#eee", // 边框颜色
+ "width":"1px", // 边框宽度
+ "style":"solid", // 边框样式
+ "radius":"5px" // 边框圆角,不支持百分比
+ },
+ "border":false, // 是否显示边框
+ "dividline":true // 是否显示分隔线
+}
+```
+
+### image-styles 格式
+
+```json
+{
+ "height": 60, // 边框高度
+ "width": 60, // 边框宽度
+ "border":{ // 如果为 Boolean 值,可以控制边框显示与否
+ "color":"#eee", // 边框颜色
+ "width":"1px", // 边框宽度
+ "style":"solid", // 边框样式
+ "radius":"50%" // 边框圆角,支持百分比
+ }
+}
+```
+
+### FilePicker Events
+
+|事件称名 |说明 | 返回值 |
+|:-: |:-: | :-: |
+|@select | 选择文件后触发 | 见下文|
+|@progress|文件上传时触发 | 见下文|
+|@success |上传成功触发 | 见下文|
+|@fail |上传失败触发 | 见下文|
+|@delete |文件从列表移除时触发| 见下文|
+
+
+#### Callback Params
+
+`**注意**:如果绑定的是腾讯云的服务空间 ,tempFilePaths 将返回 fileID`
+
+```json
+{
+ "progress" : Number, // 上传进度 ,仅 @progress 事件包含此字段
+ "index" : Number, // 上传文件索引 ,仅 @progress 事件包含此字段
+ "tempFile" : file, // 当前文件对象 ,包含文件流,文件大小,文件名称等,仅 @progress 事件包含此字段
+ "tempFiles" : files, // 文件列表,包含文件流,文件大小,文件名称等
+ "tempFilePaths" : filePaths, // 文件地址列表,@sucess 事件为上传后的线上文件地址
+}
+
+```
+
+
+### FilePicker Methods
+
+通过 `$ref` 调用
+
+| 方法称名 | 说明 | 参数 |
+| :-: | :-: | :-: |
+| upload() | 手动上传 ,如`autoUpload`为`false` ,必须调用此方法| - |
+| clearFiles(index:Number) | 清除选择结果| 传如 Number 为删除指定下标的文件 ,不传为删除所有|
+
+### FilePicker Slots
+
+插槽可定义上传按钮显示样式
+
+| 插槽名 | 说明 |
+| :-: | :-: |
+| default |默认插槽|
+
+## 组件用法
+
+### 基础用法
+
+```html
+
+```
+
+```javascript
+export default {
+ data() {
+ return {
+ imageValue:[]
+ }
+ },
+ methods:{
+ // 获取上传状态
+ select(e){
+ console.log('选择文件:',e)
+ },
+ // 获取上传进度
+ progress(e){
+ console.log('上传进度:',e)
+ },
+
+ // 上传成功
+ success(e){
+ console.log('上传成功')
+ },
+
+ // 上传失败
+ fail(e){
+ console.log('上传失败:',e)
+ }
+ }
+}
+
+```
+
+### 选择指定后缀图片,且限制选择个数
+
+配置 `file-mediatype` 属性为 `image`,限定只选择图片
+
+配置 `file-extname` 属性为 `'png,jpg'`,限定只选择 `png`和`jpg`后缀的图片
+
+配置 `limit` 属性为 1 ,则最多选择一张图片
+
+配置 `mode` 属性为 `grid` ,可以使用九宫格样式选择图片
+
+
+```html
+
+```
+
+### 手动上传
+
+配置 `auto-upload` 属性为 `false` ,可以停止自动上传,通过`ref`调用`upload`方法自行选择上传时机
+
+```html
+
+
+ 上传文件
+
+```
+
+```javascript
+export default {
+ data() {},
+ methods:{
+ upload(){
+ this.$refs.files.upload()
+ }
+ }
+}
+
+```
+
+### 单选图片且点击再次选择
+
+配置 `disable-preview` 属性为 `true`,禁用点击预览图片功能
+
+配置 `del-icon` 属性为 `false`,隐藏删除按钮
+
+配置 `return-type` 属性为 `object`,设置 `value` 类型 ,如需绑定 `array`类型 ,则设置`limit:1`,可达到一样的效果
+
+
+
+```html
+选择头像
+```
+
+### 自定义样式
+
+配置 `image-styles` 属性,可以自定义`mode:image`时的回显样式
+
+配置 `list-styles` 属性,可以自定义`mode:video|| mode:all`时的回显样式
+
+```html
+
+
+
+
+```
+
+```javascript
+export default {
+ data() {
+ imageStyles:{
+ width:64,
+ height:64,
+ border:{
+ color:"#ff5a5f",
+ width:2,
+ style:'dashed',
+ radius:'2px'
+ }
+ },
+ listStyles:{
+ // 是否显示边框
+ border: true,
+ // 是否显示分隔线
+ dividline: true,
+ // 线条样式
+ borderStyle: {
+ width:1,
+ color:'blue',
+ radius:2
+ }
+ }
+ }
+}
+
+```
+
+
+
+### 使用插槽
+
+使用默认插槽可以自定义选择文件按钮样式
+
+```html
+
+ 选择文件
+
+```
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/file-picker/file-picker](https://hellouniapp.dcloud.net.cn/pages/extUI/file-picker/file-picker)
\ 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 0000000000000000000000000000000000000000..b5b12f0b47b16bb62aab302b6812283f3536e757
--- /dev/null
+++ b/uni_modules/uni-forms/changelog.md
@@ -0,0 +1,53 @@
+## 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 0000000000000000000000000000000000000000..5837320edd038d76ee904f3f12314e974656cf06
--- /dev/null
+++ b/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue
@@ -0,0 +1,509 @@
+
+
+
+
+
+
+ *
+
+ {{ label }}
+
+
+
+
+
+
+
+ {{ showMsg === 'undertext' ? msg : '' }}
+
+
+
+
+
+
+
+
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 0000000000000000000000000000000000000000..057afc8fedaf34f397fb4afdf1afff6d8955b430
--- /dev/null
+++ b/uni_modules/uni-forms/components/uni-forms/uni-forms.vue
@@ -0,0 +1,472 @@
+
+
+
+
+
+
+
+
+
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 0000000000000000000000000000000000000000..1834c6cf61559bd1a9b8f2a984ef9b8e13350e98
--- /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 0000000000000000000000000000000000000000..9d949b2be4a7f85c9cbba6fc3ecab4cb25f86382
--- /dev/null
+++ b/uni_modules/uni-forms/package.json
@@ -0,0 +1,89 @@
+{
+ "id": "uni-forms",
+ "displayName": "uni-forms 表单",
+ "version": "1.2.7",
+ "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-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": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-forms/readme.md b/uni_modules/uni-forms/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..e8352620b6f85056593f571568f6cdfb8dc11406
--- /dev/null
+++ b/uni_modules/uni-forms/readme.md
@@ -0,0 +1,830 @@
+
+
+## Forms 表单
+
+> **组件名:uni-forms**
+> 代码块: `uForms`、`uni-forms-item`
+> 关联组件:`uni-forms-item`、`uni-easyinput`、`uni-data-checkbox`、`uni-group`。
+
+
+uni-app的内置组件已经有了 `