commit fe37e2e1dfda90295f2b7add3024aa40b42aef66 Author: weicw <594098497@qq.com> Date: Tue Nov 7 17:15:33 2023 +0800 1107 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8bbff90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.hbuilderx +/node_modules +/unpackage diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..2006917 --- /dev/null +++ b/App.vue @@ -0,0 +1,130 @@ + + + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..9461fd6 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 VK + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0463ae1 --- /dev/null +++ b/README.md @@ -0,0 +1,305 @@ + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/ad18e7d6-ae0e-4424-bf3d-6e3dad1036a1.png) + +### 插件名称:`vk-unicloud-admin` +### 作者:VK + +## 序 +* 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +* 无需转变开发习惯,0成本上手云开发。 +* 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +* 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +* `client端`框架地址: [https://ext.dcloud.net.cn/plugin?id=2204](https://ext.dcloud.net.cn/plugin?id=2204) +* `admin端`框架地址:[https://ext.dcloud.net.cn/plugin?id=5043](https://ext.dcloud.net.cn/plugin?name=vk-unicloud-admin) +* `client端`框架文档:[点击查看](https://vkdoc.fsq.pub/client/) +* `admin端`框架文档:[点击查看](https://vkdoc.fsq.pub/admin/) + +#### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 框架体验地址:[点击进入『框架体验地址』](https://vkunicloud.fsq.pub/admin/) + +#### 体验账号: + +* 高级管理员:test11(账号)123456(密码)可以执行绝大部分功能 +* 初级管理员:test12(账号)123456(密码)只能执行查询功能 +* 无权限用户:test13(账号)123456(密码)无admin登录权限 + +[点击体验『表单可视化生成器』](https://vkunicloud.fsq.pub/vk-form-visualizer/) + +### 什么是 `vk-unicloud-admin` ? + +* `vk-unicloud-admin` 是基于 `uniapp` + `unicloud` + `uni-id` +`element` + `vk-unicloud-router` 的一套快速 `admin` 完整开发框架 +* (只兼容PC,只为PC admin而生,但Ta也是uniapp项目,非传统vue-admin项目,你可以用Ta来做你H5、小程序、app的admin管理端) + +**注意:TA是uniapp项目,支持uniapp所有H5的API和插件市场所有uni-admin插件** + +**最大亮点:使用 `vk-unicloud-admin` 后,即使你是一个纯后端,不会写任何css,照样可以写出功能强大且页面好看的admin管理系统。** + +### `vk-unicloud-admin` 主要功能 以及 对开发者的价值 + +* 1、完美集成 `vk-unicloud-router`,拥有 `vk-unicloud-router` 的所有现成API功能。让你开发事半功倍。[点击查看](https://vkdoc.fsq.pub/client/) +* 2、完美集成 `element` UI框架,并在 `element` 基础上进行了深度封装(支持原生 `element`)[element官网](https://element.eleme.cn/#/zh-CN/component/button) +* 3、`表单可视化拖拽工具`(可直接生成 `vk框架代码 `和 `element` 原生代码 [点击体验](https://vkunicloud.fsq.pub/vk-form-visualizer/) +* 4、`万能表格组件`,通过少量代码即可完成 `CRUD`,同时还拥有较高的自由度。几分钟完成一个页面 `CRUD`。 +* 5、`万能表单组件`,通过少量代码即可完成表单渲染 + 表单请求。 +* 6、超高自由度,支持使用插槽的形式自定义已有的功能和渲染方式,也支持直接使用 `element` 原生代码来写页面。 +* 7、完善的用户角色权限,无需开发即可拥有(权限可精确到每一个云函数)。 +* 8、`pages-dev.json` 机制,开发调试页面不会被发布到正式版中。 +* 9、只要你开发过传统 `vue admin` 项目,那么上手此框架的学习成本几乎为0 +* 10、众多示例代码,为你的云开发之路扫平障碍。 +* 11、内置3个主题(纯黑,纯白,黑白)且支持自定义主题。[点击查看主题](https://vkdoc.fsq.pub/admin/1/theme.html) +* 12、群内众多开发者,关于框架使用问题几乎有问必答。Q群:22466457 +* 13、更多功能敬请体验。 + +### 核心功能 + +#### 一、万能表格 + +核心思想:通过 JSON 配置渲染页面(简单配置一下,表格就完成了) + +如下方JSON用于渲染头像和时间 +```js + [ + { key: "avatar", title: "头像", type: "avatar", width: 80, shape:"circle" }, + { key: "_add_time", title: "添加时间", type: "time", width: 160, valueFormat:"yyyy-MM-dd hh:mm:ss" }, + ] +``` + +* 1、查询:包含分页、排序、多条件搜索、搜索项折叠、多表连表、数据源预处理、展开行、树状结构等等 +* 2、支持多选框(用于批量操作) +* 3、自动生成详情页:点击详情按钮,自动显示详情页弹窗。 +* 4、修改:点击修改按钮,自动显示修改表单弹窗。 +* 5、删除:点击删除,显示气泡二次确认提示,再点击确定,则删除数据。 +* 6、自定义操作按钮:如发货、审核等自定义按钮。 +* 7、高自由度:每个字段都有插槽,在内置组件不满足需求的情况下,可以使用插槽自己编写该字段的渲染规则。(内置组件基本上可满足90%以上的渲染需求) +* 8、导出excel表格:通过内置api只需一行代码即可直接导出表格数据。 +* 9、导出满足表格查询条件的数据库内所有数据(unicloud的查询有限制每次500条记录,但万能表格解决了此问题,可以导出数据库内全部数据) +* 10、异常重试机制:一般不需要此功能,但是由于unicloud-阿里云空间会偶尔查询失败,此时此功能就派上用场了(会自动重新再查询,用户体验上只是感觉这次查询慢了一点而已(因为第一次失败了,查了2次或2次以上)) +* 11、不仅仅支持unicloud云函数请求,还支持http请求。 +* 12、支持下方自动显示合计 +* 13、更多功能敬请体验 [万能表格文档地址](https://vkdoc.fsq.pub/admin/2/table.html) + +#### 二、万能表单 + +核心思想:通过 JSON 配置渲染表单(简单配置一下,表单就完成了) + +如下方JSON用于渲染 一个昵称输入框 和 性别单选按钮组 +```js + [ + { key:"nickname", title:"昵称", type:"text" }, + { + key:"gender", title:"性别", type:"radio", + data:[ + { value:1, label:"男" }, + { value:2, label:"女" } + ] + } + ] +``` + +* 1、自动提交表单 +* 2、提交前自动表单验证 +* 3、防止表单重复提交(提交后按钮自动进入loading状态,不可再点击) +* 4、同一表单可复用(如一般添加和修改的表单基本是一样的) +* 5、表单复用时,支持字段显示规则(如添加时有A字段,修改时,无A字段等) +* 6、拦截器:表单提交前拦截,执行自己逻辑,再放行或终止。 +* 7、高自由度:每个字段都有插槽,在内置组件不满足需求的情况下,可以使用插槽自己编写该字段的渲染规则。(内置组件基本上可满足90%以上的渲染需求) +* 8、重置表单:一键重置表单 +* 9、表单可视化拖拽工具 [点击查看](https://vkunicloud.fsq.pub/vk-form-visualizer/#/) +* 10、更多功能敬请体验 [万能表单文档地址](https://vkdoc.fsq.pub/admin/3/form.html) + +`vk-unicloud-admin` 框架同时还包含 `vk-unicloud-router` 所有功能,[点击查看vk-unicloud-router功能列表](https://vkdoc.fsq.pub/client/) + +### 同时 admin 框架内置了以下页面 + +* 1、用户管理 +* 2、角色管理 +* 3、权限管理 +* 4、菜单管理 +* 5、应用管理 +* 6、系统缓存管理 +* 7、动态组件数据 +* 8、用户登录日志 +* 9、系统操作日志 +* 10、VK框架组件演示 +* 11、element静态功能演示 +* 12、素材管理(图片、视频、文件) +* 13、App升级中心管理(新增于1.14.0) +* 14、持续完善中。。。 + +## 2、快速上手 - 安装步骤 + +* 1、`项目根目录` 执行 `npm i` 命令(必须先执行此npm命令,安装必要的依赖,否则会无法启动。) + +#### 接下来是后端(云函数端)安装步骤 + +* 通常一个完整的项目分为 `client端`(客户端)、`admin端`(管理端)、`service端`(服务端,这里指云函数端) + +#### 这里需要分三种情况 +#### [情况一](#情况一):你之前已经在用 `vk-unicloud-router` 框架开发H5、小程序、APP的开发者。 + +#### [情况二](#情况二):你之前是用别的框架开发H5、小程序、APP,现在只想用VK框架单独开发 admin 项目。 + +#### [情况三](#情况三):你的项目刚开始,`client端` 和 `admin端` 都还没开发。 + +### 情况一 + +#### 思路:因为云函数会互相覆盖,因此我们可以把 `service端(云函数端)` 统一放在 `client端` 的项目中,而 `admin端` 项目 直接绑定 `client端` 项目 +#### 安装步骤: +* 1、把 `admin端` 内的 `uniCloud/router/service/admin` 内的以下文件复制到你之前的 `client端` 项目 `uniCloud/router/service/admin` 内(复制整个目录) +* 2、把 `admin端` 内的 `uniCloud/router/service/template` 内的以下文件复制到你之前的 `client端` 项目 `uniCloud/router/service/template` 内(复制整个目录) +* 3、把 `admin端` 内的 `uniCloud/database/db_init/` 目录下的3个数据库表数据导入对应的表内(导入方法:服务空间后台 - 数据库 - 导入) +```js +uni-id-roles 角色表 +uni-id-permissions 权限表 +opendb-admin-menus 菜单表 +``` +* 3、把 `admin端` 的服务空间直接绑定 `client端` 项目(注意是 `绑定` 不是 `关联`)(注意是 `绑定` 不是 `关联`)(注意是 `绑定` 不是 `关联`) + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/98c6961a-22c8-4d61-833f-f558d848b0e5.png) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/8a9406fd-ff00-48d4-b1fe-6e133c2bf13a.png) + +* 4、上传 `router` 云函数 + +* 5、完成 + +### 情况二 +已完成情况一的请直接跳过情况二和情况三 +#### 安装步骤: +* 1、在 `项目根目录` 目录执行 `npm i` + +* 2、右键 `uniCloud` 目录 点击 `运行云服务空间初始化向导` + +* 3、完成 + +### 情况三 + +#### 安装步骤: +* 建议你先使用 `vk-unicloud-router` 框架进行 `client端` 开发,`client端` 开发完成后,使用 `vk-unicloud-admin` 开发 `admin端` + +* 当然你也可以先开发 `admin端`,再开发 `client端`。 + +* 如果先开发 `admin端`,则直接用 `情况二` 的安装步骤即可。 + +* 如果先开发 `client端`,则先下载 `client端` 开发框架,等 `client端` 开发完后再用 `情况一` 的安装步骤即可 [点击前往下载client端开发框架](https://ext.dcloud.net.cn/plugin?id=2204) + +#### 初始admin账号密码:123456 + +#### 如密码错误,可以强制重置admin账号密码 +[点击查看『强制重置admin账号密码步骤』](https://vkdoc.fsq.pub/admin/4/forceResetAdminPassword.html) + +### 安装代码快捷提示步骤 +* 1、将 `根目录/使用帮助/代码快捷提示/javascript代码块提示.json` 内的代码 复制到 hbx 工具 - 代码块设置 - javascript代码块 +* 2、将 `根目录/使用帮助/代码快捷提示/vue代码块提示.json` 内的代码 复制到 hbx 工具 - 代码块设置 - vue代码块 + +### 其他 +删除 `pages.json` 内的 `pages_template/components` 和 `pages_template/element` 分包(此为发布演示版本需要而加,你的项目可以删除,删除后开发模式下依然存在(因为在`pages-dev.json`中配置了),发布到线上环境时自动屏蔽) + +### 若提示上传云函数失败,请仔细对比下你的项目 `uniCloud/common` 目录是否跟下图完全一致 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/7ae174db-7666-4301-b017-725edc73e3a3.png) + +如果不一致,特别是 `uni-id` 目录下没有这个文件 `uni-id/node_modules/uni-config-center/uni-id/config.json`,则在 `uni-id` 目录执行 `npm i` 试试(如果有这个`uni-id/node_modules`目录,先删除目录,再执行npm i) + +### 若新建的用户登录提示用户不存在(数据库明明有数据),此时是因为不同端用户隔离导致的 + +* 1、先用admin账号登录后台,进入应用管理 + +因为每个人的 `DCloud Appid`是不一样的,所以你需要在应用管理中添加自己的应用(或直接修改内置的2条数据的appid即可) + +`DCloud Appid` 获取方法 + +复制 `uniapp` 项目根目录的 `manifest.json` 文件内的 `appid` + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/e717232f-0f18-4dee-8437-5dec2c224920.png) + +* 2、再进入用户管理,对需要设置的用户点击编辑,设置该用户可以登录哪些端。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/18cd54d5-bedc-4d4f-bda2-7c339c865257.png) + +* 3、完成,可以登录了。 + + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! + +[点击查看『完整安装步骤』](https://vkdoc.fsq.pub/admin/1/quickstart.html) + +## 3、框架目录结构 + +[点击查看『目录结构』](https://vkdoc.fsq.pub/admin/1/catalogue.html) + +## 4、万能表格 + +[点击查看『万能表格』](https://vkdoc.fsq.pub/admin/2/table.html) + +## 5、万能表单 + +[点击查看『万能表单』](https://vkdoc.fsq.pub/admin/3/form.html) + +[点击查看『表单可视化生成器』](https://vkunicloud.fsq.pub/vk-form-visualizer/) + +## 6、用户角色权限 + +[点击查看『用户角色权限』](https://vkdoc.fsq.pub/admin/4/role.html) + +## 7、创建我的第一个带CRUD的页面 + +[点击查看『如何创建我的第一个带CRUD的页面』](https://vkdoc.fsq.pub/admin/5/template.html) + +## 8、HBX代码块提示 + +[点击查看『HBX代码块提示』](https://vkdoc.fsq.pub/admin/4/codeTips.html) + +## 9、admin框架更新步骤指南 + +[点击查看『admin框架更新步骤指南』](https://vkdoc.fsq.pub/admin/1/update.html) + +## 10、强制重置admin账号密码 + +[点击查看『强制重置admin账号密码』](https://vkdoc.fsq.pub/admin/4/forceResetAdminPassword.html) + +## 11、admin框架内置组件参数说明 + +[点击查看『admin框架内置组件参数说明』](https://vkdoc.fsq.pub/admin/components/1%E3%80%81text.html) + +## 20、云函数开发文档 + +[点击查看『云函数开发文档』](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/catalogue.html) + +## 21、vk.baseDao数据库API + +[点击查看『vk.baseDao』数据库API](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +## 22、数据库缓存API + +[点击查看『数据库缓存API』](https://vkdoc.fsq.pub/client/uniCloud/cache/cache.html) + +## 23、中间件开发文档 + +[点击查看『中间件开发文档』](https://vkdoc.fsq.pub/client/uniCloud/middleware/filter.html) + +## 24、JS API文档大全 + +[点击查看『JS API文档大全』](https://vkdoc.fsq.pub/client/jsapi.html) + +## 25、前端请求云函数 + +[点击查看『前端请求云函数』](https://vkdoc.fsq.pub/client/pages/callFunction.html) + +## 26、配置前端非法token拦截器 + +[点击查看『前端请求云函数』](https://vkdoc.fsq.pub/client/pages/interceptor1.html) + +## 27、配置前端全局异常拦截器 + +[点击查看『前端请求云函数』](https://vkdoc.fsq.pub/client/pages/interceptor2.html) + +## 28、vuex使用文档 + +[点击查看『vuex使用文档』](https://vkdoc.fsq.pub/client/pages/vuex.html) + +## 29、更多其他功能敬请在框架内体验 + +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 \ No newline at end of file diff --git a/app.config.js b/app.config.js new file mode 100644 index 0000000..61f103f --- /dev/null +++ b/app.config.js @@ -0,0 +1,135 @@ +// 引入自定义公共函数 +import myPubFunction from '@/common/function/myPubFunction.js' +// 引入静态菜单 +import staticMenu from '@/app.config.menu.js' +// 引入主题配置文件 +import themeConfig from '@/common/theme/index.js' +export default { + // 开发模式启用调式模式(请求时会打印日志) + debug: process.env.NODE_ENV !== "production", + // 主云函数名称 + functionName: "router", + // 登录页面路径 + login: { + url: "/pages/login/index", + testUser: { + show: false, // 是否显示 + list: [ + { username: "test11", password: "123456", nickname: "高级管理员" }, + { username: "test12", password: "123456", nickname: "初级管理员" }, + { username: "test13", password: "123456", nickname: "无权限用户" } + ] + } + }, + // 首页页面路径 + index: { + url: '/pages/index/index' + }, + // 404 Not Found 错误页面路径 + error: { + url: "/pages_plugs/error/404" + }, + // 前端默认时区(中国为8) + targetTimezone:8, + globalError: true, // 是否开启全局错误提示 + // 需要检查是否登录的页面列表 + // let { mode, list } = config.checkTokenPages + checkTokenPages: { + /** + * 如果 mode = 0 则代表自动检测 + * 如果 mode = 1 则代表list内的页面需要登录,不在list内的页面不需要登录 + * 如果 mode = 2 则代表list内的页面不需要登录,不在list内的页面需要登录 + * 注意1: list内是通配符表达式,非正则表达式 + * 在无需登录的页面上执行kh或sys函数,也会自动判断是否登录,未登录会自动跳登录页面,登录成功后会自动返回本来要跳转的页面。 + */ + mode: 2, + list: [ + "/pages/login/*", + "/pages_template/*", + ] + }, + // 静态文件的资源URL地址 + staticUrl: { + // 顶部导航 + navBar: { + // 正方形 Logo 160*160 + logo: "/static/logo.png", + // 长方形 Logo 224*160 + logo1: "/static/logo1.png", + // 横幅 Logo 480*100 + logo2: "/static/logo2.png" + }, + }, + // 自定义公共函数,myPubFunction内的函数可通过vk.myfn.xxx() 调用 + myfn: myPubFunction, + // 第三方服务配置 + service: { + // 阿里云oss配置 + aliyunOSS: { + // 密钥和签名信息 (由于签名的获取比较麻烦,建议初学者使用上传到unicloud的方案,上传到阿里云OSS是给有特殊需求的用户使用) + // 相关文档 : https://help.aliyun.com/document_detail/31925.html?spm=a2c4g.11186623.6.1757.b7987d9czoFCVu + uploadData: { + OSSAccessKeyId: "", + policy: "", + signature: "", + }, + // oss上传地址 + action: "", + // 根目录名称 + dirname: "", + // oss外网访问地址,也可以是阿里云cdn地址 + host: "", + // 上传时,是否按用户id进行分组储存 + groupUserId: true, + // vk.callFunctionUtil.uploadFile 是否默认上传到阿里云OSS + isDefault: false + } + }, + // 全局异常码,可以自定义提示结果 + globalErrorCode: { + // 阿里云10秒非正常超时,其实请求还在执行(且一般已经成功了,但前端接受不到成功结果) + "cloudfunction-unusual-timeout": "请求超时,但请求还在执行,请重新进入页面。", + // 请求超时(真正的请求超时) + "cloudfunction-timeout": "请求超时,请重试!", + // 不在预期内的异常(如数据库异常、云函数编译异常等) + "cloudfunction-system-error": "网络开小差了!" + }, + // 页面风格 + pageStyle: { + // 表单组件和表格组件的size + size: "auto", // medium / small / mini / auto + }, + // 左侧菜单 + sideBar: { + // 配置静态菜单列表 + "staticMenu": staticMenu + }, + // 主题配置 + theme: { + // 当前使用哪个主题 + use: "blackWhite", // white blackWhite black custom + ...themeConfig, + // 自定义主题 + custom: { + // 左侧菜单样式 + leftMenu: { + backgroundColor: "", + subBackgroundColor: "", + textColor: "", + activeTextColor: "", + activeBackgroundColor: "", + collapseActiveTextColor:"", + collapseActiveBackgroundColor: "", + hoverTextColor: "", + hoverBackgroundColor: "", + boxShadow: "", + borderTop: "" + }, + // 顶部菜单样式 + topMenu: { + backgroundColor: "", + textColor: "", + } + } + } +} diff --git a/app.config.menu.js b/app.config.menu.js new file mode 100644 index 0000000..f36295e --- /dev/null +++ b/app.config.menu.js @@ -0,0 +1,13 @@ +const debug = process.env.NODE_ENV !== 'production'; +// 开发环境和正式环境中都会显示的静态菜单 +import menus from './static_menu/menu.json' +// 只在开发环境中显示的静态菜单 +import devMenus from './static_menu/menu-dev.json' +var menusList = []; +if (debug && devMenus) { + menusList = menus.concat(devMenus); +} else { + menusList = menus; +} + +export default menusList; diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..b0c6809 --- /dev/null +++ b/changelog.md @@ -0,0 +1,1748 @@ +## 1.17.3(2023-09-25) +* 【升级】`vk-unicloud-admin-ui` 包升级至 `1.17.45` +* 【调整】`万能表单` `vk-data-input-editor` 组件的js依赖内置到项目里,防止因quill官方CDN无法访问导致editor组件渲染失败的问题 +* 【修复】`万能表单` 部分复杂情况下表单验证未生效的问题 +* 【修复】`万能表格` `object` 内 `oneLine:true` 不生效的bug +* 【修复】`万能表单` `object` 内 `disabled` 不生效的bug +* 【修复】`万能表格` `:searched-clean-selection="false"` 时,分页会导致多选框清空的问题 +* 【修复】`万能表格` 点击右侧按钮时可能会出现请先选中一行的bug +* 【优化】`pages_plugs/system_uni/vk-pay-orders.vue`页面新增支付渠道区分 +* 【优化】`万能表格` 导出的文件名支持自定义扩展名 +* 【优化】`万能表格` 新增 `getRowIndex` 方法 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 +## 1.17.2(2023-07-20) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.17.17` +* 2、【调整】`万能表单` 支持 `object` 新增 `showErrMsg` 属性,默认 `false`,如果设置为 `true`,会多个 `margin-bottom: 22px;` 的样式 +* 3、【修复】`万能表单` `tag` 不触发 `watch` 的问题 +* 4、【优化】`万能表单` `table-select`、`remote-select`、`cascader`、`tree-select`、`checkbox`、`radio` 的 `action` 属性均支持传函数(自定义function请求模式)[传送门](https://vkdoc.fsq.pub/admin/components/12%E3%80%81table-select.html#%E8%87%AA%E5%AE%9A%E4%B9%89function%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) +* 5、【优化】`万能表单` `上传组件` 支持拖拽排序 +* 6、【优化】`万能表单` 新增 `needAlert` 属性,设置false则取消默认的错误弹窗 +* 7、【优化】`万能表单` `object` 支持 `bar-title` +* 8、【优化】`万能表单` `color` 支持 `activeChange` 事件 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 +## 1.17.0(2023-07-04) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.17.0` +* 2、【重要】`万能表格` 的 `action` 属性支持传函数 [传送门 - 自定义function请求模式](https://vkdoc.fsq.pub/admin/2/table.html#%E8%87%AA%E5%AE%9A%E4%B9%89function%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) +* 3、【重要】`万能表单` 的 `action` 属性支持传函数 [传送门 - 自定义function请求模式](https://vkdoc.fsq.pub/admin/3/form.html#%E8%87%AA%E5%AE%9A%E4%B9%89function%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) +* 4、【修复】`万能表单` `group + object` 会报错的问题 +* 5、【修复】`万能表单` `group` 内的组件 `disabled` 函数和字符串表达式不生效的问题 +* 6、【修复】`万能表格` `group` 内的 `object` 的 `showLabel` 属性不生效的问题 +* 7、【修复】`万能表格` `this.$refs.table1.updateRows` 执行后再次点击编辑会报错的问题 +* 8、【优化】`万能表单` `tag` 组件支持 `max` 属性 +* 9、【优化】`万能表单` `上传组件` 支持属性 `cloudDirectory` 可以设置上传至指定的云端目录 +* 10、【优化】`万能表单` `file-select` 支持预览非图片和视频的文件(无法预览的会触发下载) + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 + +## 1.16.2(2023-06-01) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.16.15` +* 2、【修复】`缓存管理` 页面添加缓存后,`vk.globalDataCache.get(key);` 无法获取到数据的问题(需要手动替换目录`router/service/admin/system_uni/global-data/`) +* 3、【优化】`素材管理` 上传素材时的进度条样式 +* 4、【优化】`万能表格` 新增 `needAlert` 属性,设为false可以取消默认的错误弹窗(默认为true) + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 +## 1.16.1(2023-05-17) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.16.9` +* 2、【优化】`万能表格` 右侧按钮支持属性 icon、plain、round、circle、loading +* 3、【优化】其他细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 + +## 1.16.0(2023-04-23) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.16.0` +* 2、【升级】`element-ui` 包升级至 `2.15.13` +* 3、【修复】`table-select` 在多选模式下,控制台可能会报 `Cannot read properties of undefined(reading 'length')` 警告的问题。 +* 4、【优化】`topWindow` 支持显示正方形logo+文本(暂无开关,需手动切换注释) +* 5、【优化】`万能表单` `素材选择组件` 多选时显示文件顺序 +* 6、【优化】`万能表单` `富文本` 支持从素材库选择图片 +* 7、【优化】`素材管理` 批量上传时显示上传进度 +* 8、【优化】角色管理页面细节 +* 9、【优化】菜单管理页面细节 +* 10、【优化】权限管理页面细节 +* 11、【新增】内置支付订单明细页面(支持回调失败后重试) + +**注意:本次更新涉及内置页面改动,请仔细比对** + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 +## 1.15.12(2023-03-20) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.25` +* 2、【优化】`万能表单` `array` `array` 新增属性 `showDelete` 控制是否显示右侧删除图标 + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.15.11(2023-01-19) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.23` +* 2、【调整】router云函数运行内存调整为512M(实测512M即可达到最优性能) +* 3、【修复】`万能表单` object内的字段disabled不生效的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.15.10(2022-12-29) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.19` +* 2、【优化】兼容阿里云新版 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.15.9(2022-12-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.14` +* 2、【优化】leftWindow,左侧菜单支持自定义默认图标(可设置为默认不显示图标) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.15.8(2022-11-24) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.8` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.15.1(2022-10-25) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.5` +* 2、【优化】`万能表单` 的 `图标选择` 选择时,支持搜索 +* 3、【优化】因 `1.15.0` 导致的表格卡顿问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.15.0(2022-10-10) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.15.2` +* 2、【重要】应用管理内置 `生成统一发布页` [传送门 - 应用管理](https://vkdoc.fsq.pub/admin/6/app.html) +* 3、【重要】新增自定义图标库 [传送门 - 拓展教程](https://vkdoc.fsq.pub/admin/components2/1%E3%80%81vk-data-icon.html#%E5%A6%82%E4%BD%95%E6%89%A9%E5%B1%95%E5%9B%BE%E6%A0%87%E5%BA%93) +* 4、【优化】`万能表单` 图标选择组件支持图标过滤 [传送门 - 组件文档](https://vkdoc.fsq.pub/admin/components/26%E3%80%81icon.html#filter) +* 5、【新增】`万能表格` 支持视频预览,设置 `type` 为 `file` 即可 + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/service/admin/system/app/`(替换整个目录) +* 2、`根目录/pages_plugs/system/app/`(替换整个目录) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.14.4(2022-10-07) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.14.4` +* 2、【优化】`万能表单` 针对 `type` 为 `object` 且多层嵌套时的内部细节处理优化。(现在可以无限嵌套) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.14.3(2022-10-07) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.14.2` +* 2、【优化】更新依赖 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.14.2(2022-09-29) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.14.2` +* 2、【修复】升级HBX后带来的部分兼容性问题。 +* 3、【优化】`部分组件` 的 `placeholder` 可能不生效的问题 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.14.1(2022-09-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.14.1` +* 2、【优化】`vk-data-input-cascader`、`vk-data-input-checkbox`、`vk-data-input-radio`、`vk-data-input-remote-select`、`vk-data-input-tree-select` 组件均支持 `http方式请求数据`(用法与 `vk-data-input-table-select` 一致) +如: +```js +{ + key:"select1", title:"远程select", type:"remote-select", + showAll: true, + isRequest: true, + //requestHeader: {}, // 请求头 + action: "https://www.xxx.com", + props: { list: "rows", value: "id", label: "name" }, +}, +``` +* 3、【优化】`用户管理`、`角色管理`、`权限管理`、`菜单管理` 的内部细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.14.0(2022-09-12) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.14.0` +* 2、【重要】`vk-admin` 内置 `App升级中心`(新增 `opendb-app-versions` 表)[传送门](https://vkdoc.fsq.pub/admin/6/app-upgrade-center.html) +* 3、【重要】`应用管理` 重构(对齐官方 `opendb-app-list` 表)[传送门](https://vkdoc.fsq.pub/admin/6/app.html) + +**可以右键项目根目录的 `package.json` 一键更新(注意对比自己修改过的文件)** + +**以下是手动改更新步骤,本次改动涉及到的框架内置文件变动** + +* pages_plugs/system/app/ (替换整个目录) +* pages_plugs/system/app-upgrade-center/ (替换整个目录) +* cloudfunctions/router/service/admin/system/app/ (替换整个目录) +* cloudfunctions/router/service/admin/system/app-upgrade-center/ (替换整个目录) + +**添加菜单** + +进入 `vk-admin` 菜单管理,点击【通过JSON数组批量导入菜单】粘贴下方json数组 导入 + +```js +[{"_id": "sys-app-upgrade-center","_add_time": 1596416400000,"menu_id":"sys-app-upgrade-center","name": "App升级中心","icon":"vk-icon-shengji3-xianxing","url": "/pages_plugs/system/app-upgrade-center/list","comment":"管理和发布新的app版本","sort": 6,"parent_id":"sys-admin","enable":true}] +``` + +**添加pages.json内的页面** + +```js +{ "path": "system/app-upgrade-center/list" }, +``` + +**完成上述步骤后,进入应用管理->编辑->开启App升级中心->即可进入版本管理。** + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.13.2(2022-08-30) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.13.6` +* 2、【优化】`万能表格` 的合计功能支持指定精度(默认2位小数)[传送门](https://vkdoc.fsq.pub/admin/2/table.html?t=20220826#%E4%B8%87%E8%83%BD%E8%A1%A8%E6%A0%BC%E5%90%88%E8%AE%A1%E5%88%97%E7%9A%84%E7%A4%BA%E4%BE%8B) +* 3、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.13.1(2022-08-20) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.13.1` +* 2、【优化】左侧菜单的最大层级支持自定义,需替换 `router/service/user/kh/getMenu.js` 文件,同时 `uni_modules/vk-unicloud` 模块更新到最新版 +* 2、【优化】菜单管理的最大层级支持自定义,需替换 `router/service/admin/system/menu/sys/getAll.js` 文件 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.13.0(2022-08-17) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.13.1` +* 2、【优化】`万能表单` `数值类型` 的输入组件当值为""空字符串时,可通过设置 `emptyValue` 属性更改空值转化的值(默认为null) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.10(2022-08-15) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.45` +* 2、【修复】`万能表单` `table-select` 组件若设置http请求模式后,init方法不走http请求的bug +* 3、【修复】`万能表单` `数值类型` 的输入组件直接在 `template` 使用时,值为0时不显示值的bug +* 4、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.12.9(2022-08-15) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.43` +* 2、【修复】`万能表单` `table-select` 组件若设置http请求模式后,init方法不走http请求的bug +* 3、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.8(2022-08-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.42` +* 2、【优化】表格搜索组件新增 `data` 和 `time` 组件(原先只有范围选择,现在支持单个日期的选择)(属性与万能表单一致) +* 3、【优化】一些细节 +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.7(2022-07-30) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.36` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.12.6(2022-07-25) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.35` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.5(2022-07-23) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.35` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.12.4(2022-07-23) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.32` +* 2、【优化】一些细节 + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.3(2022-07-21) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.29` +* 2、【修复】`vk-data-upload` 组件 `before-upload` 属性没有接收到 `file` 参数的问题。 +* 3、【优化】`数字类型` 输入框的交互体验 +* 4、【优化】`icon` 组件文档新增icon预览 [传送门](https://vkdoc.fsq.pub/admin/components/26%E3%80%81icon.html#%E5%9B%BE%E6%A0%87%E5%88%97%E8%A1%A8) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.2(2022-07-20) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.21` +* 2、【优化】`万能表单` 的 `array` 支持内嵌 `array`,用以渲染对象数组字段内还有对象数组字段的数据形式。(理论上可以无限嵌套) [传送门](https://vkdoc.fsq.pub/admin/components/24%E3%80%81array.html#array%E5%B5%8C%E5%A5%97array) +* 3、【优化】`万能表单` 的 `array` 新增属性 `incMode`(可规定每行数据必须递增或递减)[传送门](https://vkdoc.fsq.pub/admin/components/24%E3%80%81array.html#incmode) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.1(2022-07-09) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.0` +* 2、【更新】省市区数据源 +* 3、【新增】`vk-data-input-tag` 组件 [传送门](https://vkdoc.fsq.pub/admin/components/29%E3%80%81tag.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.12.0(2022-07-09) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.12.0` +* 2、【更新】省市区数据源 +* 3、【新增】`vk-data-input-tag` 组件 [传送门](https://vkdoc.fsq.pub/admin/components/29%E3%80%81tag.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.7(2022-07-05) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.22` +* 2、【优化】`万能表单` `remote-select` 组件 当设置 `showAll:true` 时,新增 `刷新选项按钮`(方便数据库数据变动后手动刷新选项)[传送门](https://vkdoc.fsq.pub/admin/components/10%E3%80%81remote-select.html) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/06e4bb4b-da42-46d8-83e2-a6a99618bdd5.png) +* 3、【优化】`万能表格` `switch` 组件 支持直接在表格行内编辑 [传送门](https://vkdoc.fsq.pub/admin/components/14%E3%80%81switch.html#%E8%A1%A8%E6%A0%BC%E8%A1%8C%E5%86%85%E5%8A%A8%E6%80%81%E7%BC%96%E8%BE%91%E6%A8%A1%E5%BC%8F) +* 4、【优化】`万能表格` `buttons`(字段扩展按钮列表)新增对应参数 `buttonsPosition` 默认为right(支持 left right bottom top)[传送门](https://vkdoc.fsq.pub/admin/2/table.html#buttons-%E5%AD%97%E6%AE%B5%E6%89%A9%E5%B1%95%E6%8C%89%E9%92%AE%E5%88%97%E8%A1%A8) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.6(2022-07-01) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.9` +* 2、【优化】`万能表单` 的 `tips` 属性支持解析 `html字符串` 和 `对象数组` [查看详情](https://vkdoc.fsq.pub/admin/3/form.html#tips-%E4%B8%8B%E6%96%B9%E7%9A%84%E5%9B%BA%E5%AE%9A%E6%8F%90%E7%A4%BA) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.5(2022-06-25) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.6` +* 2、【优化】一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.4(2022-06-18) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.6` +* 2、【新增】万能表单公共属性 `watch` 用于监听key对应的值的改变(只监听组件内部造成的值的改变)`watch` 是 `onChange` 的上位替代 [点击查看](https://vkdoc.fsq.pub/admin/3/form.html#watch-%E7%9B%91%E5%90%AC) +* 3、【修复】万能表单公共属性 `disabled` 数组模式不生效的bug + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.3(2022-06-16) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.4` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.2(2022-06-16) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.4` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.1(2022-06-15) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.4` +* 2、【优化】一些细节 +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.11.0(2022-06-10) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.11.4` +* 2、【新增】`左侧菜单` 支持折叠模式 +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/4d823e27-bfb8-4b0f-9387-b22e72d29389.png) + +**由于改动涉及框架文件较多,建议直接更新框架项目(如果你改动了框架内置的部分代码,你改动过的代码可能会被还原,因此如果你改动过框架内置代码,合并的时候,可以先看下改动的文件。)** + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.10.6(2022-06-09) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.13` +* 2、【优化】一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.10.5(2022-06-02) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.10` +* 2、【优化】`万能表单` `table-select` 组件支持对已选择的数据进行求和。如下图效果所示。[点击查看](https://vkdoc.fsq.pub/admin/components/12%E3%80%81table-select.html#summarykey-%E6%B1%82%E5%92%8C) + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/cd2a4240-a665-4209-bd82-75ba1870e95a.png) + +* 3、【优化】`万能表单` `file-select` 组件新增属性 `upload`(是否允许上传,默认true) `updateCategory` (是否允许编辑分类,默认true)[点击查看](https://vkdoc.fsq.pub/admin/components/25%E3%80%81file-select.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.10.4(2022-05-26) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.7` +* 2、【优化】`vk.baseDao.selects` 和 `vk.baseDao.getTableData` API新增 `lastSortArr` 参数,用于聚合后再排序。 +* 注意:`lastWhereJson` 和 `lastSortArr` 在数据量大的情况下是有性能问题的,(建议主表的where条件中先进行筛选,如只查本季度数据,只要主表过滤完后数据量不大,则没有性能问题。) +* 3、【修复】`lastWhereJson` 后,返回的 `total` 不准确的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.10.3(2022-05-25) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.6` +* 2、【优化】应用管理页面,当前项目未添加时,进行友情提醒。 +* 3、【优化】其他细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.10.2(2022-05-18) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.4` +* 2、【优化】`万能表单` 内公共属性 `disabled` 额外支持函数形式和字符串简写形式(和showRule写法一致)[查看详情](https://vkdoc.fsq.pub/admin/3/form.html#disabled) +* 3、【优化】`万能表格` 右侧按钮宽度计算内部算法。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.10.1(2022-05-14) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.2` +* 2、【优化】`万能表格` 的导出功能内部逻辑 +* 3、【优化】`万能表单` 上传组件的内部逻辑 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.10.0(2022-05-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.10.0` +* 2、【新增】`万能表格` 右侧按钮区 `right-btns`、`right-btns-more`、`custom-right-btns` 升级显示规则,可自定义根据行记录设置按钮是否显示或禁用 [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#right-btns-%E5%8F%B3%E4%BE%A7%E5%9B%BA%E5%AE%9A%E6%8C%89%E9%92%AE%E5%88%97%E8%A1%A8) +* 3、【新增】`万能表格` 属性 `right-btns-align` 控制右侧按钮的对齐方式,默认center(可选: center left right) [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#%E5%B1%9E%E6%80%A7) +* 4、【优化】其他细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.9.6(2022-05-05) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.9.15` +* 2、【重要】vk实例对象已调整为页面内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uni.vk.xxx() 的方式来调用。 +* 3、【重要】vk实例对象已调整为云函数内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uniCloud.vk.xxx() 的方式来调用。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.9.5(2022-04-28) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.9.14` +* 2、【优化】`万能表单` 中的表格选择组件细节。 +* 3、【修复】`万能表格` 中的图片可能会不显示的问题。 + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.9.4(2022-04-21) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.9.12` +* 2、【重要】`uni-id` 配置新增 `tokenMaxLimit` 每个账户的最大token数量,0为不限,淘汰策略:新的淘汰旧的(注意,即使设置为0,框架也会自动淘汰已过期的token)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) +* 3、【新增】全局参数 `targetTimezone` 可设置默认时区(中国为8,8代表东8区,-8代表西8区) + +> [查看前端全局配置](https://vkdoc.fsq.pub/client/pages/config.html) + +> [查看云函数全局配置](https://vkdoc.fsq.pub/client/uniCloud/config/vk-unicloud.html) + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/middleware/modules/returnUserInfoFilter.js` (此为用户登录注册全局中间件) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.9.3(2022-04-21) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.9.12` +* 2、【重要】`uni-id` 配置新增 `tokenMaxLimit` 每个账户的最大token数量,0为不限,淘汰策略:新的淘汰旧的(注意,即使设置为0,框架也会自动淘汰已过期的token)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) +* 3、【新增】全局参数 `targetTimezone` 可设置默认时区(中国为8,8代表东8区,-8代表西8区) + +> [查看前端全局配置](https://vkdoc.fsq.pub/client/pages/config.html) + +> [查看云函数全局配置](https://vkdoc.fsq.pub/client/uniCloud/config/vk-unicloud.html) + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/middleware/modules/returnUserInfoFilter.js` (此为用户登录注册全局中间件) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.9.2(2022-04-14) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.9.11` +* 2、【重要】新增 `云对象` 路由模式 [什么是云对象?](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html) +* 3、【重要】自此,在VK框架中,可以做到云对象和云函数同时存在。即在VK框架中,同时支持 `云对象路由模式` 和 `云函数路由模式`。 +* 4、【新增】本地运行支持云对象 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#%E6%9C%AC%E5%9C%B0%E8%BF%90%E8%A1%8C) +* 5、【新增】地图选址组件 `type = "map"` [点击查看](https://vkdoc.fsq.pub/admin/components/28%E3%80%81map.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.9.1(2022-03-23) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.9.8` +* 2、【优化】`万能表格` 行内图片支持预览 +* 3、【优化】`万能表格` 新增本地数据过滤器,同elementui的 `filters` [查看详情](https://vkdoc.fsq.pub/admin/2/table.html#filter-%E6%9C%AC%E5%9C%B0%E6%95%B0%E6%8D%AE%E8%BF%87%E6%BB%A4%E5%99%A8) +* 4、【修复】`万能表格` 导出表格时,若值为0,会导出为空字符串的问题。 +* 5、【修复】`万能表格` 导出表格时,字段 `type` 为 `time` 时 `valueFormat` 属性无效的问题。 +* 6、【修复】`万能表格` `radio` `checkbox` `select` 的选项数据data不支持函数计算的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.9.0(2022-02-26) +###【重要】由于uni官方限制自定义表不可以用 `opendb-` 和 `uni-` 开头,故以下数据库表名只能进行调整 + +* 1、`opendb-components-dynamic` 改为 `vk-components-dynamic` +* 2、`opendb-global-data` 改为 `vk-global-data` +* 3、`uni-id-files` 改为 `vk-files` +* 4、`uni-id-files-categories` 改为 `vk-files-categories` + +___更改表名势必会对老项目产生影响。(对新项目无影响)___ + +### 老项目更新注意事项: +* 1、老项目更新后,还需要从 `unicloud控制台` 把表名改成对应的新表名 +* 2、在项目代码中全局搜索旧表名,替换成新表名 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.13(2022-02-24) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.36` +* 2、【新增】`addAdminLog` 中间件示例。 +* 3、【修复】`vk-data-input-editor` 组件通过外部赋值无法达到双向绑定的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.12(2022-02-10) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.27` +* 2、【优化】一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.11(2022-01-20) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.26` +* 2、【优化】一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.10(2021-12-24) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.24` +* 2、【修复】`万能表单` 的 `树形选择` 搜索可能会报错的bug。 +* 3、【优化】一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.9(2021-12-20) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.23` +* 2、【修复】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.8(2021-12-19) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.22` +* 2、【新增】`万能表格` 新增 `pagination-change` 事件 (主要用于手动模式分页)[点击查看](https://vkdoc.fsq.pub/admin/2/table.html#%E4%BA%8B%E4%BB%B6) +* 3、【修复】`万能表格` type 为 `money` 、`percentage` 、`discount` 时,部分情况下,默认值不生效的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.7(2021-12-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.15` +* 2、【重要】`万能表格` `columns` 内 `buttons` 属性新增 `showRule` 属性(用于实现根据行记录显示不同按钮) [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#buttons-%E5%AD%97%E6%AE%B5%E6%89%A9%E5%B1%95%E6%8C%89%E9%92%AE%E5%88%97%E8%A1%A8) +* 3、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.6(2021-12-11) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.9` +* 2、【重要】`万能表格` `columns` 内新增 `buttons` 属性(扩展按钮列表,可实现快速修改这1个字段的功能)[点击查看](https://vkdoc.fsq.pub/admin/2/table.html#buttons-%E5%AD%97%E6%AE%B5%E6%89%A9%E5%B1%95%E6%8C%89%E9%92%AE%E5%88%97%E8%A1%A8) +* 3、【优化】`万能表格` 合计功能的简单模式支持金额 [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#%E7%AE%80%E5%8D%95%E6%A8%A1%E5%BC%8F) +* 4、【优化】`万能表单` `cascader` 组件支持 `actionData` [点击查看](https://vkdoc.fsq.pub/admin/components/11%E3%80%81cascader.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.5(2021-12-08) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.7` +* 2、【优化】上传api的url自动去除原文件名的中文部分。 +* 3、【优化】`tree-select` 树形选择组件 [点击查看](https://vkdoc.fsq.pub/admin/components/27%E3%80%81tree-select.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.4(2021-12-08) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.7` +* 2、【优化】上传api的url自动去除原文件名的中文部分。 +* 3、【优化】`tree-select` 树形选择组件 [点击查看](https://vkdoc.fsq.pub/admin/components/27%E3%80%81tree-select.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.3(2021-12-04) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.5` +* 2、【优化】一些细节 +* +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.2(2021-12-01) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.5` +* 2、【升级】`element-ui` 包升级至 `2.15.7` +* 3、【新增】自 `1.8.0` 起,支持自定义主题,内置纯白、纯黑、黑白3个主题,同时支持编写自定义主题。[点击查看主题说明](https://vkdoc.fsq.pub/admin/1/theme.html) +* 4、【优化】主题细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.1(2021-12-01) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.2` +* 2、【升级】`element-ui` 包升级至 `2.15.7` +* 3、【新增】自 `1.8.0` 起,支持自定义主题,内置纯白、纯黑、黑白3个主题,同时支持编写自定义主题。[点击查看主题说明](https://vkdoc.fsq.pub/admin/1/theme.html) +* 4、【优化】主题细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.8.0(2021-11-30) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.8.1` +* 2、【新增】自 `1.8.0` 起,支持自定义主题,内置纯白、纯黑、黑白3个主题,同时支持编写自定义主题。[点击查看主题说明](https://vkdoc.fsq.pub/admin/1/theme.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.7.4(2021-11-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.7.7` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.7.3(2021-11-09) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.7.6` +* 2、【优化】`万能表单` `radio` `checkbox` `select` `cascader` `tree-select` 的 `data` 静态模式数据源 支持 `function` 模式 [点击查看](https://vkdoc.fsq.pub/admin/components/9%E3%80%81select.html#%E9%9D%99%E6%80%81%E6%95%B0%E6%8D%AE%E6%96%B9%E5%BC%8F2) +* 3、【修复】`万能表单` `tree-select` 点击清除按钮可能会报错的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.7.2(2021-11-02) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.7.4` +* 2、【优化】美化默认滚动条样式 [点击查看](https://vkdoc.fsq.pub/admin/question/question.html#%E5%A6%82%E4%BD%95%E7%BE%8E%E5%8C%96%E9%BB%98%E8%AE%A4%E6%BB%9A%E5%8A%A8%E6%9D%A1) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.7.1(2021-10-26) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.7.3` +* 2、【重要】`万能表格` 支持导出数据库内所有数据 [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#%E5%AF%BC%E5%87%BA%E6%BB%A1%E8%B6%B3%E8%A1%A8%E6%A0%BC%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%86%85%E6%89%80%E6%9C%89%E6%95%B0%E6%8D%AE) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.7.0(2021-10-22) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.7.2` +* 2、【重要】万能表单每个字段的 `showRule` 属性支持 `函数`(现在可以用自定义函数来控制表单字段的显示和隐藏)[点击查看](https://vkdoc.fsq.pub/admin/3/form.html#show) +* 3、【重要】万能表单 新增组件 图标选择组件 type: `icon` [点击查看](https://vkdoc.fsq.pub/admin/components/26%E3%80%81icon.html) +* 4、【重要】万能表单 新增组件 树型选择组件 type: `tree-select` [点击查看](https://vkdoc.fsq.pub/admin/components/27%E3%80%81tree-select.html) +* 5、【优化】菜单管理和权限管理页面应用 `icon` 和 `tree-select` 组件。 +* 6、【优化】菜单管理和权限管理在修改时,禁止设置自己为自己的父级。(替换 `admin/system/menu/sys/update` 和 `admin/system/permission/sys/update`) +* 7、【优化】`windows/topWindow.vue` 页面逻辑(替换页面代码),现在可以通过调用 `vk.menuTabs.closeCurrent();` 关闭当前tabs页面 [点击查看](https://vkdoc.fsq.pub/admin/question/question.html#%E5%A6%82%E4%BD%95%E5%85%B3%E9%97%AD%E5%BD%93%E5%89%8D%E6%89%93%E5%BC%80%E7%9A%84tabs%E9%A1%B5%E9%9D%A2) +* 8、【优化】表单示例组件中的关闭按钮 +* 9、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.9(2021-10-14) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.39` +* 2、【优化】`富文本编辑器` 现在无需使用插槽的形式(需要在 `main.js` 中 `Vue.use(vkAdminUI);` 的下方添加如下代码) [点击查看](https://vkdoc.fsq.pub/admin/components/22%E3%80%81editor.html) +```js +// 引入 富文本编辑器 组件(必须加在Vue.use(vkAdminUI);的后面) +import VkDataInputEditor from "@/components/vk-data-input-editor/vk-data-input-editor"; +Vue.component("vk-data-input-editor", VkDataInputEditor); +``` + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.8(2021-10-11) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.34` +* 2、【优化】`App.vue` 内的 `init` 逻辑(可以有效解决首次进入首页再返回登录页面的显示问题) +* 3、【修复】`万能表单` 时间选择组件 `pickerOptions` 参数不生效的问题 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.7(2021-10-08) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.31` +* 2、【优化】`万能表单` `table-select` 新增属性 `dataPreprocess` +* 3、【优化】`万能表单` `table-select` 内部缓存逻辑 +* 4、【优化】`万能表单` `array` 新增属性 `size` 可选值:medium / small / mini + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.6(2021-10-07) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.28` +* 2、【新增】`万能表格` 新增 `type` : `dateDiff2` 计算出还剩多少时间到期。 +```js +{ key:"exp_time", title:"到期剩", type:"dateDiff2", endText:"已到期", width:80, defaultValue: "永久", sortable:"custom" }, +``` +* 3、【优化】`万能表格` `avatar` 新增属性 `shape` 默认为 `circle` circle 圆形 square 方形 +* 4、【优化】其他细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.5(2021-09-30) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.13` +* 2、【优化】`万能表格` 查询接口支持异常重试机制(可有效解决阿里云空间偶尔出现数据库连接超时导致异常的问题)[点击查看](https://vkdoc.fsq.pub/admin/2/table.html#%E5%BC%82%E5%B8%B8%E9%87%8D%E8%AF%95%E6%9C%BA%E5%88%B6) +* `万能表单` 暂无计划支持异常重试机制(因为阿里云虽然前端会报超时(执行10秒后),但云函数其实可能还在运行,所以此时重试机制可能会造成表单重复提交多次) +* 3、【优化】其他一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.4(2021-09-30) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.13` +* 2、【优化】`万能表格` 查询接口支持异常重试机制(可有效解决阿里云空间偶尔出现数据库连接超时导致异常的问题) +* `万能表单` 暂无计划支持异常重试机制(因为阿里云虽然前端会报超时(执行10秒后),但云函数其实可能还在运行,所以此时重试机制可能会造成表单重复提交多次) +* 3、【优化】其他一些细节。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.3(2021-09-27) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.10` +* 2、【优化】`万能表单` 新增属性 `success-msg` 可以设置表单提交成功后右上角的提示 +* 3、【优化】`table-select` 的查询action支持http请求(传统后端请求)[点击查看](https://vkdoc.fsq.pub/admin/components/12%E3%80%81table-select.html#http%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.2(2021-09-18) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.7` +* 2、【升级】`element-ui` 包升级至 `2.15.6` [点击查看](https://element.eleme.cn/#/zh-CN/component/changelog) +* 3、【优化】`vk-data-dialog` + `万能表单` 触发 `before-close` 的逻辑。 +* 4、【优化】`vk-data-drawer` + `万能表单` 触发 `before-close` 的逻辑。 + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.1(2021-09-17) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.6` +* 2、【优化】`万能表单` `array` 新增 `maxlength` 属性,控制最大可添加的数量 [点击查看文档](https://vkdoc.fsq.pub/admin/components/24%E3%80%81array.html) +* 3、【优化】`万能表单` `array` 新增 `maxlength` 属性,控制最大可添加的数量 [点击查看文档](https://vkdoc.fsq.pub/admin/components/24%E3%80%81array.html) + + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.6.0(2021-09-17) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.6.1` +* 2、【优化】`万能表格` 新增 `leftFixed` 和 `rightFixed` 属性,默认均为true,当为false时,可以取消列固定。 +* 3、【优化】`table-select` 新增 `leftFixed` 和 `rightFixed` 属性,默认均为true,当为false时,可以取消列固定。 +* 4、【优化】`array` 新增 `leftFixed` 和 `rightFixed` 属性,默认均为true,当为false时,可以取消列固定。 +* 5、【修复】`vk-data-dialog` 无法正常触发 `before-close` 的问题 +* 6、【修复】`vk-data-drawer` 无法正常触发 `before-close` 的问题 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.17(2021-09-16) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.30` +* 2、【优化】一些细节 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.16(2021-09-15) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.29` +* 2、【优化】`万能表格` 在弹窗模式下,行高自适应逻辑。 +* 3、【优化】`万能表单` `table-select` 行高自适应逻辑。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.15(2021-09-14) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.27` +* 2、【优化】当页面中有多个 `万能表格` 组件时,表格高度可能无法正常自适应的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.14(2021-09-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.23` +* 2、【优化】补全内置的3个组件(icon、dialog、link)文档 [点击查看](https://vkdoc.fsq.pub/admin/components2/1%E3%80%81vk-data-icon.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.13(2021-09-13) +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.23` +* 2、【修复】`素材管理` 上传图片后有概率无法及时回显的bug。(需同时更新uni_modules/vk-unicloud) [点击查看](https://vkdoc.fsq.pub/admin/components/25%E3%80%81file-select.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.12(2021-09-05) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.21` +* 2、【修复】因`1.5.11`更新造成的`db_init.json`数据格式错误,导致权限管理页面无法正常打开的问题。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.11(2021-09-04) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.21` +* 2、【优化】`万能表格` `tag` 类型渲染支持 数组形式(渲染标签组),同时新增effect:dark / light / plain 3选1 + +```js +{ + key:"xxxxx", title:"身份类型", type:"tag", width:200, + effect:"light", + data:[ + { value:"region", label:"区域代理" }, + { value:"shareholder", label:"商城股东", tagType:"danger" } + ] +} +``` + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.10(2021-09-01) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 【修复】`素材管理` 上传图片后有概率无法及时回显的bug。(需同时更新uni_modules/vk-unicloud) [点击查看](https://vkdoc.fsq.pub/admin/components/25%E3%80%81file-select.html) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.9(2021-09-01) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.19` +* 2、【优化】`database`内的初始化文件 +* 3、【优化】`菜单管理`中菜单标识长度修改为2-40个字符。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.8(2021-08-31) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.19` +* 2、【新增】配置`vk.db.unicloud.getTableData.sortArr`,可以设置`vk.baseDao.getTableData`全局默认排序规则 +* 3、【修复】`万能表单`中 `money`、`number`、`percentage`、`discount` 的 `onChange` 返回的值不是数值类型的bug。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.7(2021-08-28) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.18` +* 2、【优化】`用户管理` 需自行替换新版文件 /pages_plugs/system/user/list +* 3、【优化】`应用管理` 需自行替换新版文件 /pages_plugs/system/app/list +* 4、【优化】`万能表单` `cascader` 组件支持 `onChange` [点击查看](https://vkdoc.fsq.pub/admin/components/11%E3%80%81cascader.html#onchange-%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.6(2021-08-28) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.18` +* 2、【优化】`用户管理` 需自行替换新版文件 /pages_plugs/system/user/list +* 3、【优化】`应用管理` 需自行替换新版文件 /pages_plugs/system/app/list +* 4、【优化】`万能表单` `cascader` 组件支持 `onChange` [点击查看](https://vkdoc.fsq.pub/admin/components/11%E3%80%81cascader.html#onchange-%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B) + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.5(2021-08-28) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.16` +* 2、【修复】万能表格前端`queryForm1.sortRule`(排序)不生效的bug。 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.4(2021-08-26) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.13` +* 2、【优化】使用帮助/代码快捷提示/javascript代码块提示.json 新增新加的几个api的代码提示,同时输入`qw`可以快捷输出常用过滤器代码。 +* 3、【优化】`万能表格` 支持展开行 [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#http%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) +* 4、【修复】`万能表格` 树形结构展示的bug + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.3(2021-08-26) +#### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +#### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.13` +* 2、【优化】使用帮助/代码快捷提示/javascript代码块提示.json 新增新加的几个api的代码提示,同时输入`qw`可以快捷输出常用过滤器代码。 +* 3、【优化】`万能表格` 支持展开行 [点击查看](https://vkdoc.fsq.pub/admin/2/table.html#http%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) +* 4、【修复】`万能表格` 树形结构展示的bug + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +#### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.2(2021-08-24) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 + +* 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.11` +* 2、【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 3、【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 4、【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 5、【优化】`万能表格` 的查询action支持http请求(传统后端请求)[点击查看](https://vkdoc.fsq.pub/admin/2/table.html#http%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) +* 6、【优化】`万能表单` 的提交action支持http请求(传统后端请求)[点击查看](https://vkdoc.fsq.pub/admin/3/form.html#http%E8%AF%B7%E6%B1%82%E6%A8%A1%E5%BC%8F) + +#### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.1(2021-08-16) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.2` +#### 2、【重要】文档已搬家(gitee文档地址仅作为备用地址)[查看新版文档地址](https://vkdoc.fsq.pub/) + +#### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.5.0(2021-08-11) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.5.1` +#### 2、【升级】`element-ui` 包升级至 `2.15.5` +#### 3、【优化】一些细节 +#### 4、【新增】万能表格新增方法`getTableFormatterData`(获取整个表格数据(格式化后的数据)) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003876&doc_id=975983) +```js +let info = this.$refs.table1.getTableFormatterData(); +console.log(info); +``` +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.4.2(2021-08-06) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.4.1` +#### 2、【新增】登录日志支持按应用搜索,支持显示登录用户头像昵称 +#### 3、【优化】一些细节 +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.4.1(2021-08-04) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.4.0` +#### 2、【重要】适配`uni-id 3.3.3`:支持不同端用户隔离 [点击查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4313231&doc_id=975983) +#### 3、【重要】用户管理全面升级,支持展示不同端用户,支持`批量设置可登录的应用` +#### 4、【重要】新增应用管理 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.4.0(2021-08-04) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.4.0` +#### 2、【重要】适配`uni-id 3.3.2`:支持不同端用户隔离 [点击查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4313231&doc_id=975983) +#### 3、【重要】用户管理全面升级,支持展示不同端用户。 +#### 4、【重要】新增应用管理 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.6(2021-07-28) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.3.4` +#### 2、【修复】万能表单 `array` 嵌套 `array`时,控制台会报错的问题。 +#### 3、【优化】万能表单 `table-select` 组件新增 `dialogWidth` 属性(控制弹窗宽度) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.5(2021-07-22) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【修复】常用的 vk.baseDao `javascript代码块提示`(有部分错误的问题:少,号的问题)(在编辑器输入dao.即可弹出代码提示)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4019184&doc_id=975983) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/fe965ad9-e9ed-44fc-ad0b-5bc286988e09.png) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.4(2021-07-22) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.3.3` +#### 2、【优化】新增常用的 vk.baseDao `javascript代码块提示` (在编辑器输入dao.即可弹出代码提示)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4019184&doc_id=975983) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/fe965ad9-e9ed-44fc-ad0b-5bc286988e09.png) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.3(2021-07-12) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【修复】已知问题 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.2(2021-07-12) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.3.2` +#### 2、【优化】部分输入性组件补全 readonly(只读)属性 +#### 3、【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.1(2021-07-12) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.3.2` +#### 2、【优化】部分输入性组件补全 readonly(只读)属性 +#### 3、【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.3.0(2021-07-09) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.3.0` +#### 2、【升级】`element-ui` 包升级至 `2.15.3`(有新增2个组件) [查看elementUI更新日志](https://element.eleme.cn/#/zh-CN/component/changelog) +#### 3、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 3、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 3、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 4、【重要】万能表格搜索组件`vk-data-table-query`文档(支持搜索折叠) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4214905&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.7(2021-07-07) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.18` +#### 2、【新增】`admin/system/menu/sys/getCascader`(cascader 级联选择组件 远程懒加载方式的云函数示例)[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050268&doc_id=975983) +#### 3、【新增】`万能表格`新增合计列的属性show-summary、summary-method 、total-option [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003876&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.6(2021-07-05) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.16` +#### 2、【优化】权限管理页面逻辑(部分修改完成后,减少一次数据库查询) +#### 3、【优化】菜单管理页面逻辑(部分修改完成后,减少一次数据库查询) +#### 4、【优化】优化手机H5浏览时的部分样式。 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.5(2021-07-03) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.15` +#### 2、【调整】去除系统内置的`初级管理员`、`中级管理员`、`高级管理员`角色 +#### 3、【优化】权限管理页面逻辑 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.4(2021-07-03) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.15` +#### 2、【调整】万能表格 `getCurrentRow()` 方法调整如下 +```js +// 获取当前选中行的数据(拷贝一份新的数据),此时若改变item对象内属性的值,不影响表格本行数据。 +let item = that.$refs.table1.getCurrentRow(); +// 获取当前选中行的数据,此时若改变item对象内属性的值,可以实时更新表格本行数据。 +let item = that.$refs.table1.getCurrentRow(true); +``` +#### 3、【修复】万能表单 `checkbox` 第二次显示可能会报错的问题。 + + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.3(2021-07-02) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.12` +#### 2、【修复】`万能表单`的 `remote-select` 当 showAll:true 时,actionData参数无效的问题。 +#### 3、【修复】`万能表单`的 `file-select` 已知bug。 + + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.2(2021-07-01) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.9` +#### 2、【修复】`素材管理`优化。需替换目录`/pages_plugs/system_uni/uni-id-files/` +#### 3、【优化】`万能表单`的 `remote-select`、 `radio`、 `checkbox`新增属性 `dataPreprocess`(数据预处理函数)[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050267&doc_id=975983) +#### 4、【修复】`万能表单`的 `file-select` 已知bug [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4176041&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.1(2021-06-28) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.7` +#### 2、【修复】已知bug + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.2.0(2021-06-28) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.2.6` +#### 2、【修复】`manifest.json`的 H5 配置中运行的基础路径 由 `admin` 改成 `/admin/`(规范)(如果你的前端托管只发布admin,则可以设置为空) +#### 3、【新增】万能表单新增 `file-select` 组件(素材库选择组件),可以直接选择已上传的素材。[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4176041&doc_id=975983) +#### 4、【重要】新增 `素材管理` 页面,可管理已上传的图片、视频、文件等素材。[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4176041&doc_id=975983) +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/f795789f-a7e7-4117-953f-07fe2a25f300.png) +#### 5、【优化】万能表单`remote-select` 新增属性`actionData` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050267&doc_id=975983) +#### 6、【优化】万能表单`radio` 新增属性`actionData` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050276&doc_id=975983) +#### 7、【优化】万能表单`checkbox` 新增属性`actionData` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050277&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + + +## 1.1.9(2021-06-23) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.19` +#### 2、【修复】`万能表格` 导出 `Excel` 的一些已知问题。 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + + +## 1.1.8(2021-06-22) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.17` +#### 2、【修复】`万能表单` 组件 `table-select` 当设置为单选时 `onChange` 事件 返回参数 `option` 的值改为对象(之前是数组)[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050276&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论。 +## 1.1.7(2021-06-21) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.15` +#### 2、【升级】`element-ui` 包升级至 `2.15.2` +#### 3、【优化】`万能表单` 组件 `remote-select`、`table-select`、`select`、`checkbox`、`radio` 的 `onChange` 事件 新增返回参数 `option` 值为选项的对象值 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050276&doc_id=975983) +```js +{ + key:"user_id", title:"用户选择器", type:"remote-select", placeholder:"请输入用户账号/昵称", + action:"admin/select/kh/user", + onChange:function(val, formData, column, index, option){ + // option内的值为与val匹配的选项的数据源完整数据 + console.log(1,val, formData, column, index, option); + } +} +``` + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.1.6(2021-06-18) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.13` +#### 2、【修复】`vk.baseDao.add` 因hbx 3.1.18版本导致的本地运行时 `_add_time_str` 错误的问题。 +#### 3、【新增】万能表单 `array` 的 `columns` 中每个元素新增 `onChange` 属性 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4109698&doc_id=975983) +#### 4、【新增】万能表单 `table-select` 新增 `valueFields` 属性(用于控制value的值由哪些字段组成) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050269&doc_id=975983) +```js +// 不设置 `valueFields` 时 表单绑定的值为`字符串数组形式` +["001","002"] +// 设置 `valueFields` 时 表单绑定的值为`对象数组形式` +// 如 `valueFields:["_id","nickname","mobile"]` 表单绑定的值为 +[ + {"_id":"001","nickname":"昵称1","mobile":"手机号1"}, + {"_id":"002","nickname":"昵称2","mobile":"手机号2"} +] +``` +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + + +## 1.1.5(2021-06-15) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.11` +#### 2、【新增】`万能表单` 新增组件 `array`(子表单-对象数组) [点击查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4109698&doc_id=975983) +#### ![查看示例图](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/67cda695-e3f9-469f-9870-9f248b415400.png) +#### 3、【新增】`万能表单` 新增组件 `array`(字符串数组) + ```js +{ key:"array1", title:"数组字符串类型", type:"array" } +``` + +#### 4、【新增】`万能表单` 新增组件 `array`(数字数组) +```js +{ key:"array2", title:"数组数字类型", type:"array" } +``` + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + + +## 1.1.4(2021-06-10) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.5` +#### 2、【新增】`万能表格`新增属性`default-sort`,支持表格默认排序 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003876&doc_id=975983) +#### 如默认按时间降序 +```html + +``` +#### 3、【优化】`el-button` 组件支持 `vk-icon` 内置图标 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + + +## 1.1.3(2021-05-31) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.2` +#### 2、【优化】`万能表格`中`tag`组件当没有匹配到值时进行忽略处理。 +#### 3、【优化】`万能表格`中`time`组件正确识别10位数时间戳和13位时间戳,同时支持自定义时间g格式化 +```js +{ key:"_add_time", title:"添加时间", type:"time", width:160, valueFormat:"yyyy-MM-dd hh:mm:ss" } +``` + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论。 +## 1.1.2(2021-05-31) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.1` +#### 2、【新增】补全内置组件文档 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050270&doc_id=975983) +#### 3、【修复】`上传组件` 上传视频时后缀名可能会错误的问题。 +#### 4、【优化】`云函数URL化` 路由模式下,URL重写支持只允许部分云函数可被访问。(可以做到只暴露指定的API接口,增加URL化后的安全性)[点击URL重写规则](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.1.1(2021-05-29) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.1.0` +#### 2、【新增】用户管理新增强制重置其他账号登录密码。 +#### 3、【新增】`table-select`、`address` 等组件文档 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050269&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.1.0(2021-05-29) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.19` +#### 2、【新增】用户管理新增强制重置其他账号登录密码。 +#### 3、【新增】`table-select`、`address` 等组件文档 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050269&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.9(2021-05-28) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.19` +#### 2、【新增】强制重置admin账号密码教程 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4064984&doc_id=975983) +#### 3、【优化】`下拉选择`支持分组 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050278&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 +## 1.0.8(2021-05-27) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.18` +#### 2、【优化】`cascader` 组件的内部逻辑,支持异步加载。 +#### 3、【修复】`上传组件` 上传视频时后缀名可能会错误的问题。 +#### 4、【优化】将`系统设置`菜单变更为动态菜单(导入`database/动态菜单导入/系统设置.json`即可) +```js +动态菜单导入方式: +1、进入admin,点击菜单管理 +2、点击通过JSON批量导入菜单 +3、将`database/动态菜单导入/系统设置.json`内的全部内容复制到JSON内容中,点确定即可 +4、可以删除`static_menu/menu.json`内的系统设置相关的菜单了。(由静态菜单变成了动态菜单) +``` + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.7(2021-05-26) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.18` +#### 2、【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 3、【优化】`万能表格`的搜索组件 新增`cascader`、`table-select`组件渲染。 +#### 4、【优化】`万能表格`组件新增API `deleteRows`、`updateRows` (只更新表格内数据,不更新数据库) +```js +// 删除指定的行(不删数据库数据) +that.$refs.table1.deleteRows({ + ids:["60acf6248a69dc00018d8520"], + success:function(){ + + } +}); +// 更新指定的行数据(不更新据库数据) +that.$refs.table1.updateRows({ + mode:"update", // update 局部字段更新 set 覆盖字段更新 + rows:[ + { _id:"60acf6248a69dc00018d8520", remark:"被修改了", money:10000 } + ], + success:function(){ + + } +}); +``` + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.6(2021-05-24) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.13` +#### 2、【优化】`万能表单`中单选和多选组的样式排版。增加属性`itemWidth` 所有选项的最小宽度。 +#### 3、【优化】`remote-select`新增属性 `props` [点击查看组件文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050267&doc_id=975983) +#### 4、【优化】`radio` 和 `checkbox` 支持远程数据(通过云函数获取选项) [点击查看组件文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050276&doc_id=975983) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.5(2021-05-24) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.11` +#### 2、【优化】`万能表单`中单选和多选组的样式排版。增加属性`itemWidth` 所有选项的最小宽度。 +#### 3、【优化】`remote-select`新增属性 `props` [点击查看组件文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050267&doc_id=975983) +#### 4、【优化】`radio` 和 `checkbox` 支持远程数据(通过云函数获取选项) [点击查看组件文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4050276&doc_id=975983) +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.4(2021-05-22) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】`vk.baseDao` API的查询性能。 +#### 2、【调整】`vk.baseDao.getTableData` 默认排序规则调整为`_id`降序,之前是`_add_time`降序 +#### 3、【优化】`vk.baseDao.getTableData` 和 `vk.baseDao.selects` 连表查询逻辑。 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.3(2021-05-20) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.10` +#### 2、【修复】`pages_plugs/permission/list`页面`sort`的`type`为`number`(原本为`text`) + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.2(2021-05-18) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.9` +#### 2、【新增】`JSON编辑器` `type: "json"` 可自由的编辑json对象 +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/f3181c8a-efc7-4a73-8595-d7c029d0eac3.png) +#### 3、【修复】`vk-data-input-editor` 组件在其他组件中使用时功能异常的bug + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.1(2021-05-17) +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【升级】`vk-unicloud-admin-ui` 包升级至 `1.0.4` +#### 2、【优化】`opendb-admin-menus`(菜单表) 新增属性`hidden_menu` 若为true,则菜单存在,但在左侧菜单列表中隐藏。 +#### 3、【修复】手机访问时,不显示用户角色权限菜单的bug。 + +#### 框架更新步骤指南 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4023455&doc_id=975983) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 1.0.0(2021-05-15) + +### 2021-05-15 `vk-unicloud-admin` 框架正式发布。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/6deebd32-8075-4bdb-8e04-5839516ef4f4.png) + +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 插件名称:`vk-unicloud-admin` +### 作者:VK + +## 序 +##### 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +##### 无需转变开发习惯,0成本上手云开发。 +##### 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +##### 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +##### `client端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983) +##### `admin端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 框架体验地址 + +[点击进入admin框架体验地址](https://vkunicloud.fsq.pub/admin/) + +#### 体验账号: +##### 高级管理员:test11(账号)123456(密码)可以执行绝大部分功能 +##### 初级管理员:test12(账号)123456(密码)只能执行查询功能 +##### 无权限用户:test13(账号)123456(密码)无admin登录权限 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2021-05-15 `vk-unicloud-admin` 框架正式发布。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/6deebd32-8075-4bdb-8e04-5839516ef4f4.png) + +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 插件名称:`vk-unicloud-admin` +### 作者:VK + +## 序 +##### 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +##### 无需转变开发习惯,0成本上手云开发。 +##### 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +##### 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +##### `client端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983) +##### `admin端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 框架体验地址 + +[点击进入admin框架体验地址](https://vkunicloud.fsq.pub/admin/) + +#### 体验账号: +##### 高级管理员:test11(账号)123456(密码)可以执行绝大部分功能 +##### 初级管理员:test12(账号)123456(密码)只能执行查询功能 +##### 无权限用户:test13(账号)123456(密码)无admin登录权限 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2021-05-15 `vk-unicloud-admin` 框架正式发布。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/6deebd32-8075-4bdb-8e04-5839516ef4f4.png) + +### vk-unicloud-admin 框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 +### 插件名称:`vk-unicloud-admin` +### 作者:VK + +## 序 +##### 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +##### 无需转变开发习惯,0成本上手云开发。 +##### 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +##### 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +##### `client端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912167&doc_id=975983) +##### `admin端`框架文档:`https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983` [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003875&doc_id=975983) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 框架体验地址 + +[点击进入admin框架体验地址](https://vkunicloud.fsq.pub/admin/) + +#### 体验账号: +##### 高级管理员:test11(账号)123456(密码)可以执行绝大部分功能 +##### 初级管理员:test12(账号)123456(密码)只能执行查询功能 +##### 无权限用户:test13(账号)123456(密码)无admin登录权限 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + diff --git a/changelog.new.md b/changelog.new.md new file mode 100644 index 0000000..a8dfd35 --- /dev/null +++ b/changelog.new.md @@ -0,0 +1,14 @@ +* 【升级】`vk-unicloud-admin-ui` 包升级至 `1.17.45` +* 【调整】`万能表单` `vk-data-input-editor` 组件的js依赖内置到项目里,防止因quill官方CDN无法访问导致editor组件渲染失败的问题 +* 【修复】`万能表单` 部分复杂情况下表单验证未生效的问题 +* 【修复】`万能表格` `object` 内 `oneLine:true` 不生效的bug +* 【修复】`万能表单` `object` 内 `disabled` 不生效的bug +* 【修复】`万能表格` `:searched-clean-selection="false"` 时,分页会导致多选框清空的问题 +* 【修复】`万能表格` 点击右侧按钮时可能会出现请先选中一行的bug +* 【优化】`pages_plugs/system_uni/vk-pay-orders.vue`页面新增支付渠道区分 +* 【优化】`万能表格` 导出的文件名支持自定义扩展名 +* 【优化】`万能表格` 新增 `getRowIndex` 方法 + +##### 框架更新步骤 [点击查看](https://vkdoc.fsq.pub/admin/1/update.html) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 +##### 如果你觉得框架对你有用,可以在下方进行评论或赞赏。 diff --git a/common/css/app.scss b/common/css/app.scss new file mode 100644 index 0000000..dd8bc6f --- /dev/null +++ b/common/css/app.scss @@ -0,0 +1,47 @@ +/* 这里是你自己写的全局css样式 */ + +/* 滚动条美化方案开始 去掉下方css的注释即可 */ + +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-track { + background: rgba(135, 135, 135, 0.1); +} +::-webkit-scrollbar-thumb { + background: rgba(135, 135, 135, 0.4); + border-radius: 6px; +} +::-webkit-scrollbar-thumb:hover { + background: rgba(135, 135, 135, 0.8); +} + +/* 滚动条美化方案结束 */ + +/* 富文本编辑器样式开始 */ +.ql-indent-1{ + padding-left: 3em; +} +.ql-indent-2{ + padding-left: 6em; +} +.ql-indent-3{ + padding-left: 9em; +} +.ql-indent-4{ + padding-left: 12em; +} +.ql-indent-5{ + padding-left: 15em; +} +.ql-indent-6{ + padding-left: 18em; +} +.ql-indent-7{ + padding-left: 21em; +} +.ql-indent-8{ + padding-left: 24em; +} +/* 富文本编辑器样式结束 */ \ No newline at end of file diff --git a/common/css/uni.scss b/common/css/uni.scss new file mode 100644 index 0000000..3e8a5dc --- /dev/null +++ b/common/css/uni.scss @@ -0,0 +1,104 @@ +// 这里是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:#e4e7ed; + +// 尺寸变量 + +// 文字尺寸 +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +// 图片尺寸 +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +// Border Radius +$uni-border-radius-sm: 3px; +$uni-border-radius-base: 5px; +$uni-border-radius-lg: 10px; +$uni-border-radius-circle: 50%; + +// 水平间距 +$uni-spacing-row-sm: 10px; +$uni-spacing-row-base: 15px; +$uni-spacing-row-lg: 20px; + +// 垂直间距 +$uni-spacing-col-sm: 5px; +$uni-spacing-col-base: 10px; +$uni-spacing-col-lg: 15px; + +// 透明度 +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +// 文章场景相关 +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:18px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:14px; + + +$menu-bg-color:#fff; // 一级菜单背景色 +$sub-menu-bg-color:darken($menu-bg-color, 8%); // 二级以下菜单背景色 +$menu-bg-color-hover:darken($menu-bg-color, 15%); // 菜单 hover 背景颜色 + +$menu-text-color: #333; // 菜单前景色 +$menu-text-color-actived: #409eff; // 菜单激活前景色 + +$left-window-bg-color: $menu-bg-color; // 左侧窗口背景色 + +$top-window-bg-color: #fff; // 顶部窗口背景色 +$top-window-text-color: #999; // 顶部窗口前景色 +// 水平垂直居中 +@mixin flex_center_center { + display: flex; + justify-content: center; + align-items: center; +} +// 换行居中 +@mixin flex_direction_center { + display: flex; + justify-content: center; + flex-direction: column; +} +// 水平可换行居中 +@mixin flex_justify_center{ + display: flex; + align-items: center; + flex-wrap: wrap; +} diff --git a/common/function/myPubFunction.js b/common/function/myPubFunction.js new file mode 100644 index 0000000..87a7a33 --- /dev/null +++ b/common/function/myPubFunction.js @@ -0,0 +1,15 @@ +/** + * 自定义公共函数 + */ +var myfn = {}; +/** + * 测试函数test1 + * vk.myfn.test1(); + */ +myfn.test1 = function(obj = {}) { + let vk = uni.vk; + console.log("执行了自定义公共函数test1"); + return obj; +}; + +export default myfn; diff --git a/common/theme/black.js b/common/theme/black.js new file mode 100644 index 0000000..df1a8b8 --- /dev/null +++ b/common/theme/black.js @@ -0,0 +1,23 @@ +// 纯黑主题 +export default { + // 左侧菜单样式 + leftMenu: { + backgroundColor: "#191a23", + subBackgroundColor:"#101117", + textColor: "rgba(255,255,255,0.9)", + activeTextColor: "#ffffff", + activeBackgroundColor: "#2d8cf0", + collapseActiveTextColor:"#2d8cf0", + collapseActiveBackgroundColor: "#2c3239", + hoverTextColor: "#ffffff", + hoverBackgroundColor: "#545f6c", + boxShadow: "0px 0 0px rgba(0,21,4,0.2)", + //boxShadow: "2px 0 2px rgba(0,21,4,0.2)", + //borderTop: "1px solid #101117" + }, + // 顶部菜单样式 + topMenu: { + backgroundColor: "#191a23", + textColor: "#f0f0f0", + } +} diff --git a/common/theme/blackWhite.js b/common/theme/blackWhite.js new file mode 100644 index 0000000..485c0e9 --- /dev/null +++ b/common/theme/blackWhite.js @@ -0,0 +1,23 @@ +// 黑白主题(左侧菜单黑,顶部白) +export default { + // 左侧菜单样式 + leftMenu: { + backgroundColor: "#191a23", + subBackgroundColor:"#101117", + textColor: "rgba(255,255,255,0.9)", + activeTextColor: "#ffffff", + activeBackgroundColor: "#2d8cf0", + collapseActiveTextColor:"#2d8cf0", + collapseActiveBackgroundColor: "#2c3239", + hoverTextColor: "#ffffff", + hoverBackgroundColor: "#545f6c", + boxShadow: "0px 0 0px rgba(0,21,4,0.25)", + //boxShadow: "2px 0 4px rgba(0,21,4,0.25)", + //borderTop: "1px solid #101117" + }, + // 顶部菜单样式 + topMenu: { + backgroundColor: "#ffffff", + textColor: "#999999", + } +} diff --git a/common/theme/index.js b/common/theme/index.js new file mode 100644 index 0000000..a68f4db --- /dev/null +++ b/common/theme/index.js @@ -0,0 +1,9 @@ +import white from './white.js' +import black from './black.js' +import blackWhite from './blackWhite.js' + +export default { + white, + black, + blackWhite +}; diff --git a/common/theme/white.js b/common/theme/white.js new file mode 100644 index 0000000..efe5da6 --- /dev/null +++ b/common/theme/white.js @@ -0,0 +1,23 @@ +// 纯白主题 +export default { + // 左侧菜单样式 + leftMenu: { + backgroundColor: "#ffffff", + subBackgroundColor:"#ffffff", + textColor: "#303133", + activeTextColor: "#409EFF", + activeBackgroundColor: "#ecf5ff", + collapseActiveTextColor:"#409EFF", + collapseActiveBackgroundColor: "#ecf5ff", + hoverTextColor: "#303133", + hoverBackgroundColor: "#efefef", + boxShadow: "0px 0 0px 0 rgba(29,35,41,0.05)", + //boxShadow: "2px 0 0px 0 rgba(29,35,41,0.05)", + borderTop: "1px solid #f8f8f9" + }, + // 顶部菜单样式 + topMenu: { + backgroundColor: "#ffffff", + textColor: "#999999", + } +} diff --git a/common/uni-admin/css/uni-icons.css b/common/uni-admin/css/uni-icons.css new file mode 100644 index 0000000..e6e5859 --- /dev/null +++ b/common/uni-admin/css/uni-icons.css @@ -0,0 +1,542 @@ +@font-face { + font-family: uni-icons; + src: url('data:application/octet-stream;base64,AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzI8PEmfAAABjAAAAGBjbWFwI/huxgAABGgAAAo2Z2x5ZjdREQoAAA/gAABxyGhlYWQeRxNVAAAA4AAAADZoaGVhB94EIAAAALwAAAAkaG10eHwAAAAAAAHsAAACfGxvY2G+ANjyAAAOoAAAAUBtYXhwAbUAqgAAARgAAAAgbmFtZTe8RacAAIGoAAACZ3Bvc3S0buJjAACEEAAAB54AAQAAA4D/gABcBAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAJ8AAQAAAAEAAFISLZRfDzz1AAsEAAAAAADdk+etAAAAAN2T560AAP/gBAADHgAAAAgAAgAAAAAAAAABAAAAnwCeAAwAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAQEAAGQAAUAAAKJAswAAACPAokCzAAAAesAMgEIAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAwOYn5s8DgP+AAAAD3ACAAAAAAQAAAAAAAAAAAAAAAAACBAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAABQAAAAMAAAAsAAAABAAAAr4AAQAAAAABuAADAAEAAAAsAAMACgAAAr4ABAGMAAAAEAAQAAMAAOYn5izmM+Y65j/mQebP//8AAOYn5inmL+Y55jzmQeZD//8AAAAAAAAAAAAAAAAAAAABABAAEAAWAB4AIAAmACYAAACYAJkAlwCaAJsAnACdAJ4AlgCVAJQAjQCOAI8AkACRAJIAkwCMAH0AfgB/AIAAJACBAIIAgwCEAIUAhgCHACAAiACJAIoAiwB7AHwAawBsAG0AbgBvAHAAcQByAHMAdAB1AHYAdwB4AHkAegBoAGkAIQBqAFsAXABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAVQBWAFcAWABZAFoASABJAEoASwAqAEwATQBOAE8AKwBQAFEAUgBTAFQARQAsAEYARwA/AEAAQQBCAEMARAAVADkAOgA7ADwAFAA9AD4ALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAJwAoACkAEwAmAAIAJQAiACMAHQAeAB8AHAAWABcAGAAZABoAGwASAAwADQAOAA8AEAARAAcACAAJAAoACwAGAAQABQADAAEAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAB3gAAAAAAAAAngAA5icAAOYnAAAAmAAA5ikAAOYpAAAAmQAA5ioAAOYqAAAAlwAA5isAAOYrAAAAmgAA5iwAAOYsAAAAmwAA5i8AAOYvAAAAnAAA5jAAAOYwAAAAnQAA5jEAAOYxAAAAngAA5jIAAOYyAAAAlgAA5jMAAOYzAAAAlQAA5jkAAOY5AAAAlAAA5joAAOY6AAAAjQAA5jwAAOY8AAAAjgAA5j0AAOY9AAAAjwAA5j4AAOY+AAAAkAAA5j8AAOY/AAAAkQAA5kEAAOZBAAAAkgAA5kMAAOZDAAAAkwAA5kQAAOZEAAAAjAAA5kUAAOZFAAAAfQAA5kYAAOZGAAAAfgAA5kcAAOZHAAAAfwAA5kgAAOZIAAAAgAAA5kkAAOZJAAAAJAAA5koAAOZKAAAAgQAA5ksAAOZLAAAAggAA5kwAAOZMAAAAgwAA5k0AAOZNAAAAhAAA5k4AAOZOAAAAhQAA5k8AAOZPAAAAhgAA5lAAAOZQAAAAhwAA5lEAAOZRAAAAIAAA5lIAAOZSAAAAiAAA5lMAAOZTAAAAiQAA5lQAAOZUAAAAigAA5lUAAOZVAAAAiwAA5lYAAOZWAAAAewAA5lcAAOZXAAAAfAAA5lgAAOZYAAAAawAA5lkAAOZZAAAAbAAA5loAAOZaAAAAbQAA5lsAAOZbAAAAbgAA5lwAAOZcAAAAbwAA5l0AAOZdAAAAcAAA5l4AAOZeAAAAcQAA5l8AAOZfAAAAcgAA5mAAAOZgAAAAcwAA5mEAAOZhAAAAdAAA5mIAAOZiAAAAdQAA5mMAAOZjAAAAdgAA5mQAAOZkAAAAdwAA5mUAAOZlAAAAeAAA5mYAAOZmAAAAeQAA5mcAAOZnAAAAegAA5mgAAOZoAAAAaAAA5mkAAOZpAAAAaQAA5moAAOZqAAAAIQAA5msAAOZrAAAAagAA5mwAAOZsAAAAWwAA5m0AAOZtAAAAXAAA5m4AAOZuAAAAXQAA5m8AAOZvAAAAXgAA5nAAAOZwAAAAXwAA5nEAAOZxAAAAYAAA5nIAAOZyAAAAYQAA5nMAAOZzAAAAYgAA5nQAAOZ0AAAAYwAA5nUAAOZ1AAAAZAAA5nYAAOZ2AAAAZQAA5ncAAOZ3AAAAZgAA5ngAAOZ4AAAAZwAA5nkAAOZ5AAAAVQAA5noAAOZ6AAAAVgAA5nsAAOZ7AAAAVwAA5nwAAOZ8AAAAWAAA5n0AAOZ9AAAAWQAA5n4AAOZ+AAAAWgAA5n8AAOZ/AAAASAAA5oAAAOaAAAAASQAA5oEAAOaBAAAASgAA5oIAAOaCAAAASwAA5oMAAOaDAAAAKgAA5oQAAOaEAAAATAAA5oUAAOaFAAAATQAA5oYAAOaGAAAATgAA5ocAAOaHAAAATwAA5ogAAOaIAAAAKwAA5okAAOaJAAAAUAAA5ooAAOaKAAAAUQAA5osAAOaLAAAAUgAA5owAAOaMAAAAUwAA5o0AAOaNAAAAVAAA5o4AAOaOAAAARQAA5o8AAOaPAAAALAAA5pAAAOaQAAAARgAA5pEAAOaRAAAARwAA5pIAAOaSAAAAPwAA5pMAAOaTAAAAQAAA5pQAAOaUAAAAQQAA5pUAAOaVAAAAQgAA5pYAAOaWAAAAQwAA5pcAAOaXAAAARAAA5pgAAOaYAAAAFQAA5pkAAOaZAAAAOQAA5poAAOaaAAAAOgAA5psAAOabAAAAOwAA5pwAAOacAAAAPAAA5p0AAOadAAAAFAAA5p4AAOaeAAAAPQAA5p8AAOafAAAAPgAA5qAAAOagAAAALQAA5qEAAOahAAAALgAA5qIAAOaiAAAALwAA5qMAAOajAAAAMAAA5qQAAOakAAAAMQAA5qUAAOalAAAAMgAA5qYAAOamAAAAMwAA5qcAAOanAAAANAAA5qgAAOaoAAAANQAA5qkAAOapAAAANgAA5qoAAOaqAAAANwAA5qsAAOarAAAAOAAA5qwAAOasAAAAJwAA5q0AAOatAAAAKAAA5q4AAOauAAAAKQAA5q8AAOavAAAAEwAA5rAAAOawAAAAJgAA5rEAAOaxAAAAAgAA5rIAAOayAAAAJQAA5rMAAOazAAAAIgAA5rQAAOa0AAAAIwAA5rUAAOa1AAAAHQAA5rYAAOa2AAAAHgAA5rcAAOa3AAAAHwAA5rgAAOa4AAAAHAAA5rkAAOa5AAAAFgAA5roAAOa6AAAAFwAA5rsAAOa7AAAAGAAA5rwAAOa8AAAAGQAA5r0AAOa9AAAAGgAA5r4AAOa+AAAAGwAA5r8AAOa/AAAAEgAA5sAAAObAAAAADAAA5sEAAObBAAAADQAA5sIAAObCAAAADgAA5sMAAObDAAAADwAA5sQAAObEAAAAEAAA5sUAAObFAAAAEQAA5sYAAObGAAAABwAA5scAAObHAAAACAAA5sgAAObIAAAACQAA5skAAObJAAAACgAA5soAAObKAAAACwAA5ssAAObLAAAABgAA5swAAObMAAAABAAA5s0AAObNAAAABQAA5s4AAObOAAAAAwAA5s8AAObPAAAAAQAAAAAAAAC+ASYBlgH0AloCsAL8A0QDkAQSBGYEygUUBVgF3gZiBqoG7gc6B2gHygfeB/IIIghSCIIIsgjcCQYJMAlaCaIJ5ApuCsYLDAtiC9YMTAyCDOoNTA3IDgQOhA8ID6YP7hCGEOYRTBHGEj4SqBMiE5wT6BQwFHoU8hU+FZ4V7BZMFowW3BdWF74YChhsGPIZPBmgGewagBsKG34b6hxwHMgdvB50HuwfTh/YIBwgSiCCILghPiFsIb4iIiJ4IrgjJCN2I+QkVCSSJPglTiWMJd4mRCaiJwgnVifmKCooVii+KRQpgCnEKj4qeCrAK54rxCv+LFgsvC1ALawt5i5QLoou8i9QL4ov4DAOMHYw0DE0MdQyFjJQMnoyzDMaM5Yz4jReNIo08DVSNeA18jZCNn424jdGN444KjiCOOQABwAAAAADkwL/ACYATwBYAGEAawB0AH0AACUiJyMmJyYnMSYnJjc+ATc2FxYXFhcWHwEWBwYHBicmBw4BFxYHBicXFjc1NicmPgIfARY3Njc2JzEmJyYnJicmBwYHBgcGFxYfARYXFhcDFBYyNjQmIgY3FBYyNjQmIgY3FBYyNjQmIgYHFxQWMjY0JiIGFxQWMjY0JiIGAd8VHgVSTScZPAgHIyF9T1RWX1JELRYLARhAKEcnIx0RCAUDEAsilwVuHAMJCAofLRsDHR05HS4UCxQoPEhSS0tFNjUdIQUGNwIcIUBBtBsmGxsmGzUbJhsbJhuLGicbGycaAZobJhsbJhtNGyYbGyYbBgQNRSMjXGJYU01wGhwOD0I4UyomAoQ+JwUCBwMUChoJMBtKMwERPQENHBQxJhIDAQYCAh0saiQlSi87DgwYFzIwP0lNWFUCJRw3CgE3ExsbJhsbdxMbGyYbGjkTGxsmGxsTJhMbGyYbG44TGxsmGxsAAAAEAAAAAAOBAwEAEwAtADYAQgAAATIWFxUeARcTFAYHBSImJxE0NjcHERQWFwUyNjc1IyIuATQ+ATczNTQmJyEiJwUjIgYUFh8BNQMhIgYUFhchNTQmJwLGKj8DISsCATsr/dIrPgM7KioZEwIsExwCiSA3IB4zH5AZE/3UFhQCgokZIh4XkID+JxQdGRMCDxoTAwA7KzsKNSL+bys/AgE7KwIuKz4Dzf46Ex0BARoTUyA2PzUhAU8THAIJxCIvIgIBdwFYHSccAjETHAIAAAAAAwAAAAADgQLGABkAMQBMAAABMjY3MzI2NCYrAS4BIgYHISIGFBYzIR4BMwUiBhQWOwEeATI2NyEyNjQmIyEuASIGBwEyNjczMjY0JisBLgEiBgchIgYVMRQWMyEeAQKJHDAKhAwREQyECi87Lwr+bA0SEg0BlAowHP4VDBISDIgJMDowCgGPDRISDf5xCjA6LwoBZB0vCoQMEREMhAovOy8K/mwNEhINAZQKLwIOIRsTGRIbIiIbEhkTGyFvEhoRHCIiHBEaEhsiIhv+nCIbEhoSGyIiGxINDRIbIgAAAAAEAAAAAAOwArkADAAZACYAOgAAATI+ATQuASIOARQeARc0NyYnBycOAQchLgE3Ig4BFB4BMj4CLgEXDwEGIi8BJjQ/ATYyHwE3NjIWFAGgLEsrLEpZSiwsStALJShiYVp/EgJ4PEzHLUwsLExaTCwBLUwwWAsEDgRBBAQBBA0ENlkFDAkBcyxKWUosLEpZSixxISEZDnBvHp5oFGfnLUxZTC0tTFlMLYBoCwUFQwUNBAEEBThpBAoNAAAAAAMAAAAAA4gC1AAnADkARQAAATAxJzQvAS4BByEmBg8BFQYVFB4BFzMyNjceATY3NjceATMxFjc+AQcjBgcVITUmJxUUFjMhMjY9ASchIiY0NjMhMhYUBgN3AQJACS0b/joaLAlGCCdDKQUiPRUaTE8fCggWPCInIjAoSwEeGf33IR0bEwIoExuE/oQNExMNAXwOEhIB8AEEBKIaHwICHhmrAhgZKUcpAR0aIBsOGwkJGhwBEhtoqA4FsbMGD9cTFxcT1OkSGRISGRIAAAIAAAAAA4QCwgAhADsAAAE+ATU0LgEjIgYUFjMyFhQGIyIGFBYzMh4BFRQWMjY1NiYDMjY1NCYnPgE1NC4BIg4BFRQWFw4BFRQWMwMGExUlPyUMExMMHi4uHg0SEg0qSSsTFxMERJMMFWJQKC40WWpaNC4pUWEUDAFtFTYdKUQoFRkUMkIxEh8RL04uDBUVDEV0/vMUDFSLIB1ULzVYMzNYNS9UHSCLVAwUAAACAAAAAAOFAs8AIAAsAAABBg8BBi8BJgYHBhcTHgEzITI2NxM2JicmDwEGLwEuAQcTMhYUBgcjIiY0NjcB3AoHgwMDYxgzDAsFRwc3JAGrIzcHSAUeGhYUZwMCgA8zFooNERAL0g0REAsCvwcJugMBMwwQGBQW/pkjLS0jAWcbLAYECjQBA7oVCg3+LhEZEQESGBEBAAAAAAIAAP//A4EDAAAUADEAACEyNzY3NjQnJicmIgcGBwYUFxYXFjciJj0BIyImNDY3MzU0NjIWHQEzMhYUBisBFRQGAgBnWlczNTUzV1rOWlczNTUzV1pmDxF8ERUUEnwRHxJ8ERQUEXwSNDRXWs5aVzM1NTNXWs9ZVzQ0xBUQdhEfEQF8ERUVEXwSHxF1EhQAAAIAAAAAA4EC1QAYADUAAAEhJy4BKwEiDgEVERQeATMhMj4BNRE0LgEDIxUUBiImPQEjIiY0NjsBNTQ2MhYdATMyFhQGIwMN/s0rECsWah81Hx81HwIZHzUfHzW4VxEYEFcMEBAMVxAYEVcLEREMAogrEBIfNR/+NCA1Hx81IAF/HzUf/rBWDBERDFYRGBFWDBERDFYRGBEABgAAAAADkwL/ACYALwA4AEIASwBUAAAlIicjJicmJzEmJyY3PgE3NhcWFxYXFh8BFgcGBwYnJgcOARcWBwYBFBYyNjQmIgY3FBYyNjQmIgY3FBYyNjQmIgYHFxQWMjY0JiIGFxQWMjY0JiIGAd8VHgVSTScZPAgHIyF9T1RWX1JELRYLARhAKEcnIx0RCAUDEAsi/rUbJhsbJhs1GyYbGyYbixonGxsnGgGaGyYbGyYbTRsmGxsmGwYEDUUjI1xiWFNNcBocDg9COFMqJgKEPicFAgcDFAoaCTAbSgFpExsbJhsbdxMbGyYbGjkTGxsmGxsTJhMbGyYbG44TGxsmGxsAAAACAAD/+wOBAv8AGwA3AAABMhYXITIWFAYjIQ4CJy4BJyMiJjQ2OwE+AhMyFhczMhYUBisBDgInLgEnISImNDYzIT4CAao7WgwBFA4TEw7+7Ak6UysxRQpmDRQUDWYHLkTWO1oMZQ4TEw5lCTpTLDBGCf7rDRQUDQEVBy5EAUlKORMbFCtBHAkKRTAUGxMlPCIBtUo5ExsUK0EcCQlGMBQbEyU8IgAAAAAEAAD//wN9AwEAEwAlADIAPwAAASEiDgEVERQeATMhMj4BNRE2LgEDDwEOAS8BLgE+AR8BNzYyHgEBMhYXFRQGIiYnNTQ2ITIWFxUUBiImJzUmNgLI/nIxUzExUzEBjjFTMAExU3MCfwgXClwKAhAZCkZqCRoSAv7iDRIBExkSARIBKgwTARMZEgEBEwLTMVMx/pcxUzExUzEBaTFTMf65A4IIAwdPCRoTAwc8bgkRGQFrEQxmDRMRDGYNExEMZg0TEQxmDRMAAAIAAAAAA4ADAAApAC8AAAEyFxYXFhcVFB8BFhQHBgcjFA4BIi4BLwEjIiY1ND8BNjc9ATQ3Njc2MxMjFBYyNgIBUUdEKSoDEisQEA4TtilGUkUqAgGwFiANKxUCKSlFR1NgwDhQOAMAKCdDRVGFHBUsDy0QDgIqRionQygIHxcTECoUHAd5U0hFKSr9mig4OAAAAAADAAAAAAOBAwAAEwAbACcAAAEyFhcVHgEXExQGBwUiJicRNDY3ASMiBhQWHwEDISIGFBYXITU0JicCxio/AyErAgE7K/3SKz4DOyoCX4kZIh4XkID+JxQdGRMCDxoTAwA7KzsKNSL+bys/AgE7KwIuKz4D/m0jLyICAQHPHSccAjETHAIAAAAABAAAAAADgQLhAC8AOQBMAFcAAAEjNTQuASMhDgEdAQcOARcWFxYXHgEXFSMOARQWMyE+ATQmKwE1PgE3Njc2NzU0JgUmJyYnNSY2NzMFDgEHBi4BNj8BNjc2PwE+AR4BNwcGBwYHPQEzHgEDLUQbLhz+5Ck4NiMtAwIdKkYWa0VwDBASDQEbDBASDW1EahZWLx0DMf24HhQRAwEMCDMBcgoxHAoUBwcJAxEQDgcCBBQUCcYBAxEaK0YJCwJVJxsvGwI6KScBAjQjKig5E0FZCWsBEhkRAREZEmsJVj8QQSgqBiMxsg8bFxgECA4BmxoxCgQJFBMEAQYQDw8DCgkIFHoEGBckDg5uAQ4AAAUAAAAAA5EDBgAqADYARABLAFIAAAE1IicjBgcVITU0NjsBJicmNjc2FxYXFhc2NzY3NhceAQcGBwYHMzIWHQEBJgYPAQYXFhcWNyYFNiYnJgcGBxY3Mjc2NwMhIiY1ESEBFAYjIREhAiMIDwQTEP6UFxGmTgEBHhgdIC4sHyQnHy8xHRwYHAMEFxUjpBAY/eESKAkBEw8WOyw6KwEwDBEVFhdCLSYnIBokDf/+1w8VAU0BhhUP/tcBTQGrsgMDAbGOEBgQMBYyDQ8HCiUaLDAZJwYEEA4vFRkRDwcXEI8BLgkMEwIeDxYFBAY+JQ8rCwwLIzsEAgUGD/1yFQ8BZv6aDxYBiwAAAAEAAAAAAzwDAwAtAAABHgEVFBcWHwIWFxYVFAcOASMiJyYnJjU0NzY3PgEyFh8CHgEXJjY3Nj8BNgI/BgoSFiYjDjMZISsqkVVSRksqLw8MFAQSFhIFEwUKHBUYMC0hLAgKAvkDEQskLzgmHw4xMT5IS0A/SSMlREtkL0E4OQoODgo3DBwkD06fOioeAwUAAAEAAP/1A3UC+QAnAAABJzcuASMmBwYHDgEXFhcWMxY2NzMGBwYHBiYnJicmNjc2NzYXFhc3A3TnaC2CSVZKSCsrASsqR0pWWpkpQSdRTmJkvD07Dg1OUU5iZF5XO1EBzgVnOkABKypISa1KSCosAV5QXj08DQ5PUU5iZLw9Ow4NJyRJUAAAAAADAAAAAAM0AvkAGQAmAC8AAAEiBwYHBhUUFxYXFh8BNzY3Njc2NTQnJicmAyIuATQ+ATIeARQOASciBhQWMjY0JgIBVEdFKSpJNFUuIxAPIy5VNEkqKEZHUyU9JSU9ST4kJD4kHyoqPSsrAvgqKEZHVEltUFowIA4OIDBaT25JVEdGKCr+SiU9ST4kJD5JPSXQKz0qKj0rAAIAAAAAA2MCywAMABkAAAEyPgE0LgEiDgEUHgEXJicHJwYHDgEHIS4BAgMvTy4uT11PLy9P0RwfaGgeHUlkDwK+D2QBci9PXU8uLk9dTy8kEQp2dgoRKpRcW5UABAAAAAADsAK5AAwAGQAmAEIAAAEyPgE0LgEiDgEUHgEXNDcmJwcnDgEHIS4BNyIOARQeATI+Ai4BFyMVFAYiJj0BIyImNDY7ATU0NjIWHQEzMhYUBgGgLEsrLEpZSiwsStALJShiYVp/EgJ4PEzHLUwsLExaTCwBLUwlOw0TDjsKDQ0KOw4TDTsKDg4BcyxKWUosLEpZSixxISEZDnBvHp5oFGfnLUxZTC0tTFlMLb07CQ4OCTsOEw08CQ4OCTsOEw4AAAEAAAAAAqQC4wAFAAABJwkBNwECpDn+ngFiNf7WAq41/p3+njgBKgABAAAAAALCAuMABQAAJRcJAQcBASc5AWL+njUBKlI0AWIBYzn+1gAAAQAAAAADYgKdABwAABMUFjMhNw8BBhQWMj8BNjQvASYiBhQfAichIgadEw4B7lJ9VAkTGwv6Cwv6CxsTCVR8Uf4SDhMBgA8TAW5VCR0TC/kLHAv5ChIdCVVvARIAAAAAAQAAAAADYgKdABwAAAE0JiMhIz8BNjQmIg8BBhQfARYyNjQvAhchMjYDYhMO/hJSfVQJExsL+gsL+gsbEwlUfFEB7g4TAYAOE25VCR0SCvkLHAv5CxMdCVVuARMAAAAAAQAAAAADGgLhABwAACUyNjURJx8BFjI2NC8BJiIPAQYUFjI/AgcRFBYB/Q8TAW5WCRwTC/kKHQv5ChIdCVVvARIcEg8B7lJ9VQkTGwv6Cwv6CxsTClR7UP4SDxIAAAAAAQAAAAADHALjABwAAAEiBhURFS8BJiIGFB8BFjI/ATY0LgEPAjcRNCYCAA8TbVYJHRIK+QscC/kLEx0IVm4BEwLiEg/+ElJ9VAoTHAv5Cwv6ChwSAQpUe1AB7g8SAAAAAQAAAAADYgI3ABUAACUWNwE2NCYrASIHCQEuAQYdARQXARYB/xELATwLFRABDwv+3f7eCx8WCwE8DKgBDAFECh8WCv7XASkKARYPAQ8M/r4MAAAAAQAAAAACxQLkABUAAAE0JwEuAQYdARQXCQEGFBY7ATI3ATYCxQz+vQsfFgsBKP7YCxUPAQ8MAUMMAYEQCwE8CwEWDwEPDP7e/t4LHxYLATwMAAAAAQAAAAADYgIxABUAAAEiBwEGFBY7ATI3CQEeATY3NTQnASYB/xAL/sQLFQ8CDwsBIgEjCx4WAQv+xAwCMQz+vAofFgoBKf7XCgEWDwEPDAFDDAAAAQAAAAACxQLkABUAAAEUFwEeATY3NTQnCQE2NCYrASIHAQYBNgwBQwseFgEL/tcBKQsVEAEPC/69DAGBEAv+xAsBFg8BEAsBIgEiDB4WC/7EDAAABAAAAAADoAK3AAwAEwAgACkAACUiAyY0NxIgExYUBwIDIgcWIDcmAyIuATQ+ATIeARQOAScyNjQmIgYUFgIB47QICLQBxbQICLTivqCgAXyfn74oQygoQ09EJydEJyIxMUUxMUkBGwweDQEb/uUNHQ3+5QIv+fj4+f52J0NPQicnQk9DJz8wRTAwRTAAAAAAAwAAAAADngK3AAwAGQAmAAABMhMWFAcCIAMmNDcSFyIOARQeATI+ATQuAQMyPgE0LgEiDgEUHgECAOK0CAi0/jyzCQi04jNVMjJVZlUyMlUzIjkhITlEOSEhOQK2/uYNHgz+5QEbDB4NARp8MlVlVjIyVmVVMv7KITlEOSEhOUQ5IQAABQAAAAADmAL4ABIALgA1AEUAVgAAATEmJwcWFw4BIyInBxYzIBM2NAMnJiIPASYjIAMxBhcWFwcGFB8BFjI3ATY0JzABJj4BNzYXNyYOAQcGFBcHJic+ATMyFwMiJwcWPgE3NjQnBxYOAQcGA5IzRy89LTqncUg7M1JkAQyFBkEoAgYCbVJl/vSFCwszR14CAigCBgICmQIC/kEGECgcGBcvKFdJEw8PTz0uOqdxSDyHCQkvKFdHEQ4OLwQTKxwIAZhrQi84Xnh1GDMoARgLGgFBJwICbSj+6BgYa0JeAgcCJwICApgCBgP+mhw1JgcFBS4TBzIoIUohUDheeHUY/sMBLxIKNCkfRB8vHDQkBQEAAAAAAwAAAAADlwLxABMALQA2AAABJyYnBxYVFA4BIyInBxYzIBM2JwMnJiIPASYjIAMxBhcWFwcGFB8BFjI3ATY0ASY1ND4BMzIXA4wBMkaCDSxKLCIecFFjAQiDDAw6JwIHAmtRY/74gwsLMkZdAgInAwYCAo8C/hcPK0osJSEBlgFqQIIeIixKLA1wJwEUGBcBMicCAmwo/usXGGpBXAIHAicCAgKPAgf+dCAlLEosEAADAAAAAAN+AvkAFAAkAC0AAAEiBwYHBhQXFhcWMjc2NzY0JyYnJgMUBisBIiY9ATQ2OwEyFhUnIiY0NjIWFAYCAWdZVjI0NDJWWc5ZVjI0NDJWWUwEAygDBAQDKAMEGxEYGCIYGAL5NDJWWc9YVjM0NDNWWM9ZVjI0/cwCBQUC5wMEBAM9GCIYGCIYAAEAAAAAA1oDAwA4AAAlMjc2NzY1NCcmJyYOARYXFhcWFRQHDgEiJyYnJjU0PgE3FRQWPwE2NC8BJgYdAQ4BBwYVFBcWFxYB/F5RUC4wKCZECxkNBgo4ICEnJ4WfREImKDpnQBUObgwMbQ8VT4IkJjAuUFECMC5QUV5VS0oxCAQVFwgoPD9IUENCTicnQkNQRHdSDzISCQpNBxYJTQoKEjAQY0dKU15RUC4wAAAFAAD/4QNvAx4ACQAVADkARQBNAAABNTQuASIOAR0BARYyNjQnASYiBhQXEyIGFBYzITI2NCYrATU2NycGIyIuAT0BNCYiBh0BFB4BFxUjATQmIgYdAQYHFzY1BycVBh4BMzICZB83RjcfAcgJGRIJ/WMJGhIJlAwSEgwBdQwSEgycSzgqM0Q+YTYRGhA8bUicAcoQGhABBDAP2LABHzgjHgGp9CU6IiA5JAb9ngkRGgkCnQkSGgn9SRMYEhIYE1cHKCoiN2A9XQ4QEA5dSXRIBlgBwA4QEA5dGBcwLTJysD8kOyEAAAAAAwAA//0DawMCABsAJABRAAAlMjY3Nj0BPgE1NC4BKwEiDgEVFBYXFRQXHgEzAyImPgEyFg4BEzI3PgE1NCcmJyYjFTIXFhcWFRQGBwYiJy4BNTQ3Njc2MzUiBwYHBhUUFhcWAgEIEAUGLzwmQiYBJkImPS4GBREHKBMeAR0nHQEcFW5VT1cuKEE8NyUrLR0gRT5CqUE+RSAcLSsmNz1BKC5XT1WKKSUpNbMMTTEnQScnQScxTQyzNColKQHhHSgdHSgd/ZIYFksrMCgjFRQ7DA0VFxseMg4PDw4yHhsXFQ0MOxQVIygwK0sWGAACAAD//AKLAwUAGAAhAAAFMjY3NjURPgE1NC4BIg4BFRQWFxEUFx4BAyImNDYyFhQGAgEIEAUFLjolP0tAJTstBgQRIBMcHCYcHAQoJCgzAVILSzAlPyYmPyUwSwv+rjMoJCgCdxwnHBwnHAAEAAAAAAM0AvkAGAAsADkAQgAAJScmJyYnJjU0NzY3NjIXFhcWFRQHBgcGBwMiDgEVFBcWFxYXNjc2NzY1NC4BAyIuATQ+ATIeARQOASciBhQWMjY0JgIBECMuVTRJKilFR6dHRigqSTRVLiMPRHJDLyVAMTQzMUAmLkNyQyU+JCQ+ST4kJD4kHysrPSsrBw8fMVpPbklTSEUpKiopRUhTSW5PWjAgAqZDckQxTD5JOTExOUk+TDFEckP+kSQ9ST4kJD5IPiTPKzwrKzwrAAAAAwAAAAADgwLtAAAAJgA9AAAlEy4BLwIuASIGDwIOAhYfAQcGHgEzMj8BFxYzMj4BLwE3PgEPAQ4BHwEUBiIvASYjBzYTFx4BHwEeAQLDuQYdErpRCCEmIQhRuhIdDAgOiB8DDiEVEg+iog4SFCEPBB+IDgg/jQgIAiEEBAKoCwwDBxRDBRMLwQQCFAHKERcDG6QRFBQRpBsDFyIjDoW5EiIWCFVVCBYiErmFDSQGiggVC8ACAwFYBgFcAYGHCg4BHAEFAAIAAAAAA4MC7QAlAE8AACUGLwEHBiMiLgE/AScuAT4BPwI+ATIWHwIeAgYPARcWDgEjJzIfARYyNjUnJjY/ATYmLwEuAS8BJiIPAQYPAQ4BHwEeAQ8BBhYyPwE2AsMSDqOhEBEVIQ8EH4gOCAwdErpRCCEmIQhRuhIdDAgOiB8DDiEUwwwLqAIEBCECCAiNAgIEwQsTBVQCCQFUCxjCBAICjggHAiEBBQQCqAsVAQhWVggWIhO4hg0jIxYDG6QRFBQRpBsDFyIkDYW4EyIWmwVZAQMCwAsWCIoBBQEcAQ4LqgMEqhUFGwEFAooIFgu/AgQBWQYAAAAAAQAAAAADgwLtACQAACUiLwEHBiMiLgE/AScuAT4BPwI+ATIWHwIeAgYPARcWDgECwxIOo6EQERUhDwQfiA4IDB0SulEIISYhCFG6Eh0MCA6IHwMOIRQIVVUIFiISuYYNIyIXAxukERQUEaQbAxciJA2FuRIiFgAABQAA//8DfQMBABMAKAA5AEYAUwAAATIeARURFg4BIyEiLgE1ETQ+ATMFISIOAQcRFB4BFyEyPgE3ETQuAScHNjIeAQ8BDgEvAS4BPgEfAQMyFhcVFAYiJic1NDYhMhYXFRQGIiYvATQ2AsgxUzABMVMx/nIxUzExUzEBjv5yHzUgAR40HwGSHzUgAR40H3UJGhICCIEIFwpcCgIQGQpGfQ0SARMZEgESASoMEwETGRIBARMC0zFTMf6XMVMxMVMxAWkxUzE/HzQf/pMgNSABHjQfAW4fNSAC3gkRGQmFCAMHTwkaEwMHPAG4EQxmDRMRDGYNExEMZg0TEQxmDRMAAAIAAAAAAzwDAwAtAFYAAAEeARUUFxYfAhYXFhUUBw4BIyInJicmNTQ3Njc+ATIWHwIeARcmNjc2PwE2BwYPAQYXFgYHDgEnJicmLwEGFRQXFhcWMzI3PgE1NCcmLwEmJyYnJicCPwYKEhYmIw4zGSErKpFVUkZLKi8PDBQEEhYSBRMFChwVGDAtISwIChI6GQQTDwYJDA8jER8VEA0GGCckPThBRTw6RRcRJSgcEBcNEQYC+QMRCyQvOCYfDjExPkhLQD9JIyVES2QvQTg5Cg4OCjcMHCQPTp86Kh4DBVA6Tg07RBEhDQwECBMbFB4PUzdUPTcdHB4dZDo3LSInKRwTGxwcHwAAAAUAAAAAA4EC4gAvAD8AUwBfAGoAAAEyHgEdATMyFh0BBgcGBw4BBxUzMhYUBgchIiY0NjczNS4BJyYnJicmNj8BNTQ2NwUhIgYdARQeATI+AT0BNCYDHgEHDgEHBi4BNj8BNjc2PwE+ATcjHQE2NzY/ATQmJyErAQ4BFxUWFxYXAoQcLhtEIjEDHS9WFmpEbQ0SEAz+5Q0SEAxwRWsWRiodAwItIzY4KQEc/ugRFzBTYlIxFysKCQQKMRwKFAcHCgIREA4HAgQUzUQrGhEDAQsJ/dgwAwgMAQMRFB4C4RsvGycxIwYqKEEQP1YJaxIZEQERGRIBawlZQRM5KCojNAIBJyk6Aj0YENMwUzAwUzDTEBj++gQUChoxCgQJFBMEAQYRDg8DCgl1bg4OJBcYBAgOAQEOCAQYFxsPAAAEAAAAAAOhAo4ABwAPACQALwAAJSMnIwcjEzMTJyYnIwYPASU2MzIdASM1IwYjIiY1ND8BNCMiBxcOARUUFjMyNj0BAkRMN980TMxKNFEEBQEEBVABmjlLikMCKE04QX9xTkQ5cS8jJx8sOnaTkwIY/rffCxoYDd+VI5H2O0Q8M2wREF4vbgYjHxsjPi8lAAAHAAAAAAOBAwEAMAA3AD4ASABSAFwAZgAAATIWHwE3PgE3MzIWFRQPATMyFhcVFAYPAREUDgEHISIuAScRLgEnNTQ2NzMmNjc2NxMhFRQWOwEBIREzMjY3ASEiBh0BFBYzISUhFSEyNj0BNCYnIyIPATMyNjQmISMiBhQWOwEnJgGEFicPMi0OJhYPJzgFA1UeLAISDwUdMR7+Lx40HwIQFAIoHlsQHSQPEW/+/iIYyAE8/v7IFiEC/sX+6wgLCwgBFQFP/usBFQgLC7QIFg4vWxAWFv7sCBAWFhBbLw4DABEQPjgRFAI4JxAPCCgeeRMhCwP+/R00HwIcMh4BCQkgE3keLAIkShAHAf5v+RciATL+zh4WAdALCHMIC5mZCwhzCAuGEjsXHxcXHxc8EQAAAwAAAAADsQJEABsANwBDAAABMzIWFAYrASIOARQeATsBMhYUBisBIi4BND4BITMyHgEUDgErASImNDY7ATI+ATQuASsBIiY0NgchMhYUBiMhIiY0NgE7gA0TEw2AJkAlJUAmgA0TEw2AN103N10BYYA3XjY2XTiADRMTDYAmQCUlQCaADRMTyAEADRMTDf8ADRMTAkQTGhMlQEtAJRMbEjZdbl03N11uXTYSGxMlQEtAJRMaE6sSGxMTGxIAAAAAAwAAAAADgAMAACkALwBCAAABMhcWFxYXFRQfARYUBwYHIxQOASIuAS8BIyImNTQ/ATY3PQE0NzY3NjMTIxQWMjYDIg4BBxUUBg8BIScuAS8BNC4BAgFRR0QpKgMSKxAQDhO2KUZSRSoCAbAWIA0rFQIpKUVHU2DAOFA4X0JwRAISEScCgyESFAEBQ3IDACgnQ0VRhRwVLA8tEA4CKkYqJ0MoCB8XExAqFBwHeVNIRSkq/ZooODgCVEBuQoIZLxMlIBItGINEckIAAAAAAwAAAAADhALVACEASABVAAABPgE1NC4BIyIGFBYzMhYUBiMiBhQWMzIeARUUFjI2NTYmJT4BNTQuASIOARUUFhcOAhUUFjI2NTQ+ATIeARUUFjI2NTQuAScDMh4BFA4BIi4BND4BAwYTFSU/JQwTEwweLi4eDRISDSpJKxMXEwRE/uIsMDdfcV44MSs5VS8VGhY+bIFsPxUaFS5WOXIkQCUjP04/JCY/AW0VNh0pRCgVGRQyQjESHxEvTi4MFRUMRXQRHVoyOF03N104MlodF1NrOw0VFQ09aD09aD0NFRUNO2tTFgEyJT9IPyUlP0g/JQAAAAMAAAAAA4UCzwAgAD4ASgAAAQYPAQYvASYGBwYXEx4BMyEyNjcTNiYnJg8BBi8BLgEHHwEeAT8BNhcWFQMOASMhIiYnAyY3Mh8BFjY/ATYXEzIWFAYHIyImNDY3AdwKB4MDA2MYMwwLBUcHNyQBqyM3B0gFHhoWFGcDAoAPMxYmgA4vFWgDAgFIAxUO/lUOFgJIAQUBAWQVLw6EAgRlDREQC9INERALAr8HCboDATMMEBgUFv6ZIy0tIwFnGywGBAo0AQO6FQoNNbkUDAszAgQBAv6ZDhISDgFnBAEBMgsLFLoEA/5iERkRARIYEQEAAAMAAAAAA4EC1gAYAC4ASwAAATIWHwEhMh4BFREUDgEjISIuATURND4BMxcjIgYVERQWMyEyNjURNCYjISIvASYXIgYdASMiDgEWOwEVFBYyNj0BMzI2NCYrATU0JgFeFisQKwEzHzUfHzUf/ecfNR8fNR9qahgiIhgCGRgiIhj+zRgRKxCKDBBXDBABEQxXEBgRVgwREQxWEQLVEhArHzUf/oAfNR8fNR8BzR81HzohGP4zGCEhGAGAGCIRKxC2EQxWERgRVgwREQxWERgRVgwRAAAABAAA//sDgQL/ABsAKQBFAFIAAAEyFhchMhYUBiMhDgInLgEnIyImNDY7AT4CFyIOARQeATI+ATQuASMTMhYXMzIWFAYrAQ4CJy4BJyEiJjQ2MyE+AhciDgEUHgEyPgE0LgEBqjtaDAEUDhMTDv7sCTpTKzFFCmYNFBQNZgcuRCcaLRsbLTUtGxstG687WgxlDhMTDmUJOlMsMEYJ/usNFBQNARUHLkQnGy0aGi02LRsbLQFJSjkTGxQrQRwJCkUwFBsTJTwiQRstNi0aGi02LRoB90o5ExsUK0EcCQlGMBQbEyU8IkEbLTYtGhotNi0bAAAAAAMAAAAAA4UC/AAuAEAATQAAATIeARUUBgcWFxYXFg4BJicmJy4BIyIHBgcGFRQWDgEmJyY1NDc+ATcuATY3PgEBFhQPAQ4BLwEmNDYyHwE3NjIBIg4BFB4BMj4BNC4BAe8zVjMmIVRAFBIIAxUZCA8RLHA9VUlHKioCERoTAgEiIHVLKSUMHxpPAbgICNEIFwhrCREZCFS8CRj+fCI6IiI6RToiIjoC/DNWMitNGxo9FBcKGg8DChMRKi0rKkdJVQ0bEwMRDQ8RUklIaRkfXGMoIyf+FgkYCdEIAQdrCBkRCVO8CAGlIjpFOiIiOkU6IgAAAAACAAD//wN/Av8AIwAxAAABPgE1NC4BIg4BFRQWFw4BBwYVMzQ3Njc2MhcWFxYVMzQnLgEnIi4BND4BMh4BFA4BIwJ4LjU8ZHdkPDUuTHghIjctLEpNsU1KLC03IiF4xC1LLS1LWUstLUstAWwdYjk7ZTs7ZTs5Yh0YbElMU1lMSysuLitLTFlTTElsKy1LWUwsLExZSy0AAAQAAAAAA5ACuAALABIAGQAmAAABMjcBJiMhIgcBFhcFLQEGFREUBTY1ETQnBwEhMjcBBwYiLwEBFjMCAhYWATsUNv26LhIBPBcW/nkBAP7/CAMWCAj//lsCRS4S/vsYJE0kGP78FTMBVxYBOBMS/scWAdP9/A8l/nEmDxAlAY8lDvv+yREBAhgjIxj+/xIAAAEAAAAAA38DAQAwAAAlFhcWMjc2NTQvASYjIgYPAQYjIicmJy4BJyYnJjQ/AT4BNTQvASYjIgYHBhUUFxYXAVNeYmqnNyMbfh0WDRoPHQcJBwoSHx0/GBoKBAYdDw4UWRQlFCoROjw3XtdfOD08KCkjE1oUDg8dBwUKGhg/HR8SCBIGHg8aDRYdfRwSEjdTVWlhXgACAAAAAAN7Av0AJwBMAAAlMjY/ATY1NC8BJgYPAQYuAScmJyY2PwE+AS8BJiciDwEOARUGHgI3BicuAScmNzY3Njc2Mh8BFg8BDgEeBDY/ATYfARYUDwEGArgzRx4JIjNxGzoXHg0cNxY1FgQCBh4XAhNPIyslJwohHQFlu8JUSFtVnjE0AQEtBAQRJQpLDhEiFAEgMy4+Ki4UIhEUcREQBigDHiEKJiYqJE8TAhceDBIvFjUjBwwGHhg6G3EyASMIHkczVMK7ZTwBMi+eV15IQycDAw8QcRQRIxMuKjstNyABFCIRDksLJBEILAAAAAAFAAAAAAORArgADQAXABsAHwArAAA3ITI2NRE0IyEiBhURFAkBNjMhMhcBBiIFERcHAREnNwEiJzcXFjI/ARcGI+QCRTI1cf26MjUBZP7vDBECPxEM/u8WK/690M8Cr8/P/YkQC9gYI08kF9gLEEk5NwGPcDk3/nFwASUBDQUF/vMWnwGTzM0Blf5szMr+NgXWGCMjGNYFAAMAAAAAA4QC/wAbADUAQgAAJSM1NCYiBh0BIyIGFBY7ARUUFjI2PQEzMjY0JgM0LgEiDgEVFBYXDgEHBhUzNDc2NzYzMj4BByIuATQ+ATIeARQOAQNobRAYD20LEQ8Mbg8ZD20LEQ+WO2R3ZDw1Lkx4ISI3LStLTFk8ZDvbLEstLUtZSy0tS8BuChEPDW0PGQ9tCxEPDW0QGA8BZDtlOztlOzliHRhsSUtUWU1KLC07ZWksS1lMLCxMWUssAAAAAAIAAAAAA74CwwAdADYAACUyNj8BJicmPQE0NjsBNS4BIyEiBhURFBY7ARUUFgUyNj0BMzI2PQE0JiMhIgYdARQWOwEXHgEBFwgPDFsQBwlRR9kEPTX+WDZAQDYzDwIBDQ8gNkBANv7OOD4/N2NwCw8rCQtUDBEWI85HUAwwOD03/tA3QloPESsSDlpCN7w3PTw4vDdCZgsJAAAAAAMAAP//A4IDAAAUAC0APAAABTI3Njc2NCcmJy4BBwYHBhQXFhcWEyIHBgcuATU0NzY3NjIXFhcWFRQGByYnJicyPgE1NC4BIg4BFxQeAQIBZ1pXMzU1M1hZz1lXNDQ1M1daZ1FDPB8mKysrSEqvSkkqLConHzxDUSQ7IiM7RzsjASI7ATUzV1rOWlc0NAE1NFdazlpXMzUBABoXJSxuPFhKSSosLCpJSlg9biskGBpAJUEoJUAmJkAlKEElAAAAAAEAAAAAA4EC4wAnAAATNDc2NzYyFxYXFhQHBgcGIyInMSYHBgcGBwYHBiY3Njc2JyYnJicmgDQzV1rRWVczNTUzV1lpIiESEgsZHRMiJxIEDh4LDhcEDzwiIwGgV0tJKywsK0lLr0tJKywFBQcEEBIJEAoFCg8fICYRAwstPUAAAwAAAAADgQMBABQAIwAxAAAhMjc2NzY0JyYnJiIHBgcGFBcWFxYTMh4BFRQOAS4CNSY+AQEXDgEiJic3Njc2MhcWAgFnWVc0NTYzV1rOWVczNTUzV1loIzsjIjxHOyIBIzsBCQEseYN5LAIbOEGhQTg1M1dazlpXMzU1M1dazlpXMzUCWSZAJShBJgElQSglQCb+SAUuMzMvBCcaHh4aAAMAAAAAA5MCwQApAEIAWwAAJTI2PwEWOwEXFhcWMzI2PQEzMjY9ATQmKwE1NCYjISIGFREUFjsBFRQWNzQmKwEiJjURNDYXITYWHQEjIgYdARQXBwUnLgErASImPQE0NjMhMhYdARQGKwEiBhUBKgsTDV8eO2FeDgcJCg4QCzZAQDUtQDn+bzhCQjglDxsMCjcmKSkmAYwmKbc3PgVnAbJaCQ4LXCQnJyQBCyMoKCMeCQxeCQxUIlANBAUTEEM+NqY2PhU5QEA5/v45QEwREoIMDCgnAQAnKQEBKScUPTemFxJgHlAIBScloyQnJySjJScLDAACAAAAAAOCAuMAHABEAAAlNhcWMzI3PgE0JicmIgcOARUUFh8BOAEjFxYXNgM0NzY3NjIXFhcWFAcGBwYjIicxJgcGBwYHBgcGJjc2NzYnJicmJyYBgiIjHR1aTktYWEtOtU5LWDgzDwEFJwMa9zQzV1rRWlczNDQzV1poIyESEQwZHBQhJxMEDh4MDhgFDjwiI5QMCAQlJHuPeyQlJSR7RzhnJgoDHS8OARBXS0krLCwrSUuvS0krLAUEBwQPEgoQCgQJDyAgJhEDCi0+QAAAAgAAAAADgAMBABsAMwAAAREUBiMhIiY1ETQ2OwEyFhceATI2Nz4BOwEyFgEXFg4BKwEVFAYrASImPQEjIi4BPwE2MgOANib9tyY1NSZQEx4EDlhzWQ0FHhJDLzr+mokLARUPQBYPSQ8VQBAUAQuJCx4Bbv7uJjY2JgESJjUWETdGRjcRFjQBYIgLHhaJDxYWD4kWHQyICwACAAAAAAOAAwAAFwBEAAABJyYiDwEGFBYyPwERFBYyNjURFxYyNjQ3IgYUFjMyFhURFgYjISImNRE0NjMyNjQmIyIOARURFB4BMyEyPgE1ETQuASMC0KYRMRKlChQbCn8UGxR/ChsTHQ4UFA0eKgErHf4VHioqHg4TEw4lQCUlQCUB6yU/JiY/JQJIphERpgkcEwp//poOExMOAWZ/ChMcaRQbFCoe/n8eKioeAYEeKhQbFCY/Jv5/JUAlJUAlAYEmPyUABgAAAAADlQLLAB0AJgAvAEYAUABaAAABMhcuAiMiBgcGFRQXFhcHNxcWFxYzMjcmNTQ+AScyFhQGIiY0NgciJjQ2MhYUBgU0Jy4BIyIOARQeATMyNzY/ARcnNjc2JSImNDYzMhYUBjMiJjQ2MzIWFAYCkA8MDFN8RU6DJiceHTccZBEbDhYUDQ4JQW9XEBQUIRoatxEaGiEUFAJXIyFwP0NvQUFvQxEXDRsGThUuGR3+vgsREQsQFBSNChISChAUFAIDATlbNUE3OUI6Mi8nVjIDBgIDAR0fPmg8ThQgExQfFEcUHxQUIBPlNzEvODhfcV84BAMGAitHIigtUhEWEhIWEREWEhIWEQAAAAMAAP/1A4ADCgAJABEAKwAAATc2NC8BJgYPAQE3AScBBwYWAyEyNjURBxEUBiMhIiY1ETQ2MyE3ISIVERQDWRwKCggJGgkd/nVMAVg2/qkjAgmdAco1OT8bFf45Hh8fHgFQP/5vegKtHAsZCgkJAQoc/jYhAVc1/qhJBQr+4T08AbE//pEdIB8eAboeHz95/kB5AAABAAD//ANHAwAAPgAAJQYnJicjFgcGBxYXFgcGIyInBiMiJyY3NjcmJyY1BwYHBicmJyY3Njc2PwEmNzY3NjIXFhcWBxcWFxYXFgcGAzwLHQ8MAQETFSUeExwICGFTNTVSYgcJHRMeJhQTDhANEQgFAgMEBQ8NIw0DGRo1OaY5NRoZAw0jDQ8FBAMChwEoFBQmJywgCQsRDwwGBgwPEQsJICwnJhUYDhUBAQ8SHiYwKlceXEZMKS0sKUtHXSBWKTAmHhIQAAAAAAIAAAAAA4AC/wAbADMAAAERFAYjISImNRE0NjsBMhYXHgEyNjc+ATsBMhYFJyY0NjsBNTQ2OwEyFh0BMzIeAQ8BBiIDgDYm/bgmNTUmUBMeBA1Zc1gOBB4SQy86/meJCxUPQBYPSQ8VQBAUAQuJCx4Bbf7vJjY2JgERJjYWEjZHRzYSFjUKiQseFYoPFRUQiRUeC4kKAAAACQAA//0DggL/AAgAEQAaACMAKwBEAE0AVgBeAAAlIgYfAT4BNyEnFRYzMjcnJgYTIgcXFjY9ASYFBhUUFzc2JiM3DgEHITI2JwcVFB8BFjsBMj8BNj0BNC8BJisBIg8BBhUlBwYWOwE2NTQDERQWPwEuAScBHgEXETQmBwH2AwICjzpiI/61mk5WJybrAgSkJSbrAgRO/k0mCOsCAgIQO2IjAU0CAgKzAlwDA4IEAlwCAlwDA4IEAlwCAh7qAgICyiWqBAKOFUw0/cAVTTQFAqkFAo8VTTNFyyUI6gICAhAI6gICAsom3E5XJyXrAgTGFU00BQKbggQCXAICXAMDgwMCXAICXAMCCeoCBE1YJgEa/rUDAgKOO2Ij/j87YiMBTAMCAgAAAAAEAAAAAAOBAq0AHAAxAEgAXgAAJTI2NRE0JiMiBwYPAQYrASIGHQEUFjsBMh8BHgElFjY3PgE0JicuAQ4BFx4BFAYHBhYFIi8BJisBIj0BNDsBMjY/ATYzMhURFDcWNjc+ATQmJy4BBw4BFx4BFAYHBhYB+BEWFhEMCggPmwMFYiMjIyNiBQObDRUBKAoVByEkJCEHFRMDCBsfHxsIA/7ZAgOSCg5uExNuBwsGkgMCBagIFgcTFhYTCBUICwMIDhERDggDUBYQAg4RGAYFDYkDJCaDJSQDiwsKQwcFCi51fnUuCgQNFgopZWtmJwsWBAOECROMEwMGhAMF/jgFVwYEChpITUgbCgQGBxcLEzg6OBQLFgAFAAAAAAM6Av8AHwApADYAQwBPAAABEx4BMyEyNjcTMzI2NCYrATU0JisBIgYdASMiBh4BMzc0NjsBMhYdASMTIiY1EzQ2MhYVAw4BIyImNQM0NjIWFRMUBjcUBiImNRE0NjIWFQEKFgIlIQExISUCFikLDw8LkSsjgiMrkAsQAQ8LwRQQdRAUvdEKDQ8OEw4QAQzvCg0QDhMODw2BDxMODhMPAkn9/CEkJCECBA8WEDIkKyskMhAWD2gPExMPM/3KEAsBmgoQDwv+ZgwPDwsBmwsODwr+ZgsQGwsQEAsBmgoQEAoAAAAAAwAAAAADgwKnABsAMABGAAAlMjY1ETQmIyIGDwEGKwEiBh0BHgE7ATIfAR4BJRY2Nz4BNCYnLgEOARceARQGBwYWJxY2Nz4BNCYnLgEHDgEXHgIGBwYWAeURFRYQDBIOjQMFXyIkASMiXwUDjQwVAUEJFQcfIyIgBxUSAwcbHh4bBwN3CBUHExUVEwcUCQoDCA4PAREOBwNbFRAB/xAXCg2FAyUkfCQlA4YLCkEGBAoscntxLQkEDBULJ2JpYiYKFlEGBAkZRktGGgoEBgcWCxM1OTYTCxUABgAAAAADRwL/AB8AKQAzAEAATgBbAAAlEzMyNjQmKwE1NCYrASIGHQEjIgYUFjsBEx4BMyEyNgE0NjsBMhYdASMDIiYnAyEDDgEjJzI2NRM2JiIGBwMUFiMyNicDNCYiBhUTFBYzNxE0JiIGFREeATI2NQLzGCIKDw8Kli8ngCgulQsPDwsiGAEuJQE7JC7+sRMQeBATvjkPFAEYAacXARQPMggMCgEMEQsBCgvCCAwBCgwRCwsLCHsMEQ0BDBEMUQH2DxUQMyUsLCUzEBUP/golLCwCfw4TEw4w/bkUDwHw/hAPFDwNCgFqCQ0NCf6WCg0NCgFqCQ0NCf6VCQ0XAWoJDQ0J/pUJDQ0JAAIAAAAAA4IClgAnADkAAAE0LgEjISIOARURFB4BMyEyPgE1NDY7ARcWNjc2NRE0JiMiDwEGJicBNTQ2MzIfAR4BBwYPAQYmJyYC4xwwHP5tHTAcHDAdAZMcMBwHBQNZEB8FAhkRBwVaBAgB/nkZEgwKkA4ICQUIkA8iCQcCLRwwHBwwHP6iHDAcHDAcBQcbBRERBgYBLBIZAhsBBAT++LUSGQdbCSIPCAVbCQcPCwAADAAAAAADgAMAAAwAGQAoADUAQgBPAFwAaQB2AIMAkACdAAABIgYdARQWMjY9ATQmBw4BHwEeAT4BLwEuAQUmBg8BBhYXMRY2PwE2JgUGFh8BFj4BJi8BJgYFLgEPAQ4BHgE/AT4BFzQmKwEiBhQWOwEyNiUUFjsBMjY0JisBIgYFNiYvASYOARYfARY2JR4BPwE+AS4BDwEOAQU+AS8BLgEOAR8BHgElFjY/ATYuAQYPAQYWFzI2PQE0JiIGHQEUFgIACg4OFA4OygkFBTwGExEGBT0FEwF3CRMGPAUFCQkTBT0FBf3qBQYIaQkTCwUJaQkUApUGEwlpCQUKEwlpCQUvDwp5Cg4OCnkKD/0ADgp5Cw4OC3kKDgLMBQUJaQkTCgUJaQkT/WwFFAlpCQUKFAlpCAYCEgkFBT0FExIFBTwGE/6JCRMFPQUFEhMGPAUFyQoODhQPDwMADgt4Cw4OC3kKDjMFFAlpCQUKEwlqCAYFBQYIaQkUBQUFCWkJFIgJEwU9BQUSEwY8BQUJCQUFPAYTEgUFPQUTtwsODhUODgoKDg4VDg7LCRMGPAUFEhMFPQUFCQkFBT0FExIFBTwGE5UFEwlpCQUKEwlpCQUFBQUJaQkTCgUJaQkTOQ8KeQoODgp5Cg8AAAAHAAAAAAOTAsgADgAxAD4AVABhAGoAcwAAATYuAQYmNjc2HgEHDgEmASInJicmNTQ+ATc+ARYHBjc2MTYyFxYHBhYXFhcWBgcGBwY3LgIOAh4CPgIDDgEWNzYXFhcWBwYWNjc2Jy4BJyYHAw4CLgI+Ah4CJyYOAR4BPgEmNyYOAR4BPgEmAukGDiAiEggQJUAcDAUcFf7dVEtNLjE9cDk2VCEQBRcBPWASFBQDBgo9FxUfLzFHToMERnGBaDgIRnGBaDgUEwgVEzYwLRUVEQYYIQYSDQxJMzY5eQ03RD8mBxs0QD4qCpIPIhMIHiMTCCIGDAcDDA0HBAHgEiERBxYcBAgkQyQPBRX+cRkaLjI+M3NvIB0CODUSCAEZGhwzCgcDEygmXyosGRzhKkEfDTROVEEfDTROAcMFIBoECxoZMDI1EhgFEjg3NVEREw3+IR0oDBQsOTYlDhArORIGDB0fDgweHxsCBAwLBQULDAAAAAQAAAAAA4ICmgAjADYAOgBMAAABHgIXFTc2Fh8BFh8BERQGIyIvARUOAQ8BISIuAScRND4BNwUhDgEHERQWFyEyNj8BMRE0JicXDwEXJQcGJicmPQE0NjM2HwEeAQcGAmAlQScCNBIrDwYIAwEiGBAOOwdJMwb+qSZAJwIlPyUBWP6uIDACLSABViAvAgEtIN5UAVX+z38KFAUEDwsHBYAJBgYDApoBJD8lBCULBA8HDQ8G/u0ZIggoAjJGBAElPiYBHiVBJwE8ASwh/uQhLwItIAUBGCAvAmA5lTt2SwUFCgYGlQsOAQRKBhQJBgAAAAIAAAAAA4EC+AAXAEMAAAEXFjI/ATY0JiIPARE0LgEGFREnJiIGFCUiBhQWMzIWFREUBiMhIiY1ETQ2MzI2NCYjIg4BFREUHgEzITI+ATURNC4BATCmETIRpgkTHAmAExwTgAkcEwHPDhMTDh4qKx3+FB0rKx0OFBQOJUAlJUAlAewlQCUlQAHApRISpQocEwp/AWYOEwEUDv6afwoTHNYUGxQqHv5+HioqHgGCHioUGxQmPyb+fiVAJSVAJQGCJj8mAAAEAAD//wOCAwEAFAApAFUAXgAAITI3Njc2NCcmJyYiBwYHBhQXFhcWNyInJicmNDc2NzYyFxYXFhQHBgcGJzI2PQE0Njc2NzY1NCcmIyIHBgcGFRQWMjc2PwE2MzIWFRQHBgcGBwYdARQXMjY0JiIGFBYCAWdaVzM1NTNYWc9ZVzQ0NTNXWmdYSkgqLCsrSEqvSkkqLCsrSEtfDhERFSANESMiMi8hHggDEBUHBQcHEyQaHwwJHBcLDR0RGBgiFxg1M1dazlpXMzU1M1dazlpXMzVAKypJSq9LSCsrKytIS69KSSor8g8MBA8XDhURFh8tGxgTEhwLCAsPBQMKCCEaFhIOChMQDxMZBR5xFyEXFyEXAAACAAD//wOCAv8AFAAqAAAhMjc2NzY0JyYnJiIHBgcGFBcWFxYnIiY0NxM2MhcTFhUUBiIvASYiDwEGAgJnWVczNTUzV1rNWlYzNTUzV1kuCQsDiwklB4wDCxIGfQUIBX0GNTNXWc5ZVzM1NTNXWc5ZVzM1vwsQBwFjFhb+nQgGCQsGfQUFfQYAAQAAAAADdAMBABwAACUyNjURITI2NCYjIRE0JiIGFREhIgYeATMhEQYWAgEQGAEjEBgYEf7eGCEY/t4QGQEYEAEjARgLFxABKxghGAErEBcXEP7UFyEY/tUQFwACAAD//wOCAv8AFAAhAAAhMjc2NzY0JyYnJiIHBgcGFBcWFxYTIi4BND4BMh4BFA4BAgJnWVczNTUzV1rNWlYzNTUzV1lnHzUgIDU+Nh8fNjUzV1nOWVczNTUzV1nOWVczNQELHzY+NR8fNT42HwAAAgAA//8DgQMBABQAIAAAITI3Njc2NCcmJyYiBwYHBhQXFhcWAyImNDYzITIWFAYjAgFnWlczNTUzWFnPWVczNTUzV1o4EhQUEQE/ERQUETUzV1rOWlczNTUzV1rOWlczNQFeEh8SEh8SAAAABQAA/+ADbQMeABIAHgBBAE0AXAAAATIWHQEXNTQuASMiBg8BFzU0NgEWMjY0JwEmIgYUFxMiBhQWMyEyNjQmKwE1NjcnBiMuAj0BNCYiBh0BFB4BFxUBNC4BBh0BFAcXNjUFMjcnBiMiJj0BJxUUFxYB7CEqPCI+JzRJCAE7KgFtCRkSCf1pCRoRCJMMEhIMAXIMEhIMm0o4KjNDPWA2EhcSPG1HASsRFxIFMQ7+6ykdMQcNHyQ9JCMC5DAkvz36KUIlQDILOikkMP1TCRIZCQKXCRIZCf1OEhgSEhgSVwYoKiIBNl88XgsREQteSHNHBlcBvQsRARILXhcXMC0xiBEwBycfGD5OQiQiAAEAAAAAAz8CvwAbAAA3BhQWMj8BFxYyNjQvATc2NCYiDwEnJiIGFB8BzgwYJA319QwkGQ309A0ZJAz19Q0kGAz1iwwkGQz29gwZJAz19QwlGAz19QwYJQz1AAAAAgAAAAADgQMAABUANgAAJTI3Njc2NCcmJyYiBwYHBhQXFhcWMyciJjUxND8BJyY0NjIfATc2MhYUDwEXFhQGIzEiLwEHBgIBZlpXMzU1M1dazlpWMzU1M1dZZ4cNEwpwcAkSGwhxcgkZEwlxcAoTDQ0JcXAJATQ0V1nOWlczNTUzV1rOWVc0NNgTDQ0JcXEIGxIKcHEKExoJcXAKGhMKcXEKAAADAAD//wOCAwAAFAApAD8AAAUyNzY3NjQnJicmIgcGBwYUFxYXFjciJyYnJjQ3Njc2MhcWFxYUBwYHBicyPwE2Mh8BFjI2NTQnAyYiBwMGFBYCAWdaVzM1NTNYWc9ZVzQ0NTNXWmdYSkgqLCsrSEqvSkkqLCsrSEvyCgWDBQgFggYTCwOQCSYJkAMLATU0V1nPWVc0NTU0V1nPWVc0NUAsKklKr0tIKiwsKkhLr0pJKix8BoIFBYIGCwkGCgFwFhb+kAgRCwAAAAMAAAAAA4IDAQAUACkANgAAITI3Njc2NCcmJyYiBwYHBhQXFhcWNyInJicmNDc2NzYyFxYXFhQHBgcGAyEyNjQmIyEiBhQWMwIBZ1pXMzU1M1dazlpXMzU1M1daZ1dLSCorKypISq9KSSosKytIS+4BLhAUExH+0hEUFBA1M1dazlpXMzU1M1dazlpXMzVALCpIS65LSCsrLCpIS65LSCosASAQHhERHhAAAAADAAAAAAOCAqoACwAeACgAADchMjURNCMhIhURFAEmIg8BJyYiDwERNDYzITIWFRElMjY0JiIGFBYz5wI0Zmb9zGYCHRc1FpM9FSwUYhoZAjIYG/4mIC0tPy0tIFJlAY5lZf5yZQEtFBSDNhMSWAFnGRoaGf6ZoC1ALS1ALQAAAAMAAAAAAwsDHQAPABsAUAAAATU0LgEiDgEdARQeATI+AScUBiImPQE0NjIWFQMiBh0BFBYzITI2NTE0JisBNT4CPQE0JicjIgYdARQOASIuAT0BNCYnMSIGHQEUHgEXFSMCiCI+Tz0iIj1PPiI4K0grK0gr9QwQEAsBTQwQEAuLRmw8EAsBDBA0X35fNBAMDBA7bEeKAaHqKkIlJUIq6itCJSVCKyoxMSrqKTExKf2uEQsBCxEQDAwQVwZEckhMCxABEQtKP181NV8/SgsQARELTEhyRAZXAAMAAAAAA4IC/gAWACIALwAAITI3EzY0JiIHBQYHBhUUFxYXBRMWFxYDJyY0NyU2PwEHBgcDIi8BNzY3BwYHAwYHAk0kFvAKFSQa/YsYDhARDR8BCEwKCg1d/AgHAe4VKBgOLBGBAwNN/BUqDRIHuwMEOgJxGyMVCvEKDQ8TFw4KCU3++yENEgF8TQMHA7sIEwsLJBD92Qj8/BU2HSUU/hIHAQAAAwAA//0DggMBABQAKQBIAAAFMjc2NzY0JyYnJiIHBgcGFBcWFxY3IicmJyY0NzY3NjIXFhcWFAcGBwYnMj8BFxYyNjQvATc2NCYrASIPAScmIgYUHwEHBhQWAgBnWlgzNTU0V1rPWlczNTUzWFloWEpJKiwsKkhLr0tIKywsKklK2Q0IbGsJGRIJa2sJEQwBDAlsbAkZEQlrawkRAjUzWFnPWlc0NTUzWFrPWVgzNUAsKklKsEpJKiwsKklLr0pJKiyhCWxsCRIZCWtsChgSCmtrCREaCGxrCBoSAAMAAP/9A4EC/wAUAEIASwAABTI3Njc2NCcmJyYiBwYHBhQXFhcWEyI9ATQ3Njc2NzY1NCYjIgYPAQYHBiImNTQ3Njc2MzIXFhUUBwYHBgcGHQEUBgciJjQ2MhYUBgH/Z1pXNDU1NFdaz1pXMzU1M1hZYSAOCxkdCQ0hGxMeCQYIBQgXEAMIICMxNSMmEw0iFgkKEQ0RGRkiGRkDNTNYWs5aVzQ1NTRXWs9ZWDM1AS8fBRsUEBEUCw4TFxwTEAgKBAUPDAkLHRMUGRwvIRgRFw8LDBAFDBBxFyIYFyMXAAAAAQAA//0DhAMBACMAAAUyNxM2NCYiBwUGBwYVFBcWHwEWNjcBNjIWFAcBDgEfARYXFgJNJBfxChUkGv2IGg0QEQ0fxxIWDAGTBAcGA/6ICgMFOgoKDgI6AnUbIxUK8goODxMXDQoKPAYDCwF5AwYHBP5sDBYTwiENEgAAAAMAAP//A4IC/wAUACkARgAAITI3Njc2NCcmJyYiBwYHBhQXFhcWNyInJicmNDc2NzYyFxYXFhQHBgcGJzI2PQEzMjYuASsBNTQmIgYdASMiBhQWOwEVFBYCAmdZVzM1NTNXWs1aVjM1NTNXWWdXSkkqKysqSEqvSkgrKysqSUpYDxF2EBQBExB2ER4QdRETFBB1EDUzV1nOWVczNTUzV1nOWVczNUArKkhLrkpJKisrKklKrktIKiuNExBvER0RdhETFBB2ER0RbxATAAIAAP/gAxEDHgAPADsAAAERNC4BIg4BFREUHgEyPgEBIgYUFjMhMjY0JisBNT4CPQE0JiIGHQEUDgEiLgE9ATQmDgEdARQeARcVAnofOEY3Hx83Rjgf/ssMEhIMAXcMEhMLnUhuPBIYETZie2I2EhcSPG5IAX8BHiU6IiI6Jf7iJToiITv+whIYEhIYElgGSHVIXgwSEgxePGE3N2E8XgwSAREMXkh1SAZYAAADAAAAAAOcAsEACwAUACgAADchMjURNCMhIhURFAEiJjQ2MhYUBgMiJj0BNzYzMh8BNzYyHwEVFAYj0AJebm79om4BByQzM0czM7sZHWsXGRsXQ6caPhmhHhk8bAGsbGz+VGwBOTNHMzNHM/7/HRoVXhUWPJQXF5U2GR0AAwAA//wDSwMBABkALgA4AAABIzUuAiIOAR0BIyIGFREUFjMhMjY1ETQmAxQGKwEiJjU3LgE1NDYyFhUUBgc0NyE1ND4BMh4BFQMIMQE5Y3VjOjIbJycbAhIcJibzDwoxCw4ODhEnNycRDmH+9yQ8SD0kAb9wOWA5OWA5cCYb/r8bJiYbAUEbJv7GCg4OClMIHREaJiYaER0IAuVwIzsjIzsjAAAEAAAAAAN+AvkAFAApADIAQgAAASIHBgcGFBcWFxYyNzY3NjQnJicmAyInJicmNDc2NzYWFxYXFhQHBgcGAxQWMjY0JiIGFyMiBh0BFBY7ARY2PQE0JgIBZ1lWMjQ0MlZZzllWMjQ0MlZZZ1ZJSCorKypISaxJSCorKypISX8YIhgYIhg9KAMEBAMoAwQEAvk0MlZZz1hWMzQ0M1ZYz1lWMjT9SCsqR0qrSkgpLAErKkdKq0pHKisB0REYGCIYGHAEA+cCBAEFAucDBAAEAAD//AM/Av0AGQAjACcAPQAAASM1NC4BIg4BHQEjIgYVERQWMyEyNjURNCYlND4BMh4BHQEhASERIQMUBisBLgE1Ny4BNTQ2MhYVDgEHNBcDBjg4X3BeODgXISEXAg0XISH+TClFUUUo/tQBnf3zAg3SDQkrCQwMDQ4iMCIBDgwEAeRLOF44OF44SyEY/okXISEXAXcYIUsoRSkpRShL/lABd/7vCQ0BDAhJBxkPFyEhFw8ZCAEYAAAAAAQAAAAAA4YCygAdACoANQBGAAA3ITInETYrASImLwEmJyYrASIHBg8BDgErASIVERQlIi4BND4BMh4BFA4BEyImNDYyFh0BFAYHMj4BNTE0LgEjMSIOARQeAegCNmgBAWhNEhIMGg0OEBmCGRANDhoMEhJLZwGCMVIwMFJiUjAwUrsRGBgiGBj9IzwjIzwjIzwjIzxXZgFYZggNHg4HBwgGDh4NCGb+qGZpMFNiUzAwU2JTMAEEGCEYGBABEBjSIzskIzwjIzxGPCMAAAQAAAAAA4EC5gAYACEAKgAzAAAlMjY/ATMyNjURNCYjISIGFREUFjsBFRQWExQGIiY0NjIWFxQGIiY0NjIWFxQGIiY0NjIWAVAKEQ1+601SUk3+QE5SUk4QEUcfKh8fKh+uHykfHiofrh4qHx8pHxMKDHNTTAELTVJSTf71TVJlEBQBnxQfHykfHxUUHx8pHx8VFB8fKR8fAAAAAAUAAAAAA4ACxwAdAD0ASwBWAGYAADchMjURNCsBIiYvASYnJisBIgcGDwEOASsBIhURFDciJjURNDY7ATI2PwE+ATsBMhYfAR4BOwEyFhURFAYjJTI+ATQuASIOARQeATMTMjY0JiIGHQEUFgciLgE0PgEyHgEdARQOASPpAjBmZkwSEgwaDQ0QGIIYDw4NGgwSEkpmZxgbGxhWFhsMGg4VFmAWFQ4aDBsWWBkaGhn+6TBSLy9RYVIvL1Iw6hAYGCEYGNkjOyIiO0Y7IiI7I1tkAVVkCQweDgYHBwYOHgwJZP6rZDQaGQFPGRoKDR0QCgoQHQ0KGhn+sRkaNC9SYVIvL1JhUjABAhchGBgQARAX0CI7RjsjIzsiASM6IwAAAAIAAAAAA4EDAAAUACkAACEyNzY3NjQnJicmIgcGBwYUFxYXFjciJyYnJjQ3Njc2MhcWFxYUBwYHBgIBZ1pXMzU1NFdZzlpXMzQ0NFZaZ1dLSCorKypIS65LSCosKytISzUzV1rOWlczNTUzV1rOWlczNUAsKkhLrktIKiwsKkhLrktIKiwAAAABAAAAAAN/ArAAFwAAARcWFAcBBiIvASY0PwE2Mh8BFjI3ATYyA2QODQ3+IwwiDc4NDQ4MIwyFDCMMAZQMIwKkDwwjDP4jDAzPDCIMDwwMhQwMAZQMAAAABQAAAAADgQLmABkALgA4AEEASgAAJTI3Nj8BMzI2NRE0JiMhIgYVERQWOwEVFBY3NTQmKwEiNRE0MyEyFREUKwEiBgcnNCYiBhQWMjY1MzQmIgYUFjI2NzQmIgYUFjI2AVkMDAkReN5OUVFO/kFNUlJNERQgDA4qaGgBvmdn4Q8RCkEcJhscJRueGyUcHCUbnxwmGxsmHBcHBg9rUk0BCU1SUk3+9kxSWxQYQGQPC2gBCWdn/vdoBgrvEhwcJRwcExIcHCUcHBMSHBwlHBwAAAMAAAAAA4ADAQAUACkANgAAITI3Njc2NCcmJyYiBwYHBhQXFhcWNyInJicmNDc2NzYyFxYXFhQHBgcGJzI+ATQuASIOARQeAQH/Z1pXMzU1M1dazlpXMzU1M1daZ1dLSCorKypISq9LSCosKytIS1dBcENDcINwQkJwNTRWWs5aVzM1NTNXWs5aVzM1QCwqSEuuS0grKysrSEuuS0gqLExCcIRwQkJwhHBCAAACAAAAAANAAt0ALABJAAA3MjY9ATY3NjMyFx4BFxYzMjc2NzY1ETQmIyIHBiInLgEnJiMiBwYHBhURFBYlIicmJyYnJiMiBxE2NzYzMhceARcWMzI3EQYHBt8LEA0SHiItMBxqHC0qJxcTFikVEAYSMFEuG2odMC0nFxMXKREB2ycrGjI4HjIwPyAEFhomKi4bah0wLDcoBBYaHg8MxwUEBwoGIQUKBAQKEi0Baw4RBQsKBiEGCgQEChIs/a0LEOgJBg8RBwoNAVEKCAoKBiAHCgz+sQoICgABAAAAAANBAt0ALAAANzI2PQE2NzYzMhceARcWMzI3Njc2NRE0JiciBwYiJy4BJyYjIgcGBwYVERQW3gwQDRIeIi0wHWobLikoFxMWKRUQBhMvUi0cah0wLScYExYpEBwQDMcFBAcKBiEGCgUEChItAWwOEAEFCwoGIQYKBAQKEi39rQwQAAAAAgAA//8DgwMDAD8ATAAAISYnNzYuAQ8BJic3PgEmLwE2NxcWPgEvATY3Fx4BNj8BFhcHBh4BPwEWFwcOARYfAQYHJyYOAR8BBgcnLgEGBzcyPgE0LgEiDgEeAgGqPDUCARgsGywfECMUDg4UJQ4dMxosGAECMTgiETEwEh85MwMBGCwbKB8NHBQNDhMaDyIhGywYAQI1PhcSMDASPC1MLCxMWUwtASxMDR8oGywYAQMyOh8SMDESITgyAwEYLBsyHQ4lFA4OFCMPICwbLBgBAjU8GRIxMBIXPTYCARgsGyEiDxoUDQ4TwS1LWkstLUtaSy0AAAIAAAAAA4EC+wAVACIAAAkBIyIHBgcBIgYVERQWMyEyNjURNCYDIzU0JiIGHQEjEQkBA3L+oxUHAwYF/qMFCRMQAroQEwk23zhUON8BQQFBAdYBJQECBP7bEAX+chATExABjgUR/nigKjg4KqEBZQEJ/vcAAgAAAAADpAL8AB8ALQAACQEmIgcBDgEeATsBEQYXFhcWMyEyNzY3NjURNzI+ASYFMDE1NDc2MzIXFhcVIwOZ/ncIEwj+fAYEBg0JNgECBA4XJwHvDg4UDxw9CA0FBP4eAw8wKhEGAYQBoAFVBwf+qAUQEAn+8Q4PGBAaBAYOGS4BEAIJEA+wAQIDDw0EBrIABAAAAAADgQMBADUAdQCCAI8AACU2NyY+ATM2Ny4BNjcmJwYuATc1JicHDgEmLwEHFxYOAScjBxceAQYPARYXMzYeAQcWFz4BFgcmJzc2LgEPASYnNz4BJi8BNjcXFj4BLwE2NxceATY/ARYXBwYeAT8BFhcHDgEWHwEGBycmDgEfAQYHJy4BBgcTMj4BLgIiDgEUHgEXIi4BND4BMh4BFA4BAngODgErSiwHBSAWGCEEBS9OLAMKCgMgV1ggBRIBAixPMAgHBiMZGSMDBAUDL08tAgwNH1RUrTw1AgIZKxssHxAjFA4OFCUOHTIbKxkCAjE4IRIwMBEgOTECARgsGigfDRwTDg4TGg8hIhosGAECNj0XETAwEjwbLRsBGi02LRoaLRsoRCcnRFBEKChEQgUHLEorDQ4gVFQfDQwCLU8vAwUEAyMZGSMGBwgwTywCEQUgWFcgAwkLAyxOLwUEIRgWYA0fKBsrGAECMjkfEjAwESI3MgMBGCwaMxwOJRMODhMjEB8sGiwYAQI1OxkSMDASFz41AgEYKxshIg8aFA0NFAECGi02LRoaLTYtGjEnRFBEKChEUEQnAAAAAQAA//oDggL+ABQAAAUyNzY3NjQnJicmIgcGBwYUFxYXFgIAZ1pXNDU1NFdaz1pYMzU1NFdaBTUzWFrPWlc0NTU0V1rPWlgzNQAAAAMAAAAAA4EC6AAHABQAIQAAJREnJicRFxYlMj8BEQYPAQYVERQWBTY/ATY1ETQmIyIPAQJitggMuQn+UQ4RmwsKriEXAf0GBcAgFhQOEKMHAmhwBQP9kGgFCApTAnIGBmMTJP4CFRYKAgNuEiQB/xQWCVsABAAAAAADgQLqABwAJQAsADgAACUyPwE2NRE0JiMiDwEnJiIPAQYVERQWMzI/ARcWJSInETY/AREHBSYvAREfARMRNzYzMhURFA8CAnoVEMEgFhQNEcTJESgSwCAWFA0Su80U/lwFAQEMpKYBkgMGpwykPKYEAgUMmA0CCW4SJQIAFBYJbXsKCm0TJf4BFBcKZXILWwYByQ0HYP4aXA0CA14B5Qdk/h0B5lsCBv42DQdZBwAAAgAA//8DgQMBABQAQwAAITI3Njc2NCcmJyYiBwYHBhQXFhcWAzQ+ATMyMycmNDYyHwEeAQ8BBiImND8BJiMiDgEUHgEyPgE1NDYyFhUOAiIuAQIAZ1pXMzU1NFdazlpXMzU1M1daRC5LKwUFGwYNFgZKBgEHSggUDQclBAogNx8fN0A3HxAVEAEtTl1PLjUzV1rOWlc0NTU0V1nPWlczNQFxLU4sGwcVDgdLBxYHSgcOFQYlASA1QTcfIDYgCw8PCi9PLi5QAAADAAAAAAN+AwEAFAApAFgAACUyNzY3NjQnJicmIgcGBwYUFxYXFjciJyYnJjQ3Njc2MhcWFxYUBwYHBgMUHgEyPgE1NCYiBhUUDgEiLgE0PgEzMhcHBhQWMj8BNjQvAS4BBhQfASciDgEVAf5nWVczNTUzV1nOWVczNDQzV1lnV0pIKisrKkhKrkpIKysrKkhL/ixNW00tDxUPHzY/NR8fNSAKAyQHDRQHSQYGSAcVDQYbCipKLQM1M1dZzllXMzU1M1dZzllXMzVAKypJSq5KSCosLCpISq5KSSorAS4uTi0tTS4KDw8KIDYfHzY/NR8BJAcUDgdJBhYGSgcBDxMIGwEsSy0AAAACAAAAAAO/AsEACQBKAAABFzcnBxc3BzMnEy4CIyIHDgEHDgEVFB4BOwE1IyIuATQ2NzYzMhc0JjU0Nz4BMhYXFh0BMTYzMhceARUUBgcGByMVMz4CNC4BAjJHKpiQLkMBRwHLEk5pOUU8OkwJO003XTiIiB8+KCAaGx8SCQQdG1xjWRscGxIlHRsfHxkbHoiIOF02M1kBMksrnp4sTOxHAX40Ui8gH2tCFGxCOF03Ryg+PkAUFQQJHwkxKigvLScpMQkJGRdLKCJFFxkFRgc/Y3NjPwAAAAACAAAAAAO/AsEAGQAjAAAlIyIuATU0Njc+ATc2MzIeARceAhQOAQcjLwEHFzcnBzcjFwG2iDheNkw8CE06PEU5aU4SNlk0Nl44iH9IKZeRLkMBRwFGNl43Q2wUQmweIC9SNAc/Y3RiQAfKSyqfnyxN7UcAAAIAAAAAA78CwQAJAEoAACUnBxc3Jwc3IxclLgIjIgcOAQcOARUUHgE7ATUjIi4BNDY3NjMyFzQmNTQ3PgEyFhcWHQExNjMyFx4BFRQGBwYHIxUzPgI0LgEB7Egpl5EuQwFHAQEPEk5pOUU8OkwJO003XTiIiB8+KCAaGx8SCQQdG1xjWRscGxIlHRsfHxkbHoiIOF02M1nESyqfnyxN7EahNFIvIB9rQhRsQjhdN0coPj5AFBUECR8JMSooLy0nKTEJCRkXSygiRRcZBUYHP2NzYz8AAgAAAAADvwLBABkAIwAAJSMiLgE1NDY3PgE3NjMyHgEXHgIUDgEHIwMXNycHFzcHMycBtog4XjZMPAhNOjxFOWlOEjZZNDZeOIg5RyqYkC5DAUcBRjZeN0NsFEJsHiAvUjQHP2N0YkAHAThKKp+fLEzsRwACAAAAAAOhAusAJABIAAAlMjY3ATY0JwEmJyYjIgYdASMiBwYVFBYyNzY3PgE3NjsBFRQWNyI9ATQrASIHBgcGIjU2NzY3NjsBMj0BNDYzMTIXBRYUBwUGAjwNFg8BHxMT/uESCAsMExkKv19aFh0KDAkfUzczSgoZJwUMMX9VUiACBAQeIkROdjEMAwICBAEDBAT+/QNODAwBDxMpEwENDwQHGxKKdW/RFhsFBhA7RA4OixIZTwWNDCkoRgQEX0dTLTMMkQIDA/kDBgT2AwAABAAAAAADiAK/AA4AGwAkAD8AABM0NjMhNTQjISIVERQ7ARchMjURNCMhIgcRFjM3IiY0NjIeAQYHIiY9ATc2NzYyFxYfATc2NzYyFxYfARUUBiPkQUABj13+Pl1dD4YBwV1d/j9dAQFcchwpKTgoASmRFBY9EwgOGQ8JFSNjHQwUIxQOHEwWFAHbP0EHXFz+yFuPXAE7W1v+xVz8KTgpKTgpzBUVGDcSBQkJBhMfWBsIDQ0KGkg9FRUAAAABAAAAAAOCAuoAJAAAJTI2PQEzMhceARcWFxYyNjU0JyYrATU0JiMiBwYHAQYUFwEeAQHdEhgKSDI3UB8IDQkdFVhduwoYEwwLBxL+5hISARoOFlsYEogND0I5EAYFGhbMbXOHEhoHBA/++RIpEv72DAsAAAYAAAAAA4EB9gAJABMAHAAlAC4ANwAAASIOARYyNjQmIxciJjQ2MhYUBiMlIgYUFjI2NCYHIiY0NjIWFAYlIgYUFjI2NCYHBiY0NjIWFAYCACY0ATVLNTUmARUeHikeHhX+2yU1NUo1NSUVHh4qHh4CNyU1NUs0NCYVHR0qHh4B9TVKNTVKNYwdKh4eKh2MNUo1NUo1jB0qHh4qHo01SjU1SjWMAR4qHh4qHQADAAAAAAOBAfYACQASABsAAAEiDgEWMjY0JiMhIgYUFjI2NCYhIgYUFjI2NCYCACY0ATVLNTUm/tslNTVKNTUCJyU1NUs0NAH1NUo1NUo1NUo1NUo1NUo1NUo1AAIAAAAAA6EC6wAkAEgAACUyNj0BMzIXHgEXFhcWMjY1NCcmKwE1NCYjIgcGBwEGFBcBHgEnJSY0NyU2MzEyFh0BFDsBMhcWFxYXFCInJicmKwEiHQEUIyIB8xIZCkozN1MfCQwKHRZaX78KGRMMCwgS/uETEwEfDxYO/v0EBAEDAwMCAwwxdk5EIh4EBAIgUlV/MQwFA04ZEosODkQ7DwcEGhbRb3WKEhsHBQ/+9BMpE/7xDAxS9QQHA/kDAwKRDDMtU0dfBARGKCkMjQUAAAAEAAAAAAOIAr8AEwAkADcAQAAANzMVFDMhMjURNCsBNTQjISIVERQ3IiY1ETQ2MyEyFh0BISIHFTc0NjMhMhYdAScmIg8BJyYiDwE3MjY0JiIGFBbVN10Bwl1dN13+Pl1eFhgYFgHAFhj+pl0BMBgWAcAWGG0TMhSFNRMoE06hHCkpOSkpzzNcXAE7XDBcXP7IXDAXFwEzFxgYFy1c2NYWGBgX92cSEnYwERFDgSk6KSk6KQABAAD/+QNZAwgAOgAACQEGBwYuAjc2NwE+ARYGBwEGLgI/AT4BJiIPAQYUFxY2NwE+AS4CBgcBBgcGHgI3NjcBNjQmBgLv/vghKSdNPBYKCyIBaCBROgYf/qAMHRUBDPYIAQ8WCPcbGBtIGwFiIRYUOktOIf6WKw8OHlBpNDgrAQoIEBYBcf74IgsKFjxMJykiAWgfBjtQIP6gDQIVHA32CBUPCfYcSRkaARwBYiBOSjoVFiH+lSs3NGlQHg4OKwEKCBgQAQAAAAYAAAAAA4ECxgAZACUAPQBLAGYAcgAAATI2NzMyNjQmKwEuASIGByEiBhQWMyEeATM3IiY0NjsBMhYUBiMFIgYUFjsBHgEyNjchMjY0JiMhLgEiBgcXBiY1MSY2OwEyFhQGIwEyNjczMjY0JisBLgEiBgchIgYVMRQWMyEeATciJj0BND4BFhQGIwKJHDAKhAwREQyECi87Lwr+bA0SEg0BlAowHAETGhkTARIaGhP+FQwSEgyICTA6MAoBjw0SEg3+cQowOi8KVhIaARoSARMaGhMBDh0vCoQMEREMhAovOy8K/mwNEhINAZQKLx4TGholGhkTAg4hGxMZEhsiIhsSGRMbIS8aJRoaJRqeEhoRHCIiHBEaEhsiIhtLARoTEhsaJhr+6CIbEhoSGyIiGxINDRIbIi8aEgETGQEaJRsAAgAAAAADfQMAABwAKQAAJTI2NxcWMjY0LwE+ATU0JyYnJiIHBgcGFBcWFxY3Ii4BND4BMh4BFA4BAboxXCi/DicZDb4fISspRkmoSEYqKioqRkhUQXBCQnCDcEJCcJMeHL8OGycNvihgNFRJRikrKylGSahIRioqQ0Jwg3BCQnCDcEIAAQAAAAADggLqACQAACUyNjcBNjQnASYnJiMiBh0BIyIHBhUUFjI3Njc+ATc2OwEVFBYCJA0WDwEZEhL+5hEICwwSGAu7XVgVHQoMCB9RNjJICxdbCwwBChIpEgEHDwQHGhKHc23MFhoFBhA5Qg8NiBIYAAAGAAAAAAOHAqwAAwAHAAsADwATABcAACUhNSE1ITUhERUhNQEzNSM1MzUjNTM1IwFaAiz91AIs/dQCLPz+gYGBgYGBVVarVQEBVlb9qVarVatWAAACAAD/+gOAAxAAJwAxAAA/AScmNDclNjc2MhcWFwUWFA8BFzY1ETQmJyUmJyYiBwYHBQ4BFREUFyEyNwEmIgcBFobhvAYGASoPCAkUCgYQASsFBbvfCA0T/ucWDhIjEg8W/ucSDmMCMjMU/tEWKxX+zxE03bgGCwXmDAQFBQMN5gUMBbjdDiUBYRwhENoRBwkJBxHaECEc/p8lRxIBLBYW/tMRAAIAAAAAA3oC/gAiADIAAAErASIuAT8BPgEzITIWFRMOAQcjJgcOARUUBgciJic0NjcjJQM0NjsBMhYVERQGKwEiJgFOLggoPBwHLAdEKQGYERgBARcRFSsnJC01MS05AQgGFAHcAQwJKAkMDAgpCAwBFSZDJvgpOBcR/pEQGAEBGRdMKD08AU9AEzoZPQGXCQwMCf5pCQwMAAAAAAIAAAAAA34DAABPAFQAAAEhMhYUBiMhIgYHAwYeAjsBMh4BBgcOAQcGFxYXFjczMjY3NSY2Nz4BNxE0NjsBMhYXEQ4BKwEiDgIdARQGKwEGLgE2NyMiLgI3Ez4BBSMRMxMBXgECDBISDf7/BAcBbwUCDhYNogoQBgcJDRYCAwoHDQgLCRIaAQEcGhc5ICIZYxchAQEkGogYLCISPysIIjMaBxJmHDIfBAtvByYB+l1bAQMAEhoSBQT+/wwaFg0MExQFCT8kKR8XCAQBGxIrJUQaFxwCAVIaIyIY/q4bJRMiLRkqLT8CKFBtKxwwOhoBABUaPv6wAVAAAgAAAAADfwL/ACEAMQAAATsBMh4BDwEOASMFIiY1AzQ2MzcWNz4BNTQ2NzIWFxQGBwURFAYrASImJxE0NjsBMhYCyS0JJz0cBywIQyn+aBEYARcRFionJS01MSw5AQgG/jkMCCkIDAEMCSgIDQIJJkMn9yk4ARgRAW8QGAEBGRdMKD08AU9AEzsYPf5pCQwMCQGXCQwMAAACAAAAAAOAAwIATwBUAAAlISImNDY3IRY2NxM2LgIrASIuATY3PgE3NicmJyYjByIGHQEUBgcOAQcRFAYrASImNRE0NjsBMj4CPQE0NjsBNh4BBgczMh4CBwMOASUzESMDAsH+/gwSEgwBAgQHAW8FAg4WDaIKEAYHCQ0WAgMKBw0ICwkSGhwaFzkgIhljFyEkGogYLCISPysIIjMaBxJmHDIfBAtvByb+Bl1bAiITGRIBAQUEAQEMGhYNDBQTBgg/JCkfFwgEARoTKyVEGhcbA/6uGSQiGAFTGiUTIy0YKy0/AilQbSscMDoa/wAUGz4BUP6xAAAAAAEAAP//A6IDAQAaAAATFBcWFxYyNzY3NjU0LgEjIgcGByYnJiMiDgFiaGK3ExcTtmNoPmxDOS8tHR4tLzlDbD4CA4KEfXULC3V9hIJJc0EZGSsrGBpBcwAFAAD/8QOAAw8AFgAmAC0ANAA9AAAXITI1ETQmJyUmJyYiBwYHBQ4BFREUMwEmIg8BJyU2NzYyFxYXBQcFETUXByYnAREUByc3FgEiIzc2Mh8BI+4CJW0SGv70FQ8SJBIPFP7zGRNtAVwiTCIX0AEEDwcKFQkHDwEFz/5Wx8MEAQKWBMPGAf2hBQLyFSkW8ggObAFZJikU0xEHCQkHEdMUKSb+p2wBTSIiFs7LDAMGBgMMzM3LAWMJxcAKDgFk/p0PCb/EA/5h7xYW7wACAAD//wOiAwEAGgBAAAATFBcWFxYyNzY3NjU0LgEjIgcGByYnJiMiDgEXND4BMzIXFhceAT4BNzY3NjMyHgEVFAcGBwYPAQYiJyMmJyYnJmJoYrcTFxO2Y2g+bEM5Ly0dHi0vOUNsPkMsTTE1KR8ZCA0PDAkcHSk1ME0sMSxRSV0CBQMGAV1JUCwyAgOChH11Cwt1fYSCSXNBGRkrKxgaQXNJN1QvHhYnDAoBCA0oFR4vVDdKU0tMRj4BBAU+RkxLUwAAAgAA//wDrwMIAC4AXQAAJQYHBiMiJyYnJjU0NxceAT4BLwEuAQ8BDgEeAT8BBgcGFRQXFhcWMzI3PgEnLgE3LgEPATY1NCcmJyYjIgcOARceATc2MzIXFhcWFRQHFQYjJy4BDgEfAR4BPwE+AQKzKSwvLVhMSSssHQQDGhgMAyUDGQ1zDAwGGgwuFAoLNTVZW2t3YwwGBgkc6gcWDCUxNjRZXGt0aQwHBwkcDFZeWUtKKiwlAQMMBxYZCgYuBhcLbw0KgBoNDioqR0pWRjkcDAwGGQ1vDAwEKQMZGQsDDCsmKyxpWlczNT4JHAwTC0UMCgYQVWNpWlczNUIJHAwMBQk1KylISVdQRAICIQ0KDRYMbw0JBi0GFwAAAAABAAD//wL2Av8ABgAAIRMjESMRIwIC862MrQEbAeP+HQAAAAAFAAD/8QOPAw8ADAAZACYAMwA3AAAlFAYrARUzMj4BPQEjBTUjFRQeATsBNSMiJhE0NjsBNSMiDgEdATMBIxUzMhYdATM1NC4BASEVIQNPKByKiiM9JD/9YT8kPCSQkBwpKRyQkCQ8JD8CWoqKHChAJD39RgMZ/Od2HCk/Iz0klZWVlSQ9Iz8pAjAdKEAkPSSEAQlAKB2EhCQ9JP6eTwAAAwAAAAADaQLCAAwAGAAkAAABISIGFBYzITI2NCYjESEiBhQWMyEyNjQmASEyNjQmIyEiBhQWAzr9gBMcHBMCfxMcHBL9gBMcHBMCfxMcHP1uAn8THBwT/YETHBwBsR0lHBwlHP7wHCYcHCYcAcMcJhwcJhwAAAAABQAAAAADjQLyACYAMwA8AD8AQgAAExQWOwETHgEzITI2NCYjISImLwEhMjY/ATY1NCYjIScuASsBIgYVExQWMjY9ATQmKwEiBgUUFjI2NCYiBgM3Fwc3F24PCnU3BiklAZQKDw8L/nMPEgIGAbclKQYcAREO/csHAxQZegoP/CEuISAXARchAUMhLyEhLyHvRWxRaqQCuwsQ/oQmKQ4WDxMQJSomtwkEDQ8sFRMPC/2qFyEgFwEYICAYFyEhLyAgAgRAQCaYmAADAAD/9AODAwEAFAApAD4AAAUiJyYnJjQ3Njc2MhcWFxYUBwYHBgMiBwYHBhQXFhcWMjc2NzY0JyYnJhcHBiYvASY0PwE2Mh8BNzYWHwEWFAH9altYNDU1NFhb1FpZMzY2M1lbaV1RTS4vLy5NUbpQTi4vLy5OUGn4BAsFfwUFHgQMBFjOBAsEHgUMNjNZWtRbWDQ1NTRYW9RaWTM2At4vLk1RulBOLi8vLk5QulFNLi/6+AQBBIAEDAQeBQVXzgQBBB4ECwAAAAIAAAAAA4EDAQAUACkAAAEiBwYHBhQXFhcWMjc2NzY0JyYnJhMBBiYvASY0PwE2Mh8BNzYWHwEeAQIAaVlXMzQ0M1dZ0VpXMzQ0M1daZ/78BAsFhgQEIAUMBFzYBAwEIAQBAwE1M1Za0VlXMzU1M1dZ0VpWMzX+4v78BAEEhgQNBCAFBVvYBAEEIAULAAAAAAQAAAAAA4gC1AAnAE8AYQBtAAABMDEnNC8BLgEHISYGDwEVBhUUHgEXMzI2Nx4BNjc2Nx4BMzEWNz4BBwYrASImLwEHBgcGIyImLwEHDgErASImPQE0PwI2MyEyFh8CFgYXIwYHFSE1JicVFBYzIRY2PQEnISImNDYzITIWFAYDdwECQAktG/46GiwJRggnQykFIj0VGkxPHwoIFjwiJyIwKHUUFQMUJA0vLwYFGCETIw0wLw0kFAUkMgUBRQULAdAGCgNAAQoYDgEeGf33IR0bEwIoExuE/oQNExMNAXwOEhIB8AEEBKIaHwICHhmrAhgZKUcpAR0aIBsOGwkJGhwBEhtoTQoSDzk5BwQVEQ85ORARNiUBEA4Epw0IB6MFIT9sDgWxswYP1xMXARgT1OkSGRISGRIAAAMAAAAAA4EC5QAhADEAQQAANzMyPQE0PgEyHgEdARQ7ATI2PQE0Jy4BKwEiBgcGHQEUFhczMjY9ATYmKwEiBh0BFBYhMzI2PQE0JisBIgYdARQWohQJUpO/k1EKEw0PMC+nahlqqC4wD3YjIiQBJSIjEhQUAd4jExQVEiMiJCSyCdBWg0dHg1bQCQ4MzWBMS1RUS0xgzQwOkiMgnx8jExPYEhQUEtgTEyMfnyAjAAAABAAAAAADjALWACQAKwA4AEEAACUhMjY0JiMhIiYvASEyNj8BNjU0JiMhJy4BKwEmBhQWOwETHgEBBw4BIyEnEzI2PQE0JiMxIgYUFiEyNjQmIgYUFgGGAZUKDw8K/nEOEwIFAbclKQYcAREO/coHAhUZegoPDwp1OAUqAe8YAxEP/kYdYxchIRcYISEBWxghIS8hIdUPFg8TECQqJ7cJBA0PLBYSARAVEP6EJioBeKYREsn93yEXARchIS8hIS8hIS8hAAAAEgDeAAEAAAAAAAAAEwAAAAEAAAAAAAEACAATAAEAAAAAAAIABwAbAAEAAAAAAAMACAAiAAEAAAAAAAQACAAqAAEAAAAAAAUACwAyAAEAAAAAAAYACAA9AAEAAAAAAAoAKwBFAAEAAAAAAAsAEwBwAAMAAQQJAAAAJgCDAAMAAQQJAAEAEACpAAMAAQQJAAIADgC5AAMAAQQJAAMAEADHAAMAAQQJAAQAEADXAAMAAQQJAAUAFgDnAAMAAQQJAAYAEAD9AAMAAQQJAAoAVgENAAMAAQQJAAsAJgFjQ3JlYXRlZCBieSBpY29uZm9udHVuaWljb25zUmVndWxhcnVuaWljb25zdW5paWNvbnNWZXJzaW9uIDEuMHVuaWljb25zR2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20AQwByAGUAYQB0AGUAZAAgAGIAeQAgAGkAYwBvAG4AZgBvAG4AdAB1AG4AaQBpAGMAbwBuAHMAUgBlAGcAdQBsAGEAcgB1AG4AaQBpAGMAbwBuAHMAdQBuAGkAaQBjAG8AbgBzAFYAZQByAHMAaQBvAG4AIAAxAC4AMAB1AG4AaQBpAGMAbwBuAHMARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ8BAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEwATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwBTQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFpAWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaAABXlhbnNlBndhbGxldA9zZXR0aW5ncy1maWxsZWQLYXV0aC1maWxsZWQLc2hvcC1maWxsZWQMc3RhZmYtZmlsbGVkCnZpcC1maWxsZWQLcGx1cy1maWxsZWQRZm9sZGVyLWFkZC1maWxsZWQMeWFuc2UtZmlsbGVkC3R1bmUtZmlsbGVkD2NhbGVuZGFyLWZpbGxlZBNub3RpZmljYXRpb24tZmlsbGVkDXdhbGxldC1maWxsZWQMbWVkYWwtZmlsbGVkC2dpZnQtZmlsbGVkC2ZpcmUtZmlsbGVkDHJlZnJlc2hlbXB0eQ9sb2NhdGlvbi1maWxsZWQNcGVyc29uLWZpbGxlZBBwZXJzb25hZGQtZmlsbGVkBGJhY2sHZm9yd2FyZAthcnJvdy1yaWdodAphcnJvdy1sZWZ0CGFycm93LXVwCmFycm93LWRvd24GYm90dG9tBXJpZ2h0A3RvcARsZWZ0A2V5ZQpleWUtZmlsbGVkCWV5ZS1zbGFzaBBleWUtc2xhc2gtZmlsbGVkC2luZm8tZmlsbGVkBnJlbG9hZA1taWNvZmYtZmlsbGVkD21hcC1waW4tZWxsaXBzZQdtYXAtcGluCGxvY2F0aW9uCHN0YXJoYWxmBHN0YXILc3Rhci1maWxsZWQIY2FsZW5kYXIEZmlyZQVtZWRhbARmb250BGdpZnQEbGluawxub3RpZmljYXRpb24Fc3RhZmYDdmlwCmZvbGRlci1hZGQEdHVuZQRhdXRoBnBlcnNvbgxlbWFpbC1maWxsZWQMcGhvbmUtZmlsbGVkBXBob25lBWVtYWlsCXBlcnNvbmFkZBBjaGF0Ym94ZXMtZmlsbGVkB2NvbnRhY3QRY2hhdGJ1YmJsZS1maWxsZWQOY29udGFjdC1maWxsZWQJY2hhdGJveGVzCmNoYXRidWJibGUNdXBsb2FkLWZpbGxlZAZ1cGxvYWQGd2VpeGluB2NvbXBvc2UCcXEPZG93bmxvYWQtZmlsbGVkA3B5cQVzb3VuZAx0cmFzaC1maWxsZWQMc291bmQtZmlsbGVkBXRyYXNoD3ZpZGVvY2FtLWZpbGxlZA1zcGlubmVyLWN5Y2xlBXdlaWJvCHZpZGVvY2FtCGRvd25sb2FkBGhlbHAPbmF2aWdhdGUtZmlsbGVkCXBsdXNlbXB0eQtzbWFsbGNpcmNsZQxtaW51cy1maWxsZWQGbWljb2ZmCmNsb3NlZW1wdHkFY2xlYXIIbmF2aWdhdGUFbWludXMFaW1hZ2UDbWljCnBhcGVycGxhbmUFY2xvc2ULaGVscC1maWxsZWQRcGFwZXJwbGFuZS1maWxsZWQEcGx1cwptaWMtZmlsbGVkDGltYWdlLWZpbGxlZA1sb2NrZWQtZmlsbGVkBGluZm8GbG9ja2VkDWNhbWVyYS1maWxsZWQLY2hhdC1maWxsZWQGY2FtZXJhBmNpcmNsZQ5jaGVja21hcmtlbXB0eQRjaGF0DWNpcmNsZS1maWxsZWQEZmxhZwtmbGFnLWZpbGxlZAtnZWFyLWZpbGxlZARob21lC2hvbWUtZmlsbGVkBGdlYXISc21hbGxjaXJjbGUtZmlsbGVkCm1hcC1maWxsZWQDbWFwDnJlZnJlc2gtZmlsbGVkB3JlZnJlc2gMY2xvdWQtdXBsb2FkFWNsb3VkLWRvd25sb2FkLWZpbGxlZA5jbG91ZC1kb3dubG9hZBNjbG91ZC11cGxvYWQtZmlsbGVkBHJlZG8NaW1hZ2VzLWZpbGxlZAt1bmRvLWZpbGxlZARtb3JlC21vcmUtZmlsbGVkBHVuZG8GaW1hZ2VzCXBhcGVyY2xpcAhzZXR0aW5ncwZzZWFyY2gLcmVkby1maWxsZWQEbGlzdBBtYWlsLW9wZW4tZmlsbGVkEGhhbmQtZG93bi1maWxsZWQJaGFuZC1kb3duDmhhbmQtdXAtZmlsbGVkB2hhbmQtdXAMaGVhcnQtZmlsbGVkCW1haWwtb3BlbgVoZWFydARsb29wCHB1bGxkb3duBHNjYW4EYmFycwtjYXJ0LWZpbGxlZAhjaGVja2JveA9jaGVja2JveC1maWxsZWQEc2hvcApoZWFkcGhvbmVzBGNhcnQAAAAA') format('truetype'); + font-weight: 400; + font-display: "auto"; + font-style: normal +} + +[class*=" uni-icons-"], +[class^=uni-icons-] { + font-family: uni-icons !important; + speak: none; + font-style: normal; + font-weight: 400; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: baseline; + display: inline-block; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.uni-icons-shop:before { + content: "\e609"; +} + +.uni-icons-headphones:before { + content: "\e8bf"; +} + +.uni-icons-pulldown:before { + content: "\e588"; +} + +.uni-icons-scan:before { + content: "\e612"; +} + +.uni-icons-back:before { + content: "\e471"; +} + +.uni-icons-forward:before { + content: "\e470"; +} + +.uni-icons-refreshempty:before { + content: "\e461"; +} + +.uni-icons-checkbox-filled:before { + content: "\e442"; +} + +.uni-icons-checkbox:before { + content: "\e7fa"; +} + +.uni-icons-loop:before { + content: "\e565"; +} + +.uni-icons-arrowthindown:before { + content: "\e585"; +} + +.uni-icons-arrowthinleft:before { + content: "\e586"; +} + +.uni-icons-arrowthinright:before { + content: "\e587"; +} + +.uni-icons-arrowthinup:before { + content: "\e584"; +} + +.uni-icons-bars:before { + content: "\e563"; +} + +.uni-icons-cart-filled:before { + content: "\e7f4"; +} + +.uni-icons-cart:before { + content: "\e7f5"; +} + +.uni-icons-arrowleft:before { + content: "\e582"; +} + +.uni-icons-arrowdown:before { + content: "\e581"; +} + +.uni-icons-arrowright:before { + content: "\e583"; +} + +.uni-icons-arrowup:before { + content: "\e580"; +} + +.uni-icons-eye-filled:before { + content: "\e568"; +} + +.uni-icons-eye-slash-filled:before { + content: "\e822"; +} + +.uni-icons-eye-slash:before { + content: "\e823"; +} + +.uni-icons-eye:before { + content: "\e824"; +} + +.uni-icons-reload:before { + content: "\e462"; +} + +.uni-icons-hand-thumbsdown-filled:before { + content: "\e83b"; +} + +.uni-icons-hand-thumbsdown:before { + content: "\e83c"; +} + +.uni-icons-hand-thumbsup-filled:before { + content: "\e83d"; +} + +.uni-icons-heart-filled:before { + content: "\e83e"; +} + +.uni-icons-hand-thumbsup:before { + content: "\e83f"; +} + +.uni-icons-heart:before { + content: "\e840"; +} + +.uni-icons-mail-open-filled:before { + content: "\e84d"; +} + +.uni-icons-mail-open:before { + content: "\e84e"; +} + +.uni-icons-list:before { + content: "\e562"; +} + +.uni-icons-map-pin:before { + content: "\e85e"; +} + +.uni-icons-map-pin-ellipse:before { + content: "\e864"; +} + +.uni-icons-paperclip:before { + content: "\e567"; +} + +.uni-icons-images-filled:before { + content: "\e87a"; +} + +.uni-icons-images:before { + content: "\e87b"; +} + +.uni-icons-search:before { + content: "\e466"; +} + +.uni-icons-settings:before { + content: "\e560"; +} + +.uni-icons-cloud-download:before { + content: "\e8e4"; +} + +.uni-icons-cloud-upload-filled:before { + content: "\e8e5"; +} + +.uni-icons-cloud-upload:before { + content: "\e8e6"; +} + +.uni-icons-cloud-download-filled:before { + content: "\e8e9"; +} + +.uni-icons-more:before { + content: "\e507"; +} + +.uni-icons-more-filled:before { + content: "\e537"; +} + +.uni-icons-refresh:before { + content: "\e407"; +} + +.uni-icons-refresh-filled:before { + content: "\e437"; +} + +.uni-icons-undo-filled:before { + content: "\e7d6"; +} + +.uni-icons-undo:before { + content: "\e406"; +} + +.uni-icons-redo:before { + content: "\e405"; +} + +.uni-icons-redo-filled:before { + content: "\e7d9"; +} + +.uni-icons-camera:before { + content: "\e301"; +} + +.uni-icons-camera-filled:before { + content: "\e7ef"; +} + +.uni-icons-smallcircle-filled:before { + content: "\e801"; +} + +.uni-icons-circle:before { + content: "\e411"; +} + +.uni-icons-flag-filled:before { + content: "\e825"; +} + +.uni-icons-flag:before { + content: "\e508"; +} + +.uni-icons-gear-filled:before { + content: "\e532"; +} + +.uni-icons-gear:before { + content: "\e502"; +} + +.uni-icons-home:before { + content: "\e500"; +} + +.uni-icons-info:before { + content: "\e504"; +} + +.uni-icons-home-filled:before { + content: "\e530"; +} + +.uni-icons-info-filled:before { + content: "\e534"; +} + +.uni-icons-circle-filled:before { + content: "\e441"; +} + +.uni-icons-chat-filled:before { + content: "\e847"; +} + +.uni-icons-chat:before { + content: "\e263"; +} + +.uni-icons-checkmarkempty:before { + content: "\e472"; +} + +.uni-icons-locked-filled:before { + content: "\e856"; +} + +.uni-icons-locked:before { + content: "\e506"; +} + +.uni-icons-map-filled:before { + content: "\e85c"; +} + +.uni-icons-map:before { + content: "\e364"; +} + +.uni-icons-minus-filled:before { + content: "\e440"; +} + +.uni-icons-mic-filled:before { + content: "\e332"; +} + +.uni-icons-minus:before { + content: "\e410"; +} + +.uni-icons-micoff:before { + content: "\e360"; +} + +.uni-icons-mic:before { + content: "\e302"; +} + +.uni-icons-clear:before { + content: "\e434"; +} + +.uni-icons-smallcircle:before { + content: "\e868"; +} + +.uni-icons-close:before { + content: "\e404"; +} + +.uni-icons-closeempty:before { + content: "\e460"; +} + +.uni-icons-paperplane:before { + content: "\e503"; +} + +.uni-icons-paperplane-filled:before { + content: "\e86e"; +} + +.uni-icons-image:before { + content: "\e363"; +} + +.uni-icons-image-filled:before { + content: "\e877"; +} + +.uni-icons-location-filled:before { + content: "\e333"; +} + +.uni-icons-location:before { + content: "\e303"; +} + +.uni-icons-plus-filled:before { + content: "\e439"; +} + +.uni-icons-plus:before { + content: "\e409"; +} + +.uni-icons-plusempty:before { + content: "\e468"; +} + +.uni-icons-help-filled:before { + content: "\e535"; +} + +.uni-icons-help:before { + content: "\e505"; +} + +.uni-icons-navigate-filled:before { + content: "\e884"; +} + +.uni-icons-navigate:before { + content: "\e501"; +} + +.uni-icons-mic-slash-filled:before { + content: "\e892"; +} + +.uni-icons-sound:before { + content: "\e590"; +} + +.uni-icons-sound-filled:before { + content: "\e8a1"; +} + +.uni-icons-spinner-cycle:before { + content: "\e465"; +} + +.uni-icons-download-filled:before { + content: "\e8a4"; +} + +.uni-icons-videocam-filled:before { + content: "\e8af"; +} + +.uni-icons-upload:before { + content: "\e402"; +} + +.uni-icons-upload-filled:before { + content: "\e8b1"; +} + +.uni-icons-starhalf:before { + content: "\e463"; +} + +.uni-icons-star-filled:before { + content: "\e438"; +} + +.uni-icons-star:before { + content: "\e408"; +} + +.uni-icons-trash:before { + content: "\e401"; +} + +.uni-icons-compose:before { + content: "\e400"; +} + +.uni-icons-videocam:before { + content: "\e300"; +} + +.uni-icons-trash-filled:before { + content: "\e8dc"; +} + +.uni-icons-download:before { + content: "\e403"; +} + +.uni-icons-qq:before { + content: "\e264"; +} + +.uni-icons-weibo:before { + content: "\e260"; +} + +.uni-icons-weixin:before { + content: "\e261"; +} + +.uni-icons-pengyouquan:before { + content: "\e262"; +} + +.uni-icons-chatboxes:before { + content: "\e203"; +} + +.uni-icons-chatboxes-filled:before { + content: "\e233"; +} + +.uni-icons-email-filled:before { + content: "\e231"; +} + +.uni-icons-email:before { + content: "\e201"; +} + +.uni-icons-person-filled:before { + content: "\e131"; +} + +.uni-icons-contact-filled:before { + content: "\e130"; +} + +.uni-icons-person:before { + content: "\e101"; +} + +.uni-icons-contact:before { + content: "\e100"; +} + +.uni-icons-phone:before { + content: "\e200"; +} + +.uni-icons-personadd-filled:before { + content: "\e132"; +} + +.uni-icons-personadd:before { + content: "\e102"; +} + +.uni-icons-phone-filled:before { + content: "\e230"; +} + +.uni-icons-chatbubble-filled:before { + content: "\e232"; +} + +.uni-icons-chatbubble:before { + content: "\e202"; +} diff --git a/common/uni-admin/css/uni.css b/common/uni-admin/css/uni.css new file mode 100644 index 0000000..e26a055 --- /dev/null +++ b/common/uni-admin/css/uni.css @@ -0,0 +1,543 @@ +/* 全局公共样式 */ + +/* body, +html { + -webkit-user-select: auto; + user-select: auto; + font-size: 16px; +} */ + +/* #ifdef H5 */ + +.uni-app--showleftwindow uni-main { + position: relative; + background-color: #f5f5f5; +} + +.uni-mask+.uni-left-window, +.uni-mask+.uni-right-window { + position: fixed; +} + +.uni-app--showleftwindow uni-page-head .uni-page-head { + color: #333 !important; +} + +uni-page-head .uni-btn-icon { + color: #333 !important; +} + +.uni-app--showleftwindow uni-page-head[uni-page-head-type=default]~uni-page-wrapper { + height: auto; + padding-top: 59px; +} + +/* .uni-app--showleftwindow uni-page-head~uni-page-wrapper uni-page-body { + padding-top: 44px; +} */ + +/* +.uni-app--showleftwindow uni-page-wrapper { + position: absolute; + width: 100%; + top: 0; + bottom: 0; + padding: 15px; + overflow-y: auto; + box-sizing: border-box; + background-color: #F5F5F5; +} + +.uni-app--showleftwindow uni-page-body { + width: 100%; + min-height: 100%; + box-sizing: border-box; + border-radius: 5px; + box-shadow: -1px -1px 5px 0 rgba(0, 0, 0, .1); + background-color: #fff; +} */ + +.uni-app--showleftwindow .uni-container .uni-forms { + padding: 15px; + max-width: 600px; +} + +/* #endif */ + +/* #ifndef H5 */ +.uni-nav-menu { + height: 100vh; +} + +/* #endif */ + +.pointer { + cursor: pointer; +} + +.uni-top-window { + z-index: 998; + overflow: visible; +} + +.uni-tips { + font-size: 12px; + color: #666; +} + +/* 容器 */ +.uni-container { + padding: 15px; + box-sizing: border-box; +} + +/* 标题栏 */ +.uni-header { + padding: 0 15px; + display: flex; + min-height: 55px; + align-items: center; + justify-content: space-between; + border-bottom: 1px #f5f5f5 solid; + flex-wrap: wrap; +} + +.uni-title { + margin-right: 10px; + font-size: 16px; + font-weight: 500; + color: #333; +} + +.uni-sub-title { + margin-top: 3px; + font-size: 14px; + color: #999; +} + +.uni-link { + color: #3A8EE6; + cursor: pointer; + text-decoration: underline; +} + +.uni-group { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + word-break: keep-all; +} + +/* 按钮样式 */ +.uni-button-group { + margin-top: 30px; + display: flex; + align-items: center; + justify-content: center; +} + +.uni-button { + padding: 10px 20px; + font-size: 14px; + border-radius: 4px; + line-height: 1; + margin: 0; + box-sizing: border-box; + overflow: initial; +} + +.uni-group .uni-button { + margin: 10px; +} + +.uni-group .uni-search { + margin: 10px; +} + +.uni-group>.uni-button:first-child { + margin-left: 0; +} + +.uni-button:hover, +.uni-button:focus { + opacity: 0.9; +} + +.uni-button:active { + opacity: 1; +} + +.uni-button-full { + width: 100%; +} + +/* 搜索框样式 */ +.uni-search { + width: 268px; + height: 28px; + line-height: 28px; + font-size: 12px; + color: #606266; + padding: 0 10px; + border: 1px #dcdfe6 solid; + border-radius: 3px; +} + +/* 分页容器 */ +.uni-pagination-box { + margin-top: 20px; +} + + +.uni-input-border, +.uni-textarea-border { + width: 100%; + font-size: 14px; + color: #666; + border: 1px #e5e5e5 solid; + border-radius: 5px; + box-sizing: border-box; +} + +.uni-input-border { + padding: 0 10px; + height: 35px; + +} + +.uni-textarea-border { + padding: 10px; + height: 80px; +} + +.uni-disabled { + background-color: #F5F7FA; + color: #C0C4CC; +} + +.uni-icon-password-eye { + position: absolute; + right: 8px; + top: 6px; + font-family: uniicons; + font-size: 20px; + font-weight: normal; + font-style: normal; + width: 24px; + height: 24px; + line-height: 24px; + color: #999999; +} + +.uni-eye-active { + color: #007AFF; +} + +.uni-tabs__header { + position: relative; + background-color: #f5f7fa; + border-bottom: 1px solid #e4e7ed; +} + +.uni-tabs__nav-wrap { + overflow: hidden; + margin-bottom: -1px; + position: relative; +} + +.uni-tabs__nav-scroll { + overflow: hidden; +} + +.uni-tabs__nav { + position: relative; + white-space: nowrap; +} + + +.uni-tabs__item { + position: relative; + padding: 0 20px; + height: 40px; + box-sizing: border-box; + line-height: 40px; + display: inline-block; + list-style: none; + font-size: 14px; + font-weight: 500; + color: #909399; + margin-top: -1px; + margin-left: -1px; + border: 1px solid transparent; + cursor: pointer; +} + +.uni-tabs__item.is-active { + color: #007aff; + background-color: #fff; + border-right-color: #dcdfe6; + border-left-color: #dcdfe6; +} + +.uni-form-item-tips { + color: #999; + font-size: 12px; + margin-top: 3px; + position: absolute; + top: 40px; + +} + +.uni-form-item-empty { + color: #999; + min-height: 36px; + line-height: 36px; +} + +::v-deep .uni-forms-item__label .label-text { + color: #606266 !important; +} + +::v-deep .flex-center-x .uni-forms-item__content { + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.link-btn { + line-height: 26px; + margin-top: 5px; + color: #007AFF; + text-decoration: underline; + cursor: pointer; +} + +/* button 重置样式 */ +::v-deep button[size=mini] { + line-height: 2.4; + font-size: 12px; + border-radius: 3px; +} + + +button { + background: #fff; + border: 1px solid #dcdfe6; + color: #606266; + box-sizing: border-box; +} + +button[type=primary] { + background-color: #409EFF; + border-color: #409EFF; + border-width: 0; +} + +button[type=warn] { + background-color: #f56c6c; + border-color: #f56c6c; + border-width: 0; +} + +button[type=default] { + background: #fff; + border: 1px solid #dcdfe6; + color: #606266; + box-sizing: border-box; +} + +button[type=primary][plain] { + border-color: #409EFF; + color: #409EFF; +} + +button[type=warn][plain] { + border-color: #f56c6c; + color: #f56c6c; +} + +button[type=default][plain] { + border-color: #dcdfe6; + color: #606266; +} + +button[plain] { + border-color: #dcdfe6; + color: #606266; +} + +button:after { + border-width: 0; +} + +.uni-input-placeholder { + color: #999; +} + + +.uni-pagination-box { + display: flex; + align-items: center; + justify-content: center; +} + +.select-picker { + margin-right: 20px; +} + +.select-picker button { + margin-top: 5px; + line-height: 29px; + font-size: 14px; +} + +.select-picker button text { + color: #999; +} + +.select-picker-icon { + margin-left: 8px; +} + + +/* stat style start */ +.m-m { + margin: 15px; +} + +.mb-s { + margin-bottom: 5px; +} + +.mb-m { + margin-bottom: 15px !important; +} + +.mb-l { + margin-bottom: 30px !important; +} + +.ml-s { + margin-left: 5px; +} + +.ml-m { + margin-left: 15px !important; +} + +.ml-l { + margin-left: 30px !important; +} + +.p-m { + padding: 15px; +} + +.uni-charts-box { + width: 100%; + height: 350px; +} + +.uni-stat--x { + border-radius: 4px; + box-shadow: -1px -1px 5px 0 rgba(0, 0, 0, 0.1); + margin-bottom: 15px; +} + +.uni-stat__actived { + outline: 1px solid #2979ff; +} + +.flex { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.label-text { + font-size: 14px; + font-weight: bold; + color: #555; + margin: auto 0; + margin-right: 5px; +} + +.uni-stat-edit--x { + display: flex; + justify-content: space-between; +} + +.uni-stat-edit--btn { + cursor: pointer; +} + +.uni-stat-datetime-picker { + margin: 15px +} + +/* #ifndef APP-NVUE */ +@media screen and (max-width: 500px) { + .hide-on-phone { + display: none !important; + } + + .uni-charts-box { + width: 100%; + height: 220px; + } + + .uni-group .uni-search { + height: 32px; + line-height: 32px; + width: 100%; + margin: 20px 20px 10px 20px; + } + + .uni-header { + padding-left: 0px; + padding-right: 0px; + border: unset; + } + + .uni-group { + width: 100%; + } + + .uni-stat-breadcrumb-on-phone { + padding: 0 20px !important; + border-bottom: 1px #f5f5f5 solid; + } + + .uni-stat-datetime-picker { + flex: 1; + } +} + +@media screen and (min-width: 500px) { + .dispaly-grid { + display: grid; + grid-template-columns: 1fr 1fr; + column-gap: 15px; + } + + .pc-flex-wrap { + display: flex; + flex-wrap: wrap; + align-items: center; + } + + .uni-stat-datetime-picker { + max-width: 350px; + } + +} + +/* #endif */ + +/* #ifndef H5 */ +.fix-top-window { + margin-top: 85px; +} + +/* #endif */ diff --git a/common/uni-admin/说明.md b/common/uni-admin/说明.md new file mode 100644 index 0000000..550fd1b --- /dev/null +++ b/common/uni-admin/说明.md @@ -0,0 +1,35 @@ +### 此目录为 `uni-admin` 官方模板的一些样式文件 + +* 如果你需要引入 `uni-admin` 官方的一些插件,如[升级中心](https://ext.dcloud.net.cn/plugin?id=4470) +* 你可能会碰到样式错乱的问题,那是因为 `vk-uni-admin` 并没有引入 `uni-admin` 的公共样式 +* 但框架已经帮你整理好了公共样式的文件,就在 `common/uni-admin` 目录内 + +### 在 `App.vue` 中引入 `uni-admin` 的公共样式 + +```html + + +``` + + +### 同时官方的插件一般是不通过 `云函数` 获取数据的,而是通过 `clientDB` 操作数据库(前端操作数据库) + +* 因此,你需要上传一些数据库的 `schema.json` 文件 + +### 如 `升级中心` 需要上传以下两个 `schema.json` 文件 + +**特别注意:如果 `admin项目` 是绑定 `client项目`,则需要复制到 `client项目` 的 `uniCloud/database/`目录去上传** + +* opendb-app-list.schema.json +* opendb-app-versions.schema.json + +#### 这些 `schema.json` 文件一般在插件包里就有,直接右键点击对应的文件即可上传。 + +* 如升级中心的 `schema.json` 目录在 `uni_modules/uni-upgrade-center/uniCloud/database/opendb-app-list.schema.json` + +* 同时一般插件还会有一个自己的 `db_init.json` 文件 如 `uni_modules/uni-upgrade-center/uniCloud/database/db_init.json` (也是右键上传) + +* 如还有样式问题,建议重启项目试试。 \ No newline at end of file diff --git a/components/vk-data-input-editor/vk-data-input-editor.vue b/components/vk-data-input-editor/vk-data-input-editor.vue new file mode 100644 index 0000000..0a8b428 --- /dev/null +++ b/components/vk-data-input-editor/vk-data-input-editor.vue @@ -0,0 +1,1005 @@ + + + + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..13e92f9 --- /dev/null +++ b/main.js @@ -0,0 +1,55 @@ +import Vue from 'vue' +import App from './App' +import store from './store' +import config from '@/app.config.js' + +// 引入 elementUI +import elementUI from "element-ui"; +import 'element-ui/lib/theme-chalk/index.css'; +Vue.use(elementUI); + +// 引入 高性能表格UI 组件 +import UmyUi from 'umy-ui' +import 'umy-ui/lib/theme-chalk/index.css'; +Vue.use(UmyUi); + +// 引入 vk 实例 +import vk from 'uni_modules/vk-unicloud'; +Vue.use(vk); + +// 初始化 vk框架 +Vue.prototype.vk.init({ + Vue, // Vue实例 + config, // 配置 +}); + +// 引入 vkAdminUI 组件 +import vkAdminUI from 'vk-unicloud-admin-ui'; +import 'vk-unicloud-admin-ui/theme/index.css'; +Vue.use(vkAdminUI); + +// 自动注册全局组件(必须加在Vue.use(vkAdminUI);的后面) +const modulesFiles = require.context('./components', true, /\.vue$/); +modulesFiles.keys().map((modulePath, index) => { + const moduleNames = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1'); + const moduleSplit = moduleNames.split("/"); + const moduleName = moduleSplit[0]; + if (moduleSplit.length === 2 && moduleName === moduleSplit[1]) { + const value = modulesFiles(modulePath); + let moduleItem = value.default; + Vue.component(moduleName, moduleItem); + } +}); + +// 引入 自定义全局css 样式 +import '@/common/css/app.scss'; + +Vue.config.productionTip = false + +App.mpType = 'app' + +const app = new Vue({ + store, + ...App +}) +app.$mount() diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..ac1bfcd --- /dev/null +++ b/manifest.json @@ -0,0 +1,88 @@ +{ + "name" : "jinjiuxin-admin", + "appid" : "__UNI__E3B97BE", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + "app-plus" : { + "usingComponents" : true, + "nvueCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : {}, + "distribute" : { + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios" : {}, + "sdkConfigs" : {} + } + }, + "quickapp" : {}, + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "h5" : { + "template" : "template.h5.html", + "router" : { + "mode" : "hash", + "base" : "/admin/" + }, + "devServer" : { + "disableHostCheck" : true + }, + "sdkConfigs" : { + "maps" : { + "qqmap" : { + "key" : "3EXBZ-3NYCW-L5MRG-ONN2B-FJYR6-H7BSU" + } + } + } + }, + "vueVersion" : "2" +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3ce507d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,125 @@ +{ + "name": "vk-unicloud-admin", + "version": "1.17.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async-validator": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz", + "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==", + "requires": { + "babel-runtime": "6.x" + } + }, + "babel-helper-vue-jsx-merge-props": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz", + "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==" + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" + }, + "element-ui": { + "version": "2.15.13", + "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.13.tgz", + "integrity": "sha512-LJoatEYX6WV74FqXBss8Xfho9fh9rjDSzrDrTyREdGb1h1R3uRvmLh5jqp2JU137aj4/BgqA3K06RQpQBX33Bg==", + "requires": { + "async-validator": "~1.8.1", + "babel-helper-vue-jsx-merge-props": "^2.0.0", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1" + } + }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "sortablejs": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz", + "integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==" + }, + "throttle-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz", + "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==" + }, + "umy-table": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/umy-table/-/umy-table-1.1.8.tgz", + "integrity": "sha512-yqPMFwZ6MUNqI73KamsNKBTbHRA7VuVZDEWobaySghtf4n/s7INuTNQoADB/ROVK57WOXr99Xpnol0aMqGlASA==", + "requires": { + "async-validator": "~1.8.1", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1", + "vuedraggable": "^2.23.2", + "xe-utils": "^3.0.0-beta.12" + } + }, + "umy-ui": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/umy-ui/-/umy-ui-1.1.6.tgz", + "integrity": "sha512-wX0S29B5sFn8q0MvU9PEl8DGZeQmZXOJlLrwaCJ2UHiIQZCANWgXMBjjQgpaequ1gRZ8BekEu7Sn7hJccm9YMQ==", + "requires": { + "async-validator": "~1.8.1", + "deepmerge": "^1.2.0", + "normalize-wheel": "^1.0.1", + "resize-observer-polyfill": "^1.5.0", + "throttle-debounce": "^1.0.1", + "umy-table": "1.1.8", + "vuedraggable": "^2.23.2", + "xe-utils": "^3.0.0-beta.12" + } + }, + "vk-unicloud-admin-ui": { + "version": "1.17.46", + "resolved": "https://registry.npmjs.org/vk-unicloud-admin-ui/-/vk-unicloud-admin-ui-1.17.46.tgz", + "integrity": "sha512-VJvi8Gm3mfZOFEilIrZ1bSoi192ov9hPzSFzkR6l62pqJ3UEwgjTr5L2gQqxw4twb+y5qDmWZPS4dQMwya+iiQ==" + }, + "vuedraggable": { + "version": "2.24.3", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz", + "integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==", + "requires": { + "sortablejs": "1.10.2" + } + }, + "xe-utils": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.5.13.tgz", + "integrity": "sha512-ORT6ghCRk0mUVavMBxetcPzUPskS6NGfntzpWazJ86e+XU0uK4HwHfDhN/jKATiyInrOH5RwQo9SO/+DB8XeBw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..09ed680 --- /dev/null +++ b/package.json @@ -0,0 +1,96 @@ +{ + "id": "vk-unicloud-admin", + "name": "vk-unicloud-admin", + "version": "1.17.3", + "displayName": "【开箱即用】vk-unicloud-admin-快速开发框架-打造unicloud最好用的admin", + "description": "vk-unicloud-admin是基于uniapp+unicloud+uni-id+vk-router+element的一套快速PC admin企业级开发框架。小白几分钟即完成一个页面CRUD。", + "keywords": [ + "vk-unicloud-admin", + "支持表单可视化拖拽生成代码", + "vk云开发", + "uniapp、uni-id、vk-unicloud-router、vk-admin、element", + "内置众多API、工具包" + ], + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": "https://gitee.com/vk-uni/vk-unicloud-admin", + "author": "VK", + "license": "MIT", + "homepage": "https://vkdoc.fsq.pub/admin/", + "dependencies": { + "element-ui": "2.15.13", + "umy-ui": "1.1.6", + "vk-unicloud-admin-ui": "^1.17.45" + }, + "engines": { + "HBuilderX": "^3.1.10" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "370725567" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "https://vkdoc.fsq.pub/admin/", + "type": "unicloud-template-project" + }, + "uni_modules": { + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "n", + "app-nvue": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "n", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "n", + "阿里": "n", + "百度": "n", + "字节跳动": "n", + "QQ": "n", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "n" + } + } + } + } +} diff --git a/pages-dev.json b/pages-dev.json new file mode 100644 index 0000000..dcea019 --- /dev/null +++ b/pages-dev.json @@ -0,0 +1,61 @@ +{ + "subPackages": [{ + "root": "pages_template/components", + "pages": [ + { "path": "icons/vk-icons" }, + { "path": "icons/element-icons" }, + { "path": "table/table-basic" }, + { "path": "table/table-easy" }, + { "path": "table/table-query" }, + { "path": "table/table-expand" }, + { "path": "form/form-array-object" }, + { "path": "form/form-basic" }, + { "path": "form/form-inline" }, + { "path": "form/form-dialog" }, + { "path": "form/form-pro" }, + { "path": "form/form-dialog-2" }, + { "path": "form/form-slot" }, + { "path": "detail/detail-basic" }, + { "path": "detail/detail-table" }, + { "path": "dialog/dialog-basic" }, + { "path": "dialog/dialog-form" }, + { "path": "dialog/dialog-table" }, + { "path": "upload/upload-basic" }, + { "path": "upload/upload-drag" }, + { "path": "input/input-address" }, + { "path": "input/input-money" }, + { "path": "input/input-number" }, + { "path": "input/input-number-box" }, + { "path": "input/input-percentage" }, + { "path": "input/input-json" }, + { "path": "input/input-province" }, + { "path": "input/input-select" }, + { "path": "input/input-remote-select" }, + { "path": "input/input" }, + { "path": "editor/editor" } + ] + }, + { + "root": "pages_template/element", + "pages": [ + { "path": "detail/detail" }, + { "path": "form/basic-form" }, + { "path": "form/advanced-form" }, + { "path": "form/step-form" }, + { "path": "setting/account" }, + { "path": "popup/alert" }, + { "path": "popup/dialog" }, + { "path": "popup/drawer" }, + { "path": "popup/loading" }, + { "path": "popup/message" }, + { "path": "popup/message-box" }, + { "path": "popup/notification" }, + { "path": "popup/popconfirm" }, + { "path": "popup/popover" }, + { "path": "popup/tooltip" }, + { "path": "result/fail" }, + { "path": "result/success" } + ] + } + ] +} diff --git a/pages.js b/pages.js new file mode 100644 index 0000000..eeb9d14 --- /dev/null +++ b/pages.js @@ -0,0 +1,24 @@ +const debug = process.env.NODE_ENV !== 'production'; +var devPages; +try { + // 只在开发环境中才会被HBX打包的页面 + devPages = require('./pages-dev.json'); +} catch (err) {} +module.exports = function(pagesJson){ + try { + let newDevPages = JSON.parse(JSON.stringify(devPages)); + if(debug && newDevPages){ + for(let keyName in newDevPages){ + let item = newDevPages[keyName] + if (Object.prototype.toString.call(item) === "[object Array]") { + pagesJson[keyName].push(...item); + }else if(Object.prototype.toString.call(item)==='[object Object]'){ + pagesJson[keyName] = Object.assign(pagesJson[keyName], item); + } + } + } + } catch (err) { + console.log(err); + } + return pagesJson; +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..d29a2e5 --- /dev/null +++ b/pages.json @@ -0,0 +1,125 @@ +{ + "pages": [ + { "path": "pages/index/index" }, + { "path": "pages/product/product-category/list" }, + { "path": "pages/product/goods/list" }, + { "path": "pages/config/site"}, + { "path": "pages/enquiry/template/list"}, + { "path": "pages/enquiry/attributes/list"}, + { + "path": "pages/login/index", + "style": { + "topWindow": false, + "leftWindow": false, + "navigationBarTitleText": "登录" + } + } + + ], + "subPackages": [{ + "root": "pages_plugs", + "pages": [ + { "path": "error/404", "style": { "navigationBarTitleText": "页面不存在" } }, + { "path": "error/403", "style": { "navigationBarTitleText": "无权访问" } }, + { "path": "error/500", "style": { "navigationBarTitleText": "服务器出错了" } }, + { "path": "system/user/list" }, + { "path": "system/role/list" }, + { "path": "system/permission/list" }, + { "path": "system/menu/list" }, + { "path": "system/app/list" }, + { "path": "system/app-upgrade-center/list" }, + { "path": "system_uni/vk-global-data" }, + { "path": "system_uni/uni-id-log" }, + { "path": "system_uni/opendb-admin-log" }, + { "path": "system_uni/vk-components-dynamic" }, + { "path": "system_uni/uni-id-files/list" }, + { "path": "system_uni/vk-pay-orders" } + ] + }, + + { + "root": "pages_template/components", + "pages": [ + { "path": "icons/vk-icons" }, + { "path": "icons/element-icons" }, + { "path": "icons/vk-icons-page", "style": { "topWindow": false,"leftWindow": false } }, + { "path": "icons/element-icons-page", "style": { "topWindow": false,"leftWindow": false } }, + { "path": "table/table-basic" }, + { "path": "table/table-easy" }, + { "path": "table/table-query" }, + { "path": "table/table-expand" }, + { "path": "form/form-array-object" }, + { "path": "form/form-basic" }, + { "path": "form/form-cert" , "style": { "topWindow": false,"leftWindow": false } }, + { "path": "form/form-pay-cert" , "style": { "topWindow": false,"leftWindow": false } }, + { "path": "form/form-inline" }, + { "path": "form/form-dialog" }, + { "path": "form/form-pro" }, + { "path": "form/form-dialog-2" }, + { "path": "form/form-slot" }, + { "path": "detail/detail-basic" }, + { "path": "detail/detail-table" }, + { "path": "dialog/dialog-basic" }, + { "path": "dialog/dialog-form" }, + { "path": "dialog/dialog-table" }, + { "path": "upload/upload-basic" }, + { "path": "upload/upload-drag" }, + { "path": "input/input-address" }, + { "path": "input/input-money" }, + { "path": "input/input-number" }, + { "path": "input/input-number-box" }, + { "path": "input/input-percentage" }, + { "path": "input/input-json" }, + { "path": "input/input-province" }, + { "path": "input/input-select" }, + { "path": "input/input-remote-select" }, + { "path": "input/input" }, + { "path": "editor/editor" } + ] + }, + { + "root": "pages_template/element", + "pages": [ + { "path": "detail/detail" }, + { "path": "form/basic-form" }, + { "path": "form/advanced-form" }, + { "path": "form/step-form" }, + { "path": "setting/account" }, + { "path": "popup/alert" }, + { "path": "popup/dialog" }, + { "path": "popup/drawer" }, + { "path": "popup/loading" }, + { "path": "popup/message" }, + { "path": "popup/message-box" }, + { "path": "popup/notification" }, + { "path": "popup/popconfirm" }, + { "path": "popup/popover" }, + { "path": "popup/tooltip" }, + { "path": "result/fail" }, + { "path": "result/success" } + ] + } + ], + "globalStyle": { + "navigationStyle": "custom", + "navigationBarTextStyle": "black", + "navigationBarTitleText": "管理后台", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + }, + "topWindow": { + "path": "windows/topWindow", + "style": { + "height": "100px" + }, + "matchMedia": { + "minWidth": 0 + } + }, + "leftWindow": { + "path": "windows/leftWindow", + "style": { + "width": "240px" + } + } +} diff --git a/pages/config/site.vue b/pages/config/site.vue new file mode 100644 index 0000000..bc71001 --- /dev/null +++ b/pages/config/site.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/pages/enquiry/attributes/list.vue b/pages/enquiry/attributes/list.vue new file mode 100644 index 0000000..fa435ba --- /dev/null +++ b/pages/enquiry/attributes/list.vue @@ -0,0 +1,320 @@ + + + + \ No newline at end of file diff --git a/pages/enquiry/template/list.vue b/pages/enquiry/template/list.vue new file mode 100644 index 0000000..370a3e0 --- /dev/null +++ b/pages/enquiry/template/list.vue @@ -0,0 +1,335 @@ + + + + \ No newline at end of file diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..14c1b45 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,79 @@ + + + + diff --git a/pages/login/index.vue b/pages/login/index.vue new file mode 100644 index 0000000..49534c5 --- /dev/null +++ b/pages/login/index.vue @@ -0,0 +1,276 @@ + + + + + diff --git a/pages/product/goods/list.vue b/pages/product/goods/list.vue new file mode 100644 index 0000000..3847182 --- /dev/null +++ b/pages/product/goods/list.vue @@ -0,0 +1,358 @@ + + + + \ No newline at end of file diff --git a/pages/product/product-category/list.vue b/pages/product/product-category/list.vue new file mode 100644 index 0000000..5520718 --- /dev/null +++ b/pages/product/product-category/list.vue @@ -0,0 +1,338 @@ + + + + \ No newline at end of file diff --git a/pages/product/product-category/product-category.vue b/pages/product/product-category/product-category.vue new file mode 100644 index 0000000..9e6570d --- /dev/null +++ b/pages/product/product-category/product-category.vue @@ -0,0 +1,74 @@ + + + + diff --git a/pages_plugs/error/403.vue b/pages_plugs/error/403.vue new file mode 100644 index 0000000..344c3c4 --- /dev/null +++ b/pages_plugs/error/403.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/pages_plugs/error/404.vue b/pages_plugs/error/404.vue new file mode 100644 index 0000000..52f26ea --- /dev/null +++ b/pages_plugs/error/404.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/pages_plugs/error/500.vue b/pages_plugs/error/500.vue new file mode 100644 index 0000000..e00bc69 --- /dev/null +++ b/pages_plugs/error/500.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/pages_plugs/system/app-upgrade-center/form/addUpdate.vue b/pages_plugs/system/app-upgrade-center/form/addUpdate.vue new file mode 100644 index 0000000..1d166f2 --- /dev/null +++ b/pages_plugs/system/app-upgrade-center/form/addUpdate.vue @@ -0,0 +1,278 @@ + + + + + diff --git a/pages_plugs/system/app-upgrade-center/list.vue b/pages_plugs/system/app-upgrade-center/list.vue new file mode 100644 index 0000000..18a2d00 --- /dev/null +++ b/pages_plugs/system/app-upgrade-center/list.vue @@ -0,0 +1,305 @@ + + + + diff --git a/pages_plugs/system/app/form/addUpdate.vue b/pages_plugs/system/app/form/addUpdate.vue new file mode 100644 index 0000000..9496c76 --- /dev/null +++ b/pages_plugs/system/app/form/addUpdate.vue @@ -0,0 +1,515 @@ + + + + + diff --git a/pages_plugs/system/app/form/createPublishHtml.vue b/pages_plugs/system/app/form/createPublishHtml.vue new file mode 100644 index 0000000..b9cae1f --- /dev/null +++ b/pages_plugs/system/app/form/createPublishHtml.vue @@ -0,0 +1,207 @@ + + + + + diff --git a/pages_plugs/system/app/list.vue b/pages_plugs/system/app/list.vue new file mode 100644 index 0000000..cb32cc7 --- /dev/null +++ b/pages_plugs/system/app/list.vue @@ -0,0 +1,215 @@ + + + + diff --git a/pages_plugs/system/menu/form/addMenuByJson.vue b/pages_plugs/system/menu/form/addMenuByJson.vue new file mode 100644 index 0000000..436c3a9 --- /dev/null +++ b/pages_plugs/system/menu/form/addMenuByJson.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/pages_plugs/system/menu/form/bindPermission.vue b/pages_plugs/system/menu/form/bindPermission.vue new file mode 100644 index 0000000..c951e32 --- /dev/null +++ b/pages_plugs/system/menu/form/bindPermission.vue @@ -0,0 +1,218 @@ + + + + + diff --git a/pages_plugs/system/menu/list.vue b/pages_plugs/system/menu/list.vue new file mode 100644 index 0000000..c8bbf23 --- /dev/null +++ b/pages_plugs/system/menu/list.vue @@ -0,0 +1,364 @@ + + + + diff --git a/pages_plugs/system/permission/form/updateCategory.vue b/pages_plugs/system/permission/form/updateCategory.vue new file mode 100644 index 0000000..a798743 --- /dev/null +++ b/pages_plugs/system/permission/form/updateCategory.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/pages_plugs/system/permission/form/updateLevel.vue b/pages_plugs/system/permission/form/updateLevel.vue new file mode 100644 index 0000000..7ec060b --- /dev/null +++ b/pages_plugs/system/permission/form/updateLevel.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/pages_plugs/system/permission/list.vue b/pages_plugs/system/permission/list.vue new file mode 100644 index 0000000..c267e7c --- /dev/null +++ b/pages_plugs/system/permission/list.vue @@ -0,0 +1,386 @@ + + + + diff --git a/pages_plugs/system/role/form/bindMenu.vue b/pages_plugs/system/role/form/bindMenu.vue new file mode 100644 index 0000000..7a936e6 --- /dev/null +++ b/pages_plugs/system/role/form/bindMenu.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/pages_plugs/system/role/form/bindPermission.vue b/pages_plugs/system/role/form/bindPermission.vue new file mode 100644 index 0000000..1f371e4 --- /dev/null +++ b/pages_plugs/system/role/form/bindPermission.vue @@ -0,0 +1,264 @@ + + + + + diff --git a/pages_plugs/system/role/list.vue b/pages_plugs/system/role/list.vue new file mode 100644 index 0000000..020ed35 --- /dev/null +++ b/pages_plugs/system/role/list.vue @@ -0,0 +1,340 @@ + + + + diff --git a/pages_plugs/system/user/form/bindRole.vue b/pages_plugs/system/user/form/bindRole.vue new file mode 100644 index 0000000..2b88385 --- /dev/null +++ b/pages_plugs/system/user/form/bindRole.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/pages_plugs/system/user/form/resetPassword.vue b/pages_plugs/system/user/form/resetPassword.vue new file mode 100644 index 0000000..abbe6e8 --- /dev/null +++ b/pages_plugs/system/user/form/resetPassword.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/pages_plugs/system/user/form/setAuthorizedAppLogin.vue b/pages_plugs/system/user/form/setAuthorizedAppLogin.vue new file mode 100644 index 0000000..fa8ab5e --- /dev/null +++ b/pages_plugs/system/user/form/setAuthorizedAppLogin.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/pages_plugs/system/user/list.vue b/pages_plugs/system/user/list.vue new file mode 100644 index 0000000..7786f40 --- /dev/null +++ b/pages_plugs/system/user/list.vue @@ -0,0 +1,473 @@ + + + + diff --git a/pages_plugs/system_uni/opendb-admin-log.vue b/pages_plugs/system_uni/opendb-admin-log.vue new file mode 100644 index 0000000..4b34234 --- /dev/null +++ b/pages_plugs/system_uni/opendb-admin-log.vue @@ -0,0 +1,119 @@ + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/addCategory.vue b/pages_plugs/system_uni/uni-id-files/form/addCategory.vue new file mode 100644 index 0000000..cf13f49 --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/addCategory.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/preview.vue b/pages_plugs/system_uni/uni-id-files/form/preview.vue new file mode 100644 index 0000000..340057e --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/preview.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/updateCategory.vue b/pages_plugs/system_uni/uni-id-files/form/updateCategory.vue new file mode 100644 index 0000000..d4d2285 --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/updateCategory.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/updateFileCategory.vue b/pages_plugs/system_uni/uni-id-files/form/updateFileCategory.vue new file mode 100644 index 0000000..ef7065d --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/updateFileCategory.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/updateFileName.vue b/pages_plugs/system_uni/uni-id-files/form/updateFileName.vue new file mode 100644 index 0000000..3a98219 --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/updateFileName.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/updateVideo.vue b/pages_plugs/system_uni/uni-id-files/form/updateVideo.vue new file mode 100644 index 0000000..5bc7ae3 --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/updateVideo.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/form/uploadProgress.vue b/pages_plugs/system_uni/uni-id-files/form/uploadProgress.vue new file mode 100644 index 0000000..8713da7 --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/form/uploadProgress.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/pages_plugs/system_uni/uni-id-files/list.vue b/pages_plugs/system_uni/uni-id-files/list.vue new file mode 100644 index 0000000..81bacfe --- /dev/null +++ b/pages_plugs/system_uni/uni-id-files/list.vue @@ -0,0 +1,704 @@ + + + + diff --git a/pages_plugs/system_uni/uni-id-log.vue b/pages_plugs/system_uni/uni-id-log.vue new file mode 100644 index 0000000..d83af66 --- /dev/null +++ b/pages_plugs/system_uni/uni-id-log.vue @@ -0,0 +1,182 @@ + + + + diff --git a/pages_plugs/system_uni/vk-components-dynamic.vue b/pages_plugs/system_uni/vk-components-dynamic.vue new file mode 100644 index 0000000..62e9715 --- /dev/null +++ b/pages_plugs/system_uni/vk-components-dynamic.vue @@ -0,0 +1,289 @@ + + + + diff --git a/pages_plugs/system_uni/vk-global-data.vue b/pages_plugs/system_uni/vk-global-data.vue new file mode 100644 index 0000000..cff1dc6 --- /dev/null +++ b/pages_plugs/system_uni/vk-global-data.vue @@ -0,0 +1,221 @@ + + + + diff --git a/pages_plugs/system_uni/vk-pay-orders.vue b/pages_plugs/system_uni/vk-pay-orders.vue new file mode 100644 index 0000000..22d74bd --- /dev/null +++ b/pages_plugs/system_uni/vk-pay-orders.vue @@ -0,0 +1,227 @@ + + + + diff --git a/pages_template/components/detail/detail-basic.vue b/pages_template/components/detail/detail-basic.vue new file mode 100644 index 0000000..bdad1aa --- /dev/null +++ b/pages_template/components/detail/detail-basic.vue @@ -0,0 +1,170 @@ + + + + diff --git a/pages_template/components/detail/detail-table.vue b/pages_template/components/detail/detail-table.vue new file mode 100644 index 0000000..83a6756 --- /dev/null +++ b/pages_template/components/detail/detail-table.vue @@ -0,0 +1,169 @@ + + + + diff --git a/pages_template/components/dialog/dialog-basic.vue b/pages_template/components/dialog/dialog-basic.vue new file mode 100644 index 0000000..d0d6369 --- /dev/null +++ b/pages_template/components/dialog/dialog-basic.vue @@ -0,0 +1,101 @@ + + + + diff --git a/pages_template/components/dialog/dialog-form.vue b/pages_template/components/dialog/dialog-form.vue new file mode 100644 index 0000000..9db904b --- /dev/null +++ b/pages_template/components/dialog/dialog-form.vue @@ -0,0 +1,141 @@ + + + + diff --git a/pages_template/components/dialog/dialog-table.vue b/pages_template/components/dialog/dialog-table.vue new file mode 100644 index 0000000..3b9273f --- /dev/null +++ b/pages_template/components/dialog/dialog-table.vue @@ -0,0 +1,119 @@ + + + + diff --git a/pages_template/components/editor/editor.vue b/pages_template/components/editor/editor.vue new file mode 100644 index 0000000..b0542ab --- /dev/null +++ b/pages_template/components/editor/editor.vue @@ -0,0 +1,93 @@ + + + + diff --git a/pages_template/components/form/form-array-object.vue b/pages_template/components/form/form-array-object.vue new file mode 100644 index 0000000..7b96281 --- /dev/null +++ b/pages_template/components/form/form-array-object.vue @@ -0,0 +1,274 @@ + + + + diff --git a/pages_template/components/form/form-basic.vue b/pages_template/components/form/form-basic.vue new file mode 100644 index 0000000..972d858 --- /dev/null +++ b/pages_template/components/form/form-basic.vue @@ -0,0 +1,157 @@ + + + + diff --git a/pages_template/components/form/form-cert.vue b/pages_template/components/form/form-cert.vue new file mode 100644 index 0000000..6e1c65f --- /dev/null +++ b/pages_template/components/form/form-cert.vue @@ -0,0 +1,88 @@ + + + + diff --git a/pages_template/components/form/form-dialog-2.vue b/pages_template/components/form/form-dialog-2.vue new file mode 100644 index 0000000..8333d5a --- /dev/null +++ b/pages_template/components/form/form-dialog-2.vue @@ -0,0 +1,182 @@ + + + + diff --git a/pages_template/components/form/form-dialog.vue b/pages_template/components/form/form-dialog.vue new file mode 100644 index 0000000..556b98a --- /dev/null +++ b/pages_template/components/form/form-dialog.vue @@ -0,0 +1,142 @@ + + + + diff --git a/pages_template/components/form/form-inline.vue b/pages_template/components/form/form-inline.vue new file mode 100644 index 0000000..65a6587 --- /dev/null +++ b/pages_template/components/form/form-inline.vue @@ -0,0 +1,152 @@ + + + + diff --git a/pages_template/components/form/form-pay-cert.vue b/pages_template/components/form/form-pay-cert.vue new file mode 100644 index 0000000..72451ae --- /dev/null +++ b/pages_template/components/form/form-pay-cert.vue @@ -0,0 +1,197 @@ + + + + diff --git a/pages_template/components/form/form-pro.vue b/pages_template/components/form/form-pro.vue new file mode 100644 index 0000000..330e629 --- /dev/null +++ b/pages_template/components/form/form-pro.vue @@ -0,0 +1,543 @@ + + + + diff --git a/pages_template/components/form/form-slot.vue b/pages_template/components/form/form-slot.vue new file mode 100644 index 0000000..54b00d2 --- /dev/null +++ b/pages_template/components/form/form-slot.vue @@ -0,0 +1,142 @@ + + + + diff --git a/pages_template/components/icons/element-icons-page.vue b/pages_template/components/icons/element-icons-page.vue new file mode 100644 index 0000000..e1cabba --- /dev/null +++ b/pages_template/components/icons/element-icons-page.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/pages_template/components/icons/element-icons.vue b/pages_template/components/icons/element-icons.vue new file mode 100644 index 0000000..795eb84 --- /dev/null +++ b/pages_template/components/icons/element-icons.vue @@ -0,0 +1,121 @@ + + + + diff --git a/pages_template/components/icons/js/element-icons.js b/pages_template/components/icons/js/element-icons.js new file mode 100644 index 0000000..e8d8a1a --- /dev/null +++ b/pages_template/components/icons/js/element-icons.js @@ -0,0 +1,282 @@ +export default [ + "el-icon-platform-eleme", + "el-icon-eleme", + "el-icon-delete-solid", + "el-icon-delete", + "el-icon-s-tools", + "el-icon-setting", + "el-icon-user-solid", + "el-icon-user", + "el-icon-phone", + "el-icon-phone-outline", + "el-icon-more", + "el-icon-more-outline", + "el-icon-star-on", + "el-icon-star-off", + "el-icon-s-goods", + "el-icon-goods", + "el-icon-warning", + "el-icon-warning-outline", + "el-icon-question", + "el-icon-info", + "el-icon-remove", + "el-icon-circle-plus", + "el-icon-success", + "el-icon-error", + "el-icon-zoom-in", + "el-icon-zoom-out", + "el-icon-remove-outline", + "el-icon-circle-plus-outline", + "el-icon-circle-check", + "el-icon-circle-close", + "el-icon-s-help", + "el-icon-help", + "el-icon-minus", + "el-icon-plus", + "el-icon-check", + "el-icon-close", + "el-icon-picture", + "el-icon-picture-outline", + "el-icon-picture-outline-round", + "el-icon-upload", + "el-icon-upload2", + "el-icon-download", + "el-icon-camera-solid", + "el-icon-camera", + "el-icon-video-camera-solid", + "el-icon-video-camera", + "el-icon-message-solid", + "el-icon-bell", + "el-icon-s-cooperation", + "el-icon-s-order", + "el-icon-s-platform", + "el-icon-s-fold", + "el-icon-s-unfold", + "el-icon-s-operation", + "el-icon-s-promotion", + "el-icon-s-home", + "el-icon-s-release", + "el-icon-s-ticket", + "el-icon-s-management", + "el-icon-s-open", + "el-icon-s-shop", + "el-icon-s-marketing", + "el-icon-s-flag", + "el-icon-s-comment", + "el-icon-s-finance", + "el-icon-s-claim", + "el-icon-s-custom", + "el-icon-s-opportunity", + "el-icon-s-data", + "el-icon-s-check", + "el-icon-s-grid", + "el-icon-menu", + "el-icon-share", + "el-icon-d-caret", + "el-icon-caret-left", + "el-icon-caret-right", + "el-icon-caret-bottom", + "el-icon-caret-top", + "el-icon-bottom-left", + "el-icon-bottom-right", + "el-icon-back", + "el-icon-right", + "el-icon-bottom", + "el-icon-top", + "el-icon-top-left", + "el-icon-top-right", + "el-icon-arrow-left", + "el-icon-arrow-right", + "el-icon-arrow-down", + "el-icon-arrow-up", + "el-icon-d-arrow-left", + "el-icon-d-arrow-right", + "el-icon-video-pause", + "el-icon-video-play", + "el-icon-refresh", + "el-icon-refresh-right", + "el-icon-refresh-left", + "el-icon-finished", + "el-icon-sort", + "el-icon-sort-up", + "el-icon-sort-down", + "el-icon-rank", + "el-icon-loading", + "el-icon-view", + "el-icon-c-scale-to-original", + "el-icon-date", + "el-icon-edit", + "el-icon-edit-outline", + "el-icon-folder", + "el-icon-folder-opened", + "el-icon-folder-add", + "el-icon-folder-remove", + "el-icon-folder-delete", + "el-icon-folder-checked", + "el-icon-tickets", + "el-icon-document-remove", + "el-icon-document-delete", + "el-icon-document-copy", + "el-icon-document-checked", + "el-icon-document", + "el-icon-document-add", + "el-icon-printer", + "el-icon-paperclip", + "el-icon-takeaway-box", + "el-icon-search", + "el-icon-monitor", + "el-icon-attract", + "el-icon-mobile", + "el-icon-scissors", + "el-icon-umbrella", + "el-icon-headset", + "el-icon-brush", + "el-icon-mouse", + "el-icon-coordinate", + "el-icon-magic-stick", + "el-icon-reading", + "el-icon-data-line", + "el-icon-data-board", + "el-icon-pie-chart", + "el-icon-data-analysis", + "el-icon-collection-tag", + "el-icon-film", + "el-icon-suitcase", + "el-icon-suitcase-1", + "el-icon-receiving", + "el-icon-collection", + "el-icon-files", + "el-icon-notebook-1", + "el-icon-notebook-2", + "el-icon-toilet-paper", + "el-icon-office-building", + "el-icon-school", + "el-icon-table-lamp", + "el-icon-house", + "el-icon-no-smoking", + "el-icon-smoking", + "el-icon-shopping-cart-full", + "el-icon-shopping-cart-1", + "el-icon-shopping-cart-2", + "el-icon-shopping-bag-1", + "el-icon-shopping-bag-2", + "el-icon-sold-out", + "el-icon-sell", + "el-icon-present", + "el-icon-box", + "el-icon-bank-card", + "el-icon-money", + "el-icon-coin", + "el-icon-wallet", + "el-icon-discount", + "el-icon-price-tag", + "el-icon-news", + "el-icon-guide", + "el-icon-male", + "el-icon-female", + "el-icon-thumb", + "el-icon-cpu", + "el-icon-link", + "el-icon-connection", + "el-icon-open", + "el-icon-turn-off", + "el-icon-set-up", + "el-icon-chat-round", + "el-icon-chat-line-round", + "el-icon-chat-square", + "el-icon-chat-dot-round", + "el-icon-chat-dot-square", + "el-icon-chat-line-square", + "el-icon-message", + "el-icon-postcard", + "el-icon-position", + "el-icon-turn-off-microphone", + "el-icon-microphone", + "el-icon-close-notification", + "el-icon-bangzhu", + "el-icon-time", + "el-icon-odometer", + "el-icon-crop", + "el-icon-aim", + "el-icon-switch-button", + "el-icon-full-screen", + "el-icon-copy-document", + "el-icon-mic", + "el-icon-stopwatch", + "el-icon-medal-1", + "el-icon-medal", + "el-icon-trophy", + "el-icon-trophy-1", + "el-icon-first-aid-kit", + "el-icon-discover", + "el-icon-place", + "el-icon-location", + "el-icon-location-outline", + "el-icon-location-information", + "el-icon-add-location", + "el-icon-delete-location", + "el-icon-map-location", + "el-icon-alarm-clock", + "el-icon-timer", + "el-icon-watch-1", + "el-icon-watch", + "el-icon-lock", + "el-icon-unlock", + "el-icon-key", + "el-icon-service", + "el-icon-mobile-phone", + "el-icon-bicycle", + "el-icon-truck", + "el-icon-ship", + "el-icon-basketball", + "el-icon-football", + "el-icon-soccer", + "el-icon-baseball", + "el-icon-wind-power", + "el-icon-light-rain", + "el-icon-lightning", + "el-icon-heavy-rain", + "el-icon-sunrise", + "el-icon-sunrise-1", + "el-icon-sunset", + "el-icon-sunny", + "el-icon-cloudy", + "el-icon-partly-cloudy", + "el-icon-cloudy-and-sunny", + "el-icon-moon", + "el-icon-moon-night", + "el-icon-dish", + "el-icon-dish-1", + "el-icon-food", + "el-icon-chicken", + "el-icon-fork-spoon", + "el-icon-knife-fork", + "el-icon-burger", + "el-icon-tableware", + "el-icon-sugar", + "el-icon-dessert", + "el-icon-ice-cream", + "el-icon-hot-water", + "el-icon-water-cup", + "el-icon-coffee-cup", + "el-icon-cold-drink", + "el-icon-goblet", + "el-icon-goblet-full", + "el-icon-goblet-square", + "el-icon-goblet-square-full", + "el-icon-refrigerator", + "el-icon-grape", + "el-icon-watermelon", + "el-icon-cherry", + "el-icon-apple", + "el-icon-pear", + "el-icon-orange", + "el-icon-coffee", + "el-icon-ice-tea", + "el-icon-ice-drink", + "el-icon-milk-tea", + "el-icon-potato-strips", + "el-icon-lollipop", + "el-icon-ice-cream-square", + "el-icon-ice-cream-round" +]; diff --git a/pages_template/components/icons/js/vk-icons.js b/pages_template/components/icons/js/vk-icons.js new file mode 100644 index 0000000..938ee24 --- /dev/null +++ b/pages_template/components/icons/js/vk-icons.js @@ -0,0 +1,468 @@ +export default [ + "vk-icon-activityfill", + "vk-icon-crownfill", + "vk-icon-crown", + "vk-icon-goodsfill", + "vk-icon-messagefill", + "vk-icon-profilefill", + "vk-icon-sound", + "vk-icon-sponsorfill", + "vk-icon-sponsor", + "vk-icon-upblock", + "vk-icon-weblock", + "vk-icon-weunblock", + "vk-icon-1111", + "vk-icon-my", + "vk-icon-myfill", + "vk-icon-emojifill", + "vk-icon-emojiflashfill", + "vk-icon-flashbuyfill-copy", + "vk-icon-text", + "vk-icon-goodsfavor", + "vk-icon-musicfill", + "vk-icon-musicforbidfill", + "vk-icon-roundleftfill", + "vk-icon-triangledownfill", + "vk-icon-triangleupfill", + "vk-icon-roundleftfill-copy", + "vk-icon-pulldown1", + "vk-icon-emojilight", + "vk-icon-keyboardlight", + "vk-icon-recordfill", + "vk-icon-recordlight", + "vk-icon-appreciate", + "vk-icon-record", + "vk-icon-check", + "vk-icon-roundaddlight", + "vk-icon-close", + "vk-icon-soundlight", + "vk-icon-edit", + "vk-icon-cardboardfill", + "vk-icon-emoji", + "vk-icon-cardboard", + "vk-icon-favorfill", + "vk-icon-formfill", + "vk-icon-favor", + "vk-icon-coin", + "vk-icon-loading", + "vk-icon-sortlight", + "vk-icon-locationfill", + "vk-icon-cardboardforbid", + "vk-icon-location", + "vk-icon-circlefill", + "vk-icon-phone", + "vk-icon-circle", + "vk-icon-roundcheckfill", + "vk-icon-attentionforbid", + "vk-icon-roundcheck", + "vk-icon-attentionforbidfill", + "vk-icon-roundclosefill", + "vk-icon-attentionfavorfill", + "vk-icon-roundclose", + "vk-icon-attentionfavor", + "vk-icon-roundrightfill", + "vk-icon-piclight", + "vk-icon-roundright", + "vk-icon-shoplight", + "vk-icon-search", + "vk-icon-voicelight", + "vk-icon-taxi", + "vk-icon-attentionfavorfill-copy", + "vk-icon-timefill", + "vk-icon-full", + "vk-icon-time", + "vk-icon-mail", + "vk-icon-unfold", + "vk-icon-peoplelist", + "vk-icon-warnfill", + "vk-icon-goodsnewfill", + "vk-icon-warn", + "vk-icon-goodsnew", + "vk-icon-camerafill", + "vk-icon-medalfill", + "vk-icon-camera", + "vk-icon-medal", + "vk-icon-commentfill", + "vk-icon-newsfill", + "vk-icon-comment", + "vk-icon-newshotfill", + "vk-icon-likefill", + "vk-icon-newshot", + "vk-icon-like", + "vk-icon-news", + "vk-icon-notificationfill", + "vk-icon-videofill", + "vk-icon-notification", + "vk-icon-video", + "vk-icon-order", + "vk-icon-askfill", + "vk-icon-samefill", + "vk-icon-ask", + "vk-icon-same", + "vk-icon-exit", + "vk-icon-deliver", + "vk-icon-skinfill", + "vk-icon-evaluate", + "vk-icon-skin", + "vk-icon-pay", + "vk-icon-moneybagfill", + "vk-icon-send", + "vk-icon-usefullfill", + "vk-icon-shop", + "vk-icon-usefull", + "vk-icon-ticket", + "vk-icon-moneybag", + "vk-icon-wang", + "vk-icon-redpacket_fill", + "vk-icon-back", + "vk-icon-subscription", + "vk-icon-cascades", + "vk-icon-home_light", + "vk-icon-discover", + "vk-icon-my_light", + "vk-icon-list", + "vk-icon-community_light", + "vk-icon-more", + "vk-icon-cart_light", + "vk-icon-scan", + "vk-icon-we_light", + "vk-icon-settings", + "vk-icon-home_fill_light", + "vk-icon-questionfill", + "vk-icon-cart_fill_light", + "vk-icon-question", + "vk-icon-community_fill_light", + "vk-icon-shopfill", + "vk-icon-my_fill_light", + "vk-icon-form", + "vk-icon-we_fill_light", + "vk-icon-wangfill", + "vk-icon-skin_light", + "vk-icon-pic", + "vk-icon-search_light", + "vk-icon-filter", + "vk-icon-scan_light", + "vk-icon-footprint", + "vk-icon-people_list_light", + "vk-icon-top", + "vk-icon-message_light", + "vk-icon-pulldown", + "vk-icon-close_light", + "vk-icon-pullup", + "vk-icon-add_light", + "vk-icon-right", + "vk-icon-profile_light", + "vk-icon-refresh", + "vk-icon-service_light", + "vk-icon-moreandroid", + "vk-icon-friend_add_light", + "vk-icon-deletefill", + "vk-icon-edit_light", + "vk-icon-refund", + "vk-icon-camera_light", + "vk-icon-cart", + "vk-icon-hot_light", + "vk-icon-qrcode", + "vk-icon-refresh_light", + "vk-icon-remind", + "vk-icon-back_light", + "vk-icon-delete", + "vk-icon-share_light", + "vk-icon-profile", + "vk-icon-comment_light", + "vk-icon-home", + "vk-icon-appreciate_light", + "vk-icon-cartfill", + "vk-icon-favor_light", + "vk-icon-discoverfill", + "vk-icon-appreciate_fill_light", + "vk-icon-homefill", + "vk-icon-comment_fill_light", + "vk-icon-message", + "vk-icon-wang_light", + "vk-icon-addressbook", + "vk-icon-more_android_light", + "vk-icon-link", + "vk-icon-friend_light", + "vk-icon-lock", + "vk-icon-more_light", + "vk-icon-unlock", + "vk-icon-goods_favor_light", + "vk-icon-vip", + "vk-icon-goods_new_fill_light", + "vk-icon-weibo", + "vk-icon-goods_new_light", + "vk-icon-activity", + "vk-icon-goods_light", + "vk-icon-big", + "vk-icon-medal_fill_light", + "vk-icon-friendaddfill", + "vk-icon-medal_light", + "vk-icon-friendadd", + "vk-icon-news_fill_light", + "vk-icon-friendfamous", + "vk-icon-news_hot_fill_light", + "vk-icon-friend", + "vk-icon-news_hot_light", + "vk-icon-goods", + "vk-icon-news_light", + "vk-icon-selection", + "vk-icon-video_fill_light", + "vk-icon-tmall", + "vk-icon-message_fill_light", + "vk-icon-explore", + "vk-icon-form_light", + "vk-icon-present", + "vk-icon-video_light", + "vk-icon-squarecheckfill", + "vk-icon-search_list_light", + "vk-icon-square", + "vk-icon-form_fill_light", + "vk-icon-squarecheck", + "vk-icon-global_light", + "vk-icon-round", + "vk-icon-global", + "vk-icon-roundaddfill", + "vk-icon-favor_fill_light", + "vk-icon-roundadd", + "vk-icon-delete_light", + "vk-icon-add", + "vk-icon-back_android", + "vk-icon-notificationforbidfill", + "vk-icon-back_android_light", + "vk-icon-explorefill", + "vk-icon-down_light", + "vk-icon-fold", + "vk-icon-round_close_light", + "vk-icon-game", + "vk-icon-round_close_fill_light", + "vk-icon-redpacket", + "vk-icon-expressman", + "vk-icon-selectionfill", + "vk-icon-punch_light", + "vk-icon-similar", + "vk-icon-evaluate_fill", + "vk-icon-appreciatefill", + "vk-icon-furniture", + "vk-icon-infofill", + "vk-icon-dress", + "vk-icon-info", + "vk-icon-coffee", + "vk-icon-tao", + "vk-icon-sports", + "vk-icon-mobiletao", + "vk-icon-group_light", + "vk-icon-forwardfill", + "vk-icon-location_light", + "vk-icon-forward", + "vk-icon-attention_light", + "vk-icon-rechargefill", + "vk-icon-group_fill_light", + "vk-icon-recharge", + "vk-icon-group_fill", + "vk-icon-vipcard", + "vk-icon-play_forward_fill", + "vk-icon-voice", + "vk-icon-subscription_light", + "vk-icon-voicefill", + "vk-icon-deliver_fill", + "vk-icon-friendfavor", + "vk-icon-notice_forbid_fill", + "vk-icon-wifi", + "vk-icon-qr_code_light", + "vk-icon-share", + "vk-icon-settings_light", + "vk-icon-wefill", + "vk-icon-pick", + "vk-icon-we", + "vk-icon-form_favor_light", + "vk-icon-lightauto", + "vk-icon-round_comment_light", + "vk-icon-lightforbid", + "vk-icon-phone_light", + "vk-icon-lightfill", + "vk-icon-round_down_light", + "vk-icon-camerarotate", + "vk-icon-friend_settings_light", + "vk-icon-light", + "vk-icon-change", + "vk-icon-barcode", + "vk-icon-round_list_light", + "vk-icon-flashlightclose", + "vk-icon-ticket_fill", + "vk-icon-flashlightopen", + "vk-icon-round_friend_fill", + "vk-icon-searchlist", + "vk-icon-round_crown_fill", + "vk-icon-service", + "vk-icon-round_link_fill", + "vk-icon-sort", + "vk-icon-round_light_fill", + "vk-icon-1212", + "vk-icon-round_favor_fill", + "vk-icon-down", + "vk-icon-round_menu_fill", + "vk-icon-mobile", + "vk-icon-round_location_fill", + "vk-icon-mobilefill", + "vk-icon-round_pay_fill", + "vk-icon-copy", + "vk-icon-round_like_fill", + "vk-icon-countdownfill", + "vk-icon-round_people_fill", + "vk-icon-countdown", + "vk-icon-round_pay", + "vk-icon-noticefill", + "vk-icon-round_rank_fill", + "vk-icon-notice", + "vk-icon-round_redpacket_fill", + "vk-icon-qiang", + "vk-icon-round_skin_fill", + "vk-icon-upstagefill", + "vk-icon-round_record_fill", + "vk-icon-upstage", + "vk-icon-round_ticket_fill", + "vk-icon-babyfill", + "vk-icon-round_redpacket", + "vk-icon-baby", + "vk-icon-round_text_fill", + "vk-icon-brandfill", + "vk-icon-round_ticket", + "vk-icon-brand", + "vk-icon-round_transfer_fill", + "vk-icon-choicenessfill", + "vk-icon-subtitle_block_light", + "vk-icon-choiceness", + "vk-icon-warn_light", + "vk-icon-clothesfill", + "vk-icon-round_transfer", + "vk-icon-clothes", + "vk-icon-vip_code_light", + "vk-icon-creativefill", + "vk-icon-subtitle_unblock_light", + "vk-icon-creative", + "vk-icon-round_shop_fill", + "vk-icon-female", + "vk-icon-oppose_fill_light", + "vk-icon-keyboard", + "vk-icon-oppose_light", + "vk-icon-male", + "vk-icon-living", + "vk-icon-newfill", + "vk-icon-goods_hot_fill", + "vk-icon-new", + "vk-icon-ticket_money_fill", + "vk-icon-pullleft", + "vk-icon-arrow_left_fill", + "vk-icon-pullright", + "vk-icon-arrow_up_fill", + "vk-icon-rankfill", + "vk-icon-xiaoheiqun", + "vk-icon-rank", + "vk-icon-auction", + "vk-icon-bad", + "vk-icon-return", + "vk-icon-cameraadd", + "vk-icon-mall_light", + "vk-icon-focus", + "vk-icon-mall_fill_light", + "vk-icon-friendfill", + "vk-icon-broadcast_fill", + "vk-icon-cameraaddfill", + "vk-icon-at", + "vk-icon-apps", + "vk-icon-card_fill", + "vk-icon-paintfill", + "vk-icon-paint", + "vk-icon-picfill", + "vk-icon-refresharrow", + "vk-icon-markfill", + "vk-icon-mark", + "vk-icon-presentfill", + "vk-icon-repeal", + "vk-icon-album", + "vk-icon-peoplefill", + "vk-icon-people", + "vk-icon-servicefill", + "vk-icon-repair", + "vk-icon-file", + "vk-icon-repairfill", + "vk-icon-taoxiaopu", + "vk-icon-attentionfill", + "vk-icon-attention", + "vk-icon-commandfill", + "vk-icon-command", + "vk-icon-communityfill", + "vk-icon-community", + "vk-icon-read", + "vk-icon-suan", + "vk-icon-hua", + "vk-icon-ju", + "vk-icon-tian", + "vk-icon-calendar", + "vk-icon-cut", + "vk-icon-magic", + "vk-icon-backwardfill", + "vk-icon-playfill", + "vk-icon-stop", + "vk-icon-tagfill", + "vk-icon-tag", + "vk-icon-group", + "vk-icon-all", + "vk-icon-backdelete", + "vk-icon-hotfill", + "vk-icon-hot", + "vk-icon-post", + "vk-icon-radiobox", + "vk-icon-rounddown", + "vk-icon-upload", + "vk-icon-writefill", + "vk-icon-write", + "vk-icon-radioboxfill", + "vk-icon-punch", + "vk-icon-shake", + "vk-icon-add1", + "vk-icon-move", + "vk-icon-safe", + "vk-icon-qi", + "vk-icon-ye", + "vk-icon-cangku", + "vk-icon-cangku1", + "vk-icon-percentage", + "vk-icon-select", + "vk-icon-cascader", + "vk-icon-radio1", + "vk-icon-radio2", + "vk-icon-checkbox1", + "vk-icon-checkbox2", + "vk-icon-checkbox3", + "vk-icon-discount", + "vk-icon-number", + "vk-icon-color", + "vk-icon-json", + "vk-icon-text1", + "vk-icon-textarea", + "vk-icon-quyuguanli", + "vk-icon-dengji", + "vk-icon-jiagoufenxiao", + "vk-icon-gudongfenhong", + "vk-icon-tixianguanli", + "vk-icon-miaosha", + "vk-icon-youhuiquan", + "vk-icon-jifen1", + "vk-icon-shouqicaidan", + "vk-icon-zhankaicaidan", + "vk-icon-weixin", + "vk-icon-weixin1", + "vk-icon-zhifubaozhifu", + "vk-icon-zhifubaozhifu1", + "vk-icon-zhifubaozhifu2", + "vk-icon-anzhuo", + "vk-icon-iOS", + "vk-icon-QQ", + "vk-icon-APPku", + "vk-icon-weixingongzhonghao", + "vk-icon-weixinxiaochengxu", + "vk-icon-heading-h5", + "vk-icon-shengji3-xianxing" +]; diff --git a/pages_template/components/icons/vk-icons-page.vue b/pages_template/components/icons/vk-icons-page.vue new file mode 100644 index 0000000..308b25b --- /dev/null +++ b/pages_template/components/icons/vk-icons-page.vue @@ -0,0 +1,100 @@ + + + + + + diff --git a/pages_template/components/icons/vk-icons.vue b/pages_template/components/icons/vk-icons.vue new file mode 100644 index 0000000..691854c --- /dev/null +++ b/pages_template/components/icons/vk-icons.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/pages_template/components/input/input-address.vue b/pages_template/components/input/input-address.vue new file mode 100644 index 0000000..5627cb6 --- /dev/null +++ b/pages_template/components/input/input-address.vue @@ -0,0 +1,99 @@ + + + + diff --git a/pages_template/components/input/input-json.vue b/pages_template/components/input/input-json.vue new file mode 100644 index 0000000..dd09ddc --- /dev/null +++ b/pages_template/components/input/input-json.vue @@ -0,0 +1,85 @@ + + + + diff --git a/pages_template/components/input/input-money.vue b/pages_template/components/input/input-money.vue new file mode 100644 index 0000000..5d800eb --- /dev/null +++ b/pages_template/components/input/input-money.vue @@ -0,0 +1,98 @@ + + + + diff --git a/pages_template/components/input/input-number-box.vue b/pages_template/components/input/input-number-box.vue new file mode 100644 index 0000000..c82958e --- /dev/null +++ b/pages_template/components/input/input-number-box.vue @@ -0,0 +1,146 @@ + + + + diff --git a/pages_template/components/input/input-number.vue b/pages_template/components/input/input-number.vue new file mode 100644 index 0000000..fc1cd3b --- /dev/null +++ b/pages_template/components/input/input-number.vue @@ -0,0 +1,130 @@ + + + + diff --git a/pages_template/components/input/input-percentage.vue b/pages_template/components/input/input-percentage.vue new file mode 100644 index 0000000..2ed262c --- /dev/null +++ b/pages_template/components/input/input-percentage.vue @@ -0,0 +1,99 @@ + + + + diff --git a/pages_template/components/input/input-province.vue b/pages_template/components/input/input-province.vue new file mode 100644 index 0000000..f1dbb43 --- /dev/null +++ b/pages_template/components/input/input-province.vue @@ -0,0 +1,86 @@ + + + + diff --git a/pages_template/components/input/input-remote-select.vue b/pages_template/components/input/input-remote-select.vue new file mode 100644 index 0000000..0c3fb3c --- /dev/null +++ b/pages_template/components/input/input-remote-select.vue @@ -0,0 +1,89 @@ + + + + diff --git a/pages_template/components/input/input-select.vue b/pages_template/components/input/input-select.vue new file mode 100644 index 0000000..968325c --- /dev/null +++ b/pages_template/components/input/input-select.vue @@ -0,0 +1,119 @@ + + + + diff --git a/pages_template/components/input/input.vue b/pages_template/components/input/input.vue new file mode 100644 index 0000000..97b0db8 --- /dev/null +++ b/pages_template/components/input/input.vue @@ -0,0 +1,90 @@ + + + + diff --git a/pages_template/components/table/table-basic.vue b/pages_template/components/table/table-basic.vue new file mode 100644 index 0000000..c6eec7b --- /dev/null +++ b/pages_template/components/table/table-basic.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/pages_template/components/table/table-easy.vue b/pages_template/components/table/table-easy.vue new file mode 100644 index 0000000..011bfad --- /dev/null +++ b/pages_template/components/table/table-easy.vue @@ -0,0 +1,308 @@ + + + + diff --git a/pages_template/components/table/table-expand.vue b/pages_template/components/table/table-expand.vue new file mode 100644 index 0000000..5d4d120 --- /dev/null +++ b/pages_template/components/table/table-expand.vue @@ -0,0 +1,304 @@ + + + + diff --git a/pages_template/components/table/table-query.vue b/pages_template/components/table/table-query.vue new file mode 100644 index 0000000..0436a80 --- /dev/null +++ b/pages_template/components/table/table-query.vue @@ -0,0 +1,155 @@ + + + + diff --git a/pages_template/components/upload/upload-basic.vue b/pages_template/components/upload/upload-basic.vue new file mode 100644 index 0000000..b862c9d --- /dev/null +++ b/pages_template/components/upload/upload-basic.vue @@ -0,0 +1,93 @@ + + + + diff --git a/pages_template/components/upload/upload-drag.vue b/pages_template/components/upload/upload-drag.vue new file mode 100644 index 0000000..77476f7 --- /dev/null +++ b/pages_template/components/upload/upload-drag.vue @@ -0,0 +1,78 @@ + + + + diff --git a/pages_template/element/detail/detail.vue b/pages_template/element/detail/detail.vue new file mode 100644 index 0000000..0a1f045 --- /dev/null +++ b/pages_template/element/detail/detail.vue @@ -0,0 +1,259 @@ + + + + diff --git a/pages_template/element/form/advanced-form.vue b/pages_template/element/form/advanced-form.vue new file mode 100644 index 0000000..8883b88 --- /dev/null +++ b/pages_template/element/form/advanced-form.vue @@ -0,0 +1,484 @@ + + + + diff --git a/pages_template/element/form/basic-form.vue b/pages_template/element/form/basic-form.vue new file mode 100644 index 0000000..385ff42 --- /dev/null +++ b/pages_template/element/form/basic-form.vue @@ -0,0 +1,271 @@ + + + + diff --git a/pages_template/element/form/step-form.vue b/pages_template/element/form/step-form.vue new file mode 100644 index 0000000..dd4a7cc --- /dev/null +++ b/pages_template/element/form/step-form.vue @@ -0,0 +1,307 @@ + + + + diff --git a/pages_template/element/popup/alert.vue b/pages_template/element/popup/alert.vue new file mode 100644 index 0000000..072c3db --- /dev/null +++ b/pages_template/element/popup/alert.vue @@ -0,0 +1,132 @@ + + + + diff --git a/pages_template/element/popup/dialog.vue b/pages_template/element/popup/dialog.vue new file mode 100644 index 0000000..7598178 --- /dev/null +++ b/pages_template/element/popup/dialog.vue @@ -0,0 +1,219 @@ + + + + diff --git a/pages_template/element/popup/drawer.vue b/pages_template/element/popup/drawer.vue new file mode 100644 index 0000000..16c504a --- /dev/null +++ b/pages_template/element/popup/drawer.vue @@ -0,0 +1,256 @@ + + + + diff --git a/pages_template/element/popup/loading.vue b/pages_template/element/popup/loading.vue new file mode 100644 index 0000000..8a17b5c --- /dev/null +++ b/pages_template/element/popup/loading.vue @@ -0,0 +1,280 @@ + + + + diff --git a/pages_template/element/popup/message-box.vue b/pages_template/element/popup/message-box.vue new file mode 100644 index 0000000..ce887d2 --- /dev/null +++ b/pages_template/element/popup/message-box.vue @@ -0,0 +1,237 @@ + + + + diff --git a/pages_template/element/popup/message.vue b/pages_template/element/popup/message.vue new file mode 100644 index 0000000..457a7ac --- /dev/null +++ b/pages_template/element/popup/message.vue @@ -0,0 +1,203 @@ + + + + diff --git a/pages_template/element/popup/notification.vue b/pages_template/element/popup/notification.vue new file mode 100644 index 0000000..3b3dd55 --- /dev/null +++ b/pages_template/element/popup/notification.vue @@ -0,0 +1,267 @@ + + + + diff --git a/pages_template/element/popup/popconfirm.vue b/pages_template/element/popup/popconfirm.vue new file mode 100644 index 0000000..34ab19e --- /dev/null +++ b/pages_template/element/popup/popconfirm.vue @@ -0,0 +1,111 @@ + + + + diff --git a/pages_template/element/popup/popover.vue b/pages_template/element/popup/popover.vue new file mode 100644 index 0000000..a0d0825 --- /dev/null +++ b/pages_template/element/popup/popover.vue @@ -0,0 +1,158 @@ + + + + diff --git a/pages_template/element/popup/tooltip.vue b/pages_template/element/popup/tooltip.vue new file mode 100644 index 0000000..da556bd --- /dev/null +++ b/pages_template/element/popup/tooltip.vue @@ -0,0 +1,203 @@ + + + + diff --git a/pages_template/element/result/fail.vue b/pages_template/element/result/fail.vue new file mode 100644 index 0000000..c89bf0e --- /dev/null +++ b/pages_template/element/result/fail.vue @@ -0,0 +1,179 @@ + + + + diff --git a/pages_template/element/result/success.vue b/pages_template/element/result/success.vue new file mode 100644 index 0000000..aad0580 --- /dev/null +++ b/pages_template/element/result/success.vue @@ -0,0 +1,169 @@ + + + + diff --git a/pages_template/element/setting/account.vue b/pages_template/element/setting/account.vue new file mode 100644 index 0000000..c82b48f --- /dev/null +++ b/pages_template/element/setting/account.vue @@ -0,0 +1,429 @@ + + + + diff --git a/pages_template/kong/kong.vue b/pages_template/kong/kong.vue new file mode 100644 index 0000000..9e6570d --- /dev/null +++ b/pages_template/kong/kong.vue @@ -0,0 +1,74 @@ + + + + diff --git a/pages_template/kong/list.vue b/pages_template/kong/list.vue new file mode 100644 index 0000000..7eb7d8a --- /dev/null +++ b/pages_template/kong/list.vue @@ -0,0 +1,247 @@ + + + + diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..be3d6d2 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,23 @@ +const path = require('path') +module.exports = { + parser: 'postcss-comment', + plugins: { + 'postcss-import': { + resolve(id, basedir, importOptions) { + if (id.startsWith('~@/')) { + return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) + } else if (id.startsWith('@/')) { + return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) + } else if (id.startsWith('/') && !id.startsWith('//')) { + return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) + } + return id + } + }, + 'autoprefixer': { + overrideBrowserslist: ["> 1%", "last 2 versions"], + remove: process.env.UNI_PLATFORM !== 'h5' + }, + '@dcloudio/vue-cli-plugin-uni/packages/postcss': {} + } +} diff --git a/static/bg/001.jpg b/static/bg/001.jpg new file mode 100644 index 0000000..440f680 Binary files /dev/null and b/static/bg/001.jpg differ diff --git a/static/bg/002.jpg b/static/bg/002.jpg new file mode 100644 index 0000000..8754d51 Binary files /dev/null and b/static/bg/002.jpg differ diff --git a/static/bg/003.jpg b/static/bg/003.jpg new file mode 100644 index 0000000..46d25de Binary files /dev/null and b/static/bg/003.jpg differ diff --git a/static/bg/004.jpg b/static/bg/004.jpg new file mode 100644 index 0000000..433d19c Binary files /dev/null and b/static/bg/004.jpg differ diff --git a/static/bg/005.jpg b/static/bg/005.jpg new file mode 100644 index 0000000..5f1d732 Binary files /dev/null and b/static/bg/005.jpg differ diff --git a/static/bg/006.jpg b/static/bg/006.jpg new file mode 100644 index 0000000..b4fb412 Binary files /dev/null and b/static/bg/006.jpg differ diff --git a/static/bg/007.jpg b/static/bg/007.jpg new file mode 100644 index 0000000..934a8a2 Binary files /dev/null and b/static/bg/007.jpg differ diff --git a/static/icon/icon-403.svg b/static/icon/icon-403.svg new file mode 100644 index 0000000..e0c39ad --- /dev/null +++ b/static/icon/icon-403.svg @@ -0,0 +1,119 @@ + + + + 未命名 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/icon/icon-404.svg b/static/icon/icon-404.svg new file mode 100644 index 0000000..9bf629d --- /dev/null +++ b/static/icon/icon-404.svg @@ -0,0 +1,63 @@ + + + + 500-01 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/icon/icon-500.svg b/static/icon/icon-500.svg new file mode 100644 index 0000000..07094ea --- /dev/null +++ b/static/icon/icon-500.svg @@ -0,0 +1,162 @@ + + + + 未命名 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/icon/loading.gif b/static/icon/loading.gif new file mode 100644 index 0000000..927f430 Binary files /dev/null and b/static/icon/loading.gif differ diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..9088715 Binary files /dev/null and b/static/logo.png differ diff --git a/static/logo1.png b/static/logo1.png new file mode 100644 index 0000000..9c3ff6c Binary files /dev/null and b/static/logo1.png differ diff --git a/static/logo2.png b/static/logo2.png new file mode 100644 index 0000000..3d3ce20 Binary files /dev/null and b/static/logo2.png differ diff --git a/static/logo3.png b/static/logo3.png new file mode 100644 index 0000000..4defbb6 Binary files /dev/null and b/static/logo3.png differ diff --git a/static/plugs/element/index.css b/static/plugs/element/index.css new file mode 100644 index 0000000..68d7daf --- /dev/null +++ b/static/plugs/element/index.css @@ -0,0 +1 @@ +@charset "UTF-8";.el-pagination--small .arrow.disabled,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*,.el-table--hidden{visibility:hidden}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(fonts/element-icons.woff) format("woff"),url(fonts/element-icons.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:""}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409EFF}.el-pagination button:disabled{color:#C0C4CC;background-color:#FFF;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #FFF;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#C0C4CC;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409EFF}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#C0C4CC}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409EFF}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409EFF;color:#FFF}.el-dialog,.el-pager li{background:#FFF;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-date-table,.el-table th{-webkit-user-select:none;-moz-user-select:none}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#C0C4CC}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409EFF}.el-pager li.active{color:#409EFF;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409EFF}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #E4E7ED;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#FFF}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#F5F7FA}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#FFF}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default::before{background:rgba(220,223,230,.5)}.el-dropdown .el-dropdown__caret-button:hover::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #EBEEF5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px;background-color:#FFF}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0;background-color:#FFF}.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu::after,.el-menu::before{display:table;content:""}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409EFF;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#FFF;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409EFF;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #E4E7ED;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409EFF}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409EFF}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{white-space:nowrap;background:#FFF;border:1px solid #DCDFE6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;position:relative;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409EFF}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #409EFF;box-shadow:-1px 0 0 0 #409EFF}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#F2F6FC}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409EFF}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #DCDFE6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#DCDFE6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#FFF}.el-switch.is-checked .el-switch__core{border-color:#409EFF;background-color:#409EFF}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #E4E7ED;border-radius:4px;background-color:#FFF;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409EFF;background-color:#FFF}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#F5F7FA}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#FFF}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#F5F7FA}.el-select-dropdown__item.selected{color:#409EFF;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#E4E7ED}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#C0C4CC}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409EFF}.el-select .el-input .el-select__caret{color:#C0C4CC;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#C0C4CC;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#E4E7ED}.el-select .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#C0C4CC;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#C0C4CC;right:-7px;top:0;color:#FFF}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#FFF}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#F5F7FA}.el-table th,.el-table tr{background-color:#FFF}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table--border td:first-child .cell,.el-table--border th:first-child .cell{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #EBEEF5}.el-table th.is-sortable{cursor:pointer}.el-table th{overflow:hidden;-ms-user-select:none;user-select:none}.el-table th>.cell{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th>.cell.highlight{color:#409EFF}.el-table th.required>div::before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-right:10px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #EBEEF5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#EBEEF5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #EBEEF5}.el-table--border th.gutter:last-of-type{border-bottom:1px solid #EBEEF5;border-bottom-width:1px}.el-table--border th,.el-table__fixed-right-patch{border-bottom:1px solid #EBEEF5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#EBEEF5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#FFF}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #EBEEF5;background-color:#F5F7FA;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #EBEEF5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#F5F7FA;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #EBEEF5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#C0C4CC;top:5px}.el-table .sort-caret.descending{border-top-color:#C0C4CC;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409EFF}.el-table .descending .sort-caret.descending{border-top-color:#409EFF}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td{background-color:#ecf5ff}.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#F5F7FA}.el-table__body tr.current-row>td{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #EBEEF5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#F5F7FA}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #EBEEF5;border-radius:2px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409EFF;color:#FFF}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #EBEEF5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#F2F6FC}.el-table-filter__bottom button:hover{color:#409EFF}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{padding:3px 0;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#C0C4CC}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409EFF;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#FFF}.el-date-table td.available:hover{color:#409EFF}.el-date-table td.current:not(.disabled) span{color:#FFF;background-color:#409EFF}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#FFF}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409EFF}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#F5F7FA;opacity:1;cursor:not-allowed;color:#C0C4CC}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#F2F6FC;border-radius:15px}.el-date-table td.selected div:hover{background-color:#F2F6FC}.el-date-table td.selected span{background-color:#409EFF;color:#FFF;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #EBEEF5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409EFF;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#FFF}.el-month-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-month-table td.disabled .cell:hover{color:#C0C4CC}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409EFF}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#F2F6FC}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#FFF}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#FFF;background-color:#409EFF}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409EFF}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409EFF;font-weight:700}.el-year-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-year-table td.disabled .cell:hover{color:#C0C4CC}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409EFF}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#FFF}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #EBEEF5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409EFF}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409EFF;font-weight:700}.time-select-item.disabled{color:#E4E7ED;cursor:not-allowed}.time-select-item:hover{background-color:#F5F7FA;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#C0C4CC;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input:-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::placeholder{color:#C0C4CC}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#C0C4CC;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#409EFF}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#E4E7ED}.el-range-editor.is-disabled input{background-color:#F5F7FA;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::placeholder{color:#C0C4CC}.el-range-editor.is-disabled .el-range-separator{color:#C0C4CC}.el-picker-panel{color:#606266;border:1px solid #E4E7ED;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#FFF;border-radius:4px;line-height:30px;margin:5px 0}.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#FFF;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409EFF}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409EFF}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409EFF}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#FFF;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#FFF;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409EFF}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#F5F7FA;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#C0C4CC;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #E4E7ED;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-slider__button,.el-slider__button-wrapper{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #E4E7ED;border-bottom:1px solid #E4E7ED}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409EFF}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #E4E7ED}.el-popover{position:absolute;background:#FFF;min-width:150px;border:1px solid #EBEEF5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#FFF;border-radius:4px;border:1px solid #EBEEF5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#F56C6C}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409EFF}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67C23A}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#E6A23C}.el-message-box__status.el-icon-error{color:#F56C6C}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#F56C6C;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#409EFF;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content::after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409EFF;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-collapse-item__arrow,.el-tabs__nav{-webkit-transition:-webkit-transform .3s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#409EFF}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#E4E7ED;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409EFF inset;box-shadow:0 0 2px 2px #409EFF inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#C0C4CC;color:#FFF}.el-tabs__item.is-active{color:#409EFF}.el-tabs__item:hover{color:#409EFF;cursor:pointer}.el-tabs__item.is-disabled{color:#C0C4CC;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #E4E7ED}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #E4E7ED;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #E4E7ED;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#FFF}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#FFF;border:1px solid #DCDFE6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#F5F7FA;border-bottom:1px solid #E4E7ED;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409EFF;background-color:#FFF;border-right-color:#DCDFE6;border-left-color:#DCDFE6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409EFF}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#C0C4CC}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #DCDFE6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #E4E7ED;border-bottom:none;border-top:1px solid #E4E7ED;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #E4E7ED;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #E4E7ED;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #E4E7ED;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #E4E7ED}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #E4E7ED;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #E4E7ED;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #E4E7ED;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#FFF;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409EFF}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#F5F7FA}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409EFF;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#F5F7FA}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#C0C4CC;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#C0C4CC}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #EBEEF5;position:fixed;background-color:#FFF;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67C23A}.el-notification .el-icon-error{color:#F56C6C}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#E6A23C}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#F5F7FA;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409EFF}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409EFF}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #DCDFE6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #DCDFE6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#E4E7ED;color:#E4E7ED}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#E4E7ED;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #DCDFE6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #DCDFE6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-upload-cover::after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#FFF}.el-tooltip__popper.is-light{background:#FFF;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#FFF}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#FFF}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#FFF}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#FFF}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{vertical-align:middle;display:inline-block}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#E4E7ED;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button{border-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409EFF;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;transform:translateX(-50%);background-color:transparent;text-align:center;user-select:none;line-height:normal}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409EFF;background-color:#FFF;border-radius:50%;-webkit-transition:.2s;transition:.2s;user-select:none}.el-image-viewer__btn,.el-step__icon-inner{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#FFF;transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #DCDFE6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#C0C4CC}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409EFF}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#409EFF;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409EFF;stroke-linecap:round}.el-loading-spinner i{color:#409EFF}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0%}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0%}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0%}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0%}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0%}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0%}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409EFF;color:#409EFF}.el-upload:focus .el-upload-dragger{border-color:#409EFF}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#C0C4CC;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #DCDFE6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409EFF;font-style:normal}.el-upload-dragger:hover{border-color:#409EFF}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409EFF}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67C23A}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409EFF}.el-upload-list__item:hover{background-color:#F5F7FA}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409EFF;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409EFF}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#FFF}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#FFF;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#FFF;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#FFF;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner::after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67C23A}.el-progress.is-success .el-progress__text{color:#67C23A}.el-progress.is-warning .el-progress-bar__inner{background-color:#E6A23C}.el-progress.is-warning .el-progress__text{color:#E6A23C}.el-progress.is-exception .el-progress-bar__inner{background-color:#F56C6C}.el-progress.is-exception .el-progress__text{color:#F56C6C}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#EBEEF5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409EFF;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner::after{height:100%}.el-progress-bar__innerText{color:#FFF;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border-width:1px;border-style:solid;border-color:#EBEEF5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67C23A}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#E6A23C}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#F56C6C}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#C0C4CC;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67C23A}.el-message .el-icon-error{color:#F56C6C}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#E6A23C}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#F56C6C;border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409EFF}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}.el-card{border:1px solid #EBEEF5;background-color:#FFF;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#C0C4CC;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#F5F7FA}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#C0C4CC;border-color:#C0C4CC}.el-step__head.is-success{color:#67C23A;border-color:#67C23A}.el-step__head.is-error{color:#F56C6C;border-color:#F56C6C}.el-step__head.is-finish{color:#409EFF;border-color:#409EFF}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#FFF;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#C0C4CC}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#C0C4CC}.el-step__title.is-success{color:#67C23A}.el-step__title.is-error{color:#F56C6C}.el-step__title.is-finish{color:#409EFF}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#C0C4CC}.el-step__description.is-success{color:#67C23A}.el-step__description.is-error{color:#F56C6C}.el-step__description.is-finish{color:#409EFF}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#C0C4CC}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #EBEEF5;border-bottom:1px solid #EBEEF5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#FFF;color:#303133;cursor:pointer;border-bottom:1px solid #EBEEF5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409EFF}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#FFF;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #EBEEF5}.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#EBEEF5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#FFF;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#EBEEF5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#FFF}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#EBEEF5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#FFF;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#EBEEF5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#FFF}.el-tag{background-color:#ecf5ff;border-color:#d9ecff;display:inline-block;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#409EFF;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#409EFF}.el-tag .el-tag__close{color:#409eff}.el-tag .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67C23A}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close::before{display:block}.el-tag--dark{background-color:#409eff;border-color:#409eff;color:#fff}.el-tag--dark.is-hit{border-color:#409EFF}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#FFF;background-color:#66b1ff}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67C23A}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#b3d8ff;color:#409eff}.el-tag--plain.is-hit{border-color:#409EFF}.el-tag--plain .el-tag__close{color:#409eff}.el-tag--plain .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67C23A}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#C0C4CC}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#C0C4CC}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#FFF;border:1px solid #E4E7ED;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#C0C4CC;color:#FFF}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#F5F7FA}.el-cascader__suggestion-item.is-checked{color:#409EFF;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#C0C4CC}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#C0C4CC}.el-cascader__search-input:-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::placeholder{color:#C0C4CC}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409EFF;box-shadow:0 0 3px 2px #409EFF}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409EFF;border-color:#409EFF}.el-color-dropdown__link-btn{cursor:pointer;color:#409EFF;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409EFF,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#FFF;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{position:relative;display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#FFF;background-image:none;border:1px solid #DCDFE6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea__inner:hover{border-color:#C0C4CC}.el-textarea__inner:focus{outline:0;border-color:#409EFF}.el-textarea .el-input__count{color:#909399;background:#FFF;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea.is-exceed .el-textarea__inner{border-color:#F56C6C}.el-textarea.is-exceed .el-input__count{color:#F56C6C}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#C0C4CC;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#FFF;line-height:initial;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#FFF;background-image:none;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#C0C4CC;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input__inner::placeholder{color:#C0C4CC}.el-input__inner:hover{border-color:#C0C4CC}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409EFF;outline:0}.el-input__suffix{right:5px;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-input.is-exceed .el-input__inner{border-color:#F56C6C}.el-input.is-exceed .el-input__suffix .el-input__count{color:#F56C6C}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#F5F7FA;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #DCDFE6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#FFF;background-color:#409EFF;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #DCDFE6;background-color:#F5F7FA;color:#C0C4CC}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #EBEEF5;border-radius:4px;overflow:hidden;background:#FFF;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409EFF}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#F5F7FA;margin:0;padding-left:15px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-divider__text,.el-link{font-weight:500;font-size:14px}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#FFF;margin:0;padding:0;border-top:1px solid #EBEEF5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0}.el-container.is-vertical,.el-drawer{-webkit-box-orient:vertical;-webkit-box-direction:normal}.el-aside,.el-header{-webkit-box-sizing:border-box}.el-container.is-vertical{-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-footer,.el-main{-webkit-box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;box-sizing:border-box;padding:20px}.el-footer{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #E4E7ED}.el-timeline-item__icon{color:#FFF;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#E4E7ED;border-radius:50%;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-webkit-box;display:-ms-flexbox}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409EFF}.el-timeline-item__node--success{background-color:#67C23A}.el-timeline-item__node--warning{background-color:#E6A23C}.el-timeline-item__node--danger{background-color:#F56C6C}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0}.el-link.is-underline:hover:after{content:"";position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #409EFF}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#409EFF}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#409EFF}.el-link.el-link--default.is-disabled{color:#C0C4CC}.el-link.el-link--primary{color:#409EFF}.el-link.el-link--primary:hover{color:#66b1ff}.el-link.el-link--primary.is-disabled{color:#a0cfff}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#F56C6C}.el-link.el-link--danger{color:#F56C6C}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67C23A}.el-link.el-link--success{color:#67C23A}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#E6A23C}.el-link.el-link--warning{color:#E6A23C}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#DCDFE6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;color:#303133}.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;color:#C0C4CC;vertical-align:middle}.el-image__preview{cursor:pointer}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;user-select:none}.el-button,.el-checkbox{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:40px}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{top:50%;width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#409EFF;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#FFF;border-color:#409EFF;color:#409EFF}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#FFF;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#FFF;border-color:#EBEEF5;color:#C0C4CC}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#FFF;background-color:#409EFF;border-color:#409EFF}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#FFF}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#FFF;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409EFF;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409EFF;border-color:#409EFF;color:#FFF}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#FFF;background-color:#67C23A;border-color:#67C23A}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#FFF}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#FFF}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#FFF;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67C23A;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67C23A;border-color:#67C23A;color:#FFF}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#FFF;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#FFF;background-color:#E6A23C;border-color:#E6A23C}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#FFF}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#FFF}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#FFF;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#E6A23C;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#E6A23C;border-color:#E6A23C;color:#FFF}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#FFF;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#FFF;background-color:#F56C6C;border-color:#F56C6C}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#FFF}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#FFF}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#FFF;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#F56C6C;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#F56C6C;border-color:#F56C6C;color:#FFF}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#FFF;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#FFF;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#FFF}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#FFF}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#FFF;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#FFF}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#FFF;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#409EFF;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table;content:""}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-button.is-active,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #EBEEF5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#C0C4CC}.el-backtop,.el-calendar-table td.is-today{color:#409EFF}.el-calendar-table td{border-bottom:1px solid #EBEEF5;border-right:1px solid #EBEEF5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#F2F8FE}.el-calendar-table tr:first-child td{border-top:1px solid #EBEEF5}.el-calendar-table tr td:first-child{border-left:1px solid #EBEEF5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#F2F8FE}.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left::after{content:"";position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#DCDFE6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox-button__inner,.el-radio{font-weight:500;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409EFF}.el-checkbox.is-bordered.is-disabled{border-color:#EBEEF5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#DCDFE6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#C0C4CC}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#C0C4CC}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#C0C4CC;border-color:#C0C4CC}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409EFF;border-color:#409EFF}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#C0C4CC;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409EFF}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409EFF}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#FFF;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #DCDFE6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#FFF;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409EFF}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #FFF;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409EFF}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-radio,.el-radio__input{line-height:1;outline:0;white-space:nowrap}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409EFF}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#EBEEF5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409EFF}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.el-radio{color:#606266;cursor:pointer;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#409EFF}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#EBEEF5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#F5F7FA;border-color:#E4E7ED}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{cursor:pointer;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#F5F7FA}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#C0C4CC}.el-radio__input.is-disabled+span.el-radio__label{color:#C0C4CC;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409EFF;background:#409EFF}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409EFF}.el-radio__input.is-focus .el-radio__inner{border-color:#409EFF}.el-radio__inner{border:1px solid #DCDFE6;border-radius:100%;width:14px;height:14px;background-color:#FFF;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#409EFF}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#FFF;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-radio__label{font-size:14px;padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px;font-size:14px}.el-cascader-panel.is-bordered{border:1px solid #E4E7ED;border-radius:4px}.el-cascader-menu{min-width:180px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;border-right:solid 1px #E4E7ED}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:20px}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;-webkit-box-sizing:border-box;box-sizing:border-box}.el-avatar,.el-drawer{-webkit-box-sizing:border-box;overflow:hidden}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#C0C4CC}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409EFF;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#F5F7FA}.el-cascader-node.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;box-sizing:border-box;text-align:center;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-drawer,.el-drawer__header{display:-webkit-box;display:-ms-flexbox}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}.el-drawer.btt,.el-drawer.ttb,.el-drawer__container{left:0;right:0;width:100%}.el-drawer.ltr,.el-drawer.rtl,.el-drawer__container{top:0;bottom:0;height:100%}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@-webkit-keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@-webkit-keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@-webkit-keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}@keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#FFF;display:flex;-ms-flex-direction:column;flex-direction:column;-webkit-box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12)}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#72767b;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__title{margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__body>*{-webkit-box-sizing:border-box;box-sizing:border-box}.el-drawer__container{position:relative}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-popconfirm__main{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0}view{display: block;} \ No newline at end of file diff --git a/static/plugs/quill/image-resize.min.js b/static/plugs/quill/image-resize.min.js new file mode 100644 index 0000000..7c788a5 --- /dev/null +++ b/static/plugs/quill/image-resize.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ImageResize=e():t.ImageResize=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=39)}([function(t,e){function n(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}t.exports=n},function(t,e,n){var o=n(22),r="object"==typeof self&&self&&self.Object===Object&&self,i=o||r||Function("return this")();t.exports=i},function(t,e){function n(t){return null!=t&&"object"==typeof t}t.exports=n},function(t,e,n){function o(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e-1&&t%1==0&&t-1&&t%1==0&&t<=o}var o=9007199254740991;t.exports=n},function(t,e,n){var o=n(50),r=n(55),i=n(87),u=i&&i.isTypedArray,c=u?r(u):o;t.exports=c},function(t,e,n){function o(t){return u(t)?r(t,!0):i(t)}var r=n(44),i=n(51),u=n(12);t.exports=o},function(t,e,n){"use strict";e.a={modules:["DisplaySize","Toolbar","Resize"]}},function(t,e,n){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}n.d(e,"a",function(){return c});var u=n(9),c=function(t){function e(){var t,n,i,u;o(this,e);for(var c=arguments.length,a=Array(c),s=0;s1&&void 0!==arguments[1]?arguments[1]:{};o(this,t),this.initializeModules=function(){n.removeModules(),n.modules=n.moduleClasses.map(function(t){return new(f[t]||t)(n)}),n.modules.forEach(function(t){t.onCreate()}),n.onUpdate()},this.onUpdate=function(){n.repositionElements(),n.modules.forEach(function(t){t.onUpdate()})},this.removeModules=function(){n.modules.forEach(function(t){t.onDestroy()}),n.modules=[]},this.handleClick=function(t){if(t.target&&t.target.tagName&&"IMG"===t.target.tagName.toUpperCase()){if(n.img===t.target)return;n.img&&n.hide(),n.show(t.target)}else n.img&&n.hide()},this.show=function(t){n.img=t,n.showOverlay(),n.initializeModules()},this.showOverlay=function(){n.overlay&&n.hideOverlay(),n.quill.setSelection(null),n.setUserSelect("none"),document.addEventListener("keyup",n.checkImage,!0),n.quill.root.addEventListener("input",n.checkImage,!0),n.overlay=document.createElement("div"),n.overlay.classList.add("ql-image-overlay"),n.quill.root.parentNode.appendChild(n.overlay),n.repositionElements()},this.hideOverlay=function(){n.overlay&&(n.quill.root.parentNode.removeChild(n.overlay),n.overlay=void 0,document.removeEventListener("keyup",n.checkImage),n.quill.root.removeEventListener("input",n.checkImage),n.setUserSelect(""))},this.repositionElements=function(){if(n.overlay&&n.img){var t=n.quill.root.parentNode,e=n.img.getBoundingClientRect(),o=t.getBoundingClientRect();Object.assign(n.overlay.style,{left:e.left-o.left-1+t.scrollLeft+"px",top:e.top-o.top+t.scrollTop+"px",width:e.width+"px",height:e.height+"px"})}},this.hide=function(){n.hideOverlay(),n.removeModules(),n.img=void 0},this.setUserSelect=function(t){["userSelect","mozUserSelect","webkitUserSelect","msUserSelect"].forEach(function(e){n.quill.root.style[e]=t,document.documentElement.style[e]=t})},this.checkImage=function(t){n.img&&(46!=t.keyCode&&8!=t.keyCode||window.Quill.find(n.img).deleteAt(0),n.hide())},this.quill=e;var c=!1;r.modules&&(c=r.modules.slice()),this.options=i()({},r,u.a),!1!==c&&(this.options.modules=c),document.execCommand("enableObjectResizing",!1,"false"),this.quill.root.addEventListener("click",this.handleClick,!1),this.quill.root.parentNode.style.position=this.quill.root.parentNode.style.position||"relative",this.moduleClasses=this.options.modules,this.modules=[]};e.default=p,window.Quill&&window.Quill.register("modules/imageResize",p)},function(t,e,n){function o(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e1?n[r-1]:void 0,c=r>2?n[2]:void 0;for(u=t.length>3&&"function"==typeof u?(r--,u):void 0,c&&i(n[0],n[1],c)&&(u=r<3?void 0:u,r=1),e=Object(e);++o-1}var r=n(4);t.exports=o},function(t,e,n){function o(t,e){var n=this.__data__,o=r(n,t);return o<0?(++this.size,n.push([t,e])):n[o][1]=e,this}var r=n(4);t.exports=o},function(t,e,n){function o(){this.size=0,this.__data__={hash:new r,map:new(u||i),string:new r}}var r=n(40),i=n(3),u=n(15);t.exports=o},function(t,e,n){function o(t){var e=r(this,t).delete(t);return this.size-=e?1:0,e}var r=n(6);t.exports=o},function(t,e,n){function o(t){return r(this,t).get(t)}var r=n(6);t.exports=o},function(t,e,n){function o(t){return r(this,t).has(t)}var r=n(6);t.exports=o},function(t,e,n){function o(t,e){var n=r(this,t),o=n.size;return n.set(t,e),this.size+=n.size==o?0:1,this}var r=n(6);t.exports=o},function(t,e){function n(t){var e=[];if(null!=t)for(var n in Object(t))e.push(n);return e}t.exports=n},function(t,e,n){(function(t){var o=n(22),r="object"==typeof e&&e&&!e.nodeType&&e,i=r&&"object"==typeof t&&t&&!t.nodeType&&t,u=i&&i.exports===r,c=u&&o.process,a=function(){try{var t=i&&i.require&&i.require("util").types;return t||c&&c.binding&&c.binding("util")}catch(t){}}();t.exports=a}).call(e,n(14)(t))},function(t,e){function n(t){return r.call(t)}var o=Object.prototype,r=o.toString;t.exports=n},function(t,e){function n(t,e){return function(n){return t(e(n))}}t.exports=n},function(t,e,n){function o(t,e,n){return e=i(void 0===e?t.length-1:e,0),function(){for(var o=arguments,u=-1,c=i(o.length-e,0),a=Array(c);++u0){if(++e>=o)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}var o=800,r=16,i=Date.now;t.exports=n},function(t,e,n){function o(){this.__data__=new r,this.size=0}var r=n(3);t.exports=o},function(t,e){function n(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n}t.exports=n},function(t,e){function n(t){return this.__data__.get(t)}t.exports=n},function(t,e){function n(t){return this.__data__.has(t)}t.exports=n},function(t,e,n){function o(t,e){var n=this.__data__;if(n instanceof r){var o=n.__data__;if(!i||o.length li::before { + pointer-events: none; +} +.ql-clipboard { + left: -100000px; + height: 1px; + overflow-y: hidden; + position: absolute; + top: 50%; +} +.ql-clipboard p { + margin: 0; + padding: 0; +} +.ql-editor { + box-sizing: border-box; + line-height: 1.42; + height: 100%; + outline: none; + overflow-y: auto; + padding: 12px 15px; + tab-size: 4; + -moz-tab-size: 4; + text-align: left; + white-space: pre-wrap; + word-wrap: break-word; +} +.ql-editor > * { + cursor: text; +} +.ql-editor p, +.ql-editor ol, +.ql-editor ul, +.ql-editor pre, +.ql-editor blockquote, +.ql-editor h1, +.ql-editor h2, +.ql-editor h3, +.ql-editor h4, +.ql-editor h5, +.ql-editor h6 { + margin: 0; + padding: 0; + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol, +.ql-editor ul { + padding-left: 1.5em; +} +.ql-editor ol > li, +.ql-editor ul > li { + list-style-type: none; +} +.ql-editor ul > li::before { + content: '\2022'; +} +.ql-editor ul[data-checked=true], +.ql-editor ul[data-checked=false] { + pointer-events: none; +} +.ql-editor ul[data-checked=true] > li *, +.ql-editor ul[data-checked=false] > li * { + pointer-events: all; +} +.ql-editor ul[data-checked=true] > li::before, +.ql-editor ul[data-checked=false] > li::before { + color: #777; + cursor: pointer; + pointer-events: all; +} +.ql-editor ul[data-checked=true] > li::before { + content: '\2611'; +} +.ql-editor ul[data-checked=false] > li::before { + content: '\2610'; +} +.ql-editor li::before { + display: inline-block; + white-space: nowrap; + width: 1.2em; +} +.ql-editor li:not(.ql-direction-rtl)::before { + margin-left: -1.5em; + margin-right: 0.3em; + text-align: right; +} +.ql-editor li.ql-direction-rtl::before { + margin-left: 0.3em; + margin-right: -1.5em; +} +.ql-editor ol li:not(.ql-direction-rtl), +.ql-editor ul li:not(.ql-direction-rtl) { + padding-left: 1.5em; +} +.ql-editor ol li.ql-direction-rtl, +.ql-editor ul li.ql-direction-rtl { + padding-right: 1.5em; +} +.ql-editor ol li { + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; + counter-increment: list-0; +} +.ql-editor ol li:before { + content: counter(list-0, decimal) '. '; +} +.ql-editor ol li.ql-indent-1 { + counter-increment: list-1; +} +.ql-editor ol li.ql-indent-1:before { + content: counter(list-1, lower-alpha) '. '; +} +.ql-editor ol li.ql-indent-1 { + counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-2 { + counter-increment: list-2; +} +.ql-editor ol li.ql-indent-2:before { + content: counter(list-2, lower-roman) '. '; +} +.ql-editor ol li.ql-indent-2 { + counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-3 { + counter-increment: list-3; +} +.ql-editor ol li.ql-indent-3:before { + content: counter(list-3, decimal) '. '; +} +.ql-editor ol li.ql-indent-3 { + counter-reset: list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-4 { + counter-increment: list-4; +} +.ql-editor ol li.ql-indent-4:before { + content: counter(list-4, lower-alpha) '. '; +} +.ql-editor ol li.ql-indent-4 { + counter-reset: list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-5 { + counter-increment: list-5; +} +.ql-editor ol li.ql-indent-5:before { + content: counter(list-5, lower-roman) '. '; +} +.ql-editor ol li.ql-indent-5 { + counter-reset: list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-6 { + counter-increment: list-6; +} +.ql-editor ol li.ql-indent-6:before { + content: counter(list-6, decimal) '. '; +} +.ql-editor ol li.ql-indent-6 { + counter-reset: list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-7 { + counter-increment: list-7; +} +.ql-editor ol li.ql-indent-7:before { + content: counter(list-7, lower-alpha) '. '; +} +.ql-editor ol li.ql-indent-7 { + counter-reset: list-8 list-9; +} +.ql-editor ol li.ql-indent-8 { + counter-increment: list-8; +} +.ql-editor ol li.ql-indent-8:before { + content: counter(list-8, lower-roman) '. '; +} +.ql-editor ol li.ql-indent-8 { + counter-reset: list-9; +} +.ql-editor ol li.ql-indent-9 { + counter-increment: list-9; +} +.ql-editor ol li.ql-indent-9:before { + content: counter(list-9, decimal) '. '; +} +.ql-editor .ql-indent-1:not(.ql-direction-rtl) { + padding-left: 3em; +} +.ql-editor li.ql-indent-1:not(.ql-direction-rtl) { + padding-left: 4.5em; +} +.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right { + padding-right: 3em; +} +.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right { + padding-right: 4.5em; +} +.ql-editor .ql-indent-2:not(.ql-direction-rtl) { + padding-left: 6em; +} +.ql-editor li.ql-indent-2:not(.ql-direction-rtl) { + padding-left: 7.5em; +} +.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right { + padding-right: 6em; +} +.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right { + padding-right: 7.5em; +} +.ql-editor .ql-indent-3:not(.ql-direction-rtl) { + padding-left: 9em; +} +.ql-editor li.ql-indent-3:not(.ql-direction-rtl) { + padding-left: 10.5em; +} +.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right { + padding-right: 9em; +} +.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right { + padding-right: 10.5em; +} +.ql-editor .ql-indent-4:not(.ql-direction-rtl) { + padding-left: 12em; +} +.ql-editor li.ql-indent-4:not(.ql-direction-rtl) { + padding-left: 13.5em; +} +.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right { + padding-right: 12em; +} +.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right { + padding-right: 13.5em; +} +.ql-editor .ql-indent-5:not(.ql-direction-rtl) { + padding-left: 15em; +} +.ql-editor li.ql-indent-5:not(.ql-direction-rtl) { + padding-left: 16.5em; +} +.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right { + padding-right: 15em; +} +.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right { + padding-right: 16.5em; +} +.ql-editor .ql-indent-6:not(.ql-direction-rtl) { + padding-left: 18em; +} +.ql-editor li.ql-indent-6:not(.ql-direction-rtl) { + padding-left: 19.5em; +} +.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right { + padding-right: 18em; +} +.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right { + padding-right: 19.5em; +} +.ql-editor .ql-indent-7:not(.ql-direction-rtl) { + padding-left: 21em; +} +.ql-editor li.ql-indent-7:not(.ql-direction-rtl) { + padding-left: 22.5em; +} +.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right { + padding-right: 21em; +} +.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right { + padding-right: 22.5em; +} +.ql-editor .ql-indent-8:not(.ql-direction-rtl) { + padding-left: 24em; +} +.ql-editor li.ql-indent-8:not(.ql-direction-rtl) { + padding-left: 25.5em; +} +.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right { + padding-right: 24em; +} +.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right { + padding-right: 25.5em; +} +.ql-editor .ql-indent-9:not(.ql-direction-rtl) { + padding-left: 27em; +} +.ql-editor li.ql-indent-9:not(.ql-direction-rtl) { + padding-left: 28.5em; +} +.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right { + padding-right: 27em; +} +.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right { + padding-right: 28.5em; +} +.ql-editor .ql-video { + display: block; + max-width: 100%; + width: 100%; + min-height: 280px; +} +.ql-editor .ql-video.ql-align-center { + margin: 0 auto; +} +.ql-editor .ql-video.ql-align-right { + margin: 0 0 0 auto; +} +.ql-editor .ql-bg-black { + background-color: #000; +} +.ql-editor .ql-bg-red { + background-color: #e60000; +} +.ql-editor .ql-bg-orange { + background-color: #f90; +} +.ql-editor .ql-bg-yellow { + background-color: #ff0; +} +.ql-editor .ql-bg-green { + background-color: #008a00; +} +.ql-editor .ql-bg-blue { + background-color: #06c; +} +.ql-editor .ql-bg-purple { + background-color: #93f; +} +.ql-editor .ql-color-white { + color: #fff; +} +.ql-editor .ql-color-red { + color: #e60000; +} +.ql-editor .ql-color-orange { + color: #f90; +} +.ql-editor .ql-color-yellow { + color: #ff0; +} +.ql-editor .ql-color-green { + color: #008a00; +} +.ql-editor .ql-color-blue { + color: #06c; +} +.ql-editor .ql-color-purple { + color: #93f; +} +.ql-editor .ql-font-serif { + font-family: Georgia, Times New Roman, serif; +} +.ql-editor .ql-font-monospace { + font-family: Monaco, Courier New, monospace; +} +.ql-editor .ql-size-small { + font-size: 0.75em; +} +.ql-editor .ql-size-large { + font-size: 1.5em; +} +.ql-editor .ql-size-huge { + font-size: 2.5em; +} +.ql-editor .ql-direction-rtl { + direction: rtl; + text-align: inherit; +} +.ql-editor .ql-align-center { + text-align: center; +} +.ql-editor .ql-align-justify { + text-align: justify; +} +.ql-editor .ql-align-right { + text-align: right; +} +.ql-editor.ql-blank::before { + color: rgba(0,0,0,0.6); + content: attr(data-placeholder); + font-style: italic; + left: 15px; + pointer-events: none; + position: absolute; + right: 15px; +} +.ql-snow.ql-toolbar:after, +.ql-snow .ql-toolbar:after { + clear: both; + content: ''; + display: table; +} +.ql-snow.ql-toolbar button, +.ql-snow .ql-toolbar button { + background: none; + border: none; + cursor: pointer; + display: inline-block; + float: left; + height: 24px; + padding: 3px 5px; + width: 28px; +} +.ql-snow.ql-toolbar button svg, +.ql-snow .ql-toolbar button svg { + float: left; + height: 100%; +} +.ql-snow.ql-toolbar button:active:hover, +.ql-snow .ql-toolbar button:active:hover { + outline: none; +} +.ql-snow.ql-toolbar input.ql-image[type=file], +.ql-snow .ql-toolbar input.ql-image[type=file] { + display: none; +} +.ql-snow.ql-toolbar button:hover, +.ql-snow .ql-toolbar button:hover, +.ql-snow.ql-toolbar button:focus, +.ql-snow .ql-toolbar button:focus, +.ql-snow.ql-toolbar button.ql-active, +.ql-snow .ql-toolbar button.ql-active, +.ql-snow.ql-toolbar .ql-picker-label:hover, +.ql-snow .ql-toolbar .ql-picker-label:hover, +.ql-snow.ql-toolbar .ql-picker-label.ql-active, +.ql-snow .ql-toolbar .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker-item:hover, +.ql-snow .ql-toolbar .ql-picker-item:hover, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected { + color: #06c; +} +.ql-snow.ql-toolbar button:hover .ql-fill, +.ql-snow .ql-toolbar button:hover .ql-fill, +.ql-snow.ql-toolbar button:focus .ql-fill, +.ql-snow .ql-toolbar button:focus .ql-fill, +.ql-snow.ql-toolbar button.ql-active .ql-fill, +.ql-snow .ql-toolbar button.ql-active .ql-fill, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill, +.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill, +.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill, +.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill, +.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill, +.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill, +.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill { + fill: #06c; +} +.ql-snow.ql-toolbar button:hover .ql-stroke, +.ql-snow .ql-toolbar button:hover .ql-stroke, +.ql-snow.ql-toolbar button:focus .ql-stroke, +.ql-snow .ql-toolbar button:focus .ql-stroke, +.ql-snow.ql-toolbar button.ql-active .ql-stroke, +.ql-snow .ql-toolbar button.ql-active .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke, +.ql-snow.ql-toolbar button:hover .ql-stroke-miter, +.ql-snow .ql-toolbar button:hover .ql-stroke-miter, +.ql-snow.ql-toolbar button:focus .ql-stroke-miter, +.ql-snow .ql-toolbar button:focus .ql-stroke-miter, +.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter, +.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter { + stroke: #06c; +} +@media (pointer: coarse) { + .ql-snow.ql-toolbar button:hover:not(.ql-active), + .ql-snow .ql-toolbar button:hover:not(.ql-active) { + color: #444; + } + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill, + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill { + fill: #444; + } + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke, + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter { + stroke: #444; + } +} +.ql-snow { + box-sizing: border-box; +} +.ql-snow * { + box-sizing: border-box; +} +.ql-snow .ql-hidden { + display: none; +} +.ql-snow .ql-out-bottom, +.ql-snow .ql-out-top { + visibility: hidden; +} +.ql-snow .ql-tooltip { + position: absolute; + transform: translateY(10px); +} +.ql-snow .ql-tooltip a { + cursor: pointer; + text-decoration: none; +} +.ql-snow .ql-tooltip.ql-flip { + transform: translateY(-10px); +} +.ql-snow .ql-formats { + display: inline-block; + vertical-align: middle; +} +.ql-snow .ql-formats:after { + clear: both; + content: ''; + display: table; +} +.ql-snow .ql-stroke { + fill: none; + stroke: #444; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; +} +.ql-snow .ql-stroke-miter { + fill: none; + stroke: #444; + stroke-miterlimit: 10; + stroke-width: 2; +} +.ql-snow .ql-fill, +.ql-snow .ql-stroke.ql-fill { + fill: #444; +} +.ql-snow .ql-empty { + fill: none; +} +.ql-snow .ql-even { + fill-rule: evenodd; +} +.ql-snow .ql-thin, +.ql-snow .ql-stroke.ql-thin { + stroke-width: 1; +} +.ql-snow .ql-transparent { + opacity: 0.4; +} +.ql-snow .ql-direction svg:last-child { + display: none; +} +.ql-snow .ql-direction.ql-active svg:last-child { + display: inline; +} +.ql-snow .ql-direction.ql-active svg:first-child { + display: none; +} +.ql-snow .ql-editor h1 { + font-size: 2em; +} +.ql-snow .ql-editor h2 { + font-size: 1.5em; +} +.ql-snow .ql-editor h3 { + font-size: 1.17em; +} +.ql-snow .ql-editor h4 { + font-size: 1em; +} +.ql-snow .ql-editor h5 { + font-size: 0.83em; +} +.ql-snow .ql-editor h6 { + font-size: 0.67em; +} +.ql-snow .ql-editor a { + text-decoration: underline; +} +.ql-snow .ql-editor blockquote { + border-left: 4px solid #ccc; + margin-bottom: 5px; + margin-top: 5px; + padding-left: 16px; +} +.ql-snow .ql-editor code, +.ql-snow .ql-editor pre { + background-color: #f0f0f0; + border-radius: 3px; +} +.ql-snow .ql-editor pre { + white-space: pre-wrap; + margin-bottom: 5px; + margin-top: 5px; + padding: 5px 10px; +} +.ql-snow .ql-editor code { + font-size: 85%; + padding: 2px 4px; +} +.ql-snow .ql-editor pre.ql-syntax { + background-color: #23241f; + color: #f8f8f2; + overflow: visible; +} +.ql-snow .ql-editor img { + max-width: 100%; +} +.ql-snow .ql-picker { + color: #444; + display: inline-block; + float: left; + font-size: 14px; + font-weight: 500; + height: 24px; + position: relative; + vertical-align: middle; +} +.ql-snow .ql-picker-label { + cursor: pointer; + display: inline-block; + height: 100%; + padding-left: 8px; + padding-right: 2px; + position: relative; + width: 100%; +} +.ql-snow .ql-picker-label::before { + display: inline-block; + line-height: 22px; +} +.ql-snow .ql-picker-options { + background-color: #fff; + display: none; + min-width: 100%; + padding: 4px 8px; + position: absolute; + white-space: nowrap; +} +.ql-snow .ql-picker-options .ql-picker-item { + cursor: pointer; + display: block; + padding-bottom: 5px; + padding-top: 5px; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-label { + color: #ccc; + z-index: 2; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill { + fill: #ccc; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke { + stroke: #ccc; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-options { + display: block; + margin-top: -1px; + top: 100%; + z-index: 1; +} +.ql-snow .ql-color-picker, +.ql-snow .ql-icon-picker { + width: 28px; +} +.ql-snow .ql-color-picker .ql-picker-label, +.ql-snow .ql-icon-picker .ql-picker-label { + padding: 2px 4px; +} +.ql-snow .ql-color-picker .ql-picker-label svg, +.ql-snow .ql-icon-picker .ql-picker-label svg { + right: 4px; +} +.ql-snow .ql-icon-picker .ql-picker-options { + padding: 4px 0px; +} +.ql-snow .ql-icon-picker .ql-picker-item { + height: 24px; + width: 24px; + padding: 2px 4px; +} +.ql-snow .ql-color-picker .ql-picker-options { + padding: 3px 5px; + width: 152px; +} +.ql-snow .ql-color-picker .ql-picker-item { + border: 1px solid transparent; + float: left; + height: 16px; + margin: 2px; + padding: 0px; + width: 16px; +} +.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg { + position: absolute; + margin-top: -9px; + right: 0; + top: 50%; + width: 18px; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before { + content: attr(data-label); +} +.ql-snow .ql-picker.ql-header { + width: 98px; +} +.ql-snow .ql-picker.ql-header .ql-picker-label::before, +.ql-snow .ql-picker.ql-header .ql-picker-item::before { + content: 'Normal'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { + content: 'Heading 1'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { + content: 'Heading 2'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { + content: 'Heading 3'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { + content: 'Heading 4'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { + content: 'Heading 5'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { + content: 'Heading 6'; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { + font-size: 2em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { + font-size: 1.5em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { + font-size: 1.17em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { + font-size: 1em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { + font-size: 0.83em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { + font-size: 0.67em; +} +.ql-snow .ql-picker.ql-font { + width: 108px; +} +.ql-snow .ql-picker.ql-font .ql-picker-label::before, +.ql-snow .ql-picker.ql-font .ql-picker-item::before { + content: 'Sans Serif'; +} +.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before, +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { + content: 'Serif'; +} +.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before, +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { + content: 'Monospace'; +} +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { + font-family: Georgia, Times New Roman, serif; +} +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { + font-family: Monaco, Courier New, monospace; +} +.ql-snow .ql-picker.ql-size { + width: 98px; +} +.ql-snow .ql-picker.ql-size .ql-picker-label::before, +.ql-snow .ql-picker.ql-size .ql-picker-item::before { + content: 'Normal'; +} +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { + content: 'Small'; +} +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { + content: 'Large'; +} +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { + content: 'Huge'; +} +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { + font-size: 10px; +} +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { + font-size: 18px; +} +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { + font-size: 32px; +} +.ql-snow .ql-color-picker.ql-background .ql-picker-item { + background-color: #fff; +} +.ql-snow .ql-color-picker.ql-color .ql-picker-item { + background-color: #000; +} +.ql-toolbar.ql-snow { + border: 1px solid #ccc; + box-sizing: border-box; + font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; + padding: 8px; +} +.ql-toolbar.ql-snow .ql-formats { + margin-right: 15px; +} +.ql-toolbar.ql-snow .ql-picker-label { + border: 1px solid transparent; +} +.ql-toolbar.ql-snow .ql-picker-options { + border: 1px solid transparent; + box-shadow: rgba(0,0,0,0.2) 0 2px 8px; +} +.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label { + border-color: #ccc; +} +.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options { + border-color: #ccc; +} +.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected, +.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover { + border-color: #000; +} +.ql-toolbar.ql-snow + .ql-container.ql-snow { + border-top: 0px; +} +.ql-snow .ql-tooltip { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: 0px 0px 5px #ddd; + color: #444; + padding: 5px 12px; + white-space: nowrap; +} +.ql-snow .ql-tooltip::before { + content: "Visit URL:"; + line-height: 26px; + margin-right: 8px; +} +.ql-snow .ql-tooltip input[type=text] { + display: none; + border: 1px solid #ccc; + font-size: 13px; + height: 26px; + margin: 0px; + padding: 3px 5px; + width: 170px; +} +.ql-snow .ql-tooltip a.ql-preview { + display: inline-block; + max-width: 200px; + overflow-x: hidden; + text-overflow: ellipsis; + vertical-align: top; +} +.ql-snow .ql-tooltip a.ql-action::after { + border-right: 1px solid #ccc; + content: 'Edit'; + margin-left: 16px; + padding-right: 8px; +} +.ql-snow .ql-tooltip a.ql-remove::before { + content: 'Remove'; + margin-left: 8px; +} +.ql-snow .ql-tooltip a { + line-height: 26px; +} +.ql-snow .ql-tooltip.ql-editing a.ql-preview, +.ql-snow .ql-tooltip.ql-editing a.ql-remove { + display: none; + margin-left: 150px; +} +.ql-snow .ql-tooltip.ql-editing input[type=text] { + display: inline-block; +} +.ql-snow .ql-tooltip.ql-editing a.ql-action::after { + border-right: 0px; + content: 'Save'; + padding-right: 0px; +} +.ql-snow .ql-tooltip[data-mode=link]::before { + content: "Enter link:"; +} +.ql-snow .ql-tooltip[data-mode=formula]::before { + content: "Enter formula:"; +} +.ql-snow .ql-tooltip[data-mode=video]::before { + content: "Enter video:"; +} +.ql-snow a { + color: #06c; +} +.ql-container.ql-snow { + border: 1px solid #ccc; +} +.ql-snow .ql-tooltip { + left: 0 !important; +} \ No newline at end of file diff --git a/static/plugs/quill/quill.min.js b/static/plugs/quill/quill.min.js new file mode 100644 index 0000000..d9f46b8 --- /dev/null +++ b/static/plugs/quill/quill.min.js @@ -0,0 +1,8 @@ +/*! + * Quill Editor v1.3.7 + * https://quilljs.com/ + * Copyright (c) 2014, Jason Chen + * Copyright (c) 2013, salesforce.com + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Quill=e():t.Quill=e()}("undefined"!=typeof self?self:this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};return e.m=t,e.c=n,e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:r})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=45)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(17),o=n(18),i=n(19),l=n(48),a=n(49),s=n(50),u=n(51),c=n(52),f=n(11),h=n(29),p=n(30),d=n(28),y=n(1),v={Scope:y.Scope,create:y.create,find:y.find,query:y.query,register:y.register,Container:r.default,Format:o.default,Leaf:i.default,Embed:u.default,Scroll:l.default,Block:s.default,Inline:a.default,Text:c.default,Attributor:{Attribute:f.default,Class:h.default,Style:p.default,Store:d.default}};e.default=v},function(t,e,n){"use strict";function r(t,e){var n=i(t);if(null==n)throw new s("Unable to create "+t+" blot");var r=n;return new r(t instanceof Node||t.nodeType===Node.TEXT_NODE?t:r.create(e),e)}function o(t,n){return void 0===n&&(n=!1),null==t?null:null!=t[e.DATA_KEY]?t[e.DATA_KEY].blot:n?o(t.parentNode,n):null}function i(t,e){void 0===e&&(e=p.ANY);var n;if("string"==typeof t)n=h[t]||u[t];else if(t instanceof Text||t.nodeType===Node.TEXT_NODE)n=h.text;else if("number"==typeof t)t&p.LEVEL&p.BLOCK?n=h.block:t&p.LEVEL&p.INLINE&&(n=h.inline);else if(t instanceof HTMLElement){var r=(t.getAttribute("class")||"").split(/\s+/);for(var o in r)if(n=c[r[o]])break;n=n||f[t.tagName]}return null==n?null:e&p.LEVEL&n.scope&&e&p.TYPE&n.scope?n:null}function l(){for(var t=[],e=0;e1)return t.map(function(t){return l(t)});var n=t[0];if("string"!=typeof n.blotName&&"string"!=typeof n.attrName)throw new s("Invalid definition");if("abstract"===n.blotName)throw new s("Cannot register abstract class");if(h[n.blotName||n.attrName]=n,"string"==typeof n.keyName)u[n.keyName]=n;else if(null!=n.className&&(c[n.className]=n),null!=n.tagName){Array.isArray(n.tagName)?n.tagName=n.tagName.map(function(t){return t.toUpperCase()}):n.tagName=n.tagName.toUpperCase();var r=Array.isArray(n.tagName)?n.tagName:[n.tagName];r.forEach(function(t){null!=f[t]&&null!=n.className||(f[t]=n)})}return n}var a=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var s=function(t){function e(e){var n=this;return e="[Parchment] "+e,n=t.call(this,e)||this,n.message=e,n.name=n.constructor.name,n}return a(e,t),e}(Error);e.ParchmentError=s;var u={},c={},f={},h={};e.DATA_KEY="__blot";var p;!function(t){t[t.TYPE=3]="TYPE",t[t.LEVEL=12]="LEVEL",t[t.ATTRIBUTE=13]="ATTRIBUTE",t[t.BLOT=14]="BLOT",t[t.INLINE=7]="INLINE",t[t.BLOCK=11]="BLOCK",t[t.BLOCK_BLOT=10]="BLOCK_BLOT",t[t.INLINE_BLOT=6]="INLINE_BLOT",t[t.BLOCK_ATTRIBUTE=9]="BLOCK_ATTRIBUTE",t[t.INLINE_ATTRIBUTE=5]="INLINE_ATTRIBUTE",t[t.ANY=15]="ANY"}(p=e.Scope||(e.Scope={})),e.create=r,e.find=o,e.query=i,e.register=l},function(t,e){"use strict";var n=Object.prototype.hasOwnProperty,r=Object.prototype.toString,o=Object.defineProperty,i=Object.getOwnPropertyDescriptor,l=function(t){return"function"==typeof Array.isArray?Array.isArray(t):"[object Array]"===r.call(t)},a=function(t){if(!t||"[object Object]"!==r.call(t))return!1;var e=n.call(t,"constructor"),o=t.constructor&&t.constructor.prototype&&n.call(t.constructor.prototype,"isPrototypeOf");if(t.constructor&&!e&&!o)return!1;var i;for(i in t);return void 0===i||n.call(t,i)},s=function(t,e){o&&"__proto__"===e.name?o(t,e.name,{enumerable:!0,configurable:!0,value:e.newValue,writable:!0}):t[e.name]=e.newValue},u=function(t,e){if("__proto__"===e){if(!n.call(t,e))return;if(i)return i(t,e).value}return t[e]};t.exports=function t(){var e,n,r,o,i,c,f=arguments[0],h=1,p=arguments.length,d=!1;for("boolean"==typeof f&&(d=f,f=arguments[1]||{},h=2),(null==f||"object"!=typeof f&&"function"!=typeof f)&&(f={});h1&&void 0!==arguments[1]?arguments[1]:{};return null==t?e:("function"==typeof t.formats&&(e=(0,f.default)(e,t.formats())),null==t.parent||"scroll"==t.parent.blotName||t.parent.statics.scope!==t.statics.scope?e:a(t.parent,e))}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.BlockEmbed=e.bubbleFormats=void 0;var s=function(){function t(t,e){for(var n=0;n0&&(t1&&void 0!==arguments[1]&&arguments[1];if(n&&(0===t||t>=this.length()-1)){var r=this.clone();return 0===t?(this.parent.insertBefore(r,this),this):(this.parent.insertBefore(r,this.next),r)}var o=u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"split",this).call(this,t,n);return this.cache={},o}}]),e}(y.default.Block);x.blotName="block",x.tagName="P",x.defaultChild="break",x.allowedChildren=[m.default,y.default.Embed,O.default],e.bubbleFormats=a,e.BlockEmbed=w,e.default=x},function(t,e,n){var r=n(54),o=n(12),i=n(2),l=n(20),a=String.fromCharCode(0),s=function(t){Array.isArray(t)?this.ops=t:null!=t&&Array.isArray(t.ops)?this.ops=t.ops:this.ops=[]};s.prototype.insert=function(t,e){var n={};return 0===t.length?this:(n.insert=t,null!=e&&"object"==typeof e&&Object.keys(e).length>0&&(n.attributes=e),this.push(n))},s.prototype.delete=function(t){return t<=0?this:this.push({delete:t})},s.prototype.retain=function(t,e){if(t<=0)return this;var n={retain:t};return null!=e&&"object"==typeof e&&Object.keys(e).length>0&&(n.attributes=e),this.push(n)},s.prototype.push=function(t){var e=this.ops.length,n=this.ops[e-1];if(t=i(!0,{},t),"object"==typeof n){if("number"==typeof t.delete&&"number"==typeof n.delete)return this.ops[e-1]={delete:n.delete+t.delete},this;if("number"==typeof n.delete&&null!=t.insert&&(e-=1,"object"!=typeof(n=this.ops[e-1])))return this.ops.unshift(t),this;if(o(t.attributes,n.attributes)){if("string"==typeof t.insert&&"string"==typeof n.insert)return this.ops[e-1]={insert:n.insert+t.insert},"object"==typeof t.attributes&&(this.ops[e-1].attributes=t.attributes),this;if("number"==typeof t.retain&&"number"==typeof n.retain)return this.ops[e-1]={retain:n.retain+t.retain},"object"==typeof t.attributes&&(this.ops[e-1].attributes=t.attributes),this}}return e===this.ops.length?this.ops.push(t):this.ops.splice(e,0,t),this},s.prototype.chop=function(){var t=this.ops[this.ops.length-1];return t&&t.retain&&!t.attributes&&this.ops.pop(),this},s.prototype.filter=function(t){return this.ops.filter(t)},s.prototype.forEach=function(t){this.ops.forEach(t)},s.prototype.map=function(t){return this.ops.map(t)},s.prototype.partition=function(t){var e=[],n=[];return this.forEach(function(r){(t(r)?e:n).push(r)}),[e,n]},s.prototype.reduce=function(t,e){return this.ops.reduce(t,e)},s.prototype.changeLength=function(){return this.reduce(function(t,e){return e.insert?t+l.length(e):e.delete?t-e.delete:t},0)},s.prototype.length=function(){return this.reduce(function(t,e){return t+l.length(e)},0)},s.prototype.slice=function(t,e){t=t||0,"number"!=typeof e&&(e=1/0);for(var n=[],r=l.iterator(this.ops),o=0;o0&&n.next(i.retain-a)}for(var u=new s(r);e.hasNext()||n.hasNext();)if("insert"===n.peekType())u.push(n.next());else if("delete"===e.peekType())u.push(e.next());else{var c=Math.min(e.peekLength(),n.peekLength()),f=e.next(c),h=n.next(c);if("number"==typeof h.retain){var p={};"number"==typeof f.retain?p.retain=c:p.insert=f.insert;var d=l.attributes.compose(f.attributes,h.attributes,"number"==typeof f.retain);if(d&&(p.attributes=d),u.push(p),!n.hasNext()&&o(u.ops[u.ops.length-1],p)){var y=new s(e.rest());return u.concat(y).chop()}}else"number"==typeof h.delete&&"number"==typeof f.retain&&u.push(h)}return u.chop()},s.prototype.concat=function(t){var e=new s(this.ops.slice());return t.ops.length>0&&(e.push(t.ops[0]),e.ops=e.ops.concat(t.ops.slice(1))),e},s.prototype.diff=function(t,e){if(this.ops===t.ops)return new s;var n=[this,t].map(function(e){return e.map(function(n){if(null!=n.insert)return"string"==typeof n.insert?n.insert:a;var r=e===t?"on":"with";throw new Error("diff() called "+r+" non-document")}).join("")}),i=new s,u=r(n[0],n[1],e),c=l.iterator(this.ops),f=l.iterator(t.ops);return u.forEach(function(t){for(var e=t[1].length;e>0;){var n=0;switch(t[0]){case r.INSERT:n=Math.min(f.peekLength(),e),i.push(f.next(n));break;case r.DELETE:n=Math.min(e,c.peekLength()),c.next(n),i.delete(n);break;case r.EQUAL:n=Math.min(c.peekLength(),f.peekLength(),e);var a=c.next(n),s=f.next(n);o(a.insert,s.insert)?i.retain(n,l.attributes.diff(a.attributes,s.attributes)):i.push(s).delete(n)}e-=n}}),i.chop()},s.prototype.eachLine=function(t,e){e=e||"\n";for(var n=l.iterator(this.ops),r=new s,o=0;n.hasNext();){if("insert"!==n.peekType())return;var i=n.peek(),a=l.length(i)-n.peekLength(),u="string"==typeof i.insert?i.insert.indexOf(e,a)-a:-1;if(u<0)r.push(n.next());else if(u>0)r.push(n.next(u));else{if(!1===t(r,n.next(1).attributes||{},o))return;o+=1,r=new s}}r.length()>0&&t(r,{},o)},s.prototype.transform=function(t,e){if(e=!!e,"number"==typeof t)return this.transformPosition(t,e);for(var n=l.iterator(this.ops),r=l.iterator(t.ops),o=new s;n.hasNext()||r.hasNext();)if("insert"!==n.peekType()||!e&&"insert"===r.peekType())if("insert"===r.peekType())o.push(r.next());else{var i=Math.min(n.peekLength(),r.peekLength()),a=n.next(i),u=r.next(i);if(a.delete)continue;u.delete?o.push(u):o.retain(i,l.attributes.transform(a.attributes,u.attributes,e))}else o.retain(l.length(n.next()));return o.chop()},s.prototype.transformPosition=function(t,e){e=!!e;for(var n=l.iterator(this.ops),r=0;n.hasNext()&&r<=t;){var o=n.peekLength(),i=n.peekType();n.next(),"delete"!==i?("insert"===i&&(r0){var n=this.parent.isolate(this.offset(),this.length());this.moveChildren(n),n.wrap(this)}}}],[{key:"compare",value:function(t,n){var r=e.order.indexOf(t),o=e.order.indexOf(n);return r>=0||o>=0?r-o:t===n?0:t0){var a,s=[g.default.events.TEXT_CHANGE,l,i,e];if((a=this.emitter).emit.apply(a,[g.default.events.EDITOR_CHANGE].concat(s)),e!==g.default.sources.SILENT){var c;(c=this.emitter).emit.apply(c,s)}}return l}function s(t,e,n,r,o){var i={};return"number"==typeof t.index&&"number"==typeof t.length?"number"!=typeof e?(o=r,r=n,n=e,e=t.length,t=t.index):(e=t.length,t=t.index):"number"!=typeof e&&(o=r,r=n,n=e,e=0),"object"===(void 0===n?"undefined":c(n))?(i=n,o=r):"string"==typeof n&&(null!=r?i[n]=r:o=n),o=o||g.default.sources.API,[t,e,i,o]}function u(t,e,n,r){if(null==t)return null;var o=void 0,i=void 0;if(e instanceof d.default){var l=[t.index,t.index+t.length].map(function(t){return e.transformPosition(t,r!==g.default.sources.USER)}),a=f(l,2);o=a[0],i=a[1]}else{var s=[t.index,t.index+t.length].map(function(t){return t=0?t+n:Math.max(e,t+n)}),u=f(s,2);o=u[0],i=u[1]}return new x.Range(o,i-o)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.overload=e.expandConfig=void 0;var c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},f=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),h=function(){function t(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(i(this,t),this.options=l(e,r),this.container=this.options.container,null==this.container)return P.error("Invalid Quill container",e);this.options.debug&&t.debug(this.options.debug);var o=this.container.innerHTML.trim();this.container.classList.add("ql-container"),this.container.innerHTML="",this.container.__quill=this,this.root=this.addContainer("ql-editor"),this.root.classList.add("ql-blank"),this.root.setAttribute("data-gramm",!1),this.scrollingContainer=this.options.scrollingContainer||this.root,this.emitter=new g.default,this.scroll=w.default.create(this.root,{emitter:this.emitter,whitelist:this.options.formats}),this.editor=new v.default(this.scroll),this.selection=new k.default(this.scroll,this.emitter),this.theme=new this.options.theme(this,this.options),this.keyboard=this.theme.addModule("keyboard"),this.clipboard=this.theme.addModule("clipboard"),this.history=this.theme.addModule("history"),this.theme.init(),this.emitter.on(g.default.events.EDITOR_CHANGE,function(t){t===g.default.events.TEXT_CHANGE&&n.root.classList.toggle("ql-blank",n.editor.isBlank())}),this.emitter.on(g.default.events.SCROLL_UPDATE,function(t,e){var r=n.selection.lastRange,o=r&&0===r.length?r.index:void 0;a.call(n,function(){return n.editor.update(null,e,o)},t)});var s=this.clipboard.convert("
"+o+"


");this.setContents(s),this.history.clear(),this.options.placeholder&&this.root.setAttribute("data-placeholder",this.options.placeholder),this.options.readOnly&&this.disable()}return h(t,null,[{key:"debug",value:function(t){!0===t&&(t="log"),A.default.level(t)}},{key:"find",value:function(t){return t.__quill||w.default.find(t)}},{key:"import",value:function(t){return null==this.imports[t]&&P.error("Cannot import "+t+". Are you sure it was registered?"),this.imports[t]}},{key:"register",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if("string"!=typeof t){var o=t.attrName||t.blotName;"string"==typeof o?this.register("formats/"+o,t,e):Object.keys(t).forEach(function(r){n.register(r,t[r],e)})}else null==this.imports[t]||r||P.warn("Overwriting "+t+" with",e),this.imports[t]=e,(t.startsWith("blots/")||t.startsWith("formats/"))&&"abstract"!==e.blotName?w.default.register(e):t.startsWith("modules")&&"function"==typeof e.register&&e.register()}}]),h(t,[{key:"addContainer",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if("string"==typeof t){var n=t;t=document.createElement("div"),t.classList.add(n)}return this.container.insertBefore(t,e),t}},{key:"blur",value:function(){this.selection.setRange(null)}},{key:"deleteText",value:function(t,e,n){var r=this,o=s(t,e,n),i=f(o,4);return t=i[0],e=i[1],n=i[3],a.call(this,function(){return r.editor.deleteText(t,e)},n,t,-1*e)}},{key:"disable",value:function(){this.enable(!1)}},{key:"enable",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.scroll.enable(t),this.container.classList.toggle("ql-disabled",!t)}},{key:"focus",value:function(){var t=this.scrollingContainer.scrollTop;this.selection.focus(),this.scrollingContainer.scrollTop=t,this.scrollIntoView()}},{key:"format",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:g.default.sources.API;return a.call(this,function(){var r=n.getSelection(!0),i=new d.default;if(null==r)return i;if(w.default.query(t,w.default.Scope.BLOCK))i=n.editor.formatLine(r.index,r.length,o({},t,e));else{if(0===r.length)return n.selection.format(t,e),i;i=n.editor.formatText(r.index,r.length,o({},t,e))}return n.setSelection(r,g.default.sources.SILENT),i},r)}},{key:"formatLine",value:function(t,e,n,r,o){var i=this,l=void 0,u=s(t,e,n,r,o),c=f(u,4);return t=c[0],e=c[1],l=c[2],o=c[3],a.call(this,function(){return i.editor.formatLine(t,e,l)},o,t,0)}},{key:"formatText",value:function(t,e,n,r,o){var i=this,l=void 0,u=s(t,e,n,r,o),c=f(u,4);return t=c[0],e=c[1],l=c[2],o=c[3],a.call(this,function(){return i.editor.formatText(t,e,l)},o,t,0)}},{key:"getBounds",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=void 0;n="number"==typeof t?this.selection.getBounds(t,e):this.selection.getBounds(t.index,t.length);var r=this.container.getBoundingClientRect();return{bottom:n.bottom-r.top,height:n.height,left:n.left-r.left,right:n.right-r.left,top:n.top-r.top,width:n.width}}},{key:"getContents",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.getLength()-t,n=s(t,e),r=f(n,2);return t=r[0],e=r[1],this.editor.getContents(t,e)}},{key:"getFormat",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.getSelection(!0),e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return"number"==typeof t?this.editor.getFormat(t,e):this.editor.getFormat(t.index,t.length)}},{key:"getIndex",value:function(t){return t.offset(this.scroll)}},{key:"getLength",value:function(){return this.scroll.length()}},{key:"getLeaf",value:function(t){return this.scroll.leaf(t)}},{key:"getLine",value:function(t){return this.scroll.line(t)}},{key:"getLines",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Number.MAX_VALUE;return"number"!=typeof t?this.scroll.lines(t.index,t.length):this.scroll.lines(t,e)}},{key:"getModule",value:function(t){return this.theme.modules[t]}},{key:"getSelection",value:function(){return arguments.length>0&&void 0!==arguments[0]&&arguments[0]&&this.focus(),this.update(),this.selection.getRange()[0]}},{key:"getText",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.getLength()-t,n=s(t,e),r=f(n,2);return t=r[0],e=r[1],this.editor.getText(t,e)}},{key:"hasFocus",value:function(){return this.selection.hasFocus()}},{key:"insertEmbed",value:function(e,n,r){var o=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:t.sources.API;return a.call(this,function(){return o.editor.insertEmbed(e,n,r)},i,e)}},{key:"insertText",value:function(t,e,n,r,o){var i=this,l=void 0,u=s(t,0,n,r,o),c=f(u,4);return t=c[0],l=c[2],o=c[3],a.call(this,function(){return i.editor.insertText(t,e,l)},o,t,e.length)}},{key:"isEnabled",value:function(){return!this.container.classList.contains("ql-disabled")}},{key:"off",value:function(){return this.emitter.off.apply(this.emitter,arguments)}},{key:"on",value:function(){return this.emitter.on.apply(this.emitter,arguments)}},{key:"once",value:function(){return this.emitter.once.apply(this.emitter,arguments)}},{key:"pasteHTML",value:function(t,e,n){this.clipboard.dangerouslyPasteHTML(t,e,n)}},{key:"removeFormat",value:function(t,e,n){var r=this,o=s(t,e,n),i=f(o,4);return t=i[0],e=i[1],n=i[3],a.call(this,function(){return r.editor.removeFormat(t,e)},n,t)}},{key:"scrollIntoView",value:function(){this.selection.scrollIntoView(this.scrollingContainer)}},{key:"setContents",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:g.default.sources.API;return a.call(this,function(){t=new d.default(t);var n=e.getLength(),r=e.editor.deleteText(0,n),o=e.editor.applyDelta(t),i=o.ops[o.ops.length-1];return null!=i&&"string"==typeof i.insert&&"\n"===i.insert[i.insert.length-1]&&(e.editor.deleteText(e.getLength()-1,1),o.delete(1)),r.compose(o)},n)}},{key:"setSelection",value:function(e,n,r){if(null==e)this.selection.setRange(null,n||t.sources.API);else{var o=s(e,n,r),i=f(o,4);e=i[0],n=i[1],r=i[3],this.selection.setRange(new x.Range(e,n),r),r!==g.default.sources.SILENT&&this.selection.scrollIntoView(this.scrollingContainer)}}},{key:"setText",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:g.default.sources.API,n=(new d.default).insert(t);return this.setContents(n,e)}},{key:"update",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:g.default.sources.USER,e=this.scroll.update(t);return this.selection.update(t),e}},{key:"updateContents",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:g.default.sources.API;return a.call(this,function(){return t=new d.default(t),e.editor.applyDelta(t,n)},n,!0)}}]),t}();S.DEFAULTS={bounds:null,formats:null,modules:{},placeholder:"",readOnly:!1,scrollingContainer:null,strict:!0,theme:"default"},S.events=g.default.events,S.sources=g.default.sources,S.version="1.3.7",S.imports={delta:d.default,parchment:w.default,"core/module":_.default,"core/theme":T.default},e.expandConfig=l,e.overload=s,e.default=S},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var o=function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r(this,t),this.quill=e,this.options=n};o.DEFAULTS={},e.default=o},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=n(0),a=function(t){return t&&t.__esModule?t:{default:t}}(l),s=function(t){function e(){return r(this,e),o(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return i(e,t),e}(a.default.Text);e.default=s},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(t,e){for(var n=0;n1?e-1:0),r=1;r1?n-1:0),o=1;o-1:this.whitelist.indexOf(e)>-1))},t.prototype.remove=function(t){t.removeAttribute(this.keyName)},t.prototype.value=function(t){var e=t.getAttribute(this.keyName);return this.canAdd(t,e)&&e?e:""},t}();e.default=o},function(t,e,n){function r(t){return null===t||void 0===t}function o(t){return!(!t||"object"!=typeof t||"number"!=typeof t.length)&&("function"==typeof t.copy&&"function"==typeof t.slice&&!(t.length>0&&"number"!=typeof t[0]))}function i(t,e,n){var i,c;if(r(t)||r(e))return!1;if(t.prototype!==e.prototype)return!1;if(s(t))return!!s(e)&&(t=l.call(t),e=l.call(e),u(t,e,n));if(o(t)){if(!o(e))return!1;if(t.length!==e.length)return!1;for(i=0;i=0;i--)if(f[i]!=h[i])return!1;for(i=f.length-1;i>=0;i--)if(c=f[i],!u(t[c],e[c],n))return!1;return typeof t==typeof e}var l=Array.prototype.slice,a=n(55),s=n(56),u=t.exports=function(t,e,n){return n||(n={}),t===e||(t instanceof Date&&e instanceof Date?t.getTime()===e.getTime():!t||!e||"object"!=typeof t&&"object"!=typeof e?n.strict?t===e:t==e:i(t,e,n))}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Code=void 0;var a=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),s=function(){function t(t,e){for(var n=0;n=t+n)){var l=this.newlineIndex(t,!0)+1,a=i-l+1,s=this.isolate(l,a),u=s.next;s.format(r,o),u instanceof e&&u.formatAt(0,t-l+n-a,r,o)}}}},{key:"insertAt",value:function(t,e,n){if(null==n){var r=this.descendant(m.default,t),o=a(r,2),i=o[0],l=o[1];i.insertAt(l,e)}}},{key:"length",value:function(){var t=this.domNode.textContent.length;return this.domNode.textContent.endsWith("\n")?t:t+1}},{key:"newlineIndex",value:function(t){if(arguments.length>1&&void 0!==arguments[1]&&arguments[1])return this.domNode.textContent.slice(0,t).lastIndexOf("\n");var e=this.domNode.textContent.slice(t).indexOf("\n");return e>-1?t+e:-1}},{key:"optimize",value:function(t){this.domNode.textContent.endsWith("\n")||this.appendChild(p.default.create("text","\n")),u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"optimize",this).call(this,t);var n=this.next;null!=n&&n.prev===this&&n.statics.blotName===this.statics.blotName&&this.statics.formats(this.domNode)===n.statics.formats(n.domNode)&&(n.optimize(t),n.moveChildren(this),n.remove())}},{key:"replace",value:function(t){u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"replace",this).call(this,t),[].slice.call(this.domNode.querySelectorAll("*")).forEach(function(t){var e=p.default.find(t);null==e?t.parentNode.removeChild(t):e instanceof p.default.Embed?e.remove():e.unwrap()})}}],[{key:"create",value:function(t){var n=u(e.__proto__||Object.getPrototypeOf(e),"create",this).call(this,t);return n.setAttribute("spellcheck",!1),n}},{key:"formats",value:function(){return!0}}]),e}(y.default);O.blotName="code-block",O.tagName="PRE",O.TAB=" ",e.Code=_,e.default=O},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n-1}Object.defineProperty(e,"__esModule",{value:!0}),e.sanitize=e.default=void 0;var a=function(){function t(t,e){for(var n=0;n1&&void 0!==arguments[1]&&arguments[1],n=this.container.querySelector(".ql-selected");if(t!==n&&(null!=n&&n.classList.remove("ql-selected"),null!=t&&(t.classList.add("ql-selected"),this.select.selectedIndex=[].indexOf.call(t.parentNode.children,t),t.hasAttribute("data-value")?this.label.setAttribute("data-value",t.getAttribute("data-value")):this.label.removeAttribute("data-value"),t.hasAttribute("data-label")?this.label.setAttribute("data-label",t.getAttribute("data-label")):this.label.removeAttribute("data-label"),e))){if("function"==typeof Event)this.select.dispatchEvent(new Event("change"));else if("object"===("undefined"==typeof Event?"undefined":l(Event))){var r=document.createEvent("Event");r.initEvent("change",!0,!0),this.select.dispatchEvent(r)}this.close()}}},{key:"update",value:function(){var t=void 0;if(this.select.selectedIndex>-1){var e=this.container.querySelector(".ql-picker-options").children[this.select.selectedIndex];t=this.select.options[this.select.selectedIndex],this.selectItem(e)}else this.selectItem(null);var n=null!=t&&t!==this.select.querySelector("option[selected]");this.label.classList.toggle("ql-active",n)}}]),t}();e.default=p},function(t,e,n){"use strict";function r(t){var e=a.find(t);if(null==e)try{e=a.create(t)}catch(n){e=a.create(a.Scope.INLINE),[].slice.call(t.childNodes).forEach(function(t){e.domNode.appendChild(t)}),t.parentNode&&t.parentNode.replaceChild(e.domNode,t),e.attach()}return e}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(47),l=n(27),a=n(1),s=function(t){function e(e){var n=t.call(this,e)||this;return n.build(),n}return o(e,t),e.prototype.appendChild=function(t){this.insertBefore(t)},e.prototype.attach=function(){t.prototype.attach.call(this),this.children.forEach(function(t){t.attach()})},e.prototype.build=function(){var t=this;this.children=new i.default,[].slice.call(this.domNode.childNodes).reverse().forEach(function(e){try{var n=r(e);t.insertBefore(n,t.children.head||void 0)}catch(t){if(t instanceof a.ParchmentError)return;throw t}})},e.prototype.deleteAt=function(t,e){if(0===t&&e===this.length())return this.remove();this.children.forEachAt(t,e,function(t,e,n){t.deleteAt(e,n)})},e.prototype.descendant=function(t,n){var r=this.children.find(n),o=r[0],i=r[1];return null==t.blotName&&t(o)||null!=t.blotName&&o instanceof t?[o,i]:o instanceof e?o.descendant(t,i):[null,-1]},e.prototype.descendants=function(t,n,r){void 0===n&&(n=0),void 0===r&&(r=Number.MAX_VALUE);var o=[],i=r;return this.children.forEachAt(n,r,function(n,r,l){(null==t.blotName&&t(n)||null!=t.blotName&&n instanceof t)&&o.push(n),n instanceof e&&(o=o.concat(n.descendants(t,r,i))),i-=l}),o},e.prototype.detach=function(){this.children.forEach(function(t){t.detach()}),t.prototype.detach.call(this)},e.prototype.formatAt=function(t,e,n,r){this.children.forEachAt(t,e,function(t,e,o){t.formatAt(e,o,n,r)})},e.prototype.insertAt=function(t,e,n){var r=this.children.find(t),o=r[0],i=r[1];if(o)o.insertAt(i,e,n);else{var l=null==n?a.create("text",e):a.create(e,n);this.appendChild(l)}},e.prototype.insertBefore=function(t,e){if(null!=this.statics.allowedChildren&&!this.statics.allowedChildren.some(function(e){return t instanceof e}))throw new a.ParchmentError("Cannot insert "+t.statics.blotName+" into "+this.statics.blotName);t.insertInto(this,e)},e.prototype.length=function(){return this.children.reduce(function(t,e){return t+e.length()},0)},e.prototype.moveChildren=function(t,e){this.children.forEach(function(n){t.insertBefore(n,e)})},e.prototype.optimize=function(e){if(t.prototype.optimize.call(this,e),0===this.children.length)if(null!=this.statics.defaultChild){var n=a.create(this.statics.defaultChild);this.appendChild(n),n.optimize(e)}else this.remove()},e.prototype.path=function(t,n){void 0===n&&(n=!1);var r=this.children.find(t,n),o=r[0],i=r[1],l=[[this,t]];return o instanceof e?l.concat(o.path(i,n)):(null!=o&&l.push([o,i]),l)},e.prototype.removeChild=function(t){this.children.remove(t)},e.prototype.replace=function(n){n instanceof e&&n.moveChildren(this),t.prototype.replace.call(this,n)},e.prototype.split=function(t,e){if(void 0===e&&(e=!1),!e){if(0===t)return this;if(t===this.length())return this.next}var n=this.clone();return this.parent.insertBefore(n,this.next),this.children.forEachAt(t,this.length(),function(t,r,o){t=t.split(r,e),n.appendChild(t)}),n},e.prototype.unwrap=function(){this.moveChildren(this.parent,this.next),this.remove()},e.prototype.update=function(t,e){var n=this,o=[],i=[];t.forEach(function(t){t.target===n.domNode&&"childList"===t.type&&(o.push.apply(o,t.addedNodes),i.push.apply(i,t.removedNodes))}),i.forEach(function(t){if(!(null!=t.parentNode&&"IFRAME"!==t.tagName&&document.body.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_CONTAINED_BY)){var e=a.find(t);null!=e&&(null!=e.domNode.parentNode&&e.domNode.parentNode!==n.domNode||e.detach())}}),o.filter(function(t){return t.parentNode==n.domNode}).sort(function(t,e){return t===e?0:t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING?1:-1}).forEach(function(t){var e=null;null!=t.nextSibling&&(e=a.find(t.nextSibling));var o=r(t);o.next==e&&null!=o.next||(null!=o.parent&&o.parent.removeChild(n),n.insertBefore(o,e||void 0))})},e}(l.default);e.default=s},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(11),i=n(28),l=n(17),a=n(1),s=function(t){function e(e){var n=t.call(this,e)||this;return n.attributes=new i.default(n.domNode),n}return r(e,t),e.formats=function(t){return"string"==typeof this.tagName||(Array.isArray(this.tagName)?t.tagName.toLowerCase():void 0)},e.prototype.format=function(t,e){var n=a.query(t);n instanceof o.default?this.attributes.attribute(n,e):e&&(null==n||t===this.statics.blotName&&this.formats()[t]===e||this.replaceWith(t,e))},e.prototype.formats=function(){var t=this.attributes.values(),e=this.statics.formats(this.domNode);return null!=e&&(t[this.statics.blotName]=e),t},e.prototype.replaceWith=function(e,n){var r=t.prototype.replaceWith.call(this,e,n);return this.attributes.copy(r),r},e.prototype.update=function(e,n){var r=this;t.prototype.update.call(this,e,n),e.some(function(t){return t.target===r.domNode&&"attributes"===t.type})&&this.attributes.build()},e.prototype.wrap=function(n,r){var o=t.prototype.wrap.call(this,n,r);return o instanceof e&&o.statics.scope===this.statics.scope&&this.attributes.move(o),o},e}(l.default);e.default=s},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(27),i=n(1),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r(e,t),e.value=function(t){return!0},e.prototype.index=function(t,e){return this.domNode===t||this.domNode.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_CONTAINED_BY?Math.min(e,1):-1},e.prototype.position=function(t,e){var n=[].indexOf.call(this.parent.domNode.childNodes,this.domNode);return t>0&&(n+=1),[this.parent.domNode,n]},e.prototype.value=function(){var t;return t={},t[this.statics.blotName]=this.statics.value(this.domNode)||!0,t},e.scope=i.Scope.INLINE_BLOT,e}(o.default);e.default=l},function(t,e,n){function r(t){this.ops=t,this.index=0,this.offset=0}var o=n(12),i=n(2),l={attributes:{compose:function(t,e,n){"object"!=typeof t&&(t={}),"object"!=typeof e&&(e={});var r=i(!0,{},e);n||(r=Object.keys(r).reduce(function(t,e){return null!=r[e]&&(t[e]=r[e]),t},{}));for(var o in t)void 0!==t[o]&&void 0===e[o]&&(r[o]=t[o]);return Object.keys(r).length>0?r:void 0},diff:function(t,e){"object"!=typeof t&&(t={}),"object"!=typeof e&&(e={});var n=Object.keys(t).concat(Object.keys(e)).reduce(function(n,r){return o(t[r],e[r])||(n[r]=void 0===e[r]?null:e[r]),n},{});return Object.keys(n).length>0?n:void 0},transform:function(t,e,n){if("object"!=typeof t)return e;if("object"==typeof e){if(!n)return e;var r=Object.keys(e).reduce(function(n,r){return void 0===t[r]&&(n[r]=e[r]),n},{});return Object.keys(r).length>0?r:void 0}}},iterator:function(t){return new r(t)},length:function(t){return"number"==typeof t.delete?t.delete:"number"==typeof t.retain?t.retain:"string"==typeof t.insert?t.insert.length:1}};r.prototype.hasNext=function(){return this.peekLength()<1/0},r.prototype.next=function(t){t||(t=1/0);var e=this.ops[this.index];if(e){var n=this.offset,r=l.length(e);if(t>=r-n?(t=r-n,this.index+=1,this.offset=0):this.offset+=t,"number"==typeof e.delete)return{delete:t};var o={};return e.attributes&&(o.attributes=e.attributes),"number"==typeof e.retain?o.retain=t:"string"==typeof e.insert?o.insert=e.insert.substr(n,t):o.insert=e.insert,o}return{retain:1/0}},r.prototype.peek=function(){return this.ops[this.index]},r.prototype.peekLength=function(){return this.ops[this.index]?l.length(this.ops[this.index])-this.offset:1/0},r.prototype.peekType=function(){return this.ops[this.index]?"number"==typeof this.ops[this.index].delete?"delete":"number"==typeof this.ops[this.index].retain?"retain":"insert":"retain"},r.prototype.rest=function(){if(this.hasNext()){if(0===this.offset)return this.ops.slice(this.index);var t=this.offset,e=this.index,n=this.next(),r=this.ops.slice(this.index);return this.offset=t,this.index=e,[n].concat(r)}return[]},t.exports=l},function(t,e){var n=function(){"use strict";function t(t,e){return null!=e&&t instanceof e}function e(n,r,o,i,c){function f(n,o){if(null===n)return null;if(0===o)return n;var y,v;if("object"!=typeof n)return n;if(t(n,a))y=new a;else if(t(n,s))y=new s;else if(t(n,u))y=new u(function(t,e){n.then(function(e){t(f(e,o-1))},function(t){e(f(t,o-1))})});else if(e.__isArray(n))y=[];else if(e.__isRegExp(n))y=new RegExp(n.source,l(n)),n.lastIndex&&(y.lastIndex=n.lastIndex);else if(e.__isDate(n))y=new Date(n.getTime());else{if(d&&Buffer.isBuffer(n))return y=Buffer.allocUnsafe?Buffer.allocUnsafe(n.length):new Buffer(n.length),n.copy(y),y;t(n,Error)?y=Object.create(n):void 0===i?(v=Object.getPrototypeOf(n),y=Object.create(v)):(y=Object.create(i),v=i)}if(r){var b=h.indexOf(n);if(-1!=b)return p[b];h.push(n),p.push(y)}t(n,a)&&n.forEach(function(t,e){var n=f(e,o-1),r=f(t,o-1);y.set(n,r)}),t(n,s)&&n.forEach(function(t){var e=f(t,o-1);y.add(e)});for(var g in n){var m;v&&(m=Object.getOwnPropertyDescriptor(v,g)),m&&null==m.set||(y[g]=f(n[g],o-1))}if(Object.getOwnPropertySymbols)for(var _=Object.getOwnPropertySymbols(n),g=0;g<_.length;g++){var O=_[g],w=Object.getOwnPropertyDescriptor(n,O);(!w||w.enumerable||c)&&(y[O]=f(n[O],o-1),w.enumerable||Object.defineProperty(y,O,{enumerable:!1}))}if(c)for(var x=Object.getOwnPropertyNames(n),g=0;g1&&void 0!==arguments[1]?arguments[1]:0;i(this,t),this.index=e,this.length=n},O=function(){function t(e,n){var r=this;i(this,t),this.emitter=n,this.scroll=e,this.composing=!1,this.mouseDown=!1,this.root=this.scroll.domNode,this.cursor=c.default.create("cursor",this),this.lastRange=this.savedRange=new _(0,0),this.handleComposition(),this.handleDragging(),this.emitter.listenDOM("selectionchange",document,function(){r.mouseDown||setTimeout(r.update.bind(r,v.default.sources.USER),1)}),this.emitter.on(v.default.events.EDITOR_CHANGE,function(t,e){t===v.default.events.TEXT_CHANGE&&e.length()>0&&r.update(v.default.sources.SILENT)}),this.emitter.on(v.default.events.SCROLL_BEFORE_UPDATE,function(){if(r.hasFocus()){var t=r.getNativeRange();null!=t&&t.start.node!==r.cursor.textNode&&r.emitter.once(v.default.events.SCROLL_UPDATE,function(){try{r.setNativeRange(t.start.node,t.start.offset,t.end.node,t.end.offset)}catch(t){}})}}),this.emitter.on(v.default.events.SCROLL_OPTIMIZE,function(t,e){if(e.range){var n=e.range,o=n.startNode,i=n.startOffset,l=n.endNode,a=n.endOffset;r.setNativeRange(o,i,l,a)}}),this.update(v.default.sources.SILENT)}return s(t,[{key:"handleComposition",value:function(){var t=this;this.root.addEventListener("compositionstart",function(){t.composing=!0}),this.root.addEventListener("compositionend",function(){if(t.composing=!1,t.cursor.parent){var e=t.cursor.restore();if(!e)return;setTimeout(function(){t.setNativeRange(e.startNode,e.startOffset,e.endNode,e.endOffset)},1)}})}},{key:"handleDragging",value:function(){var t=this;this.emitter.listenDOM("mousedown",document.body,function(){t.mouseDown=!0}),this.emitter.listenDOM("mouseup",document.body,function(){t.mouseDown=!1,t.update(v.default.sources.USER)})}},{key:"focus",value:function(){this.hasFocus()||(this.root.focus(),this.setRange(this.savedRange))}},{key:"format",value:function(t,e){if(null==this.scroll.whitelist||this.scroll.whitelist[t]){this.scroll.update();var n=this.getNativeRange();if(null!=n&&n.native.collapsed&&!c.default.query(t,c.default.Scope.BLOCK)){if(n.start.node!==this.cursor.textNode){var r=c.default.find(n.start.node,!1);if(null==r)return;if(r instanceof c.default.Leaf){var o=r.split(n.start.offset);r.parent.insertBefore(this.cursor,o)}else r.insertBefore(this.cursor,n.start.node);this.cursor.attach()}this.cursor.format(t,e),this.scroll.optimize(),this.setNativeRange(this.cursor.textNode,this.cursor.textNode.data.length),this.update()}}}},{key:"getBounds",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=this.scroll.length();t=Math.min(t,n-1),e=Math.min(t+e,n-1)-t;var r=void 0,o=this.scroll.leaf(t),i=a(o,2),l=i[0],s=i[1];if(null==l)return null;var u=l.position(s,!0),c=a(u,2);r=c[0],s=c[1];var f=document.createRange();if(e>0){f.setStart(r,s);var h=this.scroll.leaf(t+e),p=a(h,2);if(l=p[0],s=p[1],null==l)return null;var d=l.position(s,!0),y=a(d,2);return r=y[0],s=y[1],f.setEnd(r,s),f.getBoundingClientRect()}var v="left",b=void 0;return r instanceof Text?(s0&&(v="right")),{bottom:b.top+b.height,height:b.height,left:b[v],right:b[v],top:b.top,width:0}}},{key:"getNativeRange",value:function(){var t=document.getSelection();if(null==t||t.rangeCount<=0)return null;var e=t.getRangeAt(0);if(null==e)return null;var n=this.normalizeNative(e);return m.info("getNativeRange",n),n}},{key:"getRange",value:function(){var t=this.getNativeRange();return null==t?[null,null]:[this.normalizedToRange(t),t]}},{key:"hasFocus",value:function(){return document.activeElement===this.root}},{key:"normalizedToRange",value:function(t){var e=this,n=[[t.start.node,t.start.offset]];t.native.collapsed||n.push([t.end.node,t.end.offset]);var r=n.map(function(t){var n=a(t,2),r=n[0],o=n[1],i=c.default.find(r,!0),l=i.offset(e.scroll);return 0===o?l:i instanceof c.default.Container?l+i.length():l+i.index(r,o)}),i=Math.min(Math.max.apply(Math,o(r)),this.scroll.length()-1),l=Math.min.apply(Math,[i].concat(o(r)));return new _(l,i-l)}},{key:"normalizeNative",value:function(t){if(!l(this.root,t.startContainer)||!t.collapsed&&!l(this.root,t.endContainer))return null;var e={start:{node:t.startContainer,offset:t.startOffset},end:{node:t.endContainer,offset:t.endOffset},native:t};return[e.start,e.end].forEach(function(t){for(var e=t.node,n=t.offset;!(e instanceof Text)&&e.childNodes.length>0;)if(e.childNodes.length>n)e=e.childNodes[n],n=0;else{if(e.childNodes.length!==n)break;e=e.lastChild,n=e instanceof Text?e.data.length:e.childNodes.length+1}t.node=e,t.offset=n}),e}},{key:"rangeToNative",value:function(t){var e=this,n=t.collapsed?[t.index]:[t.index,t.index+t.length],r=[],o=this.scroll.length();return n.forEach(function(t,n){t=Math.min(o-1,t);var i=void 0,l=e.scroll.leaf(t),s=a(l,2),u=s[0],c=s[1],f=u.position(c,0!==n),h=a(f,2);i=h[0],c=h[1],r.push(i,c)}),r.length<2&&(r=r.concat(r)),r}},{key:"scrollIntoView",value:function(t){var e=this.lastRange;if(null!=e){var n=this.getBounds(e.index,e.length);if(null!=n){var r=this.scroll.length()-1,o=this.scroll.line(Math.min(e.index,r)),i=a(o,1),l=i[0],s=l;if(e.length>0){var u=this.scroll.line(Math.min(e.index+e.length,r));s=a(u,1)[0]}if(null!=l&&null!=s){var c=t.getBoundingClientRect();n.topc.bottom&&(t.scrollTop+=n.bottom-c.bottom)}}}}},{key:"setNativeRange",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:e,o=arguments.length>4&&void 0!==arguments[4]&&arguments[4];if(m.info("setNativeRange",t,e,n,r),null==t||null!=this.root.parentNode&&null!=t.parentNode&&null!=n.parentNode){var i=document.getSelection();if(null!=i)if(null!=t){this.hasFocus()||this.root.focus();var l=(this.getNativeRange()||{}).native;if(null==l||o||t!==l.startContainer||e!==l.startOffset||n!==l.endContainer||r!==l.endOffset){"BR"==t.tagName&&(e=[].indexOf.call(t.parentNode.childNodes,t),t=t.parentNode),"BR"==n.tagName&&(r=[].indexOf.call(n.parentNode.childNodes,n),n=n.parentNode);var a=document.createRange();a.setStart(t,e),a.setEnd(n,r),i.removeAllRanges(),i.addRange(a)}}else i.removeAllRanges(),this.root.blur(),document.body.focus()}}},{key:"setRange",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:v.default.sources.API;if("string"==typeof e&&(n=e,e=!1),m.info("setRange",t),null!=t){var r=this.rangeToNative(t);this.setNativeRange.apply(this,o(r).concat([e]))}else this.setNativeRange(null);this.update(n)}},{key:"update",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:v.default.sources.USER,e=this.lastRange,n=this.getRange(),r=a(n,2),o=r[0],i=r[1];if(this.lastRange=o,null!=this.lastRange&&(this.savedRange=this.lastRange),!(0,d.default)(e,this.lastRange)){var l;!this.composing&&null!=i&&i.native.collapsed&&i.start.node!==this.cursor.textNode&&this.cursor.restore();var s=[v.default.events.SELECTION_CHANGE,(0,h.default)(this.lastRange),(0,h.default)(e),t];if((l=this.emitter).emit.apply(l,[v.default.events.EDITOR_CHANGE].concat(s)),t!==v.default.sources.SILENT){var u;(u=this.emitter).emit.apply(u,s)}}}}]),t}();e.Range=_,e.default=O},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=n(0),s=r(a),u=n(3),c=r(u),f=function(t){function e(){return o(this,e),i(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return l(e,t),e}(s.default.Container);f.allowedChildren=[c.default,u.BlockEmbed,f],e.default=f},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.ColorStyle=e.ColorClass=e.ColorAttributor=void 0;var l=function(){function t(t,e){for(var n=0;n1){var u=o.formats(),c=this.quill.getFormat(t.index-1,1);i=A.default.attributes.diff(u,c)||{}}}var f=/[\uD800-\uDBFF][\uDC00-\uDFFF]$/.test(e.prefix)?2:1;this.quill.deleteText(t.index-f,f,S.default.sources.USER),Object.keys(i).length>0&&this.quill.formatLine(t.index-f,f,i,S.default.sources.USER),this.quill.focus()}}function c(t,e){var n=/^[\uD800-\uDBFF][\uDC00-\uDFFF]/.test(e.suffix)?2:1;if(!(t.index>=this.quill.getLength()-n)){var r={},o=0,i=this.quill.getLine(t.index),l=b(i,1),a=l[0];if(e.offset>=a.length()-1){var s=this.quill.getLine(t.index+1),u=b(s,1),c=u[0];if(c){var f=a.formats(),h=this.quill.getFormat(t.index,1);r=A.default.attributes.diff(f,h)||{},o=c.length()}}this.quill.deleteText(t.index,n,S.default.sources.USER),Object.keys(r).length>0&&this.quill.formatLine(t.index+o-1,n,r,S.default.sources.USER)}}function f(t){var e=this.quill.getLines(t),n={};if(e.length>1){var r=e[0].formats(),o=e[e.length-1].formats();n=A.default.attributes.diff(o,r)||{}}this.quill.deleteText(t,S.default.sources.USER),Object.keys(n).length>0&&this.quill.formatLine(t.index,1,n,S.default.sources.USER),this.quill.setSelection(t.index,S.default.sources.SILENT),this.quill.focus()}function h(t,e){var n=this;t.length>0&&this.quill.scroll.deleteAt(t.index,t.length);var r=Object.keys(e.format).reduce(function(t,n){return T.default.query(n,T.default.Scope.BLOCK)&&!Array.isArray(e.format[n])&&(t[n]=e.format[n]),t},{});this.quill.insertText(t.index,"\n",r,S.default.sources.USER),this.quill.setSelection(t.index+1,S.default.sources.SILENT),this.quill.focus(),Object.keys(e.format).forEach(function(t){null==r[t]&&(Array.isArray(e.format[t])||"link"!==t&&n.quill.format(t,e.format[t],S.default.sources.USER))})}function p(t){return{key:D.keys.TAB,shiftKey:!t,format:{"code-block":!0},handler:function(e){var n=T.default.query("code-block"),r=e.index,o=e.length,i=this.quill.scroll.descendant(n,r),l=b(i,2),a=l[0],s=l[1];if(null!=a){var u=this.quill.getIndex(a),c=a.newlineIndex(s,!0)+1,f=a.newlineIndex(u+s+o),h=a.domNode.textContent.slice(c,f).split("\n");s=0,h.forEach(function(e,i){t?(a.insertAt(c+s,n.TAB),s+=n.TAB.length,0===i?r+=n.TAB.length:o+=n.TAB.length):e.startsWith(n.TAB)&&(a.deleteAt(c+s,n.TAB.length),s-=n.TAB.length,0===i?r-=n.TAB.length:o-=n.TAB.length),s+=e.length+1}),this.quill.update(S.default.sources.USER),this.quill.setSelection(r,o,S.default.sources.SILENT)}}}}function d(t){return{key:t[0].toUpperCase(),shortKey:!0,handler:function(e,n){this.quill.format(t,!n.format[t],S.default.sources.USER)}}}function y(t){if("string"==typeof t||"number"==typeof t)return y({key:t});if("object"===(void 0===t?"undefined":v(t))&&(t=(0,_.default)(t,!1)),"string"==typeof t.key)if(null!=D.keys[t.key.toUpperCase()])t.key=D.keys[t.key.toUpperCase()];else{if(1!==t.key.length)return null;t.key=t.key.toUpperCase().charCodeAt(0)}return t.shortKey&&(t[B]=t.shortKey,delete t.shortKey),t}Object.defineProperty(e,"__esModule",{value:!0}),e.SHORTKEY=e.default=void 0;var v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},b=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),g=function(){function t(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=y(t);if(null==r||null==r.key)return I.warn("Attempted to add invalid keyboard binding",r);"function"==typeof e&&(e={handler:e}),"function"==typeof n&&(n={handler:n}),r=(0,k.default)(r,e,n),this.bindings[r.key]=this.bindings[r.key]||[],this.bindings[r.key].push(r)}},{key:"listen",value:function(){var t=this;this.quill.root.addEventListener("keydown",function(n){if(!n.defaultPrevented){var r=n.which||n.keyCode,o=(t.bindings[r]||[]).filter(function(t){return e.match(n,t)});if(0!==o.length){var i=t.quill.getSelection();if(null!=i&&t.quill.hasFocus()){var l=t.quill.getLine(i.index),a=b(l,2),s=a[0],u=a[1],c=t.quill.getLeaf(i.index),f=b(c,2),h=f[0],p=f[1],d=0===i.length?[h,p]:t.quill.getLeaf(i.index+i.length),y=b(d,2),g=y[0],m=y[1],_=h instanceof T.default.Text?h.value().slice(0,p):"",O=g instanceof T.default.Text?g.value().slice(m):"",x={collapsed:0===i.length,empty:0===i.length&&s.length()<=1,format:t.quill.getFormat(i),offset:u,prefix:_,suffix:O};o.some(function(e){if(null!=e.collapsed&&e.collapsed!==x.collapsed)return!1;if(null!=e.empty&&e.empty!==x.empty)return!1;if(null!=e.offset&&e.offset!==x.offset)return!1;if(Array.isArray(e.format)){if(e.format.every(function(t){return null==x.format[t]}))return!1}else if("object"===v(e.format)&&!Object.keys(e.format).every(function(t){return!0===e.format[t]?null!=x.format[t]:!1===e.format[t]?null==x.format[t]:(0,w.default)(e.format[t],x.format[t])}))return!1;return!(null!=e.prefix&&!e.prefix.test(x.prefix))&&(!(null!=e.suffix&&!e.suffix.test(x.suffix))&&!0!==e.handler.call(t,i,x))})&&n.preventDefault()}}}})}}]),e}(R.default);D.keys={BACKSPACE:8,TAB:9,ENTER:13,ESCAPE:27,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46},D.DEFAULTS={bindings:{bold:d("bold"),italic:d("italic"),underline:d("underline"),indent:{key:D.keys.TAB,format:["blockquote","indent","list"],handler:function(t,e){if(e.collapsed&&0!==e.offset)return!0;this.quill.format("indent","+1",S.default.sources.USER)}},outdent:{key:D.keys.TAB,shiftKey:!0,format:["blockquote","indent","list"],handler:function(t,e){if(e.collapsed&&0!==e.offset)return!0;this.quill.format("indent","-1",S.default.sources.USER)}},"outdent backspace":{key:D.keys.BACKSPACE,collapsed:!0,shiftKey:null,metaKey:null,ctrlKey:null,altKey:null,format:["indent","list"],offset:0,handler:function(t,e){null!=e.format.indent?this.quill.format("indent","-1",S.default.sources.USER):null!=e.format.list&&this.quill.format("list",!1,S.default.sources.USER)}},"indent code-block":p(!0),"outdent code-block":p(!1),"remove tab":{key:D.keys.TAB,shiftKey:!0,collapsed:!0,prefix:/\t$/,handler:function(t){this.quill.deleteText(t.index-1,1,S.default.sources.USER)}},tab:{key:D.keys.TAB,handler:function(t){this.quill.history.cutoff();var e=(new N.default).retain(t.index).delete(t.length).insert("\t");this.quill.updateContents(e,S.default.sources.USER),this.quill.history.cutoff(),this.quill.setSelection(t.index+1,S.default.sources.SILENT)}},"list empty enter":{key:D.keys.ENTER,collapsed:!0,format:["list"],empty:!0,handler:function(t,e){this.quill.format("list",!1,S.default.sources.USER),e.format.indent&&this.quill.format("indent",!1,S.default.sources.USER)}},"checklist enter":{key:D.keys.ENTER,collapsed:!0,format:{list:"checked"},handler:function(t){var e=this.quill.getLine(t.index),n=b(e,2),r=n[0],o=n[1],i=(0,k.default)({},r.formats(),{list:"checked"}),l=(new N.default).retain(t.index).insert("\n",i).retain(r.length()-o-1).retain(1,{list:"unchecked"});this.quill.updateContents(l,S.default.sources.USER),this.quill.setSelection(t.index+1,S.default.sources.SILENT),this.quill.scrollIntoView()}},"header enter":{key:D.keys.ENTER,collapsed:!0,format:["header"],suffix:/^$/,handler:function(t,e){var n=this.quill.getLine(t.index),r=b(n,2),o=r[0],i=r[1],l=(new N.default).retain(t.index).insert("\n",e.format).retain(o.length()-i-1).retain(1,{header:null});this.quill.updateContents(l,S.default.sources.USER),this.quill.setSelection(t.index+1,S.default.sources.SILENT),this.quill.scrollIntoView()}},"list autofill":{key:" ",collapsed:!0,format:{list:!1},prefix:/^\s*?(\d+\.|-|\*|\[ ?\]|\[x\])$/,handler:function(t,e){var n=e.prefix.length,r=this.quill.getLine(t.index),o=b(r,2),i=o[0],l=o[1];if(l>n)return!0;var a=void 0;switch(e.prefix.trim()){case"[]":case"[ ]":a="unchecked";break;case"[x]":a="checked";break;case"-":case"*":a="bullet";break;default:a="ordered"}this.quill.insertText(t.index," ",S.default.sources.USER),this.quill.history.cutoff();var s=(new N.default).retain(t.index-l).delete(n+1).retain(i.length()-2-l).retain(1,{list:a});this.quill.updateContents(s,S.default.sources.USER),this.quill.history.cutoff(),this.quill.setSelection(t.index-n,S.default.sources.SILENT)}},"code exit":{key:D.keys.ENTER,collapsed:!0,format:["code-block"],prefix:/\n\n$/,suffix:/^\s+$/,handler:function(t){var e=this.quill.getLine(t.index),n=b(e,2),r=n[0],o=n[1],i=(new N.default).retain(t.index+r.length()-o-2).retain(1,{"code-block":null}).delete(1);this.quill.updateContents(i,S.default.sources.USER)}},"embed left":s(D.keys.LEFT,!1),"embed left shift":s(D.keys.LEFT,!0),"embed right":s(D.keys.RIGHT,!1),"embed right shift":s(D.keys.RIGHT,!0)}},e.default=D,e.SHORTKEY=B},function(t,e,n){"use strict";t.exports={align:{"":n(75),center:n(76),right:n(77),justify:n(78)},background:n(79),blockquote:n(80),bold:n(81),clean:n(82),code:n(40),"code-block":n(40),color:n(83),direction:{"":n(84),rtl:n(85)},float:{center:n(86),full:n(87),left:n(88),right:n(89)},formula:n(90),header:{1:n(91),2:n(92)},italic:n(93),image:n(94),indent:{"+1":n(95),"-1":n(96)},link:n(97),list:{ordered:n(98),bullet:n(99),check:n(100)},script:{sub:n(101),super:n(102)},strike:n(103),underline:n(104),video:n(105)}},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(1),o=function(){function t(t){this.domNode=t,this.domNode[r.DATA_KEY]={blot:this}}return Object.defineProperty(t.prototype,"statics",{get:function(){return this.constructor},enumerable:!0,configurable:!0}),t.create=function(t){if(null==this.tagName)throw new r.ParchmentError("Blot definition missing tagName");var e;return Array.isArray(this.tagName)?("string"==typeof t&&(t=t.toUpperCase(),parseInt(t).toString()===t&&(t=parseInt(t))),e="number"==typeof t?document.createElement(this.tagName[t-1]):this.tagName.indexOf(t)>-1?document.createElement(t):document.createElement(this.tagName[0])):e=document.createElement(this.tagName),this.className&&e.classList.add(this.className),e},t.prototype.attach=function(){null!=this.parent&&(this.scroll=this.parent.scroll)},t.prototype.clone=function(){var t=this.domNode.cloneNode(!1);return r.create(t)},t.prototype.detach=function(){null!=this.parent&&this.parent.removeChild(this),delete this.domNode[r.DATA_KEY]},t.prototype.deleteAt=function(t,e){this.isolate(t,e).remove()},t.prototype.formatAt=function(t,e,n,o){var i=this.isolate(t,e);if(null!=r.query(n,r.Scope.BLOT)&&o)i.wrap(n,o);else if(null!=r.query(n,r.Scope.ATTRIBUTE)){var l=r.create(this.statics.scope);i.wrap(l),l.format(n,o)}},t.prototype.insertAt=function(t,e,n){var o=null==n?r.create("text",e):r.create(e,n),i=this.split(t);this.parent.insertBefore(o,i)},t.prototype.insertInto=function(t,e){void 0===e&&(e=null),null!=this.parent&&this.parent.children.remove(this);var n=null;t.children.insertBefore(this,e),null!=e&&(n=e.domNode),this.domNode.parentNode==t.domNode&&this.domNode.nextSibling==n||t.domNode.insertBefore(this.domNode,n),this.parent=t,this.attach()},t.prototype.isolate=function(t,e){var n=this.split(t);return n.split(e),n},t.prototype.length=function(){return 1},t.prototype.offset=function(t){return void 0===t&&(t=this.parent),null==this.parent||this==t?0:this.parent.children.offset(this)+this.parent.offset(t)},t.prototype.optimize=function(t){null!=this.domNode[r.DATA_KEY]&&delete this.domNode[r.DATA_KEY].mutations},t.prototype.remove=function(){null!=this.domNode.parentNode&&this.domNode.parentNode.removeChild(this.domNode),this.detach()},t.prototype.replace=function(t){null!=t.parent&&(t.parent.insertBefore(this,t.next),t.remove())},t.prototype.replaceWith=function(t,e){var n="string"==typeof t?r.create(t,e):t;return n.replace(this),n},t.prototype.split=function(t,e){return 0===t?this:this.next},t.prototype.update=function(t,e){},t.prototype.wrap=function(t,e){var n="string"==typeof t?r.create(t,e):t;return null!=this.parent&&this.parent.insertBefore(n,this.next),n.appendChild(this),n},t.blotName="abstract",t}();e.default=o},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(11),o=n(29),i=n(30),l=n(1),a=function(){function t(t){this.attributes={},this.domNode=t,this.build()}return t.prototype.attribute=function(t,e){e?t.add(this.domNode,e)&&(null!=t.value(this.domNode)?this.attributes[t.attrName]=t:delete this.attributes[t.attrName]):(t.remove(this.domNode),delete this.attributes[t.attrName])},t.prototype.build=function(){var t=this;this.attributes={};var e=r.default.keys(this.domNode),n=o.default.keys(this.domNode),a=i.default.keys(this.domNode);e.concat(n).concat(a).forEach(function(e){var n=l.query(e,l.Scope.ATTRIBUTE);n instanceof r.default&&(t.attributes[n.attrName]=n)})},t.prototype.copy=function(t){var e=this;Object.keys(this.attributes).forEach(function(n){var r=e.attributes[n].value(e.domNode);t.format(n,r)})},t.prototype.move=function(t){var e=this;this.copy(t),Object.keys(this.attributes).forEach(function(t){e.attributes[t].remove(e.domNode)}),this.attributes={}},t.prototype.values=function(){var t=this;return Object.keys(this.attributes).reduce(function(e,n){return e[n]=t.attributes[n].value(t.domNode),e},{})},t}();e.default=a},function(t,e,n){"use strict";function r(t,e){return(t.getAttribute("class")||"").split(/\s+/).filter(function(t){return 0===t.indexOf(e+"-")})}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(11),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.keys=function(t){return(t.getAttribute("class")||"").split(/\s+/).map(function(t){return t.split("-").slice(0,-1).join("-")})},e.prototype.add=function(t,e){return!!this.canAdd(t,e)&&(this.remove(t),t.classList.add(this.keyName+"-"+e),!0)},e.prototype.remove=function(t){r(t,this.keyName).forEach(function(e){t.classList.remove(e)}),0===t.classList.length&&t.removeAttribute("class")},e.prototype.value=function(t){var e=r(t,this.keyName)[0]||"",n=e.slice(this.keyName.length+1);return this.canAdd(t,n)?n:""},e}(i.default);e.default=l},function(t,e,n){"use strict";function r(t){var e=t.split("-"),n=e.slice(1).map(function(t){return t[0].toUpperCase()+t.slice(1)}).join("");return e[0]+n}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(11),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.keys=function(t){return(t.getAttribute("style")||"").split(";").map(function(t){return t.split(":")[0].trim()})},e.prototype.add=function(t,e){return!!this.canAdd(t,e)&&(t.style[r(this.keyName)]=e,!0)},e.prototype.remove=function(t){t.style[r(this.keyName)]="",t.getAttribute("style")||t.removeAttribute("style")},e.prototype.value=function(t){var e=t.style[r(this.keyName)];return this.canAdd(t,e)?e:""},e}(i.default);e.default=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),s=function t(e,n,r){null===e&&(e=Function.prototype);var o=Object.getOwnPropertyDescriptor(e,n);if(void 0===o){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,n,r)}if("value"in o)return o.value;var l=o.get;if(void 0!==l)return l.call(r)},u=function(){function t(t,e){for(var n=0;n '},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;nr.right&&(i=r.right-o.right,this.root.style.left=e+i+"px"),o.leftr.bottom){var l=o.bottom-o.top,a=t.bottom-t.top+l;this.root.style.top=n-a+"px",this.root.classList.add("ql-flip")}return i}},{key:"show",value:function(){this.root.classList.remove("ql-editing"),this.root.classList.remove("ql-hidden")}}]),t}();e.default=i},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t){var e=t.match(/^(?:(https?):\/\/)?(?:(?:www|m)\.)?youtube\.com\/watch.*v=([a-zA-Z0-9_-]+)/)||t.match(/^(?:(https?):\/\/)?(?:(?:www|m)\.)?youtu\.be\/([a-zA-Z0-9_-]+)/);return e?(e[1]||"https")+"://www.youtube.com/embed/"+e[2]+"?showinfo=0":(e=t.match(/^(?:(https?):\/\/)?(?:www\.)?vimeo\.com\/(\d+)/))?(e[1]||"https")+"://player.vimeo.com/video/"+e[2]+"/":t}function s(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e.forEach(function(e){var r=document.createElement("option");e===n?r.setAttribute("selected","selected"):r.setAttribute("value",e),t.appendChild(r)})}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.BaseTooltip=void 0;var u=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"link",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;this.root.classList.remove("ql-hidden"),this.root.classList.add("ql-editing"),null!=e?this.textbox.value=e:t!==this.root.getAttribute("data-mode")&&(this.textbox.value=""),this.position(this.quill.getBounds(this.quill.selection.savedRange)),this.textbox.select(),this.textbox.setAttribute("placeholder",this.textbox.getAttribute("data-"+t)||""),this.root.setAttribute("data-mode",t)}},{key:"restoreFocus",value:function(){var t=this.quill.scrollingContainer.scrollTop;this.quill.focus(),this.quill.scrollingContainer.scrollTop=t}},{key:"save",value:function(){var t=this.textbox.value;switch(this.root.getAttribute("data-mode")){case"link":var e=this.quill.root.scrollTop;this.linkRange?(this.quill.formatText(this.linkRange,"link",t,v.default.sources.USER),delete this.linkRange):(this.restoreFocus(),this.quill.format("link",t,v.default.sources.USER)),this.quill.root.scrollTop=e;break;case"video":t=a(t);case"formula":if(!t)break;var n=this.quill.getSelection(!0);if(null!=n){var r=n.index+n.length;this.quill.insertEmbed(r,this.root.getAttribute("data-mode"),t,v.default.sources.USER),"formula"===this.root.getAttribute("data-mode")&&this.quill.insertText(r+1," ",v.default.sources.USER),this.quill.setSelection(r+2,v.default.sources.USER)}}this.textbox.value="",this.hide()}}]),e}(A.default);e.BaseTooltip=M,e.default=L},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(46),i=r(o),l=n(34),a=n(36),s=n(62),u=n(63),c=r(u),f=n(64),h=r(f),p=n(65),d=r(p),y=n(35),v=n(24),b=n(37),g=n(38),m=n(39),_=r(m),O=n(66),w=r(O),x=n(15),k=r(x),E=n(67),N=r(E),j=n(68),A=r(j),q=n(69),T=r(q),P=n(70),S=r(P),C=n(71),L=r(C),M=n(13),R=r(M),I=n(72),B=r(I),D=n(73),U=r(D),F=n(74),H=r(F),K=n(26),z=r(K),V=n(16),Z=r(V),W=n(41),G=r(W),Y=n(42),X=r(Y),$=n(43),Q=r($),J=n(107),tt=r(J),et=n(108),nt=r(et);i.default.register({"attributors/attribute/direction":a.DirectionAttribute,"attributors/class/align":l.AlignClass,"attributors/class/background":y.BackgroundClass,"attributors/class/color":v.ColorClass,"attributors/class/direction":a.DirectionClass,"attributors/class/font":b.FontClass,"attributors/class/size":g.SizeClass,"attributors/style/align":l.AlignStyle,"attributors/style/background":y.BackgroundStyle,"attributors/style/color":v.ColorStyle,"attributors/style/direction":a.DirectionStyle,"attributors/style/font":b.FontStyle,"attributors/style/size":g.SizeStyle},!0),i.default.register({"formats/align":l.AlignClass,"formats/direction":a.DirectionClass,"formats/indent":s.IndentClass,"formats/background":y.BackgroundStyle,"formats/color":v.ColorStyle,"formats/font":b.FontClass,"formats/size":g.SizeClass,"formats/blockquote":c.default,"formats/code-block":R.default,"formats/header":h.default,"formats/list":d.default,"formats/bold":_.default,"formats/code":M.Code,"formats/italic":w.default,"formats/link":k.default,"formats/script":N.default,"formats/strike":A.default,"formats/underline":T.default,"formats/image":S.default,"formats/video":L.default,"formats/list/item":p.ListItem,"modules/formula":B.default,"modules/syntax":U.default,"modules/toolbar":H.default,"themes/bubble":tt.default,"themes/snow":nt.default,"ui/icons":z.default,"ui/picker":Z.default,"ui/icon-picker":X.default,"ui/color-picker":G.default,"ui/tooltip":Q.default},!0),e.default=i.default},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(0),i=r(o),l=n(6),a=r(l),s=n(3),u=r(s),c=n(14),f=r(c),h=n(23),p=r(h),d=n(31),y=r(d),v=n(33),b=r(v),g=n(5),m=r(g),_=n(59),O=r(_),w=n(8),x=r(w),k=n(60),E=r(k),N=n(61),j=r(N),A=n(25),q=r(A);a.default.register({"blots/block":u.default,"blots/block/embed":s.BlockEmbed,"blots/break":f.default,"blots/container":p.default,"blots/cursor":y.default,"blots/embed":b.default,"blots/inline":m.default,"blots/scroll":O.default,"blots/text":x.default,"modules/clipboard":E.default,"modules/history":j.default,"modules/keyboard":q.default}),i.default.register(u.default,f.default,y.default,m.default,O.default,x.default),e.default=a.default},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=function(){function t(){this.head=this.tail=null,this.length=0}return t.prototype.append=function(){for(var t=[],e=0;e1&&this.append.apply(this,t.slice(1))},t.prototype.contains=function(t){for(var e,n=this.iterator();e=n();)if(e===t)return!0;return!1},t.prototype.insertBefore=function(t,e){t&&(t.next=e,null!=e?(t.prev=e.prev,null!=e.prev&&(e.prev.next=t),e.prev=t,e===this.head&&(this.head=t)):null!=this.tail?(this.tail.next=t,t.prev=this.tail,this.tail=t):(t.prev=null,this.head=this.tail=t),this.length+=1)},t.prototype.offset=function(t){for(var e=0,n=this.head;null!=n;){if(n===t)return e;e+=n.length(),n=n.next}return-1},t.prototype.remove=function(t){this.contains(t)&&(null!=t.prev&&(t.prev.next=t.next),null!=t.next&&(t.next.prev=t.prev),t===this.head&&(this.head=t.next),t===this.tail&&(this.tail=t.prev),this.length-=1)},t.prototype.iterator=function(t){return void 0===t&&(t=this.head),function(){var e=t;return null!=t&&(t=t.next),e}},t.prototype.find=function(t,e){void 0===e&&(e=!1);for(var n,r=this.iterator();n=r();){var o=n.length();if(ta?n(r,t-a,Math.min(e,a+u-t)):n(r,0,Math.min(u,t+e-a)),a+=u}},t.prototype.map=function(t){return this.reduce(function(e,n){return e.push(t(n)),e},[])},t.prototype.reduce=function(t,e){for(var n,r=this.iterator();n=r();)e=t(e,n);return e},t}();e.default=r},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(17),i=n(1),l={attributes:!0,characterData:!0,characterDataOldValue:!0,childList:!0,subtree:!0},a=function(t){function e(e){var n=t.call(this,e)||this;return n.scroll=n,n.observer=new MutationObserver(function(t){n.update(t)}),n.observer.observe(n.domNode,l),n.attach(),n}return r(e,t),e.prototype.detach=function(){t.prototype.detach.call(this),this.observer.disconnect()},e.prototype.deleteAt=function(e,n){this.update(),0===e&&n===this.length()?this.children.forEach(function(t){t.remove()}):t.prototype.deleteAt.call(this,e,n)},e.prototype.formatAt=function(e,n,r,o){this.update(),t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.insertAt=function(e,n,r){this.update(),t.prototype.insertAt.call(this,e,n,r)},e.prototype.optimize=function(e,n){var r=this;void 0===e&&(e=[]),void 0===n&&(n={}),t.prototype.optimize.call(this,n);for(var l=[].slice.call(this.observer.takeRecords());l.length>0;)e.push(l.pop());for(var a=function(t,e){void 0===e&&(e=!0),null!=t&&t!==r&&null!=t.domNode.parentNode&&(null==t.domNode[i.DATA_KEY].mutations&&(t.domNode[i.DATA_KEY].mutations=[]),e&&a(t.parent))},s=function(t){null!=t.domNode[i.DATA_KEY]&&null!=t.domNode[i.DATA_KEY].mutations&&(t instanceof o.default&&t.children.forEach(s),t.optimize(n))},u=e,c=0;u.length>0;c+=1){if(c>=100)throw new Error("[Parchment] Maximum optimize iterations reached");for(u.forEach(function(t){var e=i.find(t.target,!0);null!=e&&(e.domNode===t.target&&("childList"===t.type?(a(i.find(t.previousSibling,!1)),[].forEach.call(t.addedNodes,function(t){var e=i.find(t,!1);a(e,!1),e instanceof o.default&&e.children.forEach(function(t){a(t,!1)})})):"attributes"===t.type&&a(e.prev)),a(e))}),this.children.forEach(s),u=[].slice.call(this.observer.takeRecords()),l=u.slice();l.length>0;)e.push(l.pop())}},e.prototype.update=function(e,n){var r=this;void 0===n&&(n={}),e=e||this.observer.takeRecords(),e.map(function(t){var e=i.find(t.target,!0);return null==e?null:null==e.domNode[i.DATA_KEY].mutations?(e.domNode[i.DATA_KEY].mutations=[t],e):(e.domNode[i.DATA_KEY].mutations.push(t),null)}).forEach(function(t){null!=t&&t!==r&&null!=t.domNode[i.DATA_KEY]&&t.update(t.domNode[i.DATA_KEY].mutations||[],n)}),null!=this.domNode[i.DATA_KEY].mutations&&t.prototype.update.call(this,this.domNode[i.DATA_KEY].mutations,n),this.optimize(e,n)},e.blotName="scroll",e.defaultChild="block",e.scope=i.Scope.BLOCK_BLOT,e.tagName="DIV",e}(o.default);e.default=a},function(t,e,n){"use strict";function r(t,e){if(Object.keys(t).length!==Object.keys(e).length)return!1;for(var n in t)if(t[n]!==e[n])return!1;return!0}var o=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var i=n(18),l=n(1),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.formats=function(n){if(n.tagName!==e.tagName)return t.formats.call(this,n)},e.prototype.format=function(n,r){var o=this;n!==this.statics.blotName||r?t.prototype.format.call(this,n,r):(this.children.forEach(function(t){t instanceof i.default||(t=t.wrap(e.blotName,!0)),o.attributes.copy(t)}),this.unwrap())},e.prototype.formatAt=function(e,n,r,o){if(null!=this.formats()[r]||l.query(r,l.Scope.ATTRIBUTE)){this.isolate(e,n).format(r,o)}else t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.optimize=function(n){t.prototype.optimize.call(this,n);var o=this.formats();if(0===Object.keys(o).length)return this.unwrap();var i=this.next;i instanceof e&&i.prev===this&&r(o,i.formats())&&(i.moveChildren(this),i.remove())},e.blotName="inline",e.scope=l.Scope.INLINE_BLOT,e.tagName="SPAN",e}(i.default);e.default=a},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(18),i=n(1),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r(e,t),e.formats=function(n){var r=i.query(e.blotName).tagName;if(n.tagName!==r)return t.formats.call(this,n)},e.prototype.format=function(n,r){null!=i.query(n,i.Scope.BLOCK)&&(n!==this.statics.blotName||r?t.prototype.format.call(this,n,r):this.replaceWith(e.blotName))},e.prototype.formatAt=function(e,n,r,o){null!=i.query(r,i.Scope.BLOCK)?this.format(r,o):t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.insertAt=function(e,n,r){if(null==r||null!=i.query(n,i.Scope.INLINE))t.prototype.insertAt.call(this,e,n,r);else{var o=this.split(e),l=i.create(n,r);o.parent.insertBefore(l,o)}},e.prototype.update=function(e,n){navigator.userAgent.match(/Trident/)?this.build():t.prototype.update.call(this,e,n)},e.blotName="block",e.scope=i.Scope.BLOCK_BLOT,e.tagName="P",e}(o.default);e.default=l},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(19),i=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return r(e,t),e.formats=function(t){},e.prototype.format=function(e,n){t.prototype.formatAt.call(this,0,this.length(),e,n)},e.prototype.formatAt=function(e,n,r,o){0===e&&n===this.length()?this.format(r,o):t.prototype.formatAt.call(this,e,n,r,o)},e.prototype.formats=function(){return this.statics.formats(this.domNode)},e}(o.default);e.default=i},function(t,e,n){"use strict";var r=this&&this.__extends||function(){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])};return function(e,n){function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(e,"__esModule",{value:!0});var o=n(19),i=n(1),l=function(t){function e(e){var n=t.call(this,e)||this;return n.text=n.statics.value(n.domNode),n}return r(e,t),e.create=function(t){return document.createTextNode(t)},e.value=function(t){var e=t.data;return e.normalize&&(e=e.normalize()),e},e.prototype.deleteAt=function(t,e){this.domNode.data=this.text=this.text.slice(0,t)+this.text.slice(t+e)},e.prototype.index=function(t,e){return this.domNode===t?e:-1},e.prototype.insertAt=function(e,n,r){null==r?(this.text=this.text.slice(0,e)+n+this.text.slice(e),this.domNode.data=this.text):t.prototype.insertAt.call(this,e,n,r)},e.prototype.length=function(){return this.text.length},e.prototype.optimize=function(n){t.prototype.optimize.call(this,n),this.text=this.statics.value(this.domNode),0===this.text.length?this.remove():this.next instanceof e&&this.next.prev===this&&(this.insertAt(this.length(),this.next.value()),this.next.remove())},e.prototype.position=function(t,e){return void 0===e&&(e=!1),[this.domNode,t]},e.prototype.split=function(t,e){if(void 0===e&&(e=!1),!e){if(0===t)return this;if(t===this.length())return this.next}var n=i.create(this.domNode.splitText(t));return this.parent.insertBefore(n,this.next),this.text=this.statics.value(this.domNode),n},e.prototype.update=function(t,e){var n=this;t.some(function(t){return"characterData"===t.type&&t.target===n.domNode})&&(this.text=this.statics.value(this.domNode))},e.prototype.value=function(){return this.text},e.blotName="text",e.scope=i.Scope.INLINE_BLOT,e}(o.default);e.default=l},function(t,e,n){"use strict";var r=document.createElement("div");if(r.classList.toggle("test-class",!1),r.classList.contains("test-class")){var o=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(t,e){return arguments.length>1&&!this.contains(t)==!e?e:o.call(this,t)}}String.prototype.startsWith||(String.prototype.startsWith=function(t,e){return e=e||0,this.substr(e,t.length)===t}),String.prototype.endsWith||(String.prototype.endsWith=function(t,e){var n=this.toString();("number"!=typeof e||!isFinite(e)||Math.floor(e)!==e||e>n.length)&&(e=n.length),e-=t.length;var r=n.indexOf(t,e);return-1!==r&&r===e}),Array.prototype.find||Object.defineProperty(Array.prototype,"find",{value:function(t){if(null===this)throw new TypeError("Array.prototype.find called on null or undefined");if("function"!=typeof t)throw new TypeError("predicate must be a function");for(var e,n=Object(this),r=n.length>>>0,o=arguments[1],i=0;ie.length?t:e,l=t.length>e.length?e:t,a=i.indexOf(l);if(-1!=a)return r=[[y,i.substring(0,a)],[v,l],[y,i.substring(a+l.length)]],t.length>e.length&&(r[0][0]=r[2][0]=d),r;if(1==l.length)return[[d,t],[y,e]];var u=s(t,e);if(u){var c=u[0],f=u[1],h=u[2],p=u[3],b=u[4],g=n(c,h),m=n(f,p);return g.concat([[v,b]],m)}return o(t,e)}function o(t,e){for(var n=t.length,r=e.length,o=Math.ceil((n+r)/2),l=o,a=2*o,s=new Array(a),u=new Array(a),c=0;cn)v+=2;else if(x>r)p+=2;else if(h){var k=l+f-_;if(k>=0&&k=E)return i(t,e,O,x)}}}for(var N=-m+b;N<=m-g;N+=2){var E,k=l+N;E=N==-m||N!=m&&u[k-1]n)g+=2;else if(j>r)b+=2;else if(!h){var w=l+f-N;if(w>=0&&w=E)return i(t,e,O,x)}}}}return[[d,t],[y,e]]}function i(t,e,r,o){var i=t.substring(0,r),l=e.substring(0,o),a=t.substring(r),s=e.substring(o),u=n(i,l),c=n(a,s);return u.concat(c)}function l(t,e){if(!t||!e||t.charAt(0)!=e.charAt(0))return 0;for(var n=0,r=Math.min(t.length,e.length),o=r,i=0;n=t.length?[r,o,i,s,f]:null}var r=t.length>e.length?t:e,o=t.length>e.length?e:t;if(r.length<4||2*o.lengthu[4].length?s:u:s;var c,f,h,p;return t.length>e.length?(c=i[0],f=i[1],h=i[2],p=i[3]):(h=i[0],p=i[1],c=i[2],f=i[3]),[c,f,h,p,i[4]]}function u(t){t.push([v,""]);for(var e,n=0,r=0,o=0,i="",s="";n1?(0!==r&&0!==o&&(e=l(s,i),0!==e&&(n-r-o>0&&t[n-r-o-1][0]==v?t[n-r-o-1][1]+=s.substring(0,e):(t.splice(0,0,[v,s.substring(0,e)]),n++),s=s.substring(e),i=i.substring(e)),0!==(e=a(s,i))&&(t[n][1]=s.substring(s.length-e)+t[n][1],s=s.substring(0,s.length-e),i=i.substring(0,i.length-e))),0===r?t.splice(n-o,r+o,[y,s]):0===o?t.splice(n-r,r+o,[d,i]):t.splice(n-r-o,r+o,[d,i],[y,s]),n=n-r-o+(r?1:0)+(o?1:0)+1):0!==n&&t[n-1][0]==v?(t[n-1][1]+=t[n][1],t.splice(n,1)):n++,o=0,r=0,i="",s=""}""===t[t.length-1][1]&&t.pop();var c=!1;for(n=1;n0&&r.splice(o+2,0,[l[0],a]),p(r,o,3)}return t}function h(t){for(var e=!1,n=function(t){return t.charCodeAt(0)>=56320&&t.charCodeAt(0)<=57343},r=2;r=55296&&t.charCodeAt(t.length-1)<=56319}(t[r-2][1])&&t[r-1][0]===d&&n(t[r-1][1])&&t[r][0]===y&&n(t[r][1])&&(e=!0,t[r-1][1]=t[r-2][1].slice(-1)+t[r-1][1],t[r][1]=t[r-2][1].slice(-1)+t[r][1],t[r-2][1]=t[r-2][1].slice(0,-1));if(!e)return t;for(var o=[],r=0;r0&&o.push(t[r]);return o}function p(t,e,n){for(var r=e+n-1;r>=0&&r>=e-1;r--)if(r+1=r&&!a.endsWith("\n")&&(n=!0),e.scroll.insertAt(t,a);var c=e.scroll.line(t),f=u(c,2),h=f[0],p=f[1],y=(0,T.default)({},(0,O.bubbleFormats)(h));if(h instanceof w.default){var b=h.descendant(v.default.Leaf,p),g=u(b,1),m=g[0];y=(0,T.default)(y,(0,O.bubbleFormats)(m))}l=d.default.attributes.diff(y,l)||{}}else if("object"===s(o.insert)){var _=Object.keys(o.insert)[0];if(null==_)return t;e.scroll.insertAt(t,_,o.insert[_])}r+=i}return Object.keys(l).forEach(function(n){e.scroll.formatAt(t,i,n,l[n])}),t+i},0),t.reduce(function(t,n){return"number"==typeof n.delete?(e.scroll.deleteAt(t,n.delete),t):t+(n.retain||n.insert.length||1)},0),this.scroll.batchEnd(),this.update(t)}},{key:"deleteText",value:function(t,e){return this.scroll.deleteAt(t,e),this.update((new h.default).retain(t).delete(e))}},{key:"formatLine",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return this.scroll.update(),Object.keys(r).forEach(function(o){if(null==n.scroll.whitelist||n.scroll.whitelist[o]){var i=n.scroll.lines(t,Math.max(e,1)),l=e;i.forEach(function(e){var i=e.length();if(e instanceof g.default){var a=t-e.offset(n.scroll),s=e.newlineIndex(a+l)-a+1;e.formatAt(a,s,o,r[o])}else e.format(o,r[o]);l-=i})}}),this.scroll.optimize(),this.update((new h.default).retain(t).retain(e,(0,N.default)(r)))}},{key:"formatText",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return Object.keys(r).forEach(function(o){n.scroll.formatAt(t,e,o,r[o])}),this.update((new h.default).retain(t).retain(e,(0,N.default)(r)))}},{key:"getContents",value:function(t,e){return this.delta.slice(t,t+e)}},{key:"getDelta",value:function(){return this.scroll.lines().reduce(function(t,e){return t.concat(e.delta())},new h.default)}},{key:"getFormat",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=[],r=[];0===e?this.scroll.path(t).forEach(function(t){var e=u(t,1),o=e[0];o instanceof w.default?n.push(o):o instanceof v.default.Leaf&&r.push(o)}):(n=this.scroll.lines(t,e),r=this.scroll.descendants(v.default.Leaf,t,e));var o=[n,r].map(function(t){if(0===t.length)return{};for(var e=(0,O.bubbleFormats)(t.shift());Object.keys(e).length>0;){var n=t.shift();if(null==n)return e;e=l((0,O.bubbleFormats)(n),e)}return e});return T.default.apply(T.default,o)}},{key:"getText",value:function(t,e){return this.getContents(t,e).filter(function(t){return"string"==typeof t.insert}).map(function(t){return t.insert}).join("")}},{key:"insertEmbed",value:function(t,e,n){return this.scroll.insertAt(t,e,n),this.update((new h.default).retain(t).insert(o({},e,n)))}},{key:"insertText",value:function(t,e){var n=this,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return e=e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"),this.scroll.insertAt(t,e),Object.keys(r).forEach(function(o){n.scroll.formatAt(t,e.length,o,r[o])}),this.update((new h.default).retain(t).insert(e,(0,N.default)(r)))}},{key:"isBlank",value:function(){if(0==this.scroll.children.length)return!0;if(this.scroll.children.length>1)return!1;var t=this.scroll.children.head;return t.statics.blotName===w.default.blotName&&(!(t.children.length>1)&&t.children.head instanceof k.default)}},{key:"removeFormat",value:function(t,e){var n=this.getText(t,e),r=this.scroll.line(t+e),o=u(r,2),i=o[0],l=o[1],a=0,s=new h.default;null!=i&&(a=i instanceof g.default?i.newlineIndex(l)-l+1:i.length()-l,s=i.delta().slice(l,l+a-1).insert("\n"));var c=this.getContents(t,e+a),f=c.diff((new h.default).insert(n).concat(s)),p=(new h.default).retain(t).concat(f);return this.applyDelta(p)}},{key:"update",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,r=this.delta;if(1===e.length&&"characterData"===e[0].type&&e[0].target.data.match(P)&&v.default.find(e[0].target)){var o=v.default.find(e[0].target),i=(0,O.bubbleFormats)(o),l=o.offset(this.scroll),a=e[0].oldValue.replace(_.default.CONTENTS,""),s=(new h.default).insert(a),u=(new h.default).insert(o.value());t=(new h.default).retain(l).concat(s.diff(u,n)).reduce(function(t,e){return e.insert?t.insert(e.insert,i):t.push(e)},new h.default),this.delta=r.compose(t)}else this.delta=this.getDelta(),t&&(0,A.default)(r.compose(t),this.delta)||(t=r.diff(this.delta,n));return t}}]),t}();e.default=S},function(t,e){"use strict";function n(){}function r(t,e,n){this.fn=t,this.context=e,this.once=n||!1}function o(){this._events=new n,this._eventsCount=0}var i=Object.prototype.hasOwnProperty,l="~";Object.create&&(n.prototype=Object.create(null),(new n).__proto__||(l=!1)),o.prototype.eventNames=function(){var t,e,n=[];if(0===this._eventsCount)return n;for(e in t=this._events)i.call(t,e)&&n.push(l?e.slice(1):e);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(t)):n},o.prototype.listeners=function(t,e){var n=l?l+t:t,r=this._events[n];if(e)return!!r;if(!r)return[];if(r.fn)return[r.fn];for(var o=0,i=r.length,a=new Array(i);o0){if(i instanceof y.BlockEmbed||f instanceof y.BlockEmbed)return void this.optimize();if(i instanceof _.default){var h=i.newlineIndex(i.length(),!0);if(h>-1&&(i=i.split(h+1))===f)return void this.optimize()}else if(f instanceof _.default){var p=f.newlineIndex(0);p>-1&&f.split(p+1)}var d=f.children.head instanceof g.default?null:f.children.head;i.moveChildren(f,d),i.remove()}this.optimize()}},{key:"enable",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.domNode.setAttribute("contenteditable",t)}},{key:"formatAt",value:function(t,n,r,o){(null==this.whitelist||this.whitelist[r])&&(c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"formatAt",this).call(this,t,n,r,o),this.optimize())}},{key:"insertAt",value:function(t,n,r){if(null==r||null==this.whitelist||this.whitelist[n]){if(t>=this.length())if(null==r||null==h.default.query(n,h.default.Scope.BLOCK)){var o=h.default.create(this.statics.defaultChild);this.appendChild(o),null==r&&n.endsWith("\n")&&(n=n.slice(0,-1)),o.insertAt(0,n,r)}else{var i=h.default.create(n,r);this.appendChild(i)}else c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"insertAt",this).call(this,t,n,r);this.optimize()}}},{key:"insertBefore",value:function(t,n){if(t.statics.scope===h.default.Scope.INLINE_BLOT){var r=h.default.create(this.statics.defaultChild);r.appendChild(t),t=r}c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"insertBefore",this).call(this,t,n)}},{key:"leaf",value:function(t){return this.path(t).pop()||[null,-1]}},{key:"line",value:function(t){return t===this.length()?this.line(t-1):this.descendant(a,t)}},{key:"lines",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Number.MAX_VALUE;return function t(e,n,r){var o=[],i=r;return e.children.forEachAt(n,r,function(e,n,r){a(e)?o.push(e):e instanceof h.default.Container&&(o=o.concat(t(e,n,i))),i-=r}),o}(this,t,e)}},{key:"optimize",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!0!==this.batch&&(c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"optimize",this).call(this,t,n),t.length>0&&this.emitter.emit(d.default.events.SCROLL_OPTIMIZE,t,n))}},{key:"path",value:function(t){return c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"path",this).call(this,t).slice(1)}},{key:"update",value:function(t){if(!0!==this.batch){var n=d.default.sources.USER;"string"==typeof t&&(n=t),Array.isArray(t)||(t=this.observer.takeRecords()),t.length>0&&this.emitter.emit(d.default.events.SCROLL_BEFORE_UPDATE,n,t),c(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"update",this).call(this,t.concat([])),t.length>0&&this.emitter.emit(d.default.events.SCROLL_UPDATE,n,t)}}}]),e}(h.default.Scroll);x.blotName="scroll",x.className="ql-editor",x.tagName="DIV",x.defaultChild="block",x.allowedChildren=[v.default,y.BlockEmbed,w.default],e.default=x},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function l(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t,e,n){return"object"===(void 0===e?"undefined":x(e))?Object.keys(e).reduce(function(t,n){return s(t,n,e[n])},t):t.reduce(function(t,r){return r.attributes&&r.attributes[e]?t.push(r):t.insert(r.insert,(0,j.default)({},o({},e,n),r.attributes))},new q.default)}function u(t){if(t.nodeType!==Node.ELEMENT_NODE)return{};return t["__ql-computed-style"]||(t["__ql-computed-style"]=window.getComputedStyle(t))}function c(t,e){for(var n="",r=t.ops.length-1;r>=0&&n.length-1}function h(t,e,n){return t.nodeType===t.TEXT_NODE?n.reduce(function(e,n){return n(t,e)},new q.default):t.nodeType===t.ELEMENT_NODE?[].reduce.call(t.childNodes||[],function(r,o){var i=h(o,e,n);return o.nodeType===t.ELEMENT_NODE&&(i=e.reduce(function(t,e){return e(o,t)},i),i=(o[W]||[]).reduce(function(t,e){return e(o,t)},i)),r.concat(i)},new q.default):new q.default}function p(t,e,n){return s(n,t,!0)}function d(t,e){var n=P.default.Attributor.Attribute.keys(t),r=P.default.Attributor.Class.keys(t),o=P.default.Attributor.Style.keys(t),i={};return n.concat(r).concat(o).forEach(function(e){var n=P.default.query(e,P.default.Scope.ATTRIBUTE);null!=n&&(i[n.attrName]=n.value(t),i[n.attrName])||(n=Y[e],null==n||n.attrName!==e&&n.keyName!==e||(i[n.attrName]=n.value(t)||void 0),null==(n=X[e])||n.attrName!==e&&n.keyName!==e||(n=X[e],i[n.attrName]=n.value(t)||void 0))}),Object.keys(i).length>0&&(e=s(e,i)),e}function y(t,e){var n=P.default.query(t);if(null==n)return e;if(n.prototype instanceof P.default.Embed){var r={},o=n.value(t);null!=o&&(r[n.blotName]=o,e=(new q.default).insert(r,n.formats(t)))}else"function"==typeof n.formats&&(e=s(e,n.blotName,n.formats(t)));return e}function v(t,e){return c(e,"\n")||e.insert("\n"),e}function b(){return new q.default}function g(t,e){var n=P.default.query(t);if(null==n||"list-item"!==n.blotName||!c(e,"\n"))return e;for(var r=-1,o=t.parentNode;!o.classList.contains("ql-clipboard");)"list"===(P.default.query(o)||{}).blotName&&(r+=1),o=o.parentNode;return r<=0?e:e.compose((new q.default).retain(e.length()-1).retain(1,{indent:r}))}function m(t,e){return c(e,"\n")||(f(t)||e.length()>0&&t.nextSibling&&f(t.nextSibling))&&e.insert("\n"),e}function _(t,e){if(f(t)&&null!=t.nextElementSibling&&!c(e,"\n\n")){var n=t.offsetHeight+parseFloat(u(t).marginTop)+parseFloat(u(t).marginBottom);t.nextElementSibling.offsetTop>t.offsetTop+1.5*n&&e.insert("\n")}return e}function O(t,e){var n={},r=t.style||{};return r.fontStyle&&"italic"===u(t).fontStyle&&(n.italic=!0),r.fontWeight&&(u(t).fontWeight.startsWith("bold")||parseInt(u(t).fontWeight)>=700)&&(n.bold=!0),Object.keys(n).length>0&&(e=s(e,n)),parseFloat(r.textIndent||0)>0&&(e=(new q.default).insert("\t").concat(e)),e}function w(t,e){var n=t.data;if("O:P"===t.parentNode.tagName)return e.insert(n.trim());if(0===n.trim().length&&t.parentNode.classList.contains("ql-clipboard"))return e;if(!u(t.parentNode).whiteSpace.startsWith("pre")){var r=function(t,e){return e=e.replace(/[^\u00a0]/g,""),e.length<1&&t?" ":e};n=n.replace(/\r\n/g," ").replace(/\n/g," "),n=n.replace(/\s\s+/g,r.bind(r,!0)),(null==t.previousSibling&&f(t.parentNode)||null!=t.previousSibling&&f(t.previousSibling))&&(n=n.replace(/^\s+/,r.bind(r,!1))),(null==t.nextSibling&&f(t.parentNode)||null!=t.nextSibling&&f(t.nextSibling))&&(n=n.replace(/\s+$/,r.bind(r,!1)))}return e.insert(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.matchText=e.matchSpacing=e.matchNewline=e.matchBlot=e.matchAttributor=e.default=void 0;var x="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},k=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),E=function(){function t(t,e){for(var n=0;n\r?\n +\<"),this.convert();var e=this.quill.getFormat(this.quill.selection.savedRange.index);if(e[F.default.blotName]){var n=this.container.innerText;return this.container.innerHTML="",(new q.default).insert(n,o({},F.default.blotName,e[F.default.blotName]))}var r=this.prepareMatching(),i=k(r,2),l=i[0],a=i[1],s=h(this.container,l,a);return c(s,"\n")&&null==s.ops[s.ops.length-1].attributes&&(s=s.compose((new q.default).retain(s.length()-1).delete(1))),Z.log("convert",this.container.innerHTML,s),this.container.innerHTML="",s}},{key:"dangerouslyPasteHTML",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:C.default.sources.API;if("string"==typeof t)this.quill.setContents(this.convert(t),e),this.quill.setSelection(0,C.default.sources.SILENT);else{var r=this.convert(e);this.quill.updateContents((new q.default).retain(t).concat(r),n),this.quill.setSelection(t+r.length(),C.default.sources.SILENT)}}},{key:"onPaste",value:function(t){var e=this;if(!t.defaultPrevented&&this.quill.isEnabled()){var n=this.quill.getSelection(),r=(new q.default).retain(n.index),o=this.quill.scrollingContainer.scrollTop;this.container.focus(),this.quill.selection.update(C.default.sources.SILENT),setTimeout(function(){r=r.concat(e.convert()).delete(n.length),e.quill.updateContents(r,C.default.sources.USER),e.quill.setSelection(r.length()-n.length,C.default.sources.SILENT),e.quill.scrollingContainer.scrollTop=o,e.quill.focus()},1)}}},{key:"prepareMatching",value:function(){var t=this,e=[],n=[];return this.matchers.forEach(function(r){var o=k(r,2),i=o[0],l=o[1];switch(i){case Node.TEXT_NODE:n.push(l);break;case Node.ELEMENT_NODE:e.push(l);break;default:[].forEach.call(t.container.querySelectorAll(i),function(t){t[W]=t[W]||[],t[W].push(l)})}}),[e,n]}}]),e}(I.default);$.DEFAULTS={matchers:[],matchVisual:!0},e.default=$,e.matchAttributor=d,e.matchBlot=y,e.matchNewline=m,e.matchSpacing=_,e.matchText=w},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t){var e=t.ops[t.ops.length-1];return null!=e&&(null!=e.insert?"string"==typeof e.insert&&e.insert.endsWith("\n"):null!=e.attributes&&Object.keys(e.attributes).some(function(t){return null!=f.default.query(t,f.default.Scope.BLOCK)}))}function s(t){var e=t.reduce(function(t,e){return t+=e.delete||0},0),n=t.length()-e;return a(t)&&(n-=1),n}Object.defineProperty(e,"__esModule",{value:!0}),e.getLastChangeIndex=e.default=void 0;var u=function(){function t(t,e){for(var n=0;nr&&this.stack.undo.length>0){var o=this.stack.undo.pop();n=n.compose(o.undo),t=o.redo.compose(t)}else this.lastRecorded=r;this.stack.undo.push({redo:t,undo:n}),this.stack.undo.length>this.options.maxStack&&this.stack.undo.shift()}}},{key:"redo",value:function(){this.change("redo","undo")}},{key:"transform",value:function(t){this.stack.undo.forEach(function(e){e.undo=t.transform(e.undo,!0),e.redo=t.transform(e.redo,!0)}),this.stack.redo.forEach(function(e){e.undo=t.transform(e.undo,!0),e.redo=t.transform(e.redo,!0)})}},{key:"undo",value:function(){this.change("undo","redo")}}]),e}(y.default);v.DEFAULTS={delay:1e3,maxStack:100,userOnly:!1},e.default=v,e.getLastChangeIndex=s},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.IndentClass=void 0;var l=function(){function t(t,e){for(var n=0;n0&&this.children.tail.format(t,e)}},{key:"formats",value:function(){return o({},this.statics.blotName,this.statics.formats(this.domNode))}},{key:"insertBefore",value:function(t,n){if(t instanceof v)u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"insertBefore",this).call(this,t,n);else{var r=null==n?this.length():n.offset(this),o=this.split(r);o.parent.insertBefore(t,o)}}},{key:"optimize",value:function(t){u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"optimize",this).call(this,t);var n=this.next;null!=n&&n.prev===this&&n.statics.blotName===this.statics.blotName&&n.domNode.tagName===this.domNode.tagName&&n.domNode.getAttribute("data-checked")===this.domNode.getAttribute("data-checked")&&(n.moveChildren(this),n.remove())}},{key:"replace",value:function(t){if(t.statics.blotName!==this.statics.blotName){var n=f.default.create(this.statics.defaultChild);t.moveChildren(n),this.appendChild(n)}u(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"replace",this).call(this,t)}}]),e}(y.default);b.blotName="list",b.scope=f.default.Scope.BLOCK_BLOT,b.tagName=["OL","UL"],b.defaultChild="list-item",b.allowedChildren=[v],e.ListItem=v,e.default=b},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=n(39),a=function(t){return t&&t.__esModule?t:{default:t}}(l),s=function(t){function e(){return r(this,e),o(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return i(e,t),e}(a.default);s.blotName="italic",s.tagName=["EM","I"],e.default=s},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n-1?n?this.domNode.setAttribute(t,n):this.domNode.removeAttribute(t):a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"format",this).call(this,t,n)}}],[{key:"create",value:function(t){var n=a(e.__proto__||Object.getPrototypeOf(e),"create",this).call(this,t);return"string"==typeof t&&n.setAttribute("src",this.sanitize(t)),n}},{key:"formats",value:function(t){return f.reduce(function(e,n){return t.hasAttribute(n)&&(e[n]=t.getAttribute(n)),e},{})}},{key:"match",value:function(t){return/\.(jpe?g|gif|png)$/.test(t)||/^data:image\/.+;base64/.test(t)}},{key:"sanitize",value:function(t){return(0,c.sanitize)(t,["http","https","data"])?t:"//:0"}},{key:"value",value:function(t){return t.getAttribute("src")}}]),e}(u.default.Embed);h.blotName="image",h.tagName="IMG",e.default=h},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n-1?n?this.domNode.setAttribute(t,n):this.domNode.removeAttribute(t):a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"format",this).call(this,t,n)}}],[{key:"create",value:function(t){var n=a(e.__proto__||Object.getPrototypeOf(e),"create",this).call(this,t);return n.setAttribute("frameborder","0"),n.setAttribute("allowfullscreen",!0),n.setAttribute("src",this.sanitize(t)),n}},{key:"formats",value:function(t){return f.reduce(function(e,n){return t.hasAttribute(n)&&(e[n]=t.getAttribute(n)),e},{})}},{key:"sanitize",value:function(t){return c.default.sanitize(t)}},{key:"value",value:function(t){return t.getAttribute("src")}}]),e}(s.BlockEmbed);h.blotName="video",h.className="ql-video",h.tagName="IFRAME",e.default=h},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.FormulaBlot=void 0;var a=function(){function t(t,e){for(var n=0;n0||null==this.cachedText)&&(this.domNode.innerHTML=t(e),this.domNode.normalize(),this.attach()),this.cachedText=e)}}]),e}(v.default);b.className="ql-syntax";var g=new c.default.Attributor.Class("token","hljs",{scope:c.default.Scope.INLINE}),m=function(t){function e(t,n){o(this,e);var r=i(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,n));if("function"!=typeof r.options.highlight)throw new Error("Syntax module requires highlight.js. Please include the library on the page before Quill.");var l=null;return r.quill.on(h.default.events.SCROLL_OPTIMIZE,function(){clearTimeout(l),l=setTimeout(function(){r.highlight(),l=null},r.options.interval)}),r.highlight(),r}return l(e,t),a(e,null,[{key:"register",value:function(){h.default.register(g,!0),h.default.register(b,!0)}}]),a(e,[{key:"highlight",value:function(){var t=this;if(!this.quill.selection.composing){this.quill.update(h.default.sources.USER);var e=this.quill.getSelection();this.quill.scroll.descendants(b).forEach(function(e){e.highlight(t.options.highlight)}),this.quill.update(h.default.sources.SILENT),null!=e&&this.quill.setSelection(e,h.default.sources.SILENT)}}}]),e}(d.default);m.DEFAULTS={highlight:function(){return null==window.hljs?null:function(t){return window.hljs.highlightAuto(t).value}}(),interval:1e3},e.CodeBlock=b,e.CodeToken=g,e.default=m},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function l(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t,e,n){var r=document.createElement("button");r.setAttribute("type","button"),r.classList.add("ql-"+e),null!=n&&(r.value=n),t.appendChild(r)}function u(t,e){Array.isArray(e[0])||(e=[e]),e.forEach(function(e){var n=document.createElement("span");n.classList.add("ql-formats"),e.forEach(function(t){if("string"==typeof t)s(n,t);else{var e=Object.keys(t)[0],r=t[e];Array.isArray(r)?c(n,e,r):s(n,e,r)}}),t.appendChild(n)})}function c(t,e,n){var r=document.createElement("select");r.classList.add("ql-"+e),n.forEach(function(t){var e=document.createElement("option");!1!==t?e.setAttribute("value",t):e.setAttribute("selected","selected"),r.appendChild(e)}),t.appendChild(r)}Object.defineProperty(e,"__esModule",{value:!0}),e.addControls=e.default=void 0;var f=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),h=function(){function t(t,e){for(var n=0;n '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e){t.exports=' '},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.BubbleTooltip=void 0;var a=function t(e,n,r){null===e&&(e=Function.prototype);var o=Object.getOwnPropertyDescriptor(e,n);if(void 0===o){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,n,r)}if("value"in o)return o.value;var l=o.get;if(void 0!==l)return l.call(r)},s=function(){function t(t,e){for(var n=0;n0&&o===h.default.sources.USER){r.show(),r.root.style.left="0px",r.root.style.width="",r.root.style.width=r.root.offsetWidth+"px";var i=r.quill.getLines(e.index,e.length);if(1===i.length)r.position(r.quill.getBounds(e));else{var l=i[i.length-1],a=r.quill.getIndex(l),s=Math.min(l.length()-1,e.index+e.length-a),u=r.quill.getBounds(new y.Range(a,s));r.position(u)}}else document.activeElement!==r.textbox&&r.quill.hasFocus()&&r.hide()}),r}return l(e,t),s(e,[{key:"listen",value:function(){var t=this;a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"listen",this).call(this),this.root.querySelector(".ql-close").addEventListener("click",function(){t.root.classList.remove("ql-editing")}),this.quill.on(h.default.events.SCROLL_OPTIMIZE,function(){setTimeout(function(){if(!t.root.classList.contains("ql-hidden")){var e=t.quill.getSelection();null!=e&&t.position(t.quill.getBounds(e))}},1)})}},{key:"cancel",value:function(){this.show()}},{key:"position",value:function(t){var n=a(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"position",this).call(this,t),r=this.root.querySelector(".ql-tooltip-arrow");if(r.style.marginLeft="",0===n)return n;r.style.marginLeft=-1*n-r.offsetWidth/2+"px"}}]),e}(p.BaseTooltip);_.TEMPLATE=['','
','','',"
"].join(""),e.BubbleTooltip=_,e.default=m},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function l(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],r=!0,o=!1,i=void 0;try{for(var l,a=t[Symbol.iterator]();!(r=(l=a.next()).done)&&(n.push(l.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{!r&&a.return&&a.return()}finally{if(o)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),s=function t(e,n,r){null===e&&(e=Function.prototype);var o=Object.getOwnPropertyDescriptor(e,n);if(void 0===o){var i=Object.getPrototypeOf(e);return null===i?void 0:t(i,n,r)}if("value"in o)return o.value;var l=o.get;if(void 0!==l)return l.call(r)},u=function(){function t(t,e){for(var n=0;n','','',''].join(""),e.default=w}]).default}); +//# sourceMappingURL=quill.min.js.map \ No newline at end of file diff --git a/static_menu/menu-dev.json b/static_menu/menu-dev.json new file mode 100644 index 0000000..2cd9b71 --- /dev/null +++ b/static_menu/menu-dev.json @@ -0,0 +1,468 @@ +[{ + "menu_id": "components-admin", + "name": "VK框架 组件演示", + "comment":"以下菜单在正式环境不会出现!", + "icon": "el-icon-star-off", + "url": "", + "sort": 999, + "children": [ + { + "menu_id": "vk-data-icon", + "name": "Icon 图标", + "icon": "el-icon-picture", + "children": [{ + "menu_id": "vk-data-icon-vk", + "name": "VK框架 图标", + "icon": "", + "url": "/pages_template/components/icons/vk-icons" + }, + { + "menu_id": "vk-data-icon-element", + "name": "Element 图标", + "icon": "", + "url": "/pages_template/components/icons/element-icons" + } + ] + },{ + "menu_id": "vk-data-table", + "name": "Table 智能表格", + "icon": "el-icon-s-grid", + "children": [{ + "menu_id": "vk-data-table-basic", + "name": "基础用法", + "icon": "", + "url": "/pages_template/components/table/table-basic" + }, + { + "menu_id": "vk-data-table-easy", + "name": "综合用法", + "icon": "", + "url": "/pages_template/components/table/table-easy" + }, + { + "menu_id": "vk-data-table-query", + "name": "搜索折叠", + "icon": "", + "url": "/pages_template/components/table/table-query" + }, + { + "menu_id": "vk-data-table-expand", + "name": "表格行展开", + "icon": "", + "url": "/pages_template/components/table/table-expand" + } + ] + }, + { + "menu_id": "vk-data-form", + "name": "Form 万能表单", + "icon": "vk-icon-edit", + "children": [{ + "menu_id": "vk-data-form-basic", + "name": "基础用法", + "icon": "", + "url": "/pages_template/components/form/form-basic" + }, + { + "menu_id": "vk-data-form-inline", + "name": "行内表单", + "icon": "", + "url": "/pages_template/components/form/form-inline" + }, + { + "menu_id": "vk-data-form-dialog", + "name": "弹窗表单", + "icon": "", + "url": "/pages_template/components/form/form-dialog" + }, + { + "menu_id": "vk-data-form-dialog-2", + "name": "复用表单", + "icon": "", + "url": "/pages_template/components/form/form-dialog-2" + }, + { + "menu_id": "vk-data-form-slot", + "name": "插槽用法", + "icon": "", + "url": "/pages_template/components/form/form-slot" + }, + { + "menu_id": "vk-data-form-array-object", + "name": "子表单", + "icon": "", + "url": "/pages_template/components/form/form-array-object" + }, + { + "menu_id": "vk-data-form-pro", + "name": "万能表单", + "icon": "", + "url": "/pages_template/components/form/form-pro" + } + ] + }, + { + "menu_id": "vk-data-input", + "name": "Input 输入", + "icon": "el-icon-edit-outline", + "children": [{ + "menu_id": "vk-data-input-number", + "name": "数字输入框", + "icon": "", + "url": "/pages_template/components/input/input-number" + }, + { + "menu_id": "vk-data-input-number-box", + "name": "步进器", + "icon": "", + "url": "/pages_template/components/input/input-number-box" + }, + { + "menu_id": "vk-data-input-money", + "name": "金额输入框", + "icon": "", + "url": "/pages_template/components/input/input-money" + }, + { + "menu_id": "vk-data-input-percentage", + "name": "百分比输入框", + "icon": "", + "url": "/pages_template/components/input/input-percentage" + }, + { + "menu_id": "vk-data-input-json", + "name": "JSON编辑器", + "icon": "", + "url": "/pages_template/components/input/input-json" + }, + { + "menu_id": "vk-data-input-province", + "name": "省份选择器", + "icon": "", + "url": "/pages_template/components/input/input-province" + }, + { + "menu_id": "vk-data-input-address", + "name": "省市区联动", + "icon": "", + "url": "/pages_template/components/input/input-address" + }, + { + "menu_id": "vk-data-input-select", + "name": "下拉选择器", + "icon": "", + "url": "/pages_template/components/input/input-select" + }, + { + "menu_id": "vk-data-input-remote-select", + "name": "远程搜索选择器", + "icon": "", + "url": "/pages_template/components/input/input-remote-select" + }, + { + "menu_id": "vk-data-input-all", + "name": "聚合输入框", + "icon": "", + "url": "/pages_template/components/input/input" + } + ] + }, + { + "menu_id": "vk-data-detail", + "name": "Detail 详情展示", + "icon": "el-icon-document", + "children": [{ + "menu_id": "vk-data-detail-basic", + "name": "基础形式", + "icon": "", + "url": "/pages_template/components/detail/detail-basic" + }, + { + "menu_id": "vk-data-detail-table", + "name": "表格形式", + "icon": "", + "url": "/pages_template/components/detail/detail-table" + } + ] + }, + { + "menu_id": "vk-data-dialog", + "name": "Dialog 弹窗", + "icon": "el-icon-copy-document", + "children": [{ + "menu_id": "vk-data-dialog-basic", + "name": "基础用法", + "icon": "", + "url": "/pages_template/components/dialog/dialog-basic" + }, + { + "menu_id": "vk-data-dialog-form", + "name": "弹窗表单", + "icon": "", + "url": "/pages_template/components/dialog/dialog-form" + }, + { + "menu_id": "vk-data-dialog-table", + "name": "弹窗表格", + "icon": "", + "url": "/pages_template/components/dialog/dialog-table" + } + ] + }, + { + "menu_id": "vk-data-upload", + "name": "Upload 上传", + "icon": "el-icon-upload2", + "children": [{ + "menu_id": "vk-data-upload-basic", + "name": "基础用法", + "icon": "", + "url": "/pages_template/components/upload/upload-basic" + }, + { + "menu_id": "vk-data-upload-drag", + "name": "拖拽上传", + "icon": "", + "url": "/pages_template/components/upload/upload-drag" + } + ] + }, + { + "menu_id": "vk-data-editor", + "name": "editor 编辑器", + "icon": "el-icon-edit-outline", + "children": [{ + "menu_id": "vk-data-editor-1", + "name": "富文本编辑器", + "icon": "", + "url": "/pages_template/components/editor/editor" + }] + } + ] + }, + { + "menu_id": "__demo__", + "name": "Element 静态功能演示", + "comment":"以下菜单在正式环境不会出现!", + "icon": "el-icon-star-off", + "url": "", + "sort": 1000, + "children": [{ + "menu_id": "__demo__popup", + "name": "弹窗页面", + "icon": "el-icon-tickets", + "children": [{ + "menu_id": "__demo__popup-alert", + "name": "alert", + "icon": "", + "url": "/pages_template/element/popup/alert" + }, + { + "menu_id": "__demo__popup-dialog", + "name": "dialog", + "icon": "", + "url": "/pages_template/element/popup/dialog" + }, + { + "menu_id": "__demo__popup-drawer", + "name": "drawer", + "icon": "", + "url": "/pages_template/element/popup/drawer" + }, + { + "menu_id": "__demo__popup-loading", + "name": "loading", + "icon": "", + "url": "/pages_template/element/popup/loading" + }, + { + "menu_id": "__demo__popup-message", + "name": "message", + "icon": "", + "url": "/pages_template/element/popup/message" + }, + { + "menu_id": "__demo__popup-message-box", + "name": "message-box", + "icon": "", + "url": "/pages_template/element/popup/message-box" + }, + { + "menu_id": "__demo__popup-notification", + "name": "notification", + "icon": "", + "url": "/pages_template/element/popup/notification" + }, + { + "menu_id": "__demo__popup-popconfirm", + "name": "popconfirm", + "icon": "", + "url": "/pages_template/element/popup/popconfirm" + }, + { + "menu_id": "__demo__popup-popover", + "name": "popover", + "icon": "", + "url": "/pages_template/element/popup/popover" + }, + { + "menu_id": "__demo__popup-tooltip", + "name": "tooltip", + "icon": "", + "url": "/pages_template/element/popup/tooltip" + } + ] + }, + { + "menu_id": "__demo__form", + "name": "表单页面", + "icon": "el-icon-s-order", + "children": [{ + "menu_id": "__demo__form-basic-form", + "name": "基础表单", + "icon": "", + "url": "/pages_template/element/form/basic-form" + }, + { + "menu_id": "__demo__form-advanced-form", + "name": "高级表单", + "icon": "", + "url": "/pages_template/element/form/advanced-form" + }, + { + "menu_id": "__demo__form-step-form", + "name": "分步表单", + "icon": "", + "url": "/pages_template/element/form/step-form" + } + ] + }, + { + "menu_id": "__demo__result", + "name": "结果页", + "icon": "el-icon-circle-check", + "children": [{ + "menu_id": "__demo__result-success", + "name": "成功页", + "icon": "", + "url": "/pages_template/element/result/success" + }, + { + "menu_id": "__demo__result-fail", + "name": "失败页", + "icon": "", + "url": "/pages_template/element/result/fail" + } + ] + }, + { + "menu_id": "__demo__error", + "name": "异常页面", + "icon": "el-icon-warning-outline", + "children": [{ + "menu_id": "__demo__error-403", + "name": "403", + "icon": "", + "url": "/pages_plugs/error/403" + }, + { + "menu_id": "__demo__error-404", + "name": "404", + "icon": "", + "url": "/pages_plugs/error/404" + }, + { + "menu_id": "__demo__error-500", + "name": "500", + "icon": "", + "url": "/pages_plugs/error/500" + } + ] + }, + { + "menu_id": "__demo__detail", + "name": "详情页面", + "icon": "el-icon-tickets", + "children": [{ + "menu_id": "__demo__detail-comprehensive", + "name": "综合详情页", + "icon": "", + "url": "/pages_template/element/detail/detail" + }] + }, + { + "menu_id": "__demo__setting", + "name": "设置", + "icon": "el-icon-s-tools", + "children": [{ + "menu_id": "__demo__setting-account", + "name": "账户设置", + "icon": "", + "url": "/pages_template/element/setting/account" + }] + } + ] + }, + { + "menu_id": "__utils__", + "name": "VK框架实用工具", + "comment":"以下菜单在正式环境不会出现!", + "icon": "el-icon-star-off", + "url": "", + "sort": 1001, + "children": [{ + "menu_id": "__utils__vk-form-visualizer", + "name": "表单可视化设计器", + "icon": "el-icon-tickets", + "url": "https://vkunicloud.fsq.pub/vk-form-visualizer/" + }] + }, + { + "menu_id": "__links__", + "name": "友情链接", + "comment":"以下菜单在正式环境不会出现!", + "icon": "el-icon-star-off", + "url": "", + "sort": 1002, + "children": [ + { + "menu_id": "__links__1", + "name": "admin框架文档", + "icon": "el-icon-tickets", + "url": "https://vkdoc.fsq.pub/admin/" + }, + { + "menu_id": "__links__2", + "name": "更多VK插件", + "icon": "el-icon-tickets", + "url": "https://ext.dcloud.net.cn/search?q=vk" + }, + { + "menu_id": "__links__3", + "name": "unicloud文档", + "icon": "el-icon-tickets", + "url": "https://uniapp.dcloud.io/uniCloud/README" + }, + { + "menu_id": "__links__4", + "name": "element文档", + "icon": "el-icon-tickets", + "url": "https://element.eleme.cn/#/zh-CN/component/button" + }] + },{ + "menu_id": "__test__", + "name": "测试权限用", + "comment":"以下菜单在正式环境不会出现!", + "icon": "el-icon-star-off", + "url": "", + "sort": 900, + "children": [ + { + "menu_id": "__test__1", + "name": "查看表格", + "icon": "el-icon-tickets", + "url": "/pages_template/components/table/table-easy" + } + ] + } +] diff --git a/static_menu/menu.json b/static_menu/menu.json new file mode 100644 index 0000000..20214fa --- /dev/null +++ b/static_menu/menu.json @@ -0,0 +1,59 @@ +[{ + "menu_id": "vk-in", + "name": "", + "hidden_menu": true, + "children": [{ + "menu_id": "vk-in-index", + "name": "首页", + "url": "/", + "fixed": true + }, + { + "menu_id": "vk-login", + "name": "登录注册", + "children": [{ + "menu_id": "vk-login-index", + "name": "登录", + "url": "/pages/login/index", + "hidden_tab": true + }, + { + "menu_id": "vk-login-register", + "name": "注册", + "url": "/pages/login/register", + "hidden_tab": true + }, + { + "menu_id": "vk-login-retrieve", + "name": "密码找回", + "url": "/pages/login/retrieve", + "hidden_tab": true + } + ] + }, + { + "menu_id": "vk-error", + "name": "异常页面", + "icon": "el-icon-warning-outline", + "children": [{ + "menu_id": "vk-error-403", + "name": "403", + "url": "/pages_plugs/error/403", + "hidden_tab": true + }, + { + "menu_id": "vk-error-404", + "name": "404", + "url": "/pages_plugs/error/404", + "hidden_tab": true + }, + { + "menu_id": "vk-error-500", + "name": "500", + "url": "/pages_plugs/error/500", + "hidden_tab": true + } + ] + } + ] +}] diff --git a/store/index.js b/store/index.js new file mode 100644 index 0000000..d0d8912 --- /dev/null +++ b/store/index.js @@ -0,0 +1,133 @@ +// 定义不需要永久存储的目录,即下次APP启动数据会自动清空,值为在modules目录下的文件名 +let notSaveStateKeys = ['$error']; + +/* 以下代码请勿改动,除非你知道改动带来的效果 */ + +const modulesTemp = {}; + +let lifeData = uni.getStorageSync('lifeData') || {}; +// #ifdef VUE2 +const modulesFiles = require.context('./modules', true, /\.js$/); +modulesFiles.keys().map((modulePath, index) => { + let moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') + modulesTemp[moduleName] = modulesFiles(modulePath).default; +}); +// #endif + +// #ifdef VUE3 +const modulesFiles = import.meta.globEager('./modules/**/*.js'); +for (const modulePath in modulesFiles) { + const moduleName = modulePath.replace(/^\.\/modules\/(.*)\.\w+$/, '$1') + modulesTemp[moduleName] = modulesFiles[modulePath].default; +} +// #endif +const modules = {}; +for (let moduleName in modulesTemp) { + const moduleItem = modulesTemp[moduleName]; + if (moduleItem && moduleItem.namespaced) { + let moduleNameArr = moduleName.split("/"); + let lastName = moduleNameArr[moduleNameArr.length - 1]; + if (lastName === "index") { + moduleName = moduleName.replace(/\/index$/, ''); + } + modules[moduleName] = moduleItem; + } +} + +for (let moduleName in modules) { + if (notSaveStateKeys.indexOf(moduleName) === -1) { + if (!lifeData[moduleName]) lifeData[moduleName] = {}; + } +} + +uni.setStorageSync('lifeData', lifeData); + +// 保存变量到本地存储中 +const saveLifeData = function(key, value) { + // 判断变量名是否在需要存储的数组中 + if (notSaveStateKeys.indexOf(key) === -1) { + // 获取本地存储的lifeData对象,将变量添加到对象中 + let tmp = uni.getStorageSync('lifeData'); + // 第一次打开APP,不存在lifeData变量,故放一个{}空对象 + tmp = tmp ? tmp : {}; + tmp[key] = value; + // 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中 + uni.setStorageSync('lifeData', tmp); + } +} + +// #ifndef VUE3 +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +const store = new Vuex.Store({ + modules, + // 如果是开发环境,则开启严格模式 + strict: process.env.NODE_ENV === 'development', + // 公共 mutations + mutations: { + updateStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + if (typeof payload.value === "undefined") payload.value = ""; + let nameArr = payload.name.split('.'); + let saveKey = ''; + let len = nameArr.length; + if (len >= 2) { + let obj = state[nameArr[0]]; + for (let i = 1; i < len - 1; i++) { + let keyName = nameArr[i]; + if (typeof obj[keyName] !== "object") obj[keyName] = {}; + obj = obj[keyName]; + } + obj[nameArr[len - 1]] = JSON.parse(JSON.stringify(payload.value)); + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = JSON.parse(JSON.stringify(payload.value)); + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]) + } + } +}) +// #endif + +// #ifdef VUE3 +import { createStore } from 'vuex' +const store = createStore({ + modules, + // 如果是开发环境,则开启严格模式 + strict: process.env.NODE_ENV === 'development', + // 公共 mutations + mutations: { + updateStore(state, payload) { + // 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1 + if (typeof payload.value === "undefined") payload.value = ""; + let nameArr = payload.name.split('.'); + let saveKey = ''; + let len = nameArr.length; + if (len >= 2) { + let obj = state[nameArr[0]]; + for (let i = 1; i < len - 1; i++) { + let keyName = nameArr[i]; + if (typeof obj[keyName] !== "object") obj[keyName] = {}; + obj = obj[keyName]; + } + obj[nameArr[len - 1]] = JSON.parse(JSON.stringify(payload.value)); + saveKey = nameArr[0]; + } else { + // 单层级变量,在state就是一个普通变量的情况 + state[payload.name] = JSON.parse(JSON.stringify(payload.value)); + saveKey = payload.name; + } + // 保存变量到本地,见顶部函数定义 + saveLifeData(saveKey, state[saveKey]) + } + } +}) +// #endif + +export default store \ No newline at end of file diff --git a/store/modules/$app.js b/store/modules/$app.js new file mode 100644 index 0000000..b4d39f5 --- /dev/null +++ b/store/modules/$app.js @@ -0,0 +1,78 @@ +/** + * vuex 系统状态管理模块 + */ +import config from '@/app.config.js' + +let lifeData = uni.getStorageSync('lifeData') || {}; + +let $app = lifeData.$app || {}; + +export default { + // 通过添加 namespaced: true 的方式使其成为带命名空间的模块 + namespaced: true, + /** + * vuex的基本数据,用来存储变量 + */ + state: { + /** + * 是否已经初始化 + * js调用示例 + * vk.getVuex('$app.inited'); + * 页面上直接使用示例 + * {{ vk.getVuex('$app.inited') }} + * js更新示例 + * vk.setVuex('$app.inited', true); + */ + inited: $app.inited || false, + config:{ + ...config + }, + /** + * vk.getVuex('$app.originalPage'); + * vk.setVuex('$app.originalPage', originalPage); + */ + originalPage: $app.originalPage || null, // 跳登录前的页面 + // 静态资源路径 vk.getVuex('$app.staticUrl.navBar.logo1') vk.setVuex('$app.staticUrl.navBar.logo1','') + staticUrl: $app.staticUrl || config.staticUrl, + // 左侧菜单列表(树形结构) vk.getVuex('$app.navMenu'); + navMenu: $app.navMenu || [], + // 左侧菜单列表(数组形式) vk.getVuex('$app.menuList'); + menuList: $app.menuList || [], + // 菜单地图 vk.getVuex('$app.menuMap'); + menuMap: $app.menuMap || [], + // 当前打开的页面路由信息 vk.getVuex('$app.route'); vk.setVuex('$app.route', route); + route: $app.route || {}, + // 系统后台名称 + appName: process.env.VUE_APP_NAME || '', + // 屏幕宽度 + width: $app.width || '', + // 屏幕高度 + height: $app.height || '', + // 是否是PC + isPC: $app.isPC || true, + // PC状态下左侧菜单是否折叠文字(只显示图标,如果不要记忆功能,则去掉$app.leftCollapse ||即可,直接leftCollapse:false) + leftCollapse: $app.leftCollapse || false, + }, + /** + * 从基本数据(state)派生的数据,相当于state的计算属性 + */ + getters: { + + }, + /** + * 提交更新数据的方法,必须是同步的(如果需要异步使用action)。 + * 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 + * 回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。 + */ + mutations: { + + }, + /** + * 和mutation的功能大致相同,不同之处在于 ==》 + * 1. Action 提交的是 mutation,而不是直接变更状态。 + * 2. Action 可以包含任意异步操作。 + */ + actions: { + + } +} diff --git a/store/modules/$error.js b/store/modules/$error.js new file mode 100644 index 0000000..dfb2d10 --- /dev/null +++ b/store/modules/$error.js @@ -0,0 +1,54 @@ +/** + * vuex 错误日志管理模块 + */ +export default { + // 通过添加 namespaced: true 的方式使其成为带命名空间的模块 + namespaced: true, + /** + * vuex的基本数据,用来存储变量 + */ + state: { + logs: [] + }, + /** + * 从基本数据(state)派生的数据,相当于state的计算属性 + */ + getters: { + + }, + /** + * 提交更新数据的方法,必须是同步的(如果需要异步使用action)。 + * 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 + * 回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。 + */ + mutations: { + add: (state, log) => { + state.logs.unshift(log) + }, + clear: (state) => { + state.logs.splice(0); + } + }, + /** + * 和mutation的功能大致相同,不同之处在于 ==》 + * 1. Action 提交的是 mutation,而不是直接变更状态。 + * 2. Action 可以包含任意异步操作。 + */ + actions: { + // vk.vuex.dispatch('$error/add', log); + add({ commit }, log) { + if (!log.route) { + const pages = getCurrentPages(); + if (pages.length) { + log.route = pages[pages.length - 1].route; + } + } + log.route = '/' + (log.route || ''); + commit('add', log); + }, + // vk.vuex.dispatch('$error/clear'); + clear({ commit }) { + commit('clear'); + } + } +} \ No newline at end of file diff --git a/store/modules/$user.js b/store/modules/$user.js new file mode 100644 index 0000000..376f335 --- /dev/null +++ b/store/modules/$user.js @@ -0,0 +1,51 @@ +/** + * vuex 用户状态管理模块 + */ +let lifeData = uni.getStorageSync('lifeData') || {}; + +let $user = lifeData.$user || {}; + +export default { + // 通过添加 namespaced: true 的方式使其成为带命名空间的模块 + namespaced: true, + /** + * vuex的基本数据,用来存储变量 + */ + state: { + /** + * 登录用户信息 + * js调用示例 + * (推荐) vk.getVuex('$user.userInfo'); + * 或 vk.vuex.get('$user.userInfo'); + * 页面上直接使用示例 + * {{ vk.getVuex('$user.userInfo') }} + * js更新示例 + * vk.setVuex('$user.userInfo.avatar', avatar); + */ + userInfo: $user.userInfo || {}, + permission:$user.permission || [], + login:$user.login || {}, + }, + /** + * 从基本数据(state)派生的数据,相当于state的计算属性 + */ + getters: { + + }, + /** + * 提交更新数据的方法,必须是同步的(如果需要异步使用action)。 + * 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。 + * 回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。 + */ + mutations: { + + }, + /** + * 和mutation的功能大致相同,不同之处在于 ==》 + * 1. Action 提交的是 mutation,而不是直接变更状态。 + * 2. Action 可以包含任意异步操作。 + */ + actions: { + + } +} \ No newline at end of file diff --git a/template.h5.html b/template.h5.html new file mode 100644 index 0000000..7117e1c --- /dev/null +++ b/template.h5.html @@ -0,0 +1,35 @@ + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + + + + + + + + + + + + +
+ + + + diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..8b22ea6 --- /dev/null +++ b/uni.scss @@ -0,0 +1 @@ +@import "@/common/css/uni.scss"; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/config.js b/uniCloud-aliyun/cloudfunctions/router/config.js new file mode 100644 index 0000000..695c324 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/config.js @@ -0,0 +1,12 @@ +const requireFn = function(path) { + return require(path); +} +const initConfig = { + baseDir: __dirname, // 云函数根目录地址 + requireFn, + customUtil :{ + // 你自己的工具包,写这里后即可听过customUtil.mynpm1调用 + // mynpm1:mynpm1 + } +}; +module.exports = initConfig; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/dao/index.js b/uniCloud-aliyun/cloudfunctions/router/dao/index.js new file mode 100644 index 0000000..3e675db --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/dao/index.js @@ -0,0 +1,29 @@ +// 加载模块 - 数据库dao层 API 请勿改动此文件----------------------------------- +const modulesPath = __dirname + "/modules"; +const fs = require('fs'); +const fileList = fs.readdirSync(modulesPath); +const moduleObj = {}; +const modulesNames = []; +fileList.map((file, index) => { + if (file.indexOf("Dao.js") > -1) { + modulesNames.push(file.substring(0, file.length - 3)); + } +}); +modulesNames.map((modulesName, index) => { + try { + moduleObj[modulesName] = require(modulesPath + "/" + modulesName); + } catch (err) { + console.error(`【异常】加载【${modulesName}】异常,请检查!↓↓↓请查看下方的错误提示↓↓↓`); + console.error(err); + console.error(`【异常】加载【${modulesName}】异常,请检查!↑↑↑请查看上方的错误提示↑↑↑`); + } +}); +moduleObj.init = function(obj) { + modulesNames.map((modulesName, index) => { + if (typeof moduleObj[modulesName] === "object" && typeof moduleObj[modulesName].init === "function") { + moduleObj[modulesName].init(obj); + } + }); +} +module.exports = moduleObj; +// 加载模块 - 数据库dao层 API 请勿改动此文件----------------------------------- diff --git a/uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js b/uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js new file mode 100644 index 0000000..5418321 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/dao/modules/userDao.js @@ -0,0 +1,621 @@ +// 涉及的表名 +const dbName = { + user: "uni-id-users", // 用户 +}; + +var dao = {}; +var util = {}; +// 初始化 +dao.init = function(obj) { + util = obj; +} +/** + * 获取用户信息 + * 调用示例 + * await vk.daoCenter.userDao.findById(user_id); + * data 请求参数说明 + * @param {String} user_id 用户ID + */ +dao.findById = async (user_id) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.findById({ + dbName: dbName.user, + id: user_id, + fieldJson: { token: false, password: false }, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 根据whereJson获取单条记录 + * @param {Object} whereJson 条件 + * @param {Object} fieldJson 字段显示规则 + * 调用示例 +let userInfo = await vk.daoCenter.userDao.findByWhereJson({ + +}); + */ +dao.findByWhereJson = async (whereJson, fieldJson={ token: false, password: false }) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.findByWhereJson({ + dbName: dbName.user, + whereJson, + fieldJson + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 根据邀请码获取用户信息 + * let inviterUserInfo = await vk.daoCenter.userDao.findByInviteCode(invite_code); + * @param {String} invite_code 邀请码 + */ +dao.findByInviteCode = async (invite_code) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.findByWhereJson({ + dbName: dbName.user, + whereJson: { + my_invite_code: invite_code + }, + fieldJson: { token: false, password: false } + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 增 - 添加一条记录 + * @param {Object} dataJson 添加的数据 + * 调用示例 +await vk.daoCenter.userDao.add({ + +}); +或 + * 调用示例 +await vk.daoCenter.userDao.add({ + db: transaction, + dataJson: { + + } +}); + */ +dao.add = async (obj) => { + let { vk, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + if (obj.db && obj.dataJson) { + // 支持事务 + res = await vk.baseDao.add({ + ...obj, + cancelAddTime: true, // 因为user表使用了register_date作为创建时间 + dbName: dbName.user, + }); + } else { + // 不支持事务 + res = await vk.baseDao.add({ + dbName: dbName.user, + cancelAddTime: true, // 因为user表使用了register_date作为创建时间 + dataJson: obj + }); + } + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 增 - 添加多条记录 + * @param {Object} dataJson 添加的数据 + * 调用示例 +await vk.daoCenter.userDao.adds(dataArr); + */ +dao.adds = async (dataArr) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.adds({ + dbName: dbName.user, + cancelAddTime: true, // 因为user表使用了register_date作为创建时间 + dataJson: dataArr + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 删 - 删除多条记录 + * @param {Object} whereJson 条件 + * 调用示例 +await vk.daoCenter.userDao.del({ + +}); + */ +dao.del = async (whereJson) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.del({ + dbName: dbName.user, + whereJson + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 删 - 据ID删除单条数据 + * @param {String} _id + * 调用示例 +await vk.daoCenter.userDao.deleteById(_id); +或 +await vk.daoCenter.userDao.deleteById(_id, transaction); + */ +dao.deleteById = async (_id, db) => { + let { vk, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.deleteById({ + db, + dbName: dbName.user, + id: _id + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 改 - 批量修改 + * @param {Object} whereJson 条件 + * @param {Object} dataJson 修改的数据 + * 调用示例 +await vk.daoCenter.userDao.update({ + whereJson:{ + + }, + dataJson:{ + + } +}); + */ +dao.update = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.update({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 改 - 根据id修改 + * @param {Object} whereJson 条件 + * @param {Object} dataJson 修改的数据 + * 调用示例 +await vk.daoCenter.userDao.updateById({ + id: uid, + dataJson:{ + + } +}); + */ +dao.updateById = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.updateById({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 改 - 更新并返回更新后的数据(无论条件匹配到多少条记录,只会修改第一条记录,同时返回修改后的数据) + * @param {Object} whereJson 条件 + * @param {Object} dataJson 修改的数据 + * 调用示例 +await vk.daoCenter.userDao.updateAndReturn({ + whereJson:{ + + }, + dataJson:{ + + } +}); + */ +dao.updateAndReturn = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.updateAndReturn({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取记录总条数 + * @param {Object} whereJson 条件 + * 调用示例 +await vk.daoCenter.userDao.count(whereJson); + */ +dao.count = async (whereJson) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.count({ + dbName: dbName.user, + whereJson + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 查 - 求和 + * @param {String} fieldName 需要求和的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userSum = await vk.daoCenter.userDao.sum({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.sum = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.sum({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 求最大值 + * @param {String} fieldName 需要求最大值的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userMax = await vk.daoCenter.userDao.max({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.max = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.max({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 求最小值 + * @param {String} fieldName 需要求最小值的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userMin = await vk.daoCenter.userDao.min({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.min = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.min({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 求最平均值 + * @param {String} fieldName 需要求最平均值的字段名 + * @param {Object} whereJson 筛选条件 + * 调用示例 +let userAvg = await vk.daoCenter.userDao.avg({ + fieldName: "", + whereJson: { + + } +}); + */ +dao.avg = async (obj) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.avg({ + ...obj, + dbName: dbName.user, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取数据列表 + * 调用示例 +let userList = await vk.daoCenter.userDao.select({ + pageIndex:1, + pageSize:20, + getMain:false, + whereJson:{ + + }, + fieldJson:{}, + sortArr:[{ "name":"_id", "type":"desc" }], +}); + */ +dao.select = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.select({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取数据列表 + * 调用示例 +let userList = await vk.daoCenter.userDao.selects({ + pageIndex:1, + pageSize:20, + getMain:false, + whereJson:{ + + }, + fieldJson:{}, + sortArr:[{ "name":"_id", "type":"desc" }], + // 副表列表 + foreignDB:[ + { + dbName:"副表表名", + localKey:"主表外键名", + foreignKey:"副表外键名", + as:"副表as字段", + limit:1 + } + ] +}); + */ +dao.selects = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.selects({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 查 - 获取数据列表 + * 调用示例 +res = await vk.daoCenter.userDao.getTableData({ + data +}); + */ +dao.getTableData = async (obj = {}) => { + let { vk, db, _ } = util; + let res = {}; + // 数据库操作开始----------------------------------------------------------- + res = await vk.baseDao.getTableData({ + ...obj, + dbName: dbName.user + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + + +/** + * 获取用户信息(旧版) + * _id + * username + * mobile + * email + * wx_openid.app-plus + * wx_openid.mp-weixin + * wx_unionid + * ali_openid + * my_invite_code + * 调用示例 + await vk.daoCenter.userDao.findByUserInfo({ + mobile:mobile + }); + * data 请求参数说明 + * @param {Object} userInfo 用户信息 + */ +dao.findByUserInfo = async (userInfo) => { + let { vk, db, _ } = util; + let res; + // 数据库操作开始----------------------------------------------------------- + let whereJson = {}; + let list = [ + "_id", + "username", + "mobile", + "email", + "wx_openid.app-plus", + "wx_openid.mp-weixin", + "wx_unionid", + "ali_openid", + "my_invite_code" + ]; + let orArr = []; + for (let i = 0; i < list.length; i++) { + let keyName = list[i]; + let orObj = {}; + if (vk.pubfn.isNotNull(userInfo[keyName])) orObj[keyName] = userInfo[keyName]; + if (vk.pubfn.isNotNull(orObj)) { + orArr.push(orObj); + } + } + if (orArr.length > 0) { + whereJson = _.or(orArr); + res = await vk.baseDao.findByWhereJson({ + dbName: dbName.user, + fieldJson: { token: false, password: false }, + whereJson: whereJson + }); + } + // 数据库操作结束----------------------------------------------------------- + return res; +}; +/** + * 根据ID数组获取用户列表 最多支持500个 + * 调用示例 + * await vk.daoCenter.userDao.listByIds(userIdArr); + * data 请求参数说明 + * @param {Array} userIdArr 用户ID数组 + */ +dao.listByIds = async (userIdArr) => { + let { vk, db, _ } = util; + let res = await vk.baseDao.select({ + dbName: dbName.user, + pageIndex: 1, + pageSize: 500, + getMain: true, + fieldJson: { token: false, password: false }, + whereJson: { + _id: _.in(userIdArr) + }, + }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; +/** + * 根据手机号直接注册账号并登录 + * 若手机号已存在,则直接登录 + * @param {Object} data 参数 + * mobile 手机号 必填 + * password 初始密码 + * inviteCode 邀请人的邀请码 + * myInviteCode 设置当前注册用户自己的邀请码 + * needPermission 设置为true时会在checkToken时返回用户权限(permission),建议在管理控制台中使用 + * 调用示例 + await vk.daoCenter.userDao.registerUserByMobile({ + mobile, + }); + */ +dao.registerUserByMobile = async (data) => { + let { vk, db, _, uniID } = util; + let res = {}; + let { + mobile, + password, + inviteCode, + myInviteCode, + needPermission + } = data; + // 数据库操作开始----------------------------------------------------------- + let code = vk.pubfn.random(6); + // 设置验证码 + await uniID.setVerifyCode({ + mobile, + code, + expiresIn: 60, + type: "login" + }); + // 若手机号不存在,则注册并登录。存在,则直接登录。 + res = await uniID.loginBySms({ + mobile, + code, + password, + inviteCode, + myInviteCode, + needPermission + }); + if (res.uid && vk.pubfn.isNull(res.userInfo)) { + res.userInfo = await vk.daoCenter.userDao.findById(res.uid); + } + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 重置用户密码 + * data 请求参数说明 + * @param {String} uid 用户ID + * @param {String} password 需要重置的密码 + * 调用示例 +await vk.daoCenter.userDao.resetPwd({ + uid: uid, + password: "123456" +}); + */ +dao.resetPwd = async (data) => { + let { vk, db, _, uniID } = util; + let res = {}; + let { + uid, + password + } = data; + // 数据库操作开始----------------------------------------------------------- + res = await uniID.resetPwd({ uid, password }); + // 数据库操作结束----------------------------------------------------------- + return res; +}; + +/** + * 获取一个未被使用的6位数分享码 + * 调用示例 +await vk.daoCenter.userDao.getValidInviteCode(); + */ +dao.getValidInviteCode = async (data) => { + let { vk, db, _ } = util; + // 数据库操作开始----------------------------------------------------------- + let inviteCode = await vk.pubfn.randomAsync(6, "23456789ABCDEFGHJKLMNPQRSTUVWXYZ", async (val)=>{ + let num = await vk.baseDao.count({ + dbName: dbName.user, + whereJson:{ + my_invite_code: val + } + }, 10); // 最大重试10次 + return num === 0 ? true : false; + }); + // 数据库操作结束----------------------------------------------------------- + return inviteCode; +}; + +module.exports = dao; diff --git a/uniCloud-aliyun/cloudfunctions/router/index.js b/uniCloud-aliyun/cloudfunctions/router/index.js new file mode 100644 index 0000000..fcc5154 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/index.js @@ -0,0 +1,7 @@ +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vkCloud = require('vk-unicloud'); // 引入 vk-unicloud +const vk = vkCloud.createInstance(require('./config.js')); // 通过 vkCloud.createInstance 创建 vk 实例 +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/index.js b/uniCloud-aliyun/cloudfunctions/router/middleware/index.js new file mode 100644 index 0000000..39f7808 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/index.js @@ -0,0 +1,29 @@ +// 加载模块 - 中间件 请勿改动此文件----------------------------------- +const modulesPath = __dirname+"/modules"; +const fs = require('fs'); +const fileList = fs.readdirSync(modulesPath); +var moduleList = []; +var modulesNames = []; + +fileList.map((file, index) => { + if(file.indexOf(".js") > -1){ + modulesNames.push(file.substring(0,file.length-3)); + } +}); + +modulesNames.map((modulesName, index) => { + try { + moduleList.push(require(modulesPath+"/"+modulesName)); + } catch (err) { + console.error(`【异常】加载中间件【${modulesName}】异常,请检查!↓↓↓请查看下方的错误提示↓↓↓`); + console.error(err); + console.error(`【异常】加载中间件【${modulesName}】异常,请检查!↑↑↑请查看上方的错误提示↑↑↑`); + } +}); + +var middlewareList = []; +moduleList.map((moduleItem, index) => { + middlewareList = middlewareList.concat(moduleItem); +}); +module.exports = middlewareList; +// 加载模块 - 中间件 请勿改动此文件----------------------------------- \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js new file mode 100644 index 0000000..bb255a5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/addAdminLog.js @@ -0,0 +1,63 @@ +/** + * 添加操作日志 + */ + +// 需要添加日志的云函数列表 +const urlList = [ + { url: "admin/system/user/sys/add", title: "用户添加" }, + { url: "admin/system/user/sys/update", title: "用户修改" }, + { url: "admin/system/user/sys/delete", title: "用户删除" }, + { url: "admin/system/user/sys/batchUpdateStatus", title: "批量修改用户冻结状态" } +]; + +// 生成regExp规则 +let regExp = urlList.map((item, index) => { + return `^${item.url}$`; +}); + +module.exports = [{ + id: "addAdminLog", + // 需要添加操作日志的云函数列表 + regExp, + description: "添加admin操作日志", + index: 999, // 确保最后执行即可 + mode: "onActionExecuted", // 可选 onActionExecuting onActionExecuted + enable: true, // 通过设置enable=false可以关闭该中间件 + main: async function(event, serviceRes) { + let { url, data = {}, uniIdToken, util, filterResponse, originalParam } = event; + let { uniID, config, vk, db, _ } = util; + let { userInfo = {} } = filterResponse; + let res = serviceRes; + try { + // 此处加 try catch 保证即使添加日志环节出错,不影响业务运行。 + if (res.code === 0) { + // 只有请求成功的请求才添加日志 + let item = vk.pubfn.getListItem(urlList, "url", url); + let title = item && item.title ? item.title : "未分类"; + delete data.uid; + // 日志写入数据库 + // 获取请求id(只有云端云函数才有请求id,本地运行的云函数无请求id) + let request_id; + if (typeof vk.pubfn.getUniCloudRequestId === "function") { + request_id = vk.pubfn.getUniCloudRequestId(); + } + await vk.baseDao.add({ + dbName: "opendb-admin-log", + dataJson: { + user_id: userInfo._id, + user_name: userInfo.nickname, + title, + ip: originalParam.context.CLIENTIP, + url: url, + request_param: data, + response: serviceRes, + request_id + } + }); + } + } catch (err) { + console.error("添加日志异常", err); + } + return res; + } +}] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js new file mode 100644 index 0000000..1fe60a2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter1.js @@ -0,0 +1,22 @@ +/** + * 自定义过滤器 - 前置 + */ + +module.exports = [ + { + id: "xxxx1", + regExp: "^xxx1/kh", // 正则匹配规则,这个是以^xxx1/kh/开头的云函数会被拦截 + description: "这里是你过滤器1号的描述", + index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行) + mode:"onActionExecuting", // 可选 onActionExecuting onActionExecuted + main: async function(event) { + // 这里是拦截规则,可以查数据库,最终code:0 代表通过,其他均为未通过,msg是被拦截的原因 + let { data = {}, util } = event; + let { vk } = util; + return { + code: -1, + msg: "被自定义过滤器1号拦截了" + } + } + } +] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js new file mode 100644 index 0000000..84d976b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/customFilter2.js @@ -0,0 +1,19 @@ +/** + * 自定义过滤器 - 后置 + */ + +module.exports = [ + { + id: "xxxx2", + regExp: "^xxx2/kh", // 正则匹配规则,这个是以^xxx2/kh/开头的云函数会被拦截 + description: "这里是你过滤器2号的描述", + index: 310,// 此处必须>300 因为检测用户是否登录的过滤器的index是200(sys是300,因此为了能通用,建议填大于300的值)(越小越先执行) + mode:"onActionExecuted", // 可选 onActionExecuting onActionExecuted + main: async function(event, serviceRes) { + let { data = {}, util } = event; + let { vk } = util; + serviceRes.msg = "被过滤器修改后的值"; + return serviceRes; + } + } +] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js new file mode 100644 index 0000000..52dfc8b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/registerInitFilter.js @@ -0,0 +1,46 @@ +/** + * 注册成功后,统一给用户初始化字段值 + */ + +module.exports = [{ + id: "registerInit", + // 符合下方正则条件的云函数才会进入该中间件 + regExp: [ + "^user/pub/register(.*)", + "^user/pub/login(.*)", + "^admin/system/user/sys/add" + ], + description: "注册成功后,统一给用户初始化字段值", + index: 301, + mode: "onActionExecuted", // 可选 onActionExecuting onActionExecuted + enable: true, // 通过设置enable=false可以关闭该中间件 + main: async function(event, serviceRes) { + let { data = {}, util, filterResponse, originalParam } = event; + let { vk, config, db, _ } = util; + let res = serviceRes; + + // 初始化用户信息(只在用户注册成功时才执行下面的代码) + if (res.code === 0 && res.type === "register" && res.uid) { + let uniIdConfig = vk.pubfn.getUniIdConfig(config); // 获取uniID的配置 + // 你要初始化的字段数据 + let initData = { + // 这里可以加你想要初始化的其他字段,如 status字段初始化为 0 + status: 0, // 用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝 + + }; + // 如果开启了删除dcloud_appid功能,则初始化数据带上 dcloud_appid: _.remove() + if (uniIdConfig.removeDcloudAppid) { + // remove功能是删除该字段(代表关闭隔离不同端用户功能),该用户在其他项目中登录时就不会产生新的账号 详见:https://uniapp.dcloud.io/uniCloud/uni-id.html#isolate-user + initData["dcloud_appid"] = _.remove(); + } + // 修改用户信息,并返回修改后的用户信息 + res.userInfo = await vk.daoCenter.userDao.updateAndReturn({ + whereJson: { + _id: res.uid, + }, + dataJson: initData + }); + } + return res; + } +}] diff --git a/uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js new file mode 100644 index 0000000..1df61b9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/middleware/modules/returnUserInfoFilter.js @@ -0,0 +1,81 @@ +/** + * 返回用户信息 + * 由于通常前端需要对用户信息、登录token进行缓存 + * 故云函数对用户进行修改后,需要返回给前端最新的用户信息,以便前端始终能够缓存最新用户信息 + */ + +module.exports = [{ + id: "returnUserInfo", + regExp: [ + "^user/pub/login(.*)", + "^user/pub/register(.*)", + "^user/kh/bind(.*)", + "^user/kh/unbind(.*)", + "^user/kh/update(.*)", + "^user/kh/set(.*)", + "^user/kh/acceptInvite$", + "^user/kh/getMyUserInfo$", + "^client/user/pub/register(.*)", + "^client/user/pub/login(.*)" + ], + description: "用于指定哪些云函数请求后需要通知前端更新userInfo、token、tokenExpired", + index: 310, + mode: "onActionExecuted", // 可选 onActionExecuting onActionExecuted + enable: true, // 通过设置enable=false可以关闭该中间件 + main: async function(event, serviceRes) { + let { data = {}, uniIdToken, util, filterResponse, originalParam } = event; + let { uniID, config = {}, vk, db, _ } = util; + let { userInfo = {} } = filterResponse; + let res = serviceRes; + if (res.code === 0) { + if (vk.pubfn.isNull(res.userInfo)) { + if (vk.pubfn.isNotNull(res.uid)) { + res.userInfo = await vk.daoCenter.userDao.findById(res.uid); + } else if (vk.pubfn.isNotNull(uniIdToken)) { + let tokenRes = await uniID.checkToken(uniIdToken); + if (tokenRes.code === 0) { + res.userInfo = tokenRes.userInfo; + } + } + } + if (vk.pubfn.isNotNull(res.userInfo)) { + if (res.type === "login") { + // 如果是登录 + // 判断用户当前 token数量 是否超过了最大限制 若 tokenMaxLimit 设置为0,代表不限制 + let tokenMaxLimit = config.uni && config.uni.tokenMaxLimit; + if (tokenMaxLimit > 0) { + let newUserInfo = await vk.baseDao.findById({ + dbName: "uni-id-users", + id: res.userInfo._id, + fieldJson: { token: true } + }); + let token = newUserInfo.token || []; + if (token.length > tokenMaxLimit) { + // 淘汰旧的 token + token = token.splice(tokenMaxLimit * -1); + await vk.baseDao.updateById({ + dbName: "uni-id-users", + id: res.userInfo._id, + dataJson: { + token: _.set(token) + } + }); + } + } + } + res.needUpdateUserInfo = true; + // 此处可以继续去除你不想返回给前端的字段 + let deleteKeys = ["token", "password"]; + res.userInfo = vk.pubfn.deleteObjectKeys(res.userInfo, deleteKeys); + } + if (vk.pubfn.isNotNullAll(res.token, res.tokenExpired)) { + // 当返回vk_uni_token对象后,框架会让token自动被前端缓存,前端不需要手动再保存token至本地缓存了。 + res.vk_uni_token = { + token: res.token, + tokenExpired: res.tokenExpired + }; + } + } + return res; + } +}] diff --git a/uniCloud-aliyun/cloudfunctions/router/package.json b/uniCloud-aliyun/cloudfunctions/router/package.json new file mode 100644 index 0000000..f7b7059 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/package.json @@ -0,0 +1,28 @@ +{ + "name": "router", + "version": "1.0.0", + "description": "在router目录下执行 npm i", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "uni-config-center": "file:../../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "uni-id": "file:../../../uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id", + "vk-unicloud": "file:../../../uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud" + }, + "private": true, + "cloudfunction-config": { + "concurrency": 1, + "memorySize": 512, + "path": "", + "timeout": 60, + "triggers": [], + "runtime": "Nodejs12", + "keepRunningAfterReturn": false + }, + "extensions": {} +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/router.param.json b/uniCloud-aliyun/cloudfunctions/router/router.param.json new file mode 100644 index 0000000..1e0a277 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/router.param.json @@ -0,0 +1,13 @@ + +// 运行方法:右键云函数根目录(如router目录),并点击【运行-本地云函数】即可。 +// 若函数需要登录才能访问,则填写uni_id_token的值,值为对应用户的token(可直接从数据库中复制1个过来) +// $url 是 云函数运行路径,如 user/pub/checkToken +// data 是 请求参数,为标准json格式(属性名需要加双引号) + +{ + "uni_id_token":"", + "$url":"template/openapi/weixin/pub/getTemplateList", + "data":{ + + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js new file mode 100644 index 0000000..1e20c1e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/add.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 添加单条数据 + * @url admin/kong/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + params1, + params2, + params3 + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + let dbName = "vk-test"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + params1, + params2, + params3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js new file mode 100644 index 0000000..8fb19ac --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/delete.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 数据删除 + * @url admin/kong/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "vk-test"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js new file mode 100644 index 0000000..373756a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url admin/kong/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-test"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js new file mode 100644 index 0000000..859773c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/kong/sys/update.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 修改数据 + * @url admin/kong/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + params1, + params2, + params3 + } = data; + // 这里需要把 params1 params2 params3 改成你数据库里允许用户添加的字段 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '参数错误' }; + } + let dbName = "vk-test"; + await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + params1, + params2, + params3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js new file mode 100644 index 0000000..ef80325 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/select/kh/user.js @@ -0,0 +1,96 @@ +module.exports = { + /** + * 查询用户列表(用于后端用户选择器的搜索数据) + * @url admin/select/kh/user 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} searchvalue 搜索内容 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { searchvalue } = data; + if (!searchvalue) { + return { code: 0, list: [] }; + } + let dbName = "uni-id-users"; + let fieldJson = { + _id: true, + username: true, + nickname: true, + mobile: true, + }; + let sortArr = []; + // 排序规则开始----------------------------------------------------------- + sortArr.push({ + "name": "register_date", + "type": "desc" + }); + // 排序规则结束----------------------------------------------------------- + // 查询条件开始----------------------------------------------------------- + let whereJson = {}; + let andArr = []; + if (searchvalue) { + // 查询包含searchvalue的数据 + try { + let regExp = new RegExp(searchvalue); + let orObj = _.or([ + { + "username": regExp + }, + { + "nickname": regExp + }, + { + "mobile": regExp + }, + { + "_id": searchvalue + } + ]); + andArr.push(orObj); + } catch (err) { + return { code: -1, msg: '请输入合法的查询内容' }; + } + } + if (andArr.length > 0) { + whereJson = _.and(andArr); + } + // 查询条件结束----------------------------------------------------------- + let selectRes = await vk.baseDao.select({ + dbName: dbName, + pageIndex: 1, + pageSize: 10, + fieldJson: fieldJson, + whereJson: whereJson, + sortArr: sortArr + }, util); + let list = []; + for (let i in selectRes.rows) { + let item = selectRes.rows[i]; + let value = item._id; + let label = item.nickname || "未设置昵称"; + if (item.mobile) { + item.mobile = vk.pubfn.hidden(item.mobile, 3, 4); + label += `(${item.mobile})`; + } else if (item.username) { + item.username = vk.pubfn.hidden(item.username, 2, 3); + label += `(${item.username})`; + } + list.push({ + value: value, + label: label + }); + } + res.list = list; + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js new file mode 100644 index 0000000..30109cf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/addUpdate.js @@ -0,0 +1,162 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加或修改 + * @url admin/system/app-upgrade-center/sys/addUpdate, 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} appid 应用的AppID + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + if (data.platformRadio && vk.pubfn.isNull(data.platform)) { + data.platform = [data.platformRadio]; + } + let { + _id, + appid, + name, + title, + contents, + platform, + platformRadio, + type, + version, + min_uni_version, + url, + stable_publish, + is_silently, + is_mandatory, + create_env = "upgrade-center", + store_list + } = data; + // 参数合法校验开始----------------------------------------------------------- + let mode = _id ? "update" : "add"; + let formRulesRes = await formRules[mode](event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + if (type === "wgt") { + if (vk.pubfn.isNull(min_uni_version)) return { code: -1, msg: "最低app版本号不能为空" }; + } + // 参数合法校验结束----------------------------------------------------------- + appid = appid.trim(); + let create_date = Date.now(); + let uni_platform = platform.indexOf("Android") > -1 ? "android" : "ios"; + let dbName = "opendb-app-versions"; + // 添加和修改公共的dataJson + let dataJson = { + title, + contents, + url, + min_uni_version, + stable_publish, + is_silently, + is_mandatory, + store_list + }; + + if (mode === "add") { + // 获取最新的已发布的版本信息 + let info = await vk.baseDao.select({ + dbName, + getCount: false, + getMain: true, + getOne: true, + pageIndex: 1, + pageSize: 1, + whereJson: { + appid, + type, + platform, + stable_publish: true + }, + sortArr: [{ name: "create_date", type: "desc" }], + }); + // 版本必须比之前的版本高 + if (info && info.version && compareVersion(version, info.version) !== 1) { + return { code: -1, msg: `版本必须大于${info.version}` }; + } + // 添加 + vk.pubfn.objectAssign(dataJson, { + appid, + name, + platform, + version, + type, + create_date, + uni_platform, + create_env, + }); + _id = await vk.baseDao.add({ + dbName, + dataJson + }); + if (_id) { + res.success = true; + res.msg = "添加成功"; + } + } else { + // 修改并返回修改后的数据 + res.info = await vk.baseDao.updateAndReturn({ + dbName, + whereJson: { + _id + }, + dataJson + }); + if (res.info) { + res.success = true; + res.msg = "修改成功"; + } + } + + if (res.success && dataJson.stable_publish) { + // 将其他版本设置为已下线 + await vk.baseDao.update({ + dbName, + whereJson: { + appid, + type, + platform, + stable_publish: true, + _id: _.neq(_id) + }, + dataJson: { + stable_publish: false + } + }); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +/** + * 比较2个版本号的大小 + * 1 version1 > version2 + * 0 version1 = version2 + * -1 version1 < version2 + */ +function compareVersion(version1, version2) { + let arr1 = version1.split("."); + let arr2 = version2.split("."); + if (Number(arr1[0]) === Number(arr2[0]) && Number(arr1[1]) === Number(arr2[1]) && Number(arr1[2]) === Number(arr2[2])) { + return 0; + } + if (Number(arr1[0]) > Number(arr2[0])) { + return 1; + } + if (Number(arr1[0]) === Number(arr2[0]) && Number(arr1[1]) > Number(arr2[1])) { + return 1; + } + if (Number(arr1[0]) === Number(arr2[0]) && Number(arr1[1]) === Number(arr2[1]) && Number(arr1[2]) > Number(arr2[2])) { + return 1; + } + return -1; +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js new file mode 100644 index 0000000..fe695e0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/delete.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 删除 + * @url admin/system/app-upgrade-center/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: 'id不能为空' }; + let dbName = "opendb-app-versions"; + let info = await vk.baseDao.findById({ + dbName, + id: _id, + }); + if (vk.pubfn.isNull(info)) return { code: -1, msg: "版本不存在" }; + if (info.stable_publish) return { code: -1, msg: "不可删除已上线的版本" }; + res.num = await vk.baseDao.deleteById({ + dbName, + id: _id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js new file mode 100644 index 0000000..b821513 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/sys/getList.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system/app-upgrade-center/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "opendb-app-versions"; + res = await vk.baseDao.getTableData({ + dbName, + data, + sortArr: [{ name: "create_date", type: "desc" }] + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js new file mode 100644 index 0000000..f797424 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app-upgrade-center/util/formRules.js @@ -0,0 +1,83 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + appid: [ + // 必填 + { required: true, message: "appid不能为空", trigger: ['blur','change'] } + ], + contents: [ + // 必填 + { required: true, message: "更新内容不能为空", trigger: ['blur','change'] } + ], + platform: [ + // 必填 + { required: true, message: "平台不能为空", trigger: ['blur','change'] } + ], + version: [ + // 必填 + { required: true, message: "版本号不能为空", trigger: ['blur','change'] }, + { validator: vk.pubfn.validator("version"), message: '版本号格式必须为:xx.xx.xx(3个数字组成,数字范围1-99,0-99,0-99) 如1.0.1 不可以是1.0.01', trigger: 'blur' } + ], + url: [ + // 必填 + { required: true, message: "链接不能为空", trigger: ['blur','change'] } + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: 'id不能为空', trigger: 'blur' }, + ], + contents: [ + // 必填 + { required: true, message: "更新内容不能为空", trigger: ['blur','change'] } + ], + url: [ + // 必填 + { required: true, message: "链接不能为空", trigger: ['blur','change'] } + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js new file mode 100644 index 0000000..0b151c9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/add.js @@ -0,0 +1,100 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加应用 + * @url admin/system/app/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {String} appid 应用的AppID + * @param {String} type 应用类型 + * @param {String} name 应用名称 + * @param {String} description 应用描述 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + appid, + type, + name, + description, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + appid = appid.trim(); + let dbName = "opendb-app-list"; + let num = await vk.baseDao.count({ + dbName, + whereJson: { + appid + } + }); + if (num > 0) { + return { code: -1, msg: 'appid已存在,请勿重复添加' }; + } + + let create_date = Date.now(); + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + appid, + type, + name, + description, + create_date, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + creator_uid: uid, // 创建者 + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js new file mode 100644 index 0000000..6e6ffda --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/createPublishHtml.js @@ -0,0 +1,22 @@ +'use strict'; +const createPublishHtml = require('../util/createPublishHtml/index.js') +module.exports = { + /** + * 生成发布页HTML + * @url admin/system/app/sys/createPublishHtml 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { vk, db, _ } = util; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { id } = data; + res = await createPublishHtml({ + id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js new file mode 100644 index 0000000..769c131 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/delete.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 删除应用 + * @url admin/system/app/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 这里id不传默认设置成"___" 是为了防止因未传_id导致误删所有数据. + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "opendb-app-list"; + res.num = await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js new file mode 100644 index 0000000..3e9523b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getInfo.js @@ -0,0 +1,26 @@ +'use strict'; +module.exports = { + /** + * 根据id获取信息 + * @url admin/system/app/sys/getInfo 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { appid } = data; + let dbName = "opendb-app-list"; + res.info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson:{ + appid + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js new file mode 100644 index 0000000..9038302 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/getList.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 分页查询应用 + * @url admin/system/app/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "opendb-app-list"; + res = await vk.baseDao.getTableData({ + dbName, + data, + sortArr: [{ name: "_id", type: "asc" }] + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js new file mode 100644 index 0000000..1be7087 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/sys/update.js @@ -0,0 +1,98 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改应用 + * @url admin/system/app/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {String} name 应用名称 + * @param {String} type 应用类型 + * @param {String} description 应用描述 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + appid, + type, + name, + description, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + appid = appid.trim(); + let dbName = "opendb-app-list"; + let num = await vk.baseDao.count({ + dbName, + whereJson: { + _id: _.neq(_id), + appid + } + }); + if (num > 0) { + return { code: -1, msg: '修改失败,appid已存在!' }; + } + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + appid, + type, + name, + description, + // 1.13.4 新增以下字段(主要用于生成统一发布页和APP升级中心) + enable_upgrade_center, + introduction, + icon_url, + screenshot, + app_android, + app_ios, + mp_weixin, + mp_alipay, + mp_baidu, + mp_toutiao, + mp_qq, + mp_kuaishou, + mp_lark, + mp_jd, + mp_dingtalk, + quickapp, + h5, + store_list, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js new file mode 100644 index 0000000..1bc24dc --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/index.js @@ -0,0 +1,214 @@ +const fs = require('fs') +const path = require('path') +const TE = require('./lib/art-template.js'); + +// 标准语法的界定符规则 +TE.defaults.openTag = '{@' +TE.defaults.closeTag = '@}' + +const success = { + code: 0, + success: true, +} +const fail = { + code: -1, + success: false +} + +async function translateTCB(_fileList = []) { + if (!_fileList.length) return _fileList + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const { + fileList + } = await uniCloud.getTempFileURL({ + fileList: _fileList + }); + return fileList.map((item, index) => item.tempFileURL ? item.tempFileURL : _fileList[index]) +} + +function hasValue(value) { + if (typeof value !== 'object') return !!value + if (value instanceof Array) return !!value.length + return !!(value && Object.keys(value).length && value.enable) +} + +module.exports = async function(data = {}) { + let { + id, + template + } = data; + if (!id) { + return { + ...fail, + code: -1, + errMsg: 'id required' + }; + } + + // 方式一:使用网络资源 + let templatePage; + if (template) { + try { + let htmlBuffer = await vk.request({ + url: template, + method: "GET", + dataType: "default" + }); + templatePage = htmlBuffer.toString("utf8"); + } catch (err) { + return { + ...fail, + code: -2, + errMsg: 'page template no found', + err + }; + } + } else { + // 方式二:使用本地资源 + templatePage = fs.readFileSync(path.resolve(__dirname, './template.html'), 'utf8'); + if (!templatePage) { + return { + ...fail, + code: -2, + errMsg: 'page template no found' + }; + } + } + + let appInfo = await vk.baseDao.findById({ + dbName: "opendb-app-list", + id: id + }); + + if (appInfo) { + + const defaultOptions = { + hasApp: false, + hasMP: false, + hasH5: false, + hasQuickApp: false + } + + defaultOptions.mpNames = { + 'mp_weixin': '微信', + 'mp_alipay': '支付宝', + 'mp_baidu': '百度', + 'mp_toutiao': '字节', + 'mp_qq': 'QQ', + 'mp_dingtalk': '钉钉', + 'mp_kuaishou': '快手', + 'mp_lark': '飞书', + 'mp_jd': '京东' + } + + const imageList = []; + ['app_android'].forEach(key => { + if (!hasValue(appInfo[key])) return + imageList.push({ + key, + urlKey: 'url', + url: appInfo[key].url + }) + }) + Object.keys(defaultOptions.mpNames).concat('quickapp').forEach(key => { + if (!hasValue(appInfo[key])) return + imageList.push({ + key, + urlKey: 'qrcode_url', + url: appInfo[key].qrcode_url + }) + }); + ['icon_url'].forEach(key => { + if (!hasValue(appInfo[key])) return + imageList.push({ + key, + url: appInfo[key] + }) + }) + const filelist = await translateTCB(imageList.map(item => item.url)) + imageList.forEach((item, index) => { + if (item.urlKey) { + appInfo[item.key][item.urlKey] = filelist[index] + } else { + appInfo[item.key] = filelist[index] + } + }) + if (hasValue(appInfo.screenshot)) { + appInfo.screenshot = await translateTCB(appInfo.screenshot) + } + + { + const appInfoKeys = Object.keys(appInfo) + if (appInfoKeys.some(key => { + return key.indexOf('app_') !== -1 && hasValue(appInfo[key]) + })) { + defaultOptions.hasApp = true + } + if (appInfoKeys.some(key => { + return key.indexOf('mp') !== -1 && hasValue(appInfo[key]) + })) { + defaultOptions.hasMP = true + } + if (appInfo.h5 && appInfo.h5.url) { + defaultOptions.hasH5 = true + } + if (appInfo.quickapp && appInfo.quickapp.qrcode_url) { + defaultOptions.hasQuickApp = true + } + + // app + if (defaultOptions.hasApp && appInfo.app_android && appInfo.app_android.url) { + defaultOptions.android_url = appInfo.app_android.url + } else { + defaultOptions.android_url = '' + } + if (defaultOptions.hasApp && appInfo.app_ios && appInfo.app_ios.url) { + defaultOptions.ios_url = appInfo.app_ios.url + } else { + defaultOptions.ios_url = '' + } + + // mp + defaultOptions.mpKeys = Object.keys(appInfo).filter(key => { + return key.indexOf('mp') !== -1 && hasValue(appInfo[key]) + }) + } + + // 解决二维码不显示的问题 + if (appInfo.icon_url && appInfo.icon_url.indexOf("http") == 0) { + let imageBuffer = await vk.request({ + url: appInfo.icon_url, + method: "GET", + dataType: "default" + }); + appInfo.icon_url = "data:image/png;base64," + imageBuffer.toString('base64'); + } + + const html = TE.render(templatePage)(Object.assign({}, appInfo, defaultOptions)); + + if (!(defaultOptions.hasApp || defaultOptions.hasH5 || defaultOptions.hasMP || defaultOptions + .hasQuickApp)) { + return { + ...fail, + code: -100, + errMsg: '缺少应用信息,App、小程序、H5、快应用请至少填写一项' + } + } + + return { + ...success, + mpserverlessComposedResponse: true, // 使用阿里云返回集成响应是需要此字段为true + statusCode: 200, + headers: { + 'content-type': 'text/html' + }, + body: html + }; + } + + return { + ...fail, + code: -3, + errMsg: 'no record' + }; +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js new file mode 100644 index 0000000..b292990 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/lib/art-template.js @@ -0,0 +1,2 @@ +/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/ +!function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(//g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(B){throw B.temp="function anonymous($data,$filename) {"+z+"}",B}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a,b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"<",">":">",'"':""","'":"'","&":"&"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;d>c;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(j){return j.filename=h||"anonymous",j.name="Syntax Error",p(j)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;e.openTag="{{",e.closeTag="}}";var z=function(a,b){var c=b.split(":"),d=c.shift(),e=c.join(":")||"";return e&&(e=", "+e),"$helpers."+d+"("+a+e+")"};e.parser=function(a){a=a.replace(/^\s/,"");var b=a.split(" "),c=b.shift(),e=b.join(" ");switch(c){case"if":a="if("+e+"){";break;case"else":b="if"===b.shift()?" if("+b.join(" ")+")":"",a="}else"+b+"{";break;case"/if":a="}";break;case"each":var f=b[0]||"$data",g=b[1]||"as",h=b[2]||"$value",i=b[3]||"$index",j=h+","+i;"as"!==g&&(f="[]"),a="$each("+f+",function("+j+"){";break;case"/each":a="});";break;case"echo":a="print("+e+");";break;case"print":case"include":a=c+"("+b.join(",")+");";break;default:if(/^\s*\|\s*[\w\$]/.test(e)){var k=!0;0===a.indexOf("#")&&(a=a.substr(1),k=!1);for(var l=0,m=a.split("|"),n=m.length,o=m[l++];n>l;l++)o=z(o,m[l]);a=(k?"=":"=#")+o}else a=d.helpers[c]?"=#"+c+"("+b.join(",")+");":"="+a}return a},"function"==typeof define?define(function(){return d}):"undefined"!=typeof exports?module.exports=d:this.template=d}(); \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html new file mode 100644 index 0000000..c54f23d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/createPublishHtml/template.html @@ -0,0 +1,241 @@ + + + + + + + + + {@name@} + + + + +
+ +
+ +
+ +

{@name@}

+

{@introduction@}

+
+ + {@if hasApp || hasMP || hasH5 || hasQuickApp@} +
+
+ {@if hasApp@} + App + {@/if@} + {@if hasMP@} + 小程序 + {@/if@} + {@if hasH5@} + H5 + {@/if@} + {@if hasQuickApp@} + 快应用 + {@/if@} +
+
+ {@if hasApp@} +
+ +

扫码获取

+ 下载安装 + + +

Android平台尚未发布,敬请期待~

+
+ {@/if@} + {@if hasMP@} +
+
+
+ {@each mpKeys@} +
+
+
+ {@mpNames[$value]@} +
+
+ {@/each@} +
+
+ {@each mpKeys@} +
+ + +

长按图片识别小程序

+
+ {@/each@} +
+
+
+ {@/if@} + {@if hasH5@} +
+
+ + {@h5.url@} +
+
+ {@/if@} + {@if hasQuickApp@} +
+ +

快应用

+

扫描二维码或复制名称后可在手机应用市场中搜索快应用

+
+ {@/if@} +
+
+ {@/if@} + + +
+
+ +
+
+
+ +
+ + +
+

{@name@}

+

{@introduction@}

+
+ + {@if hasApp || hasMP || hasH5 || hasQuickApp@} +
+
+ {@if hasApp@} + App + {@/if@} + {@if hasMP@} + 小程序 + {@/if@} + {@if hasH5@} + H5 + {@/if@} + {@if hasQuickApp@} + 快应用 + {@/if@} +
+
+ {@if hasApp@} + + {@/if@} + {@if hasMP@} +
+ {@each mpKeys@} +
+ +
扫二维码识别小程序
+
{@mpNames[$value]@}小程序
+
+ {@/each@} +
+ {@/if@} + {@if hasH5@} +
+
+
+ {@h5.url@} +
+
+ {@/if@} + {@if hasQuickApp@} +
+ +

快应用

+

扫描二维码或复制名称后可在手机应用市场中搜索快应用

+
+ {@/if@} +
+
+ {@/if@} +
+ + {@if description && description.length@} +
+

应用描述

+
{@description@}
+
+ {@/if@} + + {@if screenshot && screenshot.length@} +
+

应用截图

+
+
+
    + {@each screenshot@} +
  • + +
  • + {@/each@} +
+
+ {@/if@} +
+

复制成功

+
+
+ + + + + \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js new file mode 100644 index 0000000..3a4c4bd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/app/util/formRules.js @@ -0,0 +1,72 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + appid: [ + { required: true, message: '应用的AppID为必填字段', trigger: 'blur' }, + ], + name: [ + { required: true, message: '应用名称为必填字段', trigger: 'blur' } + ], + type: [ + { required: true, message: '应用类型为必填字段', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: 'id不能为空', trigger: 'blur' }, + ], + appid: [ + { required: true, message: '应用的AppID为必填字段', trigger: 'blur' }, + ], + name: [ + { required: true, message: '应用名称为必填字段', trigger: 'blur' } + ], + type: [ + { required: true, message: '应用类型为必填字段', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js new file mode 100644 index 0000000..f2a3d4a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/add.js @@ -0,0 +1,87 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 新增 + * @url admin/system/menu/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} menu_id 菜单Id,唯一标识 + * @param {String} name 菜单名称 + * @param {String} comment 备注 + * @param {String} url 页面路径 + * @param {String} icon 菜单图标 + * @param {Number} sort 排序(越大越在前面) + * @param {String} parent_id 父级id + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + menu_id, + name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + hidden_menu + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if(formRulesRes.code !== 0){ + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "opendb-admin-menus"; + // 检测menu_id是否存在 + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + menu_id + } + }); + if(num > 0){ + return { code : -1, msg : `标识【${menu_id}】不能重复!` }; + } + let dataJson = { + menu_id, + name, + comment, + url, + icon, + sort, + parent_id, + enable, + hidden_menu + }; + // 检测parent_id是否不存在 + if(vk.pubfn.isNotNull(parent_id)){ + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + menu_id : parent_id + } + }); + if(num <= 0){ + return { code : -1, msg : `父标识【${parent_id}】不存在!` }; + } + }else{ + delete dataJson.parent_id; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js new file mode 100644 index 0000000..467d3b5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/adds.js @@ -0,0 +1,74 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 批量新增 + * @url admin/system/menu/sys/adds 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} mode 模式 1 :覆盖 2:忽略 + * @param {Array} menus 菜单json + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + mode, + menus, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.adds(event); + if(formRulesRes.code !== 0){ + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dataArr = []; + for(let i=0;i { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + menu_id, + permissionList, + reset + } = data; + res = await vk.system.sysDao.menuBindPermission({ + menu_id, + permissionList, + reset + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js new file mode 100644 index 0000000..d73e45a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/delete.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 删除 + * @url admin/system/menu/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} menu_id 菜单Id,唯一标识 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { menu_id } = data; + if(vk.pubfn.isNullOne(menu_id)){ + return { code : -1, msg : 'menu_id不能为空' }; + } + // 检查是否有子项 + let num = await vk.baseDao.count({ + dbName:"opendb-admin-menus", + whereJson:{ + parent_id : menu_id + } + }); + if(num > 0){ + return { code : -1, msg : '该项含有子项,请先删除子项!' }; + } + res.num = await vk.baseDao.del({ + dbName:"opendb-admin-menus", + whereJson:{ + menu_id + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js new file mode 100644 index 0000000..b0937e3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getAll.js @@ -0,0 +1,31 @@ +'use strict'; +module.exports = { + /** + * 获取菜单列表(一次性获取全部) + * @url admin/system/menu/sys/getAll 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 返回树状结构代码详情见:https://vkdoc.fsq.pub/client/uniCloud/db/getTree.html + res = await vk.system.sysDao.listMenuToTree({ + pageIndex: 1, + pageSize: 500, + whereJson: { + parent_id: _.in([null, ""]), + menu_id: _.exists(true) + }, + treeProps: { + level: 3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js new file mode 100644 index 0000000..27b0dff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/getCascader.js @@ -0,0 +1,57 @@ +'use strict'; +module.exports = { + /** + * 获取菜单级联数据(懒加载形式) + * @url admin/system/menu/sys/getCascader 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Object} node 当前点击的节点 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { node = {} } = data; + let whereJson = { + enable: true + }; + if (node.root) { + whereJson["parent_id"] = null; + } else { + whereJson["parent_id"] = node.value; + } + res = await vk.baseDao.selects({ + dbName: "opendb-admin-menus", + pageIndex: 1, + pageSize: 500, + whereJson, + sortArr: [{ name: "sort", type: "asc" }], + // 副表列表 + foreignDB: [ + { + dbName: "opendb-admin-menus", + localKey:"menu_id", + foreignKey: "parent_id", + as: "hasChildren", + limit: 1, // 避免浪费查询,这里设置limit:1 + } + ] + }); + // 数据预处理 + let rows = res.rows; + for (let i in rows) { + let item = rows[i]; + rows[i].label = `${item.name}(${item.menu_id})`; + if(vk.pubfn.isNull(item.hasChildren)){ + rows[i].leaf = true; + } + } + res.rows = rows; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js new file mode 100644 index 0000000..f69e2f2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/update.js @@ -0,0 +1,87 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改 + * @url admin/system/menu/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} menu_id 菜单Id,唯一标识 + * @param {String} name 菜单名称 + * @param {String} comment 备注 + * @param {String} url 页面路径 + * @param {String} icon 菜单图标 + * @param {Number} sort 排序(越大越在前面) + * @param {String} parent_id 父级id + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + menu_id, + name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + hidden_menu + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "opendb-admin-menus"; + let dataJson = { + name, + comment, + url, + icon, + sort, + parent_id, + enable, + hidden_menu + }; + // 检测parent_id是否不存在 + if (vk.pubfn.isNotNull(parent_id)) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + menu_id: parent_id + } + }); + if (num <= 0) { + return { code: -1, msg: `父标识【${parent_id}】不存在!` }; + } + let info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson: { + menu_id + } + }); + if (vk.pubfn.isNotNull(info) && info.menu_id === parent_id) { + return { code: -1, msg: `不可以设置自己为父菜单` }; + } + } else { + dataJson["parent_id"] = _.remove(); + } + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName, + whereJson: { + menu_id + }, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js new file mode 100644 index 0000000..4b0b1c5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/sys/updateBase.js @@ -0,0 +1,43 @@ +module.exports = { + /** + * 修改基础信息 + * @url admin/system/menu/sys/updateBase 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id _id + * @param {Number} sort 排序 + * @param {Boolean} enable 是否启用 + * @param {Boolean} hidden_menu 是否隐藏(左侧菜单中不显示) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + sort, + enable, + hidden_menu + } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: "_id不能为空" }; + + let dbName = "opendb-admin-menus"; + + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + sort, + enable, + hidden_menu + }, + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js new file mode 100644 index 0000000..c3e41f0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/menu/util/formRules.js @@ -0,0 +1,80 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event){ + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code : 0, msg : '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + menu_id: [ + { required: true, message: '菜单标识不能为空', trigger: 'blur' }, + ], + name: [ + { required: true, message: '菜单名称不能为空', trigger: 'blur' }, + ], + sort:[ + { type: 'number', message: '排序值必须为数字'} + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data : data, + rules : rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event){ + return this.add(event); + } + + /** + * 批量添加 + */ + async adds(event){ + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code : 0, msg : '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + menu_id: [ + { required: true, message: '菜单标识不能为空', trigger: 'blur' }, + ], + name: [ + { required: true, message: '菜单名称不能为空', trigger: 'blur' }, + ], + sort:[ + { type: 'number', message: '排序值必须为数字'} + ] + }; + // 验证规则结束 ----------------------------------------------------------- + let { menus } = data; + for(let i=0;i { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + permission_id, + permission_name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + match_mode = 0, + curd_category, + level + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "uni-id-permissions"; + // 检测permission_id是否存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + permission_id + } + }); + if (num > 0) { + return { code: -1, msg: `标识【${permission_id}】不能重复!` }; + } + let dataJson = { + permission_id, + permission_name, + comment, + url, + icon, + sort, + parent_id, + enable, + match_mode, + curd_category, + level + }; + // 检测parent_id是否不存在 + if (vk.pubfn.isNotNull(parent_id)) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + permission_id: parent_id + } + }); + if (num <= 0) { + return { code: -1, msg: `父标识【${parent_id}】不存在!` }; + } + } else{ + delete dataJson.parent_id; + } + if(url === "" || JSON.stringify(url) === '[""]'){ + delete dataJson.url; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js new file mode 100644 index 0000000..621b60f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/delete.js @@ -0,0 +1,39 @@ +module.exports = { + /** + * 删除权限 + * @url admin/system/permission/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} permission_id 权限Id,唯一标识 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { permission_id } = data; + if (vk.pubfn.isNullOne(permission_id)) { + return { code: -1, msg: 'permission_id不能为空' }; + } + let dbName = "uni-id-permissions"; + // 检查是否有子项 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + parent_id: permission_id + } + }); + if (num > 0) { + return { code: -1, msg: '该项含有子项,请先删除子项!' }; + } + res = uniID.deletePermission({ + permissionID: permission_id + }); + res.msg = res.message; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js new file mode 100644 index 0000000..f35b14b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/getAll.js @@ -0,0 +1,30 @@ +'use strict'; +module.exports = { + /** + * 获取权限列表 + * @url admin/system/permission/sys/getAll 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.system.sysDao.listPermissionToTree({ + pageIndex: 1, + pageSize: 500, + whereJson: { + parent_id: _.in([null, ""]), + permission_id: _.exists(true) + }, + treeProps: { + level: 3 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js new file mode 100644 index 0000000..4a8c64e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/update.js @@ -0,0 +1,97 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改权限 + * @url admin/system/permission/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} permission_id 权限Id,唯一标识 + * @param {String} permission_name 权限名称,展示用 + * @param {String} comment 备注 + * @param {String} url 云函数路径 + * @param {String} icon 图标 + * @param {Number} sort 排序(越大越在前面) + * @param {String} parent_id 父级id + * @param {Boolean} enable 是否启用 + * @param {Number} match_mode 0:完整路径 1:通配符 2:正则表达式 + * @param {Number} curd_category 0:未分类 1:增 2:删 3:改 4:查 5:特殊 + * @param {Number} level 0:未分类 1:子弹级 2:炸弹级 3:榴弹级 4:核弹级 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + permission_id, + permission_name, + comment, + url, + icon, + sort = 0, + parent_id, + enable = true, + match_mode = 0, + curd_category, + level + } = data; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "uni-id-permissions"; + let dataJson = { + permission_name, + comment, + url, + icon, + sort, + parent_id, + enable, + match_mode, + curd_category, + level + }; + // 检测parent_id是否不存在 + if (vk.pubfn.isNotNull(parent_id)) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + permission_id: parent_id + } + }); + if (num <= 0) { + return { code: -1, msg: `父标识【${parent_id}】不存在!` }; + } + let info = await vk.baseDao.findByWhereJson({ + dbName, + whereJson: { + permission_id + } + }); + if (vk.pubfn.isNotNull(info) && info.permission_id === parent_id) { + return { code: -1, msg: `不可以设置自己为父级` }; + } + } else { + dataJson["parent_id"] = _.remove(); + } + if (url === "" || JSON.stringify(url) === '[""]') { + dataJson["url"] = _.remove(); + } + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName, + whereJson: { + permission_id + }, + dataJson + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js new file mode 100644 index 0000000..07833ee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateBase.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 修改基础信息 + * @url admin/system/permission/sys/updateBase 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {Number} sort 排序 + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + sort, + enable, + } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: "_id不能为空" }; + + let dbName = "uni-id-permissions"; + + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + sort, + enable, + }, + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js new file mode 100644 index 0000000..ccb7879 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateCategory.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 修改权限分类 + * @url admin/system/permission/sys/updateCategory 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 权限Id + * @param {Number} curd_category 0:未分类 1:增 2:删 3:改 4:查 5:特殊 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + curd_category=0, + } = data; + let dbName = "uni-id-permissions"; + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + curd_category + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js new file mode 100644 index 0000000..e63a4e8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/sys/updateLevel.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 修改权限等级 + * @url admin/system/permission/sys/updateLevel 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 权限Id + * @param {Number} level 0:未分类 1:子弹级 2:炸弹级 3:榴弹级 4:核弹级 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + level=0, + } = data; + let dbName = "uni-id-permissions"; + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + level + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js new file mode 100644 index 0000000..fcdba83 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/permission/util/formRules.js @@ -0,0 +1,46 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + permission_id: [ + { required: true, message: '权限标识不能为空', trigger: 'blur' }, + ], + permission_name: [ + { required: true, message: '权限名称不能为空', trigger: 'blur' }, + ], + sort: [ + { type: 'number', message: '排序值必须为数字' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + return this.add(event); + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js new file mode 100644 index 0000000..6a576d7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/add.js @@ -0,0 +1,58 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 新增角色 + * @url admin/system/role/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} role_id 角色Id(role_id) + * @param {String} role_name 角色名称,展示用 + * @param {String} comment 备注 + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + role_id, + role_name, + comment, + enable = true, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + let dbName = "uni-id-roles"; + // 检查role_id是否存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + role_id + } + }); + if (num > 0) { + return { code: -1, msg: `标识【${role_id}】不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + role_id, + role_name, + comment, + enable + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js new file mode 100644 index 0000000..c85d05a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindMenu.js @@ -0,0 +1,49 @@ +module.exports = { + /** + * 为角色绑定菜单 + * @url admin/system/role/sys/bindMenu 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Array} role_id 角色Id(role_id) + * @param {Array} menuList 菜单Id(menu_id)列表 + * @param {Boolean} reset 是否直接覆盖菜单,true:直接将menuList设置为角色菜单,false:在角色已有菜单后追加菜单 + * @param {Boolean} addPermission 是否自动添加菜单内置的权限 默认false + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { role_id, menuList, reset, addPermission } = data; + res = await vk.system.sysDao.roleBindMenu({ + role_id, + menuList, + reset, + addPermission + }); + if (res.code !== 0) return res; + let dbName = "uni-id-roles"; + let roleInfo = await vk.baseDao.findByWhereJson({ + dbName, + whereJson: { + role_id, + } + }); + let count = roleInfo.menu ? roleInfo.menu.length : 0; + // 修改stats_count_info统计信息 + res.info = await vk.baseDao.updateAndReturn({ + dbName, + whereJson: { + role_id + }, + dataJson: { + ["stats_count_info.type.0.count"]: count + }, + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js new file mode 100644 index 0000000..a8812b1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/bindPermission.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 为角色绑定权限 + * @url admin/system/role/sys/bindPermission 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Array} role_id 角色Id(role_id) + * @param {Array} permissionList 权限Id(permission_id)列表 + * @param {Boolean} reset 是否直接覆盖角色权限,true:直接将permissionList设置为角色权限,false:在角色已有权限后追加权限 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { role_id, permissionList, reset, stats_count_info = {} } = data; + res = await uniID.bindPermission({ + roleID: role_id, + permissionList, + reset + }); + if (res.code !== 0) return res; + res.msg = res.message; + // 修改stats_count_info统计信息 + res.info = await vk.baseDao.updateAndReturn({ + dbName: "uni-id-roles", + whereJson: { + role_id + }, + dataJson: { + stats_count_info: _.set(stats_count_info) + }, + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js new file mode 100644 index 0000000..e888e71 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/delete.js @@ -0,0 +1,28 @@ +module.exports = { + /** + * 删除角色 + * @url admin/system/role/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} role_id 角色Id(role_id) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { role_id } = data; + if (vk.pubfn.isNullOne(role_id)) { + return { code: -1, msg: 'role_id不能为空' }; + } + res = uniID.deleteRole({ + roleID: role_id + }); + res.msg = res.message; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js new file mode 100644 index 0000000..f99c35e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/getList.js @@ -0,0 +1,51 @@ +module.exports = { + /** + * 查询角色列表 + * @url admin/system/role/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "uni-id-roles"; + res = await vk.baseDao.getTableData({ + dbName, + data, + // 副表列表 + foreignDB: [ + { + dbName: "uni-id-permissions", + localKey: "permission", + localKeyType: "array", + foreignKey: "permission_id", + as: "permissionList", + limit: 500, + fieldJson: { permission_id:true, permission_name:true,comment:true, enable:true, url:true }, + }, + { + dbName: "opendb-admin-menus", + localKey: "menu", + localKeyType: "array", + foreignKey: "menu_id", + as: "menuList", + limit: 500, + fieldJson: { menu_id:true, name:true,comment:true, enable:true, url:true }, + }, + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js new file mode 100644 index 0000000..a13b2f1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/update.js @@ -0,0 +1,50 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改角色 + * @url admin/system/role/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} role_id 角色Id(role_id) + * @param {String} role_name 角色名称,展示用 + * @param {String} comment 备注 + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + role_id, + role_name, + comment, + enable = true, + } = data; + + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: "uni-id-roles", + whereJson: { + role_id + }, + dataJson: { + role_name, + comment, + enable + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js new file mode 100644 index 0000000..72313b9 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/sys/updateBase.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 修改基础信息 + * @url admin/system/role/sys/updateBase 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {Boolean} enable 是否启用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + enable, + } = data; + if (vk.pubfn.isNull(_id)) return { code: -1, msg: "_id不能为空" }; + + let dbName = "uni-id-roles"; + + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + enable, + }, + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js new file mode 100644 index 0000000..cea27d5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/role/util/formRules.js @@ -0,0 +1,43 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + role_id: [ + { required: true, message: '角色标识不能为空', trigger: 'blur' }, + ], + role_name: [ + { required: true, message: '角色名称不能为空', trigger: 'change' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + return this.add(event); + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js new file mode 100644 index 0000000..358a597 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/add.js @@ -0,0 +1,93 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 添加用户 + * @url admin/system/user/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} nickname 昵称 + * @param {String} gender 性别 + * @param {Boolean} mobile 手机号 + * @param {String} comment 备注 + * @param {Array} dcloud_appid 允许登录的应用列表 + * @param {Number} login_appid_type 0:全部应用 1:部分应用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + username, + password, + nickname, + gender, + mobile, + email, + comment, + allow_login_background, + dcloud_appid = [], + login_appid_type + } = data; + if (!password) password = "234567"; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + + let dbName = "uni-id-users"; + // 检测username + let num = await vk.baseDao.count({ dbName, whereJson: { username } }); + if (num > 0) return { code: -1, msg: `用户名【${username}】已注册!` }; + // 检测mobile + if (mobile) { + let num = await vk.baseDao.count({ dbName, whereJson: { mobile } }); + if (num > 0) return { code: -1, msg: `手机号【${mobile}】已注册!` }; + } + // 检测email + if (email) { + let num = await vk.baseDao.count({ dbName, whereJson: { email } }); + if (num > 0) return { code: -1, msg: `邮箱【${email}】已注册!` }; + } + if (typeof uniID.addUser !== "function") return { code: -1, msg: `请升级uni-id版本至3.3.14或以上。` }; + let addUserRes = await uniID.addUser({ + username, + password, + mobile, + email, + authorizedApp: dcloud_appid + }); + if (addUserRes.code !== 0 || !addUserRes.uid) { + return addUserRes; + } + // 用户其他信息 + let dataJson = { + nickname, + gender, + comment, + allow_login_background, + status: 0, + }; + // 如果设置允许登录所有应用,则直接删除dcloud_appid字段 + if (login_appid_type === 0) { + dataJson["dcloud_appid"] = _.remove(); + } + // 设置用户其他信息 + await vk.baseDao.update({ + dbName, + whereJson: { + _id: addUserRes.uid + }, + dataJson + }); + res.type = "register"; + res.uid = addUserRes.uid; + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js new file mode 100644 index 0000000..ba4d693 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateAppLogin.js @@ -0,0 +1,78 @@ +'use strict'; +module.exports = { + /** + * 批量修改用户可登录的客户端 + * @url admin/system/user/sys/batchUpdateAppLogin 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { uniID, customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { + user_ids, + allow_login_background = false, + dcloud_appid, + login_appid_type, + mode + } = data; + if(vk.pubfn.isNullOne(user_ids, login_appid_type, mode)){ + return { code: -1, msg: "参数错误" }; + } + if(mode !== 1 && typeof dcloud_appid !== "string"){ + return { code: -1, msg: "新增和移除模式下,dcloud_appid只能是字符串" }; + } + let dataJson = {}; + dataJson["allow_login_background"] = allow_login_background; + if(login_appid_type === 0){ + // 可登录全部应用 + dataJson["dcloud_appid"] = _.remove(); + } else{ + res.successNum = 0; + res.failNum = 0; + for(let i=0; i { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { user_id, parent_id } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(user_id)) { + return { code: -1, msg: '参数错误' }; + } + let parentUser = await vk.baseDao.findById({ + dbName: "uni-id-users", + id: parent_id, + }); + if (vk.pubfn.isNull(parentUser)) { + return { code: -1, msg: '父标识对应的用户不存在!' }; + } + let { my_invite_code } = parentUser; + if (vk.pubfn.isNull(my_invite_code)) { + return { code: -1, msg: '父标识对应的用户无邀请码,无法邀请!' }; + } + // 执行数据库API请求 + res = await uniID.acceptInvite({ + uid: user_id, + inviteCode: my_invite_code + }); + res.msg = res.message; + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js new file mode 100644 index 0000000..8894ec6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/batchUpdateStatus.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 批量修改用户状态 + * @url admin/system/user/sys/batchUpdateStatus 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Array} user_ids 用户id数组 + * @param {Integer} status 修改成的用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { user_ids, status } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(user_ids, status)) { + return { code: -1, msg: '参数错误' }; + } + if (user_ids.indexOf(uid) > -1 && status === 1) { + return { code: -1, msg: '不可禁用自己' }; + } + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: "uni-id-users", + whereJson: { + _id: _.in(user_ids) + }, + dataJson: { + status: status + } + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js new file mode 100644 index 0000000..f06a1b2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/bindRole.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 为用户绑定角色 + * @url admin/system/user/sys/bindRole 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} user_id 用户id + * @param {Array} roleList 角色Id(role_id)列表 + * @param {Boolean} reset 是否直接覆盖用户角色,true:直接将roleList设置为用户角色,false:在用户已有角色后追加角色 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { user_id, roleList, reset } = data; + res = uniID.bindRole({ + uid: user_id, + roleList, + reset + }); + res.msg = res.message; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js new file mode 100644 index 0000000..9afafc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/delete.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 删除用户 + * @url admin/system/user/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 用户ID + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + if (vk.pubfn.isNullOne(_id)) { + return { code: -1, msg: '_id不能为空' }; + } + if (uid === _id) { + return { code: -1, msg: '请勿删除当前登录账户!' }; + } + // 执行数据库API请求 + res.num = await vk.baseDao.deleteById({ + dbName: "uni-id-users", + id:_id + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js new file mode 100644 index 0000000..13c707e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/getList.js @@ -0,0 +1,54 @@ +module.exports = { + /** + * 查询用户列表(可登录后台的) + * @url admin/system/user/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { dcloud_appid, appids } = data.formData || {}; + let whereJson = {}; + if (dcloud_appid) { + if (dcloud_appid === "___empty-array___") { + whereJson["dcloud_appid"] = []; + } else if (dcloud_appid === "___error___") { + whereJson["dcloud_appid"] = _.and(_.exists(true), _.nin(appids)); + } else if (dcloud_appid === "___non-existent___") { + whereJson["dcloud_appid"] = _.exists(false); + } else { + whereJson["dcloud_appid"] = _.or(_.eq(dcloud_appid), _.exists(false)); + } + } + let dbName = "uni-id-users"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson, + sortArr: [{ "name": "register_date", "type": "desc" }], + // 副表列表 + foreignDB: [{ + dbName: "opendb-app-list", + localKey: "dcloud_appid", + foreignKey: "appid", + localKeyType: "array", + as: "appList", + limit: 500 + }], + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js new file mode 100644 index 0000000..6fd2bc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/resetPassword.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * 强制重置用户密码 + * @url admin/system/user/sys/resetPassword 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} user_id 用户ID + * @param {String} password 重置后的密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { uniID, customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { user_id, password } = data; + // 重置密码 + res = await uniID.resetPwd({ + uid: user_id, + password + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js new file mode 100644 index 0000000..c578801 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/sys/update.js @@ -0,0 +1,102 @@ +const formRules = require("../util/formRules.js"); +module.exports = { + /** + * 修改用户信息 + * @url admin/system/user/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id 用户ID + * @param {String} nickname 昵称 + * @param {String} gender 性别 + * @param {Boolean} mobile 手机号 + * @param {String} comment 备注 + * @param {Array} dcloud_appid 允许登录的应用列表 + * @param {Number} login_appid_type 0:全部应用 1:部分应用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + nickname, + gender, + mobile, + email, + comment, + allow_login_background, + dcloud_appid = [], + login_appid_type + } = data; + let mobile_confirmed; + let email_confirmed; + // 参数合法校验开始----------------------------------------------------------- + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + // 参数合法校验结束----------------------------------------------------------- + + let dbName = "uni-id-users"; + + // 检测mobile + if (mobile) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + mobile: mobile, + _id: _.neq(_id) + } + }); + if (num > 0) return { code: -1, msg: `手机号【${mobile}】已注册!` }; + mobile_confirmed = 1; // 设置该手机号为已验证(否则无法通过手机号进行登录) + } + // 检测email + if (email) { + let num = await vk.baseDao.count({ + dbName, + whereJson: { + email: email, + _id: _.neq(_id) + } + }); + if (num > 0) return { code: -1, msg: `邮箱【${email}】已注册!` }; + email_confirmed = 1; // 设置该邮箱为已验证(否则无法通过邮箱进行登录) + } + let dataJson = { + nickname, + gender, + mobile, + mobile_confirmed, + email, + email_confirmed, + comment, + allow_login_background + }; + // 设置允许登录的应用列表 + if (login_appid_type && typeof uniID.setAuthorizedAppLogin === "function") { + let setAuthorizedAppLoginRes = await uniID.setAuthorizedAppLogin({ + uid: _id, + dcloudAppidList: dcloud_appid + }); + if (setAuthorizedAppLoginRes.code !== 0) { + return setAuthorizedAppLoginRes; + } + } else if (login_appid_type === 0) { + dataJson["dcloud_appid"] = _.remove(); + } + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js new file mode 100644 index 0000000..2bd4b00 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system/user/util/formRules.js @@ -0,0 +1,81 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + // 验证规则开始 ----------------------------------------------------------- + let rules = { + username: [ + { required: true, validator: vk.pubfn.validator("username"), + message: '用户名以字母开头,长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur' } + ], + nickname: [ + { required: true, message: '昵称为必填字段', trigger: 'blur' }, + { min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' } + ], + password: [ + { validator:vk.pubfn.validator("password"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur' } + ], + mobile: [ + { validator: vk.pubfn.validator("mobile"), message: '手机号格式错误', trigger: 'blur' } + ], + email: [ + { validator: vk.pubfn.validator("email"), message: '邮箱格式错误', trigger: 'blur' } + ], + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + _id: [ + { required: true, message: '用户ID不能为空', trigger: 'blur' }, + ], + nickname: [ + { required: true, message: '昵称为必填字段', trigger: 'blur' }, + { min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' } + ], + mobile: [ + { validator: vk.pubfn.validator("mobile"), message: '手机号格式错误', trigger: 'blur' } + ], + email: [ + { validator: vk.pubfn.validator("email"), message: '邮箱格式错误', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js new file mode 100644 index 0000000..e95103a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/admin-log/sys/getList.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/admin-log/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "opendb-admin-log"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js new file mode 100644 index 0000000..5ccc443 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/add.js @@ -0,0 +1,61 @@ +module.exports = { + /** + * 添加 + * @url admin/system_uni/components-dynamic/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} data_id 组件数据id + * @param {String} title 数据标题 + * @param {Object} data 组件数据 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + data_id, + data: dynamicData, + title, + description, + type, + sort = 0, + show = true, + name + } = data; + + // 参数非空检测 + if (vk.pubfn.isNull(data_id)) return { code: -1, msg: 'data_id不能为空' }; + + let dbName = "vk-components-dynamic"; + // 检测key是否已存在 + let num = await vk.baseDao.count({ + dbName: dbName, + whereJson: { + data_id, + } + }); + if (num > 0) { + return { code: -1, msg: `组件数据id不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + data: dynamicData, + data_id, + title, + description, + type, + sort, + show, + name + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js new file mode 100644 index 0000000..1ffbbc0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/delete.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/components-dynamic/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '_id不能为空' }; + } + // 执行数据库API请求 + let num = await vk.baseDao.del({ + dbName:"vk-components-dynamic", + whereJson:{ + _id + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js new file mode 100644 index 0000000..638b64f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/getList.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/components-dynamic/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-components-dynamic"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js new file mode 100644 index 0000000..32012d2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/components-dynamic/sys/update.js @@ -0,0 +1,69 @@ +module.exports = { + /** + * 修改 + * @url admin/system_uni/components-dynamic/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} data_id 组件数据id + * @param {String} title 数据标题 + * @param {Object} data 组件数据 + * @param {Object} description 数据描述 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + data_id, + data: dynamicData, + title, + description, + type, + sort, + show, + name + } = data; + + // 参数非空检测 + if (vk.pubfn.isNull(_id)) return { code: -1, msg: 'id不能为空' }; + + let dbName = "vk-components-dynamic"; + + if (vk.pubfn.isNotNull(data_id)) { + // 检测data_id是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + data_id, + _id: _.neq(_id) + } + }); + if (num > 0) { + return { code: -1, msg: `组件数据id不能重复!` }; + } + } + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + data: dynamicData, + data_id, + title, + description, + type, + sort, + show, + name + } + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js new file mode 100644 index 0000000..bb04e11 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/add.js @@ -0,0 +1,59 @@ +const formRules = require('../util/formRules.js'); +module.exports = { + /** + * 添加 + * @url admin/system_uni/global-data/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} key 键名 + * @param {any} value 键值 + * @param {time} expired_at 过期时间 + * @param {String} comment 备注 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + key, + value, + expired_at, + comment + } = data; + if (!expired_at) expired_at = 0; + // 参数合法校验 + let formRulesRes = await formRules.add(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + + let dbName = "vk-global-data"; + // 检测key是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson: { + key + } + }); + if (num > 0) { + return { code: -1, msg: `键值【${key}】不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson: { + _id: key, // 此处将_id也设置为key,方便使用doc查询提高性能 + key, + value, + expired_at, + comment + } + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js new file mode 100644 index 0000000..93a0943 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/delete.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/global-data/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '_id不能为空' }; + } + let dbName = "vk-global-data"; + // 执行数据库API请求 + let num = await vk.baseDao.del({ + dbName:dbName, + whereJson:{ + _id + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js new file mode 100644 index 0000000..80ca5c1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/getList.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/global-data/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-global-data"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js new file mode 100644 index 0000000..6d81565 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/sys/update.js @@ -0,0 +1,52 @@ +const formRules = require('../util/formRules.js'); +module.exports = { + /** + * 修改 + * @url admin/system_uni/global-data/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} key 键名 + * @param {any} value 键值 + * @param {time} expired_at 过期时间 + * @param {any} comment 备注 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + key, + value, + expired_at, + comment + } = data; + if (typeof expired_at !== "undefined" && !expired_at) expired_at = 0; + // 参数合法校验 + let formRulesRes = await formRules.update(event); + if (formRulesRes.code !== 0) { + return formRulesRes; + } + let dbName = "vk-global-data"; + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: dbName, + whereJson: { + _id: key + }, + dataJson: { + value, + expired_at, + comment + } + }); + + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js new file mode 100644 index 0000000..d20583c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/global-data/util/formRules.js @@ -0,0 +1,64 @@ +'use strict'; +/** + * 表单验证 + */ +class Util { + constructor() { + + } + /** + * 添加 + */ + async add(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + key: [ + { required: true, message: '键名不能为空', trigger: 'blur' }, + ], + value: [ + { required: true, message: '键值不能为空', trigger: 'change' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } + /** + * 修改 + */ + async update(event) { + let { data = {}, userInfo, util } = event; + let { vk } = util; + let res = { code: 0, msg: '' }; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + key: [ + { required: true, message: '键名不能为空', trigger: 'blur' }, + ], + value: [ + { required: true, message: '键值不能为空', trigger: 'change' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + + // 开始进行验证 + res = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + // 返回验证结果 + return res; + } +} +module.exports = new Util \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js new file mode 100644 index 0000000..0a4eae8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/afreshNotice.js @@ -0,0 +1,117 @@ +'use strict'; +module.exports = { + /** + * 重新执行回调通知 + * @url admin/system_uni/pay-orders/sys/afreshNotice 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, // 订单id + } = data; + + let dbName = "vk-pay-orders"; + + // 获取异步回调配置 + let spaceId = originalParam.context.SPACEINFO.spaceId; // 服务空间ID + let currentNotifyUrl = getNotifyUrl(config, spaceId); + if (!currentNotifyUrl || currentNotifyUrl.indexOf("http") !== 0) { + return { code: -1, msg: "请先配置正确的异步回调URL,参考配置文档:https://vkdoc.fsq.pub/vk-uni-pay/config.html" } + } + + // 获取订单信息 + let orderInfo = await vk.baseDao.findById({ + dbName, + id: _id + }); + if (vk.pubfn.isNull(orderInfo)) return { code: -1, msg: "订单不存在" }; + if (orderInfo.status !== 1) return { code: -1, msg: "订单状态错误" }; + if (orderInfo.user_order_success) return { code: -1, msg: "无需重新通知" }; + + // 先将订单的状态改为未支付(重新回调需要) + let updateNum = await vk.baseDao.update({ + dbName, + whereJson: { + _id, + status: 1 + }, + dataJson: { + status: 0, + user_order_success: _.remove() + } + }); + + if (!updateNum) { + return { code: -1, msg: "订单状态错误" }; + } + + let { original_data, out_trade_no } = orderInfo; + try { + // 执行回调 + let requestRes = await vk.request({ + url: `${currentNotifyUrl}${original_data.path}`, + method: "POST", + dataType: "text", + header: original_data.headers, + content: original_data.body + }); + } catch (err) {} + // 再次获取订单信息,判断是否回调成功 + let payOrderInfo = await vk.baseDao.findById({ + dbName, + id: _id + }); + if (payOrderInfo.status === 1) { + // 等待回调全部执行完成,最大等待20秒 + let await_max_time = 20; + if (typeof payOrderInfo.user_order_success == "undefined") { + let whileTime = 0; // 当前循环已执行的时间(毫秒) + let whileInterval = 1000; // 每次循环间隔时间(毫秒) + let maxTime = await_max_time * 1000; // 循环执行时间超过此值则退出循环(毫秒) + while (typeof payOrderInfo.user_order_success == "undefined" && whileTime <= maxTime) { + await vk.pubfn.sleep(whileInterval); + whileTime += whileInterval; + // 查询最新的订单信息 + payOrderInfo = await vk.baseDao.findById({ + dbName, + id: _id + }); + } + } + } + // 还原部分信息(如支付时间不可被重新回调修改) + await vk.baseDao.updateById({ + dbName, + id: _id, + dataJson: { + status: orderInfo.status, + pay_date: orderInfo.pay_date, + original_data: orderInfo.original_data, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +// 获取异步回调配置 +function getNotifyUrl(config, spaceId) { + const payConifg = config["uni-pay"]; + const { notifyUrl } = payConifg; + let currentNotifyUrl = notifyUrl[spaceId]; // 异步回调地址 + // 兼容正式版阿里云与公测版阿里云spaceId开始----------------------------------------------------------- + if (!currentNotifyUrl) { + if (spaceId.indexOf("mp-") === 0) { + currentNotifyUrl = notifyUrl[spaceId.substring(3)]; + } else { + currentNotifyUrl = notifyUrl[`mp-${spaceId}`]; + } + } + // 兼容正式版阿里云与公测版阿里云spaceId结束----------------------------------------------------------- + return currentNotifyUrl; +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js new file mode 100644 index 0000000..d8881f5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/pay-orders/sys/getList.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * vk-pay支付插件支付订单查询 + * @url admin/system_uni/pay-orders/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-pay-orders"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js new file mode 100644 index 0000000..6f061e1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/kh/getList.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/uni-id-files/categories/kh/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-files-categories"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson:{ + + }, + sortArr:[{ name:"_id", type:"asc" }] + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js new file mode 100644 index 0000000..88bd11b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/add.js @@ -0,0 +1,51 @@ +module.exports = { + /** + * 添加 + * @url admin/system_uni/uni-id-files/categories/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} name 分类名称 + * @param {String} description 数据描述 + * @param {Number} sort 排序值 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + name, + description, + sort, + } = data; + // 参数非空检测 + if(vk.pubfn.isNull(name)){ + return { code : -1, msg : '名称不能为空' }; + } + let dbName = "vk-files-categories"; + // 检测key是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + name, + } + }); + if(num > 0){ + return { code : -1, msg : `名称【${name}】不能重复!` }; + } + // 执行数据库API请求 + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + name, + description, + sort + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js new file mode 100644 index 0000000..92305cf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/delete.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/uni-id-files/categories/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '_id不能为空' }; + } + let dbName = "vk-files-categories"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js new file mode 100644 index 0000000..4c4694a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/categories/sys/update.js @@ -0,0 +1,57 @@ +module.exports = { + /** + * 修改 + * @url admin/system_uni/uni-id-files/categories/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} _id id + * @param {String} name 分类名称 + * @param {String} description 数据描述 + * @param {Number} sort 排序值 + * @param {String} parent_id 父id + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + name, + description, + sort + } = data; + // 参数非空检测 + if(vk.pubfn.isNull(name)){ + return { code : -1, msg : '名称不能为空' }; + } + let dbName = "vk-files-categories"; + + // 检测data_id是否已存在 + let num = await vk.baseDao.count({ + dbName, + whereJson:{ + name, + _id : _.neq(_id) + } + }); + if(num > 0){ + return { code : -1, msg : `名称【${name}】不能重复!` }; + } + // 执行数据库API请求 + res.num = await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + name, + description, + sort + } + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js new file mode 100644 index 0000000..d504d39 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/delete.js @@ -0,0 +1,60 @@ +module.exports = { + /** + * 删除 + * @url admin/system_uni/uni-id-files/files/kh/delete 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String,Array} _id id 或id数组 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(_id)) { + return { code: -1, msg: '_id不能为空' }; + } + let whereJson = {}; + let { role = [] } = userInfo; + if (role.indexOf("admin") === -1) { + // 如果不是admin角色用户,则只能删除自己上传的 + whereJson["user_id"] = uid; + } + if (typeof _id === "string") { + // 单条删除 + whereJson["_id"] = _id; + } else if (typeof _id === "object") { + // 批量删除 + whereJson["_id"] = _.in(_id); + } + let selectRes = await vk.baseDao.select({ + dbName: "vk-files", + pageIndex: 1, + pageSize: 500, + getMain: true, + whereJson, + fieldJson: { + file_id: true + } + }); + if (selectRes.length > 0) { + try { + let fileList = vk.pubfn.arrayObjectGetArray(selectRes, "file_id"); + await uniCloud.deleteFile({ fileList }); + } catch (err) {} + // 执行数据库API请求 + res.num = await vk.baseDao.del({ + dbName: "vk-files", + whereJson + }); + } + res.msg = "ok"; + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js new file mode 100644 index 0000000..f92b4da --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/getList.js @@ -0,0 +1,40 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/uni-id-files/files/kh/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-files"; + let whereJson = {}; + let { role = [] } = userInfo; + let { formData = {} } = data; + let { category_id } = formData; + if (category_id == "null") { + whereJson["category_id"] = null; + } + if (role.indexOf("admin") === -1) { + // 如果不是admin角色用户,则只能查看自己上传的 + whereJson["user_id"] = uid; + } + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson + }); + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js new file mode 100644 index 0000000..1bbf96d --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-files/files/kh/update.js @@ -0,0 +1,64 @@ +module.exports = { + /** + * 修改 + * @url admin/system_uni/uni-id-files/files/kh/update 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} display_name 显示在后台的文件名称 + * @param {String} category_id 分类id + * @param {Number} status 0:未审核 1:已审核通过 2:审核不通过 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + display_name, + category_id, + cover_image, + status = 0 + } = data; + // 参数非空检测 + if (vk.pubfn.isNullOne(_id)) { + return { code: -1, msg: '_id不能为空' }; + } + let dbName = "vk-files"; + let whereJson = {}; + let dataJson = { + display_name, + category_id, + cover_image, + status + }; + let { role = [] } = userInfo; + if (role.indexOf("admin") === -1) { + // 如果不是admin角色用户,则只能修改自己上传的 + whereJson["user_id"] = uid; + } + if (typeof _id === "string") { + // 单条操作 + whereJson["_id"] = _id; + } else if (typeof _id === "object") { + // 批量操作 + whereJson["_id"] = _.in(_id); + } + if (category_id == "null" || category_id === "") { + dataJson["category_id"] = _.remove(); + } + + // 执行数据库API请求 + res.num = await vk.baseDao.update({ + dbName: dbName, + whereJson, + dataJson + }); + + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js new file mode 100644 index 0000000..12b2194 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/system_uni/uni-id-log/sys/getList.js @@ -0,0 +1,66 @@ +module.exports = { + /** + * 分页查询 + * @url admin/system_uni/uni-id-log/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { dcloud_appid, appids } = data.formData || {}; + let whereJson = {}; + if (dcloud_appid) { + if (dcloud_appid === "___empty-array___") { + whereJson["dcloud_appid"] = []; + } else if (dcloud_appid === "___error___") { + whereJson["dcloud_appid"] = _.and(_.exists(true), _.nin(appids)); + } else if (dcloud_appid === "___non-existent___") { + whereJson["dcloud_appid"] = _.exists(false); + } else { + whereJson["dcloud_appid"] = _.or(_.eq(dcloud_appid), _.exists(false)); + } + } + let dbName = "uni-id-log"; + res = await vk.baseDao.getTableData({ + dbName, + data, + whereJson, + // 副表列表 + foreignDB: [{ + dbName: "opendb-app-list", + localKey: "dcloud_appid", + foreignKey: "appid", + localKeyType: "array", + as: "appList", + limit: 500 + }, + { + dbName: "uni-id-users", + localKey: "user_id", + foreignKey: "_id", + as: "userInfo", + limit: 1, + fieldJson: { + _id: true, + avatar: true, + nickname: true, + gender: true + } + } + ], + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md b/uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md new file mode 100644 index 0000000..8b29abf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/admin/后台PC管理端.md @@ -0,0 +1,17 @@ +## PC后台admin管理端 +#### `router/service/admin` 目录为后台管理端逻辑 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── admin──────────────────────# 后台管理端逻辑 +│ └── system────────────────# 系统(用户、角色、权限、菜单、应用) +│ └── system_uni────────────# 系统插件 +│ └── user──────────────────# 用户管理 +│ └── order─────────────────# 订单管理 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md b/uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md new file mode 100644 index 0000000..10436c3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/client/小程序、h5、APP客户端.md @@ -0,0 +1,11 @@ +## 客户端(H5、小程序、APP客户端) +#### `router/service/client` 目录为客户端端逻辑 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── client──────────────────────# 客户端逻辑 +│ └── user───────────────────# 用户服务 +│ └── order──────────────────# 订单服务 +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/common/公共逻辑(公共接口).md b/uniCloud-aliyun/cloudfunctions/router/service/common/公共逻辑(公共接口).md new file mode 100644 index 0000000..e69de29 diff --git a/uniCloud-aliyun/cloudfunctions/router/service/muban.js b/uniCloud-aliyun/cloudfunctions/router/service/muban.js new file mode 100644 index 0000000..70d64a2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/muban.js @@ -0,0 +1,35 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url user/pub/test1 前端调用的url参数地址 + * @description 此函数描述 + * @param {Object} data 请求参数 + * @param {String} uniIdToken 用户token + * @param {String} userInfo 当前登录用户信息(可信任,仅kh目录下的函数有此值) + * pub目录下请求参数需要带上 need_user_info = true + * @param {Object} util 公共工具包 + * @param {Object} filterResponse 过滤器返回的数据 + * @param {Object} originalParam 原始请求参数(包含了原始event和context) + * data 请求参数 说明 + * @param {String} uid 当前登录用户id(可信任,仅kh目录下的函数有此值) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 注意: userInfo 和 uid 是可信任的,但默认只有kh目录下的函数才有此值 + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js b/uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js new file mode 100644 index 0000000..0b95150 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/muban_easy.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 此函数名称 + * @url user/pub/test1 前端调用的url参数地址 + * data 请求参数 + * @param {String} params1 参数1 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js new file mode 100644 index 0000000..5d0ad22 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/getAccessToken.js @@ -0,0 +1,21 @@ +'use strict'; +module.exports = { + /** + * 获取accessToken + * @url plugs/baidu/client/pub/getAccessToken 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} image 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式 + * @param {String} url 图片完整URL,URL长度不超过1024字节,URL对应的图片base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式,当image字段存在时url字段失效请注意关闭URL防盗链 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + res.access_token = await vk.openapi.baidu.open.auth.getAccessToken(); + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js new file mode 100644 index 0000000..7076624 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/business_license.js @@ -0,0 +1,29 @@ +'use strict'; +module.exports = { + /** + * 营业执照识别 + * @url plugs/baidu/client/pub/ocr/business_license 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} image 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式 + * @param {String} url 图片完整URL,URL长度不超过1024字节,URL对应的图片base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式,当image字段存在时url字段失效请注意关闭URL防盗链 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + let { image, url } = data; + res = await vk.openapi.baidu.open.request({ + action:"ocr/v1/business_license", + actionVersion: "2.0", + data:{ + image, + url + } + }); + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js new file mode 100644 index 0000000..092bc79 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/baidu/client/pub/ocr/idcard.js @@ -0,0 +1,29 @@ +'use strict'; +module.exports = { + /** + * 身份证识别 + * @url plugs/baidu/client/pub/ocr/idcard 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} image 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式 + * @param {String} url 图片完整URL,URL长度不超过1024字节,URL对应的图片base64编码后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式,当image字段存在时url字段失效请注意关闭URL防盗链 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + let { image, url } = data; + res = await vk.openapi.baidu.open.request({ + action:"ocr/v1/idcard", + actionVersion: "2.0", + data:{ + image, + url + } + }); + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js new file mode 100644 index 0000000..dc8dfe7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/getComponentsDynamicData.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 此函数名称 + * @url plugs/components_dynamic/client/pub/getComponentsDynamicData 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * @params {Array} ids 需要获取的组件数据 id数组 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid, ids } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 根据ids获取组件动态数据列表 + let res_select = await vk.baseDao.select({ + dbName:"vk-components-dynamic", + getCount:false, + pageSize:100, + whereJson:{ + data_id : _.in(ids) + }, + }, event.util); + // 将数组形式 转换成 组件需要的格式 + res.componentsDynamic = {}; + for(let i in res_select.rows){ + let item = res_select.rows[i]; + res.componentsDynamic[item.data_id] = item.data; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js new file mode 100644 index 0000000..c32f528 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/init.js @@ -0,0 +1,138 @@ +module.exports = { + /** + * 初始化数据 + * @url plugs/components_dynamic/client/pub/init 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 承载所有读操作的 promise 的数组 + let dbName = "vk-components-dynamic"; + let data_ids = [ + "vk-test-notice-bar-01", + "vk-test-notice-bar-02", + "vk-test-notice-bar-03", + "vk-test-notice-bar-04", + "vk-test-index-swiper-01", + "vk-test-grid-button-01" + ]; + let whereJson = { + data_id:_.in(data_ids) + }; + res = await vk.baseDao.select({ + dbName:dbName, + getCount:true, + pageIndex:1, + pageSize:100, + whereJson:whereJson + }, event.util); + if(res.rows.length == data_ids.length){ + return res; + } + await vk.baseDao.del({ + dbName:dbName, + whereJson:whereJson + },event.util); + let dataArr = [ + { + "data_id": "vk-test-notice-bar-01", + "data": { + "list": [ + "公告111公告111公告111公告111公告111公告111公告111" + ] + } + }, + { + "data_id": "vk-test-notice-bar-02", + "data": { + "list": [ + "公告222公告222公告222公告222公告222公告222公告222" + ] + } + }, + { + "data_id": "vk-test-notice-bar-03", + "data": { + "list": [ + "公告333333公告333333公告333333公告333333公告333333" + ] + } + }, + { + "data_id": "vk-test-notice-bar-04", + "data": { + "list": [ + "公告44444公告44444公告44444公告44444公告44444公告44444" + ] + } + }, + { + "data_id": "vk-test-index-swiper-01", + "data": { + "list": [ + { + "title": "标题11111111", + "image": "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1594798331539&di=fe544344d765e4f23f90457f02a2d361&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F1%2F58f03bf05fddb.jpg%3Fdown" + }, + { + "title": "标题2222222", + "image": "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1594798658581&di=bcd5486940ad88cf88a904f411c53e94&imgtype=0&src=http%3A%2F%2Fn.sinaimg.cn%2Fsinacn15%2F600%2Fw1920h1080%2F20180505%2Fad66-hacuuvt5802647.jpg" + }, + { + "title": "标题3333333", + "image": "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1594798022306&di=ed613c19ef36df7856b383601acb2f05&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1306%2F17%2Fc1%2F22199754_1371460645988.jpg" + } + ], + "height": 300 + } + }, + { + "data_id": "vk-test-grid-button-01", + "data": { + "col":4, + "icon-size":46, + "text-margin-top":10, + "text-color":"#000000", + "icon-color":"#000000", + "border":false, + "list":[ + { + "icon":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1594798331539&di=fe544344d765e4f23f90457f02a2d361&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F1%2F58f03bf05fddb.jpg%3Fdown", + "text":"按钮1", + "page":"../vk-u-notice-bar/vk-u-notice-bar" + }, + { + "icon":"red-packet", + "text":"按钮2", + "icon-color":"red", + "page":"../vk-u-swiper/vk-u-swiper" + }, + { + "icon":"red-packet", + "text":"按钮3", + "text-color":"red" + }, + { + "icon":"red-packet", + "text":"按钮4" + } + ] + } + } + ]; + await vk.baseDao.adds({ + dbName:dbName, + dataJson:dataArr + },event.util); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js new file mode 100644 index 0000000..80a415b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/components_dynamic/client/pub/update.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 修改数据 + * @url plugs/components_dynamic/client/pub/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid, data_id, data_value } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.num = await vk.baseDao.update({ + dbName:"vk-components-dynamic", + whereJson:{ + data_id : data_id, + }, + dataJson:{ + data : data_value + } + },event.util); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md b/uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md new file mode 100644 index 0000000..35af134 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/plugs/插件.md @@ -0,0 +1,15 @@ +## 插件 +#### `router/service/plugs` +#### 此目录一般为插件作者开发的一些通用功能,如动态数据组件的API将在此目录,未来会新增微信小程序订阅消息发送等等。 + +``` +. +├── plugs──────────────────────# 插件逻辑 +│ └── plugs-A───────────────────# 插件A +│ ────└── admin───────────────────# 插件A admin端 +│ ────└── client──────────────────# 插件A client端 +│ └── plugs-B───────────────────# 插件B +│ ────└── admin───────────────────# 插件B admin端 +│ ────└── client──────────────────# 插件B client端 +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js new file mode 100644 index 0000000..52b1628 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/Promise.all.js @@ -0,0 +1,54 @@ +module.exports = { + /** + * 此函数名称 + * @url template/db_api/user/pub/Promise.all 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-test"; + let runTime1 = new Date().getTime(); + let addNum = 200; + console.log(new Date(runTime1),"开始运行,添加"+addNum+"条数据"); + // 承载所有读操作的 promise 的数组 + let tasks = []; + for(let i = 1; i <= addNum; i++){ + let promise = vk.baseDao.add({ + dbName:dbName, + dataJson:{ + "money": 10.02+i, + "_add_time": 1597456395010+i, + "user_id": "001" + } + }); + tasks.push(promise); + } + // 等待所有 + let ids = []; + try { + res = await Promise.all(tasks).then((values) => { + return { + //ids:values, + total:values.length + }; + }); + } catch (e) { + //console.log("异常:",e,res); + console.log("异常:运行超时"); + res.msg = "运行超时"; + } + let runTime2 = new Date().getTime(); + let runTime = (runTime2 - runTime1) / 1000 + "秒"; + console.log(new Date(runTime2),"运行结束,耗时:"+runTime); + res.runTime = runTime; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js new file mode 100644 index 0000000..5079bd7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/add.js @@ -0,0 +1,36 @@ +module.exports = { + /** + * 添加单条数据 + * @url template/db_api/pub/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 随机定位开始----------------------------------------------------------- + // 为了方便测试,这里固定在杭州市西湖区附近 + let longitude = 120.12792 + Math.floor(Math.random() * 500) / 10000; + let latitude = 30.228932 + Math.floor(Math.random() * 500) / 10000; + // 随机定位结束----------------------------------------------------------- + res.id = await vk.baseDao.add({ + dbName:"vk-test", + dataJson:{ + "money": Math.floor(Math.random() * 9 + 1), + "user_id": "00"+Math.floor(Math.random() * 2 + 1), + "location":new db.Geo.Point(longitude, latitude), + "position":{ + "longitude":longitude, + "latitude":latitude, + }, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js new file mode 100644 index 0000000..d75bbda --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/adds.js @@ -0,0 +1,51 @@ +module.exports = { + /** + * 批量添加数据 + * @url template/db_api/pub/adds 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let dbName = "vk-test"; + let runTime1 = new Date().getTime(); + let addNum = 10; + console.log(new Date(runTime1),"开始运行,添加"+addNum+"条数据"); + // 承载所有读操作的 promise 的数组 + let dataArr = []; + + for(let i = 1; i <= addNum; i++){ + // 随机定位开始----------------------------------------------------------- + // 为了方便测试,这里固定在杭州市西湖区附近 + let longitude = 120.12792 + Math.floor(Math.random() * 500) / 10000; + let latitude = 30.228932 + Math.floor(Math.random() * 500) / 10000; + // 随机定位结束----------------------------------------------------------- + dataArr.push({ + "money": Math.floor(Math.random() * 9 + 1), + "user_id": "00"+Math.floor(Math.random() * 2 + 1), + "location":new db.Geo.Point(longitude, latitude), + "position":{ + "longitude":longitude, + "latitude":latitude, + }, + }); + } + await vk.baseDao.adds({ + dbName:dbName, + dataJson:dataArr + }); + + let runTime2 = new Date().getTime(); + let runTime = ((runTime2 - runTime1) / 1000 + "秒"); + console.log(new Date(runTime2),"运行结束,耗时:"+runTime); + res.runTime = runTime; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js new file mode 100644 index 0000000..83b5637 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/avg.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * avg求平均值 + * @url template/db_api/pub/avg 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.avg = await vk.baseDao.avg({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js new file mode 100644 index 0000000..0d86f1f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/count.js @@ -0,0 +1,28 @@ +module.exports = { + /** + * count求总记录条数 + * @url template/db_api/pub/count 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.num = await vk.baseDao.count({ + dbName:"vk-test", + whereJson:{ + + } + }); + // 对应的sql: + // count * from vk-test + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js new file mode 100644 index 0000000..71ba0db --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/del.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 数据删除 + * @url template/db_api/pub/del 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 这里为了防止误删,故vk.baseDao.del API + * 会判断如果whereJson为空,则不执行删除操作 + * 所以这里加了个_id: _.exists(true)条件来达到删除全部的功能(实际开发时慎用删除全部功能) + */ + res.num = await vk.baseDao.del({ + dbName:"vk-test", + whereJson:{ + _id: _.exists(true) + } + }); + // 对应的sql: + // delete from vk-test where user_id != '___' + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js new file mode 100644 index 0000000..2261b44 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/deleteById.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 数据删除 + * @url template/db_api/pub/del 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id } = data; + res.num = await vk.baseDao.deleteById({ + dbName:"vk-test", + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js new file mode 100644 index 0000000..e8a0ab4 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findById.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 根据id获取记录 + * @url template/db_api/pub/findById 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let startTime = new Date().getTime(); + res.item = await vk.baseDao.findById({ + dbName:"vk-test", + id:data._id, + fieldJson:{ + + } + }); + let endTime = new Date().getTime(); + res.runTime = (endTime - startTime); + // 上面的 fieldJson 可以设置 显示什么字段或设置不显示什么字段 如 money:false 代表不显示money字段 + // 对应的sql: + // select * from vk-test where _id = "5f3a125b3d11c6000106d338" + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js new file mode 100644 index 0000000..16db31c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/findByWhereJson.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 根据where条件获取单条记录(首条) + * @url template/db_api/pub/findByWhereJson 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.item = await vk.baseDao.findByWhereJson({ + dbName:"vk-test", + fieldJson:{ + + }, + whereJson:{ + _id:data._id, + } + }); + // 上面的 fieldJson 可以设置 显示什么字段或设置不显示什么字段 如 money:false 代表不显示money字段 + // 对应的sql: + // select * from vk-test where _id = "5f3a125b3d11c6000106d338" + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js new file mode 100644 index 0000000..f1640de --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/geo.js @@ -0,0 +1,31 @@ +module.exports = { + /** + * 根据地理位置获取列表数据信息 + * @url template/db_api/pub/geo 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.baseDao.selects({ + dbName:"vk-test", + pageIndex:1, + pageSize:100, + whereJson:{ + location: _.geoNear({ + geometry: new db.Geo.Point(120.12792, 30.228932), // 点的地理位置,为了方便测试,这里固定在杭州市西湖区 + maxDistance: 4000, // 选填,最大距离,米为单位 + minDistance: 0 // 选填,最小距离,米为单位 + }) + }, + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js new file mode 100644 index 0000000..d9af7a6 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/getList.js @@ -0,0 +1,73 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url template/db_api/pub/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} tableName 表名 + * @params {String} addTime 搜索开始时间 + * @params {String} endTime 搜索截止时间 + * @params {String} searchvalue 搜索指定内容 + * @params {Number} pageIndex 当前页码 + * @params {Number} pageSize 每页显示数量 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { pageIndex, pageSize, searchvalue, timeArr = [], addTimeLong, endTimeLong, sortRule } = data; + let dbName = "vk-test"; + let fieldJson = {}; + let whereJson = {}; + let sortArr = []; + // 排序规则开始----------------------------------------------------------- + sortArr.push({ + "name":"_add_time", + "type":"desc" + }); + if(sortRule) sortArr = sortRule; + // 排序规则结束----------------------------------------------------------- + // 查询条件开始----------------------------------------------------------- + if(searchvalue){ + // 查询searchvalue开头的数据 + try{ + // 如果查询需要用到正则,建议将正则用try catch 包起来。 + //whereJson["title"] = new RegExp('^'+searchvalue); + whereJson["money"] = Number(searchvalue); + }catch(err){ + return { code : -1, msg : '请输入合法的查询内容' }; + } + } + if(timeArr.length >=2 ){ + addTimeLong = timeArr[0]; + endTimeLong = timeArr[1]; + } + if(addTimeLong && endTimeLong){ + whereJson["_add_time"] = _.gte(addTimeLong).lte(endTimeLong); + }else if(addTimeLong && !endTimeLong){ + whereJson["_add_time"] = _.gte(addTimeLong); + }else if(!addTimeLong && endTimeLong){ + whereJson["_add_time"] = _.lte(endTimeLong); + } + // 这里可以写必须满足的查询条件,如whereJson["user_id"] = uid;代表只查自己的记录 + // whereJson["user_id"] = uid; + // 查询条件结束----------------------------------------------------------- + res = await vk.baseDao.select({ + dbName:dbName, + getCount:true, + pageIndex:pageIndex, + pageSize:pageSize, + fieldJson:fieldJson, + whereJson:whereJson, + sortArr:sortArr + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js new file mode 100644 index 0000000..258ea04 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/groupCount.js @@ -0,0 +1,38 @@ +module.exports = { + /** + * 分组求count + * @url template/db_api/pub/groupCount 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + res = await vk.baseDao.selects({ + dbName: "vk-test", + pageIndex: 1, + pageSize: 10, + // 主表where条件 + whereJson: { + + }, + groupJson: { + _id: "$money", // _id是分组id, $ 后面接字段名,如按money字段进行分组 + count: _.$.addToSet("$user_id"), // $ 后面接字段名,如把user_id原样输出(去重) + }, + sortArr: [{ name: "money",type: "desc" }], // 对分组后的结果进行排序 + addFields:{ + count: _.$.size("$count") + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js new file mode 100644 index 0000000..095865b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/max.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * max求最大值 + * @url template/db_api/pub/max 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.max = await vk.baseDao.max({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js new file mode 100644 index 0000000..14152d3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/min.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * min求最小值 + * @url template/db_api/pub/min 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.min = await vk.baseDao.min({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js new file mode 100644 index 0000000..ba8fa80 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sample.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * sample随机获取N条数据 + * @url template/db_api/pub/sample 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.list = await vk.baseDao.sample({ + dbName:"vk-test", + size:1, + whereJson:{ + + }, + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js new file mode 100644 index 0000000..89c052b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 查询多条记录 + * @url template/db_api/pub/select 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.baseDao.select({ + dbName: "vk-test", + getCount: true, + pageIndex: 1, + pageSize: 10, + whereJson: { + + } + }); + // 对应的sql: + // select * from vk-test limit 0,100; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js new file mode 100644 index 0000000..e0b47f0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/select2.js @@ -0,0 +1,50 @@ +module.exports = { + /** + * 连表查询(仅限两表查询)(VK版本) + * @url template/db_api/pub/select2 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 想要两表以上的连接,请使用vk.baseDao.selects + res = await vk.baseDao.selects({ + dbName:"uni-id-users", + foreignKey:"_id", + getCount:false, + pageIndex:1, + pageSize:10, + // 主表where条件 + whereJson:{ + + }, + // 主表字段显示规则 + fieldJson:{token:false, password:false}, + // 主表排序规则 + sortArr:[{"name":"_id", "type":"desc"}], + // 副表列表 + foreignDB:[ + { + dbName:"vk-test", + foreignKey:"user_id", + as:"testList", + limit:1, + // 副表where条件 + whereJson:{ }, + // 副表字段显示规则 + fieldJson:{ }, + // 副表排序规则 + sortArr:[{"name":"money", "type":"desc"}], + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js new file mode 100644 index 0000000..028bb22 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects.js @@ -0,0 +1,51 @@ +module.exports = { + /** + * 多表查询(支持多张表连接查询)(VK版本) + * @url template/db_api/pub/selects 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 演示3表连接 + res = await vk.baseDao.selects({ + dbName:"uni-id-users", + getCount:false, + pageIndex:1, + pageSize:10, + // 主表where条件 + whereJson:{ + + }, + // 主表字段显示规则 + fieldJson:{ token:false, password:false }, + // 主表排序规则 + sortArr:[{ "name":"_id", "type":"desc" }], + // 副表列表 + foreignDB:[ + { + dbName:"vk-test", + localKey:"_id", + foreignKey:"user_id", + as:"testList", + limit:1 + }, + { + dbName:"gy-shop", + localKey:"_id", + foreignKey:"user_id", + as:"shopList", + limit:1 + }, + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js new file mode 100644 index 0000000..6a9bf76 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_geo.js @@ -0,0 +1,47 @@ +module.exports = { + /** + * 连表查询地理位置就近搜索示例 + * @url template/db_api/pub/selects_geo 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 演示3表连接 + res = await vk.baseDao.selects({ + dbName:"vk-test", + getCount:true, + pageIndex:1, + pageSize:10, + // 主表where条件 + whereJson:{ + location: _.geoNear({ + geometry: new db.Geo.Point(120.12792, 30.228932), // 点的地理位置,为了方便测试,这里固定在杭州市西湖区 + maxDistance: 4000, // 选填,最大距离,米为单位 + minDistance: 0 , // 选填,最小距离,米为单位 + distanceMultiplier:1, // 返回时在距离上乘以该数字 1代表米 100 代表厘米 0.001 代表千米 + distanceField:"distance", // 输出的每个记录中 distance 即是与给定点的距离 + }), + money:_.gt(0) + }, + // 副表列表 + foreignDB:[ + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"userInfo", + limit:1 + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js new file mode 100644 index 0000000..033b6a3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_getOne.js @@ -0,0 +1,48 @@ +module.exports = { + /** + * 连表查询,并返回第一条数据 + * @url template/db_api/pub/selects_getOne 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 演示3表连接 + res.info = await vk.baseDao.selects({ + dbName:"uni-id-users", + getOne:true, + getMain:true, + // 主表where条件 + whereJson:{ + _id:"001" + }, + // 主表字段显示规则 + fieldJson:{ token:false, password:false }, + // 副表列表 + foreignDB:[ + { + dbName:"vk-test", + localKey:"_id", + foreignKey:"user_id", + as:"testList", + limit:1 + }, + { + dbName:"gy-shop", + localKey:"_id", + foreignKey:"user_id", + as:"shopList", + limit:1 + }, + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js new file mode 100644 index 0000000..6809d77 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_2.js @@ -0,0 +1,43 @@ +module.exports = { + /** + * 多表查询(支持多张表连接查询)(VK2.0版本) + * @url template/db_api/pub/selects_mode_2 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 此为简化版 + * 此版本支持无限张表和主表进行连接 + */ + res = await vk.baseDao.selects({ + dbName:"opendb-mall-comments", + // 副表列表 + foreignDB:[ + { + dbName:"opendb-mall-goods", + localKey:"goods_id", + foreignKey:"_id", + as:"goodsInfo", + limit:1 + }, + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"userInfo", + limit:1 + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js new file mode 100644 index 0000000..b5e4459 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/selects_mode_3.js @@ -0,0 +1,44 @@ +module.exports = { + /** + * 多表查询(支持多张表连接查询)(VK3.0版本) + * @url template/db_api/pub/selects_mode_3 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + /** + * 此为演示竖向无限层连接 + */ + res = await vk.baseDao.selects({ + dbName:"opendb-mall-comments", + // 副表列表 + foreignDB:[ + { + dbName:"uni-id-users", + localKey:"user_id", + foreignKey:"_id", + as:"userInfo", + limit:1, + foreignDB:[ + { + dbName:"opendb-mall-orders", + localKey:"_id", + foreignKey:"user_id", + as:"orderList", + limit:3, + }, + ] + } + ] + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js new file mode 100644 index 0000000..5024dcf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/sum.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * sum求和 + * @url template/db_api/pub/sum 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res.sum = await vk.baseDao.sum({ + dbName:"vk-test", + fieldName:"money", + whereJson:{ + + } + }); + // 对应的sql: + // select sum(money) from vk-test + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js new file mode 100644 index 0000000..123032b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/update.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 修改数据 + * @url template/db_api/pub/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + res.num = await vk.baseDao.update({ + dbName:"vk-test", + whereJson:{ + _id:_id, + }, + dataJson:{ + money:1 + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js new file mode 100644 index 0000000..83d31be --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateAndReturn.js @@ -0,0 +1,63 @@ +module.exports = { + /** + * 修改数据,并返回修改后的数据 + * @url template/db_api/pub/updateAndReturn 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + + // 非事务版本开始----------------------------------------------------------- + res.info = await vk.baseDao.updateAndReturn({ + dbName: "vk-test", + whereJson: { + _id: _id + }, + dataJson: { + money: _.inc(1) + }, + }); + // 非事务版本结束----------------------------------------------------------- + + + // 事务版本开始----------------------------------------------------------- + /* + const transaction = await vk.baseDao.startTransaction(); + try { + res.info = await vk.baseDao.updateAndReturn({ + db:transaction, + dbName:"vk-test", + whereJson:{ + _id:_id + }, + dataJson:{ + money:_.inc(1) + }, + }); + // 提交事物 + await transaction.commit(); + console.log(`transaction succeeded`); + return res; + }catch (err) { + // 事务回滚 + return await vk.baseDao.rollbackTransaction({ + db:transaction, + err + }); + } + */ + // 事务版本结束----------------------------------------------------------- + + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js new file mode 100644 index 0000000..12b83ff --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/pub/updateById.js @@ -0,0 +1,29 @@ +module.exports = { + /** + * 修改数据,并返回修改后的数据 + * @url template/db_api/pub/updateById 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { _id = "___" } = data; + res.info = await vk.baseDao.updateById({ + dbName:"vk-test", + id:_id, + dataJson:{ + money:1 + }, + getUpdateData:true + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js new file mode 100644 index 0000000..d00f14f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/add.js @@ -0,0 +1,33 @@ +module.exports = { + /** + * 添加单条数据 + * @url template/db_api/sys/add 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + user_id, + money, + remark, + } = data; + let dbName = "vk-test"; + res.id = await vk.baseDao.add({ + dbName, + dataJson:{ + user_id, + money, + remark, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js new file mode 100644 index 0000000..12ea03b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/delete.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 数据删除 + * @url template/db_api/sys/delete 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + // 这里id不传默认设置成"___" 是为了防止因未传_id导致误删所有数据. + let { _id } = data; + if(vk.pubfn.isNull(_id)){ + return { code : -1, msg : 'id不能为空' }; + } + let dbName = "vk-test"; + await vk.baseDao.deleteById({ + dbName, + id:_id + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js new file mode 100644 index 0000000..aadac87 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/getList.js @@ -0,0 +1,30 @@ +module.exports = { + /** + * 查询多条记录 分页 + * @url template/db_api/sys/getList 前端调用的url参数地址 + * data 请求参数 说明 + * @params {Number} pageIndex 当前页码 + * @params {Number} pageSize 每页显示数量 + * @params {Array} sortRule 排序规则 + * @params {object} formData 查询条件数据源 + * @params {Array} columns 查询条件规则 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "vk-test"; + res = await vk.baseDao.getTableData({ + dbName, + data + }); + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js new file mode 100644 index 0000000..67c922e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/db_api/sys/update.js @@ -0,0 +1,39 @@ +module.exports = { + /** + * 修改数据 + * @url template/db_api/sys/update 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + _id, + user_id, + money, + remark, + } = data; + if(vk.pubfn.isNullOne(_id)){ + return { code : -1, msg : '参数错误' }; + } + let dbName = "vk-test"; + await vk.baseDao.updateById({ + dbName, + id:_id, + dataJson:{ + user_id, + money, + remark, + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js new file mode 100644 index 0000000..d1e8b63 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/imgSecCheck.js @@ -0,0 +1,39 @@ +'use strict'; +module.exports = { + /** + * 图片违规检测示例 + * @url template/openapi/qq/pub/imgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { base64 } = data; + /** + * 实际开发中,图片可能是多张图,比如多达9张图 + * 如果在一个请求中循环检测,可能会超时。 + * 方案1:前端选择完图片就自动一张一张检测和上传(即9张图会有9个请求) + * 方案2:使用Promise.all + * 特别注意:目前微信小程序的这个API有1M大小的限制。(此为微信官方限制) + */ + let imgSecCheckRes = await vk.openapi.qq.security.imgSecCheck({ + base64 + }); + if(imgSecCheckRes.code !== 0){ + // 未通过检测 + return imgSecCheckRes; + } + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js new file mode 100644 index 0000000..125eeab --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/qq/pub/msgSecCheck.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 文本违规检测示例 + * @url template/openapi/qq/pub/msgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + content, + } = data; + // 实际业务中,content可能是评论的内容等 + let msgSecCheckRes = await vk.openapi.qq.security.msgSecCheck({ + content, + }); + if (msgSecCheckRes.code !== 0) { + // 未通过检测 + return msgSecCheckRes; + } + res.result = msgSecCheckRes; + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js new file mode 100644 index 0000000..9e3da7f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/getTemplateList.js @@ -0,0 +1,27 @@ +'use strict'; +module.exports = { + /** + * 获取模板列表 + * @url template/openapi/weixin/pub/getTemplateList 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.request({ + method: "get", + url: "wxaapi/newtmpl/gettemplate", + data: { + + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js new file mode 100644 index 0000000..a3f1e44 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/imgSecCheck.js @@ -0,0 +1,39 @@ +'use strict'; +module.exports = { + /** + * 图片违规检测示例 + * @url template/openapi/weixin/pub/imgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { base64 } = data; + /** + * 实际开发中,图片可能是多张图,比如多达9张图 + * 如果在一个请求中循环检测,可能会超时。 + * 方案1:前端选择完图片就自动一张一张检测和上传(即9张图会有9个请求) + * 方案2:使用Promise.all + * 特别注意:目前微信小程序的这个API有1M大小的限制。(此为微信官方限制) + */ + let imgSecCheckRes = await vk.openapi.weixin.security.imgSecCheck({ + base64 + }); + if(imgSecCheckRes.code !== 0){ + // 未通过检测 + return imgSecCheckRes; + } + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js new file mode 100644 index 0000000..c314c80 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/msgSecCheck.js @@ -0,0 +1,48 @@ +'use strict'; +module.exports = { + /** + * 文本违规检测示例 + * @url template/openapi/weixin/pub/msgSecCheck 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { + content, + version, + scene, + openid, + title, + nickname, + signature, + } = data; + // 实际业务中,content可能是评论的内容等 + let msgSecCheckRes = await vk.openapi.weixin.security.msgSecCheck({ + content, + version, + scene, + openid, + title, + nickname, + signature, + }); + if (msgSecCheckRes.code !== 0) { + // 未通过检测 + return msgSecCheckRes; + } + res.result = msgSecCheckRes; + // 若通过检测,则继续执行自己的业务 + // ... + // ... + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js new file mode 100644 index 0000000..dfcc9fd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendMessage.js @@ -0,0 +1,45 @@ +'use strict'; +module.exports = { + /** + * 发送订阅消息 + * @url template/openapi/weixin/pub/sendMessage 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { openid } = data; + res = await vk.openapi.weixin.subscribeMessage.send({ + touser : openid, // 接收者(用户)的 openid + template_id : "UmINo5I6IcqktIwNt2TVorkU7f4dzd4eyNjfvOiwEC0", // 所需下发的订阅模板id + page : "pages/index/index", // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + data : { + character_string1:{ + value:"202008030930001" + }, + name2:{ + value:"中通快递" + }, + character_string3:{ + value:"ZT2019928321392931" + }, + thing6:{ + value:"雪花秀滋盈生人生焕颜精华露" + }, + thing8:{ + value:"杭州市xxxxxxxxx号" + } + }, + miniprogram_state : "formal", // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 + }); + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js new file mode 100644 index 0000000..a0c179a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendTemplateMessage.js @@ -0,0 +1,59 @@ +'use strict'; +module.exports = { + /** + * 发送公众号模板消息(touser只能是用户在该公众号下的openid) + * @url template/openapi/weixin/pub/sendTemplateMessage 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.h5.templateMessage.send({ + touser: "", // 接收者(用户)的 openid(该用户在公众号下的openid) + template_id: "", // 所需下发的订阅模板id + url: "https://www.baidu.com", // 跳转网页时填写(如填了miniprogram参数则忽略url参数) + miniprogram: { + appid: "", + pagepath: "pages/order/order?id=aaa" + }, + data: { + "first": { + "value": "您购买的订单已经发货啦,正快马加鞭向您飞奔而去。", + "color": "#173177" + }, + "keyword1": { + "value": "D201803111235825", + "color": "#173177" + }, + "keyword2": { + "value": "2018-03-11 19:56", + "color": "#173177" + }, + "keyword3": { + "value": "顺丰快递", + "color": "#173177" + }, + "keyword4": { + "value": "980456952123", + "color": "#173177" + }, + "keyword5": { + "value": "王先生 135xxxxxxxx 广东省深圳市龙华区建设东路", + "color": "#173177" + }, + "remark": { + "value": "欢迎再次购买!", + "color": "#173177" + } + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js new file mode 100644 index 0000000..e3bedfb --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/openapi/weixin/pub/sendUniformMessage.js @@ -0,0 +1,59 @@ +'use strict'; +module.exports = { + /** + * 发送公众号模板消息(touser可以是小程序下的openid,也可以是公众号下的openid) + * @url template/openapi/weixin/pub/sendTemplateMessage 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { config, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.uniformMessage.send({ + touser: "", // 接收者(用户)的 openid(可以是小程序下的openid,也可以是公众号下的openid) + template_id: "", // 所需下发的订阅模板id + url: "https://www.baidu.com", // 跳转网页时填写(如填了miniprogram参数则忽略url参数) + miniprogram: { + appid: "", + pagepath: "pages/order/order?id=aaa" + }, + data: { + "first": { + "value": "您购买的订单已经发货啦,正快马加鞭向您飞奔而去。", + "color": "#173177" + }, + "keyword1": { + "value": "D201803111235825", + "color": "#173177" + }, + "keyword2": { + "value": "2018-03-11 19:56", + "color": "#173177" + }, + "keyword3": { + "value": "顺丰快递", + "color": "#173177" + }, + "keyword4": { + "value": "980456952123", + "color": "#173177" + }, + "keyword5": { + "value": "王先生 135xxxxxxxx 广东省深圳市龙华区建设东路", + "color": "#173177" + }, + "remark": { + "value": "欢迎再次购买!", + "color": "#173177" + } + } + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js new file mode 100644 index 0000000..c78de33 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/addition.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 此函数名称 + * @url template/test/pub/addition 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { num1 , num2 } = data; + if(!num1 || !num2){ + return { + code : -1, + msg : "参数不能为空!" + } + } + num1 = parseFloat(num1); + num2 = parseFloat(num2); + res.value = parseFloat((num1 + num2).toFixed(2)); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js new file mode 100644 index 0000000..deec7d7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/findGoodsInfo.js @@ -0,0 +1,202 @@ +module.exports = { + /** + * 此函数名称 + * @url template/test/pub/findGoodsInfo 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let { goods_id } = data; + /** + * 这里本来是需要从数据库中获取的,这里简化一下,直接返回数据了 + * 正常业务中,是需要连表查询的,分别是订单表和SKU表 双表连接查询出最终返回给前端的数据 + */ + let goodsDB = [ + { + "_id":"001", + "name": "iphone11", + "goods_thumb":"https://img14.360buyimg.com/n0/jfs/t1/59022/28/10293/141808/5d78088fEf6e7862d/68836f52ffaaad96.jpg", + "sku_list": [ + { + "_id": "001", + "goods_id": "001", + "goods_name": "iphone11", + "image": "https://img14.360buyimg.com/n0/jfs/t1/79668/22/9987/159271/5d780915Ebf9bf3f4/6a1b2703a9ed8737.jpg", + "price": 19800, + "sku_name": "红色,128G,公开版", + "sku_name_arr": ["红色", "128G", "公开版"], + "stock": 100 + }, + { + "_id": "002", + "goods_id": "001", + "goods_name": "iphone11", + "image": "https://img14.360buyimg.com/n0/jfs/t1/52252/35/10516/124064/5d7808e0E46202391/7100f3733a1c1f00.jpg", + "price": 9800, + "sku_name": "白色,256G,公开版", + "sku_name_arr": ["白色", "256G","公开版"], + "stock": 100 + }, + { + "_id": "003", + "goods_id": "001", + "goods_name": "iphone11", + "image": "https://img14.360buyimg.com/n0/jfs/t1/79668/22/9987/159271/5d780915Ebf9bf3f4/6a1b2703a9ed8737.jpg", + "price": 19800, + "sku_name": "红色,256G,公开版", + "sku_name_arr": ["红色","256G","公开版"], + "stock": 100 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "红色" + }, + { + "name": "黑色" + }, + { + "name": "白色" + } + ], + "name": "颜色" + }, + { + "list": [ + { + "name": "128G" + }, + { + "name": "256G" + } + ], + "name": "内存" + }, + { + "list": [ + { + "name": "公开版" + }, + { + "name": "非公开版" + } + ], + "name": "版本" + } + ] + }, + { + "_id":"002", + "name": "迪奥香水", + "goods_thumb":"https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "sku_list": [ + { + "_id": "004", + "goods_id": "002", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 19800, + "sku_name": "50ml/瓶", + "sku_name_arr": ["50ml/瓶"], + "stock": 100 + }, + { + "_id": "005", + "goods_id": "002", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 9800, + "sku_name": "70ml/瓶", + "sku_name_arr": ["70ml/瓶"], + "stock": 100 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "20ml/瓶" + }, + { + "name": "50ml/瓶" + }, + { + "name": "70ml/瓶" + } + ], + "name": "规格" + } + ] + }, + { + "_id":"003", + "name": "迪奥香水", + "goods_thumb":"https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "sku_list": [ + { + "_id": "006", + "goods_id": "003", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 19800, + "sku_name": "默认", + "sku_name_arr": ["默认"], + "stock": 100 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "默认" + } + ], + "name": "默认" + } + ] + }, + { + "_id":"004", + "name": "迪奥香水", + "goods_thumb":"https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "sku_list": [ + { + "_id": "006", + "goods_id": "003", + "goods_name": "迪奥香水", + "image": "https://res.lancome.com.cn/resources/2020/9/11/15998112890781924_920X920.jpg?version=20200917220352530", + "price": 19800, + "sku_name": "默认", + "sku_name_arr": ["默认"], + "stock": 0 + } + ], + "spec_list": [ + { + "list": [ + { + "name": "默认" + } + ], + "name": "默认" + } + ] + } + ]; + res.goodsInfo = vk.pubfn.getListItem(goodsDB, "_id",goods_id); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js new file mode 100644 index 0000000..ab674b1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/pub/temporaryCache.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 临时数据缓存 + * @url template/test/pub/getTemporaryCache 前端调用的url参数地址 + * data 请求参数 说明 + * @params {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + let { key, value, second, mode } = data; + if(mode == "get"){ + res.value = vk.temporaryCache.get(key); + }else if(mode == "set"){ + res.value = vk.temporaryCache.set(key, value, second); + }else if(mode == "del"){ + res.value = vk.temporaryCache.del(key); + }else if(mode == "clear"){ + res.value = vk.temporaryCache.clear(); + }else if(mode == "isExpired"){ + res.value = vk.temporaryCache.isExpired(key); + }else if(mode == "getAll"){ + res.value = vk.temporaryCache.getAll(); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/test/sys/test.js b/uniCloud-aliyun/cloudfunctions/router/service/template/test/sys/test.js new file mode 100644 index 0000000..0fec407 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/test/sys/test.js @@ -0,0 +1,20 @@ +module.exports = { + /** + * 此函数名称 + * @url template/test/sys/test 前端调用的url参数地址 + * data 请求参数 说明 + * res 返回参数说明 + * @params {Number} code 错误码,0表示成功 + * @params {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + res.msg = "ok"; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md b/uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md new file mode 100644 index 0000000..ccf1649 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/template/云函数示例模板.md @@ -0,0 +1,11 @@ +## 云函数示例模板 +#### `router/service/template` +#### 此目录一般为插件作者给开发者提供的云函数写法示例,如数据库API的使用等等。 + +``` +. +├── template──────────────────────# 云函数模板 +│ └── db_api───────────────────# 数据库API调用示例 +│ └── test─────────────────────# 普通云函数调用示例 +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js new file mode 100644 index 0000000..6950698 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/acceptInvite.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 用户接受邀请 + * @url user/kh/acceptInvite 前端调用的url参数地址 + * @description 此接口用于在注册之后再填写邀请码的场景,多数情况下不会用到此接口而是在注册时填写邀请码 + * data 请求参数 说明 + * @param {String} inviteCode 邀请人的邀请码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID } = util; + let { uid, inviteCode = "" } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + res = await uniID.acceptInvite({ + uid:uid, + inviteCode:inviteCode + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js new file mode 100644 index 0000000..d65cd7b --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/addUploadRecord.js @@ -0,0 +1,75 @@ +module.exports = { + /** + * 添加文件上传记录 + * @url user/kh/addUploadRecord 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} url 文件外网访问url + * @param {String} name 文件名 + * @param {Number} size 文件大小 + * @param {String} file_id 文件id + * @param {String} provider 供应商 + * @param {String} category_id 分类ID + * @param {Number} width 图片\视频的宽度 + * @param {Number} height 图片\视频的高度 + * @param {Number} orientation 图片\视频的旋转方向 + * @param {Number} duration 视频的总时长 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + url, + name: original_name, + size, + provider, + file_id, + category_id, + width, + height, + orientation, + duration + } = data; + let type = "other"; + + if (vk.pubfn.test(url, "image")) { + type = "image"; + } else if (vk.pubfn.test(url, "video")) { + type = "video"; + } else if (vk.pubfn.test(url, "audio")) { + type = "video"; // 这里audio也分类为video + } + + if (vk.pubfn.isNull(original_name)) original_name = url; + let dataJson = { + user_id: uid, + sort: 0, + status: 0, + type, + url, + display_name: original_name, + original_name, + size, + file_id, + provider, + width, + height, + orientation, + duration + }; + if (vk.pubfn.isNotNull(category_id)) { + dataJson["category_id"] = category_id; + } + await vk.baseDao.add({ + dbName: "vk-files", + dataJson + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js new file mode 100644 index 0000000..d45e4be --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindAlipay.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 绑定支付宝 + * @url user/kh/bindAlipay 前端调用的url参数地址 + * @description 将当前登录用户绑定支付宝 + * data 请求参数 说明 + * @param {String} code 支付宝登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 绑定 + res = await uniID.bindAlipay(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js new file mode 100644 index 0000000..2840e23 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindEmail.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 绑定邮箱 + * @url user/kh/bindEmail 前端调用的url参数地址 + * @description 将当前登录用户绑定邮箱 + * data 请求参数 说明 + * @param {String} email 用户邮箱 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if (!data.code) return { code: -1, msg: "验证码不能为空!" } + // 绑定邮箱 + res = await uniID.bindEmail(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js new file mode 100644 index 0000000..06af23a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindMobile.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 绑定手机号 + * @url user/kh/bindMobile 前端调用的url参数地址 + * @description 将当前登录用户绑定手机号 + * data 请求参数 说明 + * @param {String} mobile 用户手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if (!data.code) return { code: -1, msg: "验证码不能为空!" } + // 绑定手机号 + res = await uniID.bindMobile(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js new file mode 100644 index 0000000..e726fc7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewEmail.js @@ -0,0 +1,72 @@ +module.exports = { + /** + * 换绑新的邮箱 + * @url user/kh/bindNewEmail 前端调用的url参数地址 + * @description 将当前登录用户换绑新的邮箱 + * data 请求参数 说明 + * @param {String} oldEmail 旧邮箱码 + * @param {String} oldEmailCode 旧邮箱收到的验证码 + * @param {String} email 新邮箱码 + * @param {String} code 新邮箱收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + oldEmail, // 旧邮箱码 + oldEmailCode, // 旧邮箱收到的验证码 + email, // 新邮箱码 + code, // 新邮箱收到的验证码 + } = data; + if (!code || !oldEmailCode) return { code: -1, msg: "验证码不能为空!" }; + if (!email || !oldEmail) return { code: -1, msg: "邮箱不能为空!" }; + // 先检查下旧邮箱码和验证码是否正确 + let verifyCodeRes; + verifyCodeRes = await uniID.verifyCode({ + email: oldEmail, + code: oldEmailCode, + type: 'unbind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `旧邮箱${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 先检查下新邮箱码和验证码是否正确 + verifyCodeRes = await uniID.verifyCode({ + email, + code: code, + type: 'bind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `新邮箱${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 解绑邮箱 + let unbindEmailRes = await uniID.unbindEmail({ + uid, + email: oldEmail + }); + if (unbindEmailRes.code !== 0) { + return unbindEmailRes; + } + await uniID.setVerifyCode({ code, email, type: "bind" }); + // 绑定新邮箱 + res = await uniID.bindEmail({ + uid, + email, + code + }); + if (res.code !== 0) { + return res; + } + res.msg = "换绑邮箱成功!"; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js new file mode 100644 index 0000000..ee256c0 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindNewMobile.js @@ -0,0 +1,70 @@ +module.exports = { + /** + * 换绑新的手机号 + * @url user/kh/bindNewMobile 前端调用的url参数地址 + * @description 将当前登录用户换绑新的手机号 + * data 请求参数 说明 + * @param {String} oldMobile 旧手机号码 + * @param {String} oldMobileCode 旧手机收到的验证码 + * @param {String} mobile 新手机号码 + * @param {String} code 新手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + oldMobile, // 旧手机号码 + oldMobileCode, // 旧手机收到的验证码 + mobile, // 新手机号码 + code, // 新手机收到的验证码 + } = data; + if (!code || !oldMobileCode) return { code: -1, msg: "验证码不能为空!" }; + if (!mobile || !oldMobile) return { code: -1, msg: "手机号不能为空!" }; + // 先检查下旧手机号码和验证码是否正确 + let verifyCodeRes; + verifyCodeRes = await uniID.verifyCode({ + mobile: oldMobile, + code: oldMobileCode, + type: 'unbind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `旧手机${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 先检查下新手机号码和验证码是否正确 + verifyCodeRes = await uniID.verifyCode({ + mobile, + code: code, + type: 'bind' + }); + if (verifyCodeRes.code !== 0) { + verifyCodeRes.msg = `新手机${verifyCodeRes.msg}` + return verifyCodeRes; + } + // 解绑手机号 + let unbindMobileRes = await uniID.unbindMobile({ + uid, + mobile: oldMobile + }); + if (unbindMobileRes.code !== 0) { + return unbindMobileRes; + } + // 绑定新手机号 + res = await uniID.bindMobile({ + uid, + mobile + }); + if (res.code !== 0) { + return res; + } + res.msg = "换绑手机号成功!"; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js new file mode 100644 index 0000000..e2b25fa --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindQQ.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 绑定QQ + * @url user/kh/bindQQ 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} code QQ登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 绑定 + res = await uniID.bindQQ(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js new file mode 100644 index 0000000..555edc5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/bindWeixin.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 绑定微信 + * @url user/kh/bindWeixin 前端调用的url参数地址 + * @description 将当前登录用户绑定微信 + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 绑定 + res = await uniID.bindWeixin(event.data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js new file mode 100644 index 0000000..24f2933 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getAlipayMiniCode.js @@ -0,0 +1,25 @@ +'use strict'; +module.exports = { + /** + * 获取支付宝小程序码 + * @url user/kh/getAlipayMiniCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {String} scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + page, + scene + } = data; + res = await vk.openapi.alipay.acode.getMiniCode(data); + res.base64 = res.qr_code_url_circle_blue; // 兼容其他小程序的返回字段 + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js new file mode 100644 index 0000000..053534a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getInvitedUser.js @@ -0,0 +1,34 @@ +module.exports = { + /** + * 获取接受邀请的用户清单 + * @url user/kh/getInvitedUser 前端调用的url参数地址 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + let dbName = "uni-id-users"; + let index = 0; + res = await vk.baseDao.getTableData({ + dbName, + data, + fieldJson:{ token:false, password:false }, + whereJson:{ + ['inviter_uid.' + index]:uid + } + }); + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js new file mode 100644 index 0000000..cc4c368 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMenu.js @@ -0,0 +1,30 @@ +'use strict'; +module.exports = { + /** + * 获取我拥有的菜单列表 + * @url user/kh/getMenu 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + role = [], + } = userInfo; + // 根据角色获取菜单 + res = await vk.system.sysDao.listMenuByRole({ + role, + treeProps:{ + level: 3 + } + }); + res.userInfo = userInfo; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js new file mode 100644 index 0000000..1480d07 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getMyUserInfo.js @@ -0,0 +1,16 @@ +module.exports = { + /** + * 获取我的用户信息 + * @url user/kh/getMyUserInfo 前端调用的url参数地址 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + res.userInfo = userInfo; + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js new file mode 100644 index 0000000..e13044f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getQQMiniCode.js @@ -0,0 +1,45 @@ +'use strict'; +module.exports = { + /** + * 获取qq小程序码 + * @url user/kh/getQQMiniCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} path 小程序页面路径 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + // 业务逻辑开始----------------------------------------------------------- + let { + path + } = data; + + res = await vk.openapi.qq.acode.getMiniCode(data); + if (typeof res === "object" && res.code) { + return res; + } + try { + // 二进制转base64 + let base64 = Buffer.from(res, 'binary').toString('base64'); + return { + code: 0, + base64: `data:image/png;base64,${base64}` + }; + } catch (err) { + // 转base64失败 + return { + code: -1, + msg: "生成小程序码失败", + err: { + message: err.message, + stack: err.stack + } + }; + } + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js new file mode 100644 index 0000000..f2357a3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPqrcode.js @@ -0,0 +1,57 @@ +'use strict'; +module.exports = { + /** + * 获取小程序码 + * @url user/kh/getWeixinMPqrcode 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} scene 自定义参数最大32个可见字符 只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {boolean} check_path 默认是true,检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用。 + * @param {String} env_version 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + * @param {number} width 二维码的宽度,单位 px,最小 280px,最大 1280px + * @param {boolean} auto_color 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false + * @param {Object} line_color auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 + * @param {boolean} is_hyaline 是否需要透明底色,为 true 时,生成透明底色的小程序 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { my_invite_code } = userInfo; + if (vk.pubfn.isNull(data.scene) && my_invite_code) { + // 若scene为空,则自动带上用户邀请码 + data.scene = `code=${my_invite_code}`; + } + if (!userInfo.role || userInfo.role.indexOf("admin") === -1) { + data.check_path = true; // 防止超限, 为 false 时允许小程序未发布或者 page 不存在, 但page 有数量上限(60000个)请勿滥用。 + } + res = await vk.openapi.weixin.wxacode.getUnlimited(data); + if (typeof res === "object" && res.code) { + return res; + } + try { + // 二进制转base64 + let base64 = Buffer.from(res, 'binary').toString('base64') + return { + code: 0, + base64: `data:image/png;base64,${base64}` + }; + } catch (err) { + // 转base64失败 + return { + code: -1, + msg: "生成小程序码失败", + err: { + message: err.message, + stack: err.stack + } + }; + } + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js new file mode 100644 index 0000000..47e5d52 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPscheme.js @@ -0,0 +1,41 @@ +'use strict'; +module.exports = { + /** + * 获取小程序scheme码,适用于短信、邮件、外部网页等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序码,目前仅针对国内非个人主体的小程序开放 + * @url user/kh/getWeixinMPscheme 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * @param {String} env_version 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + path, + query, + env_version + } = data; + // 超过180天有10万个限制,故这里强制设为90天 + res = await vk.openapi.weixin.urlscheme.generate({ + ...data, + // 跳转到的目标小程序信息。 + jump_wxa: { + path, // 小程序页面路径 + query, // 小程序页面参数 + env_version + }, + is_expire: true, + expire_type: 1, + expire_interval: 90, // 90天后失效 + }); + return res; + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js new file mode 100644 index 0000000..5ab34d4 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/getWeixinMPurl.js @@ -0,0 +1,38 @@ +'use strict'; +module.exports = { + /** + * 获取小程序 URL Link,适用于短信、邮件、网页、微信内等拉起小程序的业务场景。通过该接口,可以选择生成到期失效和永久有效的小程序链接,有数量限制,目前仅针对国内非个人主体的小程序开放 + * @url user/kh/getWeixinMPurl 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * @param {String} env_version 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + path, + query, + env_version + } = data; + // 超过180天有10万个限制,故这里强制设为90天 + res = await vk.openapi.weixin.urllink.generate({ + ...data, + path, + query, + env_version, + is_expire: true, + expire_type: 1, + expire_interval: 90, // 90天后失效 + }); + return res; + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js new file mode 100644 index 0000000..abcd2ce --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/resetPwd.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 重置密码 + * @url user/kh/resetPwd 前端调用的url参数地址 + * @description 重置当前登录用户的密码为123456 + * data 请求参数 说明 + * @param {String} uid 当前登录用户id(可信任,仅kh目录下的函数有此值) + * @param {String} password 重置后的密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { util, data={} } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 注意:虽然uid是从data中获取的,但无论前端uid传什么,最终uid都是当前登录用户的_id,因此不会出现A把B的密码改了的情况。 + let { uid, password= '123456' } = data; + res = await uniID.resetPwd({ uid, password }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js new file mode 100644 index 0000000..6c08a98 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setAvatar.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 设置头像 + * @url user/kh/setAvatar 前端调用的url参数地址 + * @description 设置当前登录用户的头像 + * data 请求参数 说明 + * @param {String} avatar 用户头像URL + * @param {Boolean} deleteOldFile 是否同时删除云储存内的头像文件 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { avatar, deleteOldFile } = data; + // 设置头像 + res = await uniID.setAvatar(event.data); + // 判断是否需要删除旧头像的云储存文件 + if(res.code ===0 && deleteOldFile && userInfo.avatar){ + try { + await uniCloud.deleteFile({ + fileList: [ + userInfo.avatar + ] + }); + }catch(err){ + res.deleteFileErr = err; + } + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js new file mode 100644 index 0000000..980d9f2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/setUserInviteCode.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 设置用户邀请码(自动生成) + * @url user/kh/setUserInviteCode 前端调用的url参数地址 + * @description 针对未生成邀请码的用户使用此方法生成邀请码(自动生成) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} myInviteCode 最终设置的邀请码 + */ + main: async (event) => { + let { data = {},userInfo, util, originalParam } = event; + let { uniID } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 判断下如果已经生成,则不再重新生成 + if(userInfo.my_invite_code){ + res = { + "code": 0, + "msg": "无需重复设置", + "myInviteCode": userInfo.my_invite_code + } + }else{ + res = await uniID.setUserInviteCode({ + uid:uid + }); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js new file mode 100644 index 0000000..b4ad3b5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindAlipay.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 解绑支付宝 + * @url user/kh/unbindAlipay 前端调用的url参数地址 + * @description 当前登录用户解绑支付宝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑支付宝!' }; + } + // 解绑 + res = await uniID.unbindAlipay(uid); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js new file mode 100644 index 0000000..e762c48 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindEmail.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 解绑邮箱 + * @url user/kh/unbindEmail 前端调用的url参数地址 + * @description 当前登录用户解绑邮箱 + * data 请求参数 说明 + * @param {String} email 邮箱 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username, userInfo.wx_openid, userInfo.ali_openid, userInfo.qq_openid)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑邮箱!' }; + } + // 解绑 + res = await uniID.unbindEmail(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js new file mode 100644 index 0000000..b237d7e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindMobile.js @@ -0,0 +1,25 @@ +module.exports = { + /** + * 解绑邮箱 + * @url user/kh/unbindMobile 前端调用的url参数地址 + * @description 当前登录用户解绑手机号 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + if (vk.pubfn.isNullAll(userInfo.username, userInfo.wx_openid, userInfo.ali_openid, userInfo.qq_openid)) { + return { code: -1, msg: '为了您的账号安全,请绑定微信或设置用户名后再解绑手机号!' }; + } + // 解绑 + res = await uniID.unbindMobile(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js new file mode 100644 index 0000000..f4211d2 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindQQ.js @@ -0,0 +1,23 @@ +module.exports = { + /** + * 解绑QQ + * @url user/kh/unbindQQ 前端调用的url参数地址 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑QQ!' }; + } + // 解绑 + res = await uniID.unbindQQ(uid); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js new file mode 100644 index 0000000..368a2ee --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/unbindWeixin.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 解绑微信 + * @url user/kh/unbindWeixin 前端调用的url参数地址 + * @description 当前登录用户解绑微信 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + // 业务逻辑开始----------------------------------------------------------- + let { data = {}, userInfo, util } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + if(vk.pubfn.isNullAll(userInfo.mobile, userInfo.username)){ + return { code : -1, msg : '为了您的账号安全,请绑定手机号后再解绑微信!' }; + } + // 解绑 + res = await uniID.unbindWeixin(uid); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js new file mode 100644 index 0000000..e96dcbd --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updatePwd.js @@ -0,0 +1,26 @@ +module.exports = { + /** + * 修改登录密码 + * @url user/kh/updatePwd 前端调用的url参数地址 + * @description 修改当前登录用户的登录密码 + * data 请求参数 说明 + * @param {String} oldPassword 旧密码 + * @param {String} newPassword 新密码 + * @param {String} passwordConfirmation 确认新密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if (userInfo.disable_update_password) { + return { code: -1, msg: "该账号不支持修改密码。" }; + } + res = await uniID.updatePwd(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js new file mode 100644 index 0000000..e422d80 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/kh/updateUser.js @@ -0,0 +1,32 @@ +module.exports = { + /** + * 修改用户信息 + * @url user/kh/updateUser 前端调用的url参数地址 + * @description 设置当前登录用户的昵称等用户信息 + * data 请求参数 说明 + * @param {String} nickname 用户的昵称 + * @param {String} avatar 用户的头像 + * @param {Number} gender 用户的性别 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 允许修改的字段列表 + let updateKeys = ["nickname", "avatar", "gender", "social_info"]; + let dataJson = {}; + for (let i in updateKeys) { + let key = updateKeys[i]; + if (vk.pubfn.isNotNull(data[key])) dataJson[key] = data[key]; + } + dataJson.uid = uid; + res = await uniID.updateUser(dataJson); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js new file mode 100644 index 0000000..307d4a5 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkToken.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * 验证token是否有效 + * @url user/pub/checkToken 前端调用的url参数地址 + * @description 验证token是否有效(会返回uid) + * @param {String} uniIdToken 用户token + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {Object} userInfo 当前用户信息 + * @param {Array} role 当前用户角色 + * @param {Array} permission 当前用户权限 + */ + main: async (event) => { + let { util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + res = await uniID.checkToken(event.uniIdToken,{ + needPermission:true, + needUserInfo:true + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js new file mode 100644 index 0000000..e9d7461 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/checkVersion.js @@ -0,0 +1,152 @@ +const platform_Android = 'Android'; +const platform_iOS = 'iOS'; +const package_app = 'native_app'; +const package_wgt = 'wgt'; +const app_version_db_name = 'opendb-app-versions' +module.exports = { + /** + * App升级中心 - 检测是当前版本是否需要升级 + * @url user/pub/checkVersion 前端调用的url参数地址 + * @description 验证token是否有效(会返回uid) + * @param {String} uniIdToken 用户token + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {Object} userInfo 当前用户信息 + * @param {Array} role 当前用户角色 + * @param {Array} permission 当前用户权限 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: "" }; + let { context } = originalParam; + // 业务逻辑开始----------------------------------------------------------- + /** + * 检测升级 使用说明 + * 上传包: + * 1. 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传 + * 2. 先从数据库取出所有该平台(从上下文读取平台信息,默认 Andriod)的所有线上发行更新 + * 3. 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新 + * 4. 使用上步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新,必须同时大于这两项,否则返回暂无更新 + * 5. 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion + */ + let { + appid, + appVersion, + wgtVersion, + } = data; + + let platform = context.OS === 'ios' ? platform_iOS : platform_Android; + + // 参数非空检测 + let nullKey = vk.pubfn.isNullOneByObject({ appid, appVersion, wgtVersion, platform }); + if (nullKey) return { code: -102, msg: '参数 ' + nullKey + ' 不能为空' }; + + let versionList = await vk.baseDao.select({ + dbName: app_version_db_name, + getCount: false, + pageIndex: 1, + pageSize: 500, + getMain: true, + whereJson: { + appid, + platform, + stable_publish: true + }, + sortArr: [{ name: "create_date", type: "desc" }], + }); + if (vk.pubfn.isNull(versionList)) return { code: -101, msg: "暂无更新或检查appid是否填写正确" }; + + const appVersionInDb = versionList.find(item => item.type === package_app) || {}; + const wgtVersionInDb = versionList.find(item => item.type === package_wgt) || {}; + const hasAppPackage = !!Object.keys(appVersionInDb).length; + const hasWgtPackage = !!Object.keys(wgtVersionInDb).length; + + // 取两个版本中版本号最大的包,版本一样,使用wgt包 + let stablePublishDb = hasAppPackage ? + hasWgtPackage ? + compare(wgtVersionInDb.version, appVersionInDb.version) >= 0 ? + wgtVersionInDb : + appVersionInDb : + appVersionInDb : + wgtVersionInDb; + + const { + version, + min_uni_version + } = stablePublishDb; + + // 库中的version必须满足同时大于appVersion和wgtVersion才行,因为上次更新可能是wgt更新 + const appUpdate = compare(version, appVersion) === 1; // app包可用更新 + const wgtUpdate = compare(version, wgtVersion) === 1; // wgt包可用更新 + + if (Object.keys(stablePublishDb).length && appUpdate && wgtUpdate) { + // 判断是否可用wgt更新 + if (min_uni_version && compare(min_uni_version, appVersion) < 1) { + return { + code: 101, + msg: 'wgt更新', + ...stablePublishDb + }; + } else if (hasAppPackage && compare(appVersionInDb.version, appVersion) === 1) { + return { + code: 102, + msg: '整包更新', + ...appVersionInDb + }; + } + } else { + return { code: 0, msg: '当前版本已经是最新的,不需要更新' }; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} + + + +/** + * 对比版本号,如需要,请自行修改判断规则 + * 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 + * @param {Object} v1 + * @param {Object} v2 + * v1 > v2 return 1 + * v1 < v2 return -1 + * v1 == v2 return 0 + */ +function compare(v1 = '0', v2 = '0') { + v1 = String(v1).split('.') + v2 = String(v2).split('.') + const minVersionLens = Math.min(v1.length, v2.length); + + let result = 0; + for (let i = 0; i < minVersionLens; i++) { + const curV1 = Number(v1[i]) + const curV2 = Number(v2[i]) + + if (curV1 > curV2) { + result = 1 + break; + } else if (curV1 < curV2) { + result = -1 + break; + } + } + + if (result === 0 && (v1.length !== v2.length)) { + const v1BiggerThenv2 = v1.length > v2.length; + const maxLensVersion = v1BiggerThenv2 ? v1 : v2; + for (let i = minVersionLens; i < maxLensVersion.length; i++) { + const curVersion = Number(maxLensVersion[i]) + if (curVersion > 0) { + v1BiggerThenv2 ? result = 1 : result = -1 + break; + } + } + } + + return result; +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js new file mode 100644 index 0000000..03bde08 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionAlipay.js @@ -0,0 +1,37 @@ +module.exports = { + /** + * 获取支付宝openid + * @url user/pub/code2SessionAlipay 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} code 支付宝登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + * @param {String} reExpiresIn refreshToken超时时间,单位(秒) + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + // 用户登录(账号+密码) + res = await uniID.code2SessionAlipay(data); + if (res.code === 0) { + let encrypted = vk.crypto.aes.encrypt({ + data: res + }); + delete res.sessionKey; // 删除明文sessionKey + delete res.accessToken; // 删除明文accessToken + delete res.refreshToken; // 删除明文refreshToken + res.encryptedKey = encrypted; // 返回前端加密内容 + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js new file mode 100644 index 0000000..aa7a836 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/code2SessionWeixin.js @@ -0,0 +1,41 @@ +module.exports = { + /** + * 获取微信openid + * @url user/pub/code2SessionWeixin 前端调用的url参数地址 + * @description 支持APP、微信小程序、微信公众号 + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus、h5-weixin,默认会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} unionid 用户unionid,可以取到此值时返回 + * @param {String} sessionKey 客户端为微信小程序时返回 + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, vk } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + platform, + appid, + needCache + } = data; + if (!platform) platform = originalParam.context.PLATFORM; + res = await vk.openapi.weixin.auth.code2Session({ + context: originalParam.context, + appid, + code, + needKey: false, // 是否需要返回明文的sessionKey或accessToken(为了安全期间,建议设置false) + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js new file mode 100644 index 0000000..cee1162 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getPhoneNumber.js @@ -0,0 +1,23 @@ +'use strict'; +module.exports = { + /** + * 获取用户微信绑定的手机号 + * 微信小程序API更新了,现在只需传code可以代替encryptedData和iv + * @url user/pub/getPhoneNumber 前端调用的url参数地址 + * data 请求参数 + * @param {String} code 通过 getphonenumber 事件获取到的code(code和encryptedData+iv二选一) + * @param {String} encryptedData(code和encryptedData+iv二选一) + * @param {String} iv(code和encryptedData+iv二选一) + * @param {String} encryptedKey code2SessionWeixin 接口返回的encryptedKey + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + res = await vk.openapi.weixin.decrypt.getPhoneNumber(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js new file mode 100644 index 0000000..df31d92 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/getUserInfoByInviteCode.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + /** + * 根据邀请码获取用户社交信息 + * @url user/pub/getUserInfoByInviteCode 前端调用的url参数地址 + * data 请求参数 + * @param {String} code + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { customUtil, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + let { code } = data; + // 参数非空检测 + let nullKey = vk.pubfn.isNullOneByObject({ code }); + if(nullKey) return { code:-1, msg:'参数 '+nullKey+' 不能为空' }; + res.userInfo = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + fieldJson:{ + _id:true, + nickname:true, + gender:true, + avatar:true, + my_invite_code:true, + social_info:true + }, + whereJson:{ + my_invite_code : code + } + }); + return res; + // 业务逻辑结束----------------------------------------------------------- + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js new file mode 100644 index 0000000..ea9c9d3 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/login.js @@ -0,0 +1,55 @@ +module.exports = { + /** + * 用户登录(账号+密码) + * @url user/pub/login 前端调用的url参数地址 + * @description 用户登录(账号+密码) + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 用户登录(账号+密码) + if (typeof data.username === "number") data.username = String(data.username).trim(); + if (typeof data.password === "number") data.password = String(data.password).trim(); + + let { + needPermission, + username, + password, + queryField = ['username', 'email', 'mobile'], // 不指定queryField的情况下只会查询username + } = data; + + res = await uniID.login({ + username, + password, + needPermission, + queryField + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "password", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } + +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js new file mode 100644 index 0000000..d255f0f --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByAlipay.js @@ -0,0 +1,55 @@ +module.exports = { + /** + * 用户登录(支付宝授权) + * @url user/pub/loginByAlipay 前端调用的url参数地址 + * @description 用户登录(支付宝授权) + * data 请求参数 说明 + * @param {String} code 支付宝登录返回的code + * @param {String} type login:登录 register:注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + type, + myInviteCode, + needPermission + } = data; + res = await uniID.loginByAlipay({ + code, + type, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + let encrypted = vk.crypto.aes.encrypt({ + data: res + }); + delete res.sessionKey; // 删除明文sessionKey + delete res.accessToken; // 删除明文accessToken + res.encryptedKey = encrypted; // 返回前端加密内容 + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "alipay", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js new file mode 100644 index 0000000..870e5da --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByEmail.js @@ -0,0 +1,56 @@ +module.exports = { + /** + * 用户登录(邮箱+验证码登录) + * @url user/pub/loginByEmail 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + * @param {String} type 指定操作类型,不传:存在则登录不存在则注册 login:只能登录 register:只能注册 + * @param {String} password 密码,当前用户为新注册时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,当前用户为新注册时生效(不传会自动生成) + * @param {Boolean} needPermission 设置为true时会在checkToken时返回用户权限(permission),如果是在admin端,需传true + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + email, + code, + type, + password, + needPermission, + myInviteCode + } = data; + res = await uniID.loginByEmail({ + email, + code, + type, + password, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "email", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js new file mode 100644 index 0000000..56d0403 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByQQ.js @@ -0,0 +1,58 @@ +module.exports = { + /** + * QQ授权登录 + * @url user/pub/loginByQQ 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} code QQ小程序登录返回的code + * @param {String} accessToken QQ APP登录返回的access_token + * @param {String} type login:登录 register:注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + code, + accessToken, + type, + myInviteCode, + needPermission + } = data; + res = await uniID.loginByQQ({ + code, + accessToken, + type, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + let encrypted = vk.crypto.aes.encrypt({ + data: res + }); + delete res.sessionKey; // 删除明文sessionKey + delete res.accessToken; // 删除明文accessToken + delete res.refreshToken; // 删除明文refreshToken + res.encryptedKey = encrypted; // 返回前端加密内容 + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "qq", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js new file mode 100644 index 0000000..ff07353 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginBySms.js @@ -0,0 +1,72 @@ +module.exports = { + /** + * 手机号登陆(手机号+手机验证码) + * @url user/pub/loginBySms 前端调用的url参数地址 + * @description 手机号登陆(手机号+手机验证码) + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 验证码 + * @param {String} type 指定操作类型,不传:存在则登录不存在则注册 login:只能登录 register:只能注册 + * @param {String} password 密码,当前用户为新注册时生效 + * @param {String} inviteCode 邀请人的邀请码,当前用户为新注册时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,当前用户为新注册时生效(不传会自动生成) + * @param {Boolean} needPermission 设置为true时会在checkToken时返回用户权限(permission),如果是在admin端,需传true + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + mobile, + code, + type, + password, + inviteCode, + myInviteCode, + needPermission + } = data; + res = await uniID.loginBySms({ + mobile, + code, + type, + password, + inviteCode, + myInviteCode, + needPermission + }); + // 修改用户昵称为:手机尾号xxxx用户 + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + let mobileStr = mobile.substring(7); + await vk.baseDao.update({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid, + nickname: null + }, + dataJson: { + nickname: `手机尾号${mobileStr}用户` + } + }); + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "sms", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js new file mode 100644 index 0000000..3022718 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByUniverify.js @@ -0,0 +1,74 @@ +module.exports = { + /** + * APP端 手机一键登录 + * @url user/pub/loginByUniverify 前端调用的url参数地址 + * @param {String} access_token uni.login登录成功后,返回的access_token参数 + * @param {String} openid uni.login登录成功后,返回的openid参数 + * @param {String} type 指定操作类型,可选值为login、register,不传此参数时表现为手机号已注册则登录,手机号未注册则进行注册 + * @param {String} password 密码,type为register时生效 + * @param {String} inviteCode 邀请人的邀请码,type为register时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,type为register时生效 + * @param {Boolean} needPermission 设置为true时会在checkToken时返回用户权限(permission),建议在管理控制台中使用 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {String} type 操作类型,login为登录、register为注册 + * @param {String} mobile 登录者手机号 + * @param {String} userInfo 用户全部信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + access_token, + openid, + type, + password, + inviteCode, + myInviteCode, + needPermission + } = data; + res = await uniID.loginByUniverify({ + access_token, + openid, + type, + password, + inviteCode, + myInviteCode, + needPermission + }); + if (res.token) { + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + if (res.type === "register") { + let mobileStr = res.userInfo.mobile.substring(7); + res.userInfo = await vk.baseDao.updateAndReturn({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid + }, + dataJson: { + nickname: data.nickname || `手机尾号${mobileStr}用户`, + }, + }); + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "univerify", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js new file mode 100644 index 0000000..729a03e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixin.js @@ -0,0 +1,58 @@ +module.exports = { + /** + * 用户登录(微信授权) + * @url user/pub/loginByWeixin 前端调用的url参数地址 + * @description 支持APP、微信小程序、微信公众号 + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} type login:登录 register:注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + // 额外写入的自定义字段数据(可以自己增加,建议只传一些显示的信息,不要传余额字段等,因为前端不可信任) + // 注意:app的微信登录已经支持自动获取昵称和头像,前端无需再传昵称和头像。 + let custom = { + nickname: data.nickname, + avatar: data.avatar + }; + /** + * 支持多小程序登录 + * 此处data可以额外接收appid和appsecret参数(appid可以从前端传,而appsecret可以配置在全局配置中(common/uni-config-center/vk-unicloud/index.js),也可以自己从数据库获取) + * 如果不传appid,则默认使用uni-id的配置信息 + * 特别注意:如果使用多小程序登录,则同一用户(同一个微信号)在不同小程序登录时,会分别创建不同的用户(除非小程序绑定在同一个开放平台下)。 + */ + + // 打开下方注释,动态赋值appid和appsecret即可支持多小程序登录 + // data.appid = "xxxx"; + // data.appsecret = "xxxx"; + + res = await vk.openapi.weixin.loginByWeixin({ + data, + context: originalParam.context, + custom, + needKey: false, // 是否需要返回明文的sessionKey或accessToken(为了安全期间,建议设置false) + }); + if (res.token) { + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: "login", + login_type: "weixin", + user_id: res.uid, + context: originalParam.context + }, util); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js new file mode 100644 index 0000000..a69e63a --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/loginByWeixinPhoneNumber.js @@ -0,0 +1,99 @@ +module.exports = { + /** + * 用户登录(微信手机号授权) + * @url user/pub/loginByWeixinPhoneNumber 前端调用的url参数地址 + * @description 用户登录(微信授权) + * data 请求参数 说明 + * @param {String} code 通过 getphonenumber 事件获取到的code(code和encryptedData+iv二选一) + * @param {String} encryptedData(code和encryptedData+iv二选一) + * @param {String} iv(code和encryptedData+iv二选一) + * @param {String} encryptedKey code2SessionWeixin 接口返回的encryptedKey + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + let { + nickname, + avatar, + gender, + inviteCode, + encryptedKey, + code, + encryptedData, + iv + } = data; + + // 获取微信绑定的手机号 + res = await vk.openapi.weixin.decrypt.getPhoneNumber({ + encryptedKey, + code, + encryptedData, + iv + }); + if (res.code !== 0) return res; + let { + mobile + } = res; + let mobileCode = vk.pubfn.random(6); + // 指定操作类型,可选值为login、register,不传此参数时表现为手机号已注册则登录,手机号未注册则进行注册 + let type; + // 通过手机号登录 + await uniID.setVerifyCode({ mobile, code: mobileCode, expiresIn: 60, type: "login" }); + res = await uniID.loginBySms({ mobile, code: mobileCode, type, inviteCode }); + if (!res.token) return res; + if (!res.msg) { + res.msg = res.type === "register" ? "注册成功" : "登录成功"; + } + if (res.type === "register") { + // 解密获得openid和unionid + let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 + }); + let wx_openid = {}; + let wx_unionid = decryptedRes.unionid; + wx_openid["mp-weixin"] = decryptedRes.openid; + // 查询openid或unionid是否已经存在,如果存在,则不绑定微信. + let queryUserInfo = await vk.daoCenter.userDao.findByUserInfo({ + "wx_openid.mp-weixin": wx_openid["mp-weixin"], + "wx_unionid": wx_unionid + }); + res.bindWeixin = vk.pubfn.isNull(queryUserInfo) ? true : false; + // 需要额外添加的字段 + let mobileStr = mobile.substring(7); + let dataJson = { + nickname: nickname || `手机尾号${mobileStr}用户`, + avatar, + gender + }; + if (res.bindWeixin) { + dataJson["wx_openid"] = wx_openid; + dataJson["wx_unionid"] = wx_unionid; + } + res.userInfo = await vk.baseDao.updateAndReturn({ + dbName: "uni-id-users", + whereJson: { + _id: res.uid + }, + dataJson + }); + } + // 日志服务 + const loginLogService = vk.require("service/user/util/login_log"); + await loginLogService.add({ + type: res.type, + login_type: "weixinPhoneNumber", + user_id: res.uid, + context: originalParam.context + }, util); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js new file mode 100644 index 0000000..d6c4653 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/logout.js @@ -0,0 +1,24 @@ +module.exports = { + /** + * 用户退出登录 + * @url user/pub/logout 前端调用的url参数地址 + * @description 用户退出登录 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + if(event.uniIdToken){ + res = await uniID.logout(event.uniIdToken); + }else{ + res.code = 0; + res.msg = "未登录"; + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js new file mode 100644 index 0000000..fb57f21 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/register.js @@ -0,0 +1,61 @@ +module.exports = { + /** + * 用户注册(账号+密码) + * @url user/pub/register 前端调用的url参数地址 + * @description 用户注册(账号+密码) + * data 请求参数 说明 + * @param {String} username 用户名,唯一 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: -1, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + if (typeof data.username === "number") data.username = String(data.username).trim(); + if (typeof data.password === "number") data.password = String(data.password).trim(); + + let { + username, + password, + needPermission, + myInviteCode + } = data; + + // 验证规则开始 ----------------------------------------------------------- + let rules = { + username: [ + { required: true, validator: vk.pubfn.validator("username"), message: '用户名以字母开头,长度在3~32之间,只能包含字母、数字和下划线', trigger: ['blur', 'change'] } + ], + password: [ + { validator: vk.pubfn.validator("password"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur' } + ] + }; + // 验证规则结束 ----------------------------------------------------------- + // 开始进行验证 + let formRulesRes = vk.pubfn.formValidate({ + data: data, + rules: rules + }); + if (formRulesRes.code !== 0) { + // 表单验证未通过 + return formRulesRes; + } + // 表单验证通过,下面写自己的业务逻辑 + res = await uniID.register({ + username, + password, + needPermission, + myInviteCode + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js new file mode 100644 index 0000000..062f601 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByEmail.js @@ -0,0 +1,52 @@ +module.exports = { + /** + * 根据邮箱+验证码重置密码 + * @url user/pub/resetPasswordByEmail 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} email 邮箱号码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { + _id, + password, + code, + email + } = data; + let res = { code : -1, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + // 检查验证码是否正确 + res = await uniID.verifyCode({ + email, + code, + type: 'reset-pwd', // 自2022-08-13起,以从reset改为reset-pwd,与官方uni-id对齐 + }); + if(res.code !== 0){ + return res; + } + // 根据email查询用户是否存在 + let userInfo = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + whereJson:{ + email + } + }); + if(!userInfo){ + return { code : -1, msg : '邮箱号未注册!' }; + } + // 重置密码 + res = await uniID.resetPwd({ + uid: userInfo._id, + password + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js new file mode 100644 index 0000000..95d96b8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/resetPasswordByMobile.js @@ -0,0 +1,52 @@ +module.exports = { + /** + * 根据手机+验证码重置密码 + * @url user/pub/resetPasswordByMobile 前端调用的url参数地址 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} mobile 手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util, originalParam } = event; + let { uniID, config, pubFun, vk , db, _ } = util; + let { + _id, + password, + code, + mobile + } = data; + let res = { code : -1, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + // 检查验证码是否正确 + res = await uniID.verifyCode({ + mobile, + code, + type: 'reset-pwd', // 自2022-08-13起,以从reset改为reset-pwd,与官方uni-id对齐 + }); + if(res.code !== 0){ + return res; + } + // 根据mobile查询用户是否存在 + let userInfo = await vk.baseDao.findByWhereJson({ + dbName:"uni-id-users", + whereJson:{ + mobile + } + }); + if(!userInfo){ + return { code : -1, msg : '手机号未注册!' }; + } + // 重置密码 + res = await uniID.resetPwd({ + uid: userInfo._id, + password + }); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js new file mode 100644 index 0000000..5cbf412 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendEmailCode.js @@ -0,0 +1,112 @@ +var vkmail; +try { + vkmail = require('vk-mail'); +} catch (err) { + console.error("请先添加公共模块:vk-mail(右键对应的云函数,点击管理公共模块或扩展库依赖,勾选vk-mail依赖)"); +} +var everyDaylimit = 30; // 限制同一个邮箱每天次数 +module.exports = { + /** + * 发送邮箱验证码 + * @url user/pub/sendEmailCode 前端调用的url参数地址 + * @description 发送邮箱验证码 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} type 验证码类型 + * @param {String} serviceType 邮件服务类型,默认为qq + * @param {Boolean|String} checkUserExist 是否需要检测邮箱对应的账号是否存在或不存在,默认不检测,若为exists代表邮箱必须已注册,若为!exists代表邮箱必须未注册 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID, config } = util; + let { + email, + type, + serviceType = "qq", + checkUserExist = false + } = data; + let res = { code: 0, msg: 'ok' }; + // 业务逻辑开始----------------------------------------------------------- + if (!vkmail) { + return { code: -1, msg: "请先添加公共模块:vk-mail(右键对应的云函数,点击管理公共模块或扩展库依赖,勾选vk-mail依赖)" }; + } + // 参数非空检测 + let nullKey = vk.pubfn.isNullOneByObject({ email, type }); + if (nullKey) return { code: -1, msg: '参数 ' + nullKey + ' 不能为空' }; + + if (!vk.pubfn.test(email, "email")) return { code: -1, msg: "邮箱格式错误" }; + if (vk.pubfn.isNull(type)) return { code: -1, msg: "type不能为空" }; + + if (checkUserExist) { + let dcloud_appid = originalParam.context.appId; + // 检测邮箱对应的账号是否存在 + let num = await vk.daoCenter.userDao.count({ + email, + dcloud_appid: _.or(_.eq(dcloud_appid), _.exists(false)) + }); + if (checkUserExist === true || checkUserExist === "exists") { + // 邮箱必须已注册用户,如果邮箱未注册,则不发短信 + if (num === 0) { + return { code: -1, msg: `邮箱:${email} 未注册`, notExists: true }; + } + } else if (checkUserExist === "!exists") { + // 邮箱必须未注册用户,如果邮箱已注册,则不发短信 + if (num > 0) { + return { code: -1, msg: `邮箱:${email} 已注册`, exists: true }; + } + } + } + + // 针对同一个邮箱,发送验证码每天有次数限制 + const cacheKey = `sys.sendEmailCode.everyDaylimit-${email}`; + let currNum = await vk.globalDataCache.get(cacheKey); + if (!currNum) currNum = 0; + if (currNum >= everyDaylimit) { + return { code: -1, msg: "此邮箱今日已超最大次数限制,请明日再试" }; + } + + let code = vk.pubfn.random(6, "0123456789"); + let param = { + code, + type, + email + }; + // 发送验证码开始 + let emailConfig = config.vk.service.email; + // 如果配置设置了过期时间,则使用配置的过期时间,否则默认180秒 + param.expiresIn = emailConfig.codeExpiresIn || 180; + let emailService = vkmail.createTransport({ + "host": emailConfig[serviceType].host, + "port": emailConfig[serviceType].port, + "secure": emailConfig[serviceType].secure, // use SSL + "auth": emailConfig[serviceType].auth + }); + try { + // 发送邮件 + await emailService.sendMail({ + "from": emailConfig[serviceType].auth.user, + "to": data.email, + "cc": emailConfig[serviceType].auth.user, // 由于邮件可能会被当成垃圾邮件,但只要把邮件抄送给自己一份,就不会被当成垃圾邮件。 + "subject": data.subject || `验证码是${code}`, // 邮件的标题 + "text": `您的验证码是${code},打死也不要告诉别人哦!`, // 邮件的内容 + }); + // 发送验证码成功后,设置验证码 + await uniID.setVerifyCode(param); + + currNum++; + let { startTime } = vk.pubfn.getDayOffsetStartAndEnd(1, new Date()); + let second = vk.pubfn.toDecimal((startTime - Date.now()) / 1000, 0) + await vk.globalDataCache.set(cacheKey, currNum, second); + } catch (err) { + console.error(err); + return { code: -1, msg: "邮件发送失败", err }; + } + // 发送验证码结束 + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js new file mode 100644 index 0000000..811d782 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/pub/sendSmsCode.js @@ -0,0 +1,86 @@ +var everyDaylimit = 12; // 限制同一个手机号每天次数 +module.exports = { + /** + * 发送短信的验证码 + * @url user/pub/sendSmsCode 前端调用的url参数地址 + * @description 发送验证码 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * @param {Boolean|String} checkUserExist 是否需要检测手机号对应的账号是否存在或不存在,默认不检测,若为exists代表手机号必须已注册,若为!exists代表手机号必须未注册 + * + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {Object} requestRes 原始返回数据 + * @param {Object} requestParam 包含服务供应商和发送的手机号 + */ + main: async (event) => { + let { data = {}, userInfo, util, originalParam } = event; + let { uniID, config, pubFun, vk, db, _ } = util; + let { uid } = data; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + mobile, + type, + checkUserExist = false + } = data; + if (vk.pubfn.isNull(mobile)) { + return { code: -1, msg: '手机号不能为空' }; + } + if (!vk.pubfn.test(mobile, 'mobile')) { + return { code: -1, msg: "手机号格式错误" }; + } + + if (checkUserExist) { + let dcloud_appid = originalParam.context.appId; + // 检测手机号对应的账号是否存在 + let num = await vk.daoCenter.userDao.count({ + mobile, + dcloud_appid: _.or(_.eq(dcloud_appid), _.exists(false)) + }); + if (checkUserExist === true || checkUserExist === "exists") { + // 手机号必须已注册用户,如果手机号未注册,则不发短信 + if (num === 0) { + return { code: -1, msg: `手机号:${mobile} 未注册`, notExists: true }; + } + } else if (checkUserExist === "!exists") { + // 手机号必须未注册用户,如果手机号已注册,则不发短信 + if (num > 0) { + return { code: -1, msg: `手机号:${mobile} 已注册`, exists: true }; + } + } + } + + // 针对同一个手机号,发送验证码每天有次数限制 + const cacheKey = `sys.sendSmsCode.everyDaylimit-${mobile}`; + let currNum = await vk.globalDataCache.get(cacheKey); + if (!currNum) currNum = 0; + if (currNum >= everyDaylimit) { + return { code: -1, msg: "此手机号今日已超最大次数限制,请明日再试" }; + } + + + let code = vk.pubfn.random(6, "0123456789"); + let provider = "unicloud"; + if (vk.pubfn.getData(config, "vk.service.sms.aliyun.enable")) { + provider = "aliyun"; + } + res = await vk.system.smsUtil.sendSmsVerifyCode({ + provider, + code, + type, + phone: mobile, + expiresIn: 180, // 验证码实际有效时间,必须是60的倍数 + }); + if (res.code == 0) { + currNum++; + let { startTime } = vk.pubfn.getDayOffsetStartAndEnd(1, new Date()); + let second = vk.pubfn.toDecimal((startTime - Date.now()) / 1000, 0) + await vk.globalDataCache.set(cacheKey, currNum, second); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js new file mode 100644 index 0000000..3aefe0e --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/encryptPwd.js @@ -0,0 +1,28 @@ +module.exports = { + /** + * 密码加密测试 + * @url user/sys/encryptPwd 前端调用的url参数地址 + * @description 密码加密测试 + * @param {Object} data 请求参数 + * @param {String} uniIdToken 用户token + * @param {Object} util 公共工具包 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} password 加密后的字符串 + */ + main: async (event) => { + let { util } = event; + let { uniID } = util; + let res = {}; + // 业务逻辑开始----------------------------------------------------------- + const password = await uniID.encryptPwd('123456'); + res = { + code: 0, + msg: '密码加密完成', + password + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js new file mode 100644 index 0000000..53d0e78 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/sys/setVerifyCode.js @@ -0,0 +1,27 @@ +module.exports = { + /** + * 设置验证码 + * @url user/sys/setVerifyCode 前端调用的url参数地址 + * @description 设置验证码(此接口正式环境不要暴露,故写在了sys目录下) + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} verifyCode 验证码(uni 1.1.2开始不再返回verifyCode) + */ + main: async (event) => { + let { data = {}, util } = event; + let { uniID } = util; + let { email, mobile, code, type } = data; + let res = {code : -1, msg : ''}; + // 业务逻辑开始----------------------------------------------------------- + res = await uniID.setVerifyCode(data); + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js b/uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js new file mode 100644 index 0000000..7ef51a7 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/util/login_log.js @@ -0,0 +1,72 @@ +module.exports = { + /** + * 添加登录日志 + * @param {Object} type 日志类型 login logout + * @param {String} login_type 登录类型 phone password weixin alipay + * @param {Object} user_id 用户ID + * @param {String} ip ip地址 + * @param {String} ua userAgent + * @param {String} os 操作系统 + * @param {String} platform 平台信息 + * @param {Object} context 请求上下文 + * @param {Number} state 1:登录成功 0 登录失败 + */ + add: async (event, util) => { + let { uniID, config, pubFun, vk, db, _ } = util; + let res = { code: 0, msg: '' }; + // 业务逻辑开始----------------------------------------------------------- + let { + type, + login_type, + user_id, + ip, + ua, + os, + platform, + context = {}, + state = 1, + dcloud_appid + } = event; + if (context) { + ip = context.CLIENTIP; + ua = context.CLIENTUA; + os = context.OS; + platform = context.PLATFORM; + dcloud_appid = context.APPID; + } + try { + if (vk.pubfn.getData(config, "vk.service.log.login.status")) { + let nowDate = new Date(); + let { + now + } = vk.pubfn.getCommonTime(nowDate); + // 增加登录日志 + await vk.baseDao.add({ + dbName: "uni-id-log", + dataJson: { + type, + login_type, + user_id, + ip, + ua, + os, + platform, + state, + dcloud_appid, + date:{ + ...now, + date_day_str: vk.pubfn.timeFormat(nowDate, "yyyy-MM-dd"), + date_month_str: vk.pubfn.timeFormat(nowDate, "yyyy-MM") + } + } + }); + } else { + console.log("已关闭登录日志"); + } + } catch (err) { + console.log("日志写入错误"); + } + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} diff --git a/uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md b/uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md new file mode 100644 index 0000000..da1abc1 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/user/统一用户中心.md @@ -0,0 +1,12 @@ +## 统一用户中心 +#### `router/service/user` +#### 此目录为集成`uni-id`账户系统的实现(开发者自己系统的逻辑尽量不要写在此处,应写在`service/admin`或`service/client`或`其他`目录下 + +``` +. +├── user──────────────────────# 统一用户中心服务(已集成uniID) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为需要授权才能访问的函数(如商家工作人员等) +└───────────────────────────────── +``` \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md b/uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md new file mode 100644 index 0000000..2dd318c --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/service/逻辑层目录说明.md @@ -0,0 +1,45 @@ +## 逻辑层 +#### `router/service` 目录为逻辑层 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── service──────────────────────# 逻辑层(用于写业务逻辑) +│ └── admin────────────────# PC后台管理端逻辑 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── client───────────────# 客户端逻辑(H5、小程序、APP) +│ ── └── user─────────────────# 用户服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 用户服务专用的工具包 +│ ── └── order────────────────# 订单服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 订单服务专用的工具包 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── common───────────────# 公共逻辑(公共接口) +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ └── user─────────────────# 统一用户中心服务(已集成uniID)(用户中心作为核心,且为了方便插件升级,故与admin和client平级) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为后端管理人员才能访问的函数(商家后台工作人员) +│ ── └── util─────────────────# 统一用户中心服务专用的工具包 +│ └── plugs───────────────# 插件逻辑(插件专用)(会陆续新增一些实用性插件给开发者使用,如微信小程序发送订阅消息等等) +│ ── └── admin────────────────# 管理端类型插件 +│ ──── └── 插件A──────────────────# 插件A +│ ──── └── 插件B──────────────────# 插件B +│ ── └── client───────────────# 客户端类型插件 +│ ──── └── 插件A──────────────────# 插件A +│ ──── └── 插件B──────────────────# 插件B +│ └── template─────────────# 云函数模板(插件内的云函数写法模板) +│ ── └── db_api───────────────# 数据库接口调用模板 +│ └── muban.js─────────────# 云函数模板(新建一个云函数应复制粘贴这个文件) +│ └── muban_easy.js────────# 云函数模板(简易版) +└───────────────────────────────── +``` diff --git a/uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js b/uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js new file mode 100644 index 0000000..b737a29 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/util/pubFunction.js @@ -0,0 +1,26 @@ +/** + * 自定义公共函数包 + * 这里可以写你自己的公共函数 + */ +var pubFun = {}; +/** + * 公共函数写法示例 + * 调用示例: + * pubFun.test(); + * 或 + * vk.myfn.test(); + */ +pubFun.test = function(path) { + // 此处可以直接使用 vk 实例 + let timeStr = vk.pubfn.timeFormat(new Date(), "yyyy-MM-dd hh:mm:ss"); + // 逻辑 + // ... + // 逻辑 + return { + timeStr, + msg: "这是公共函数test的返回" + } +} + + +module.exports = pubFun; diff --git a/uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js b/uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js new file mode 100644 index 0000000..23326bf --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/router/util/urlrewrite.js @@ -0,0 +1,15 @@ +/** + * URL重写 + */ +module.exports = { + "rule": { + // 示例1:https://xxx.bspapp.com/http/router/aaa 指向云函数 template/db_api/pub/select + "^aaa$": "template/db_api/pub/select", + // 示例2:https://xxx.bspapp.com/http/router/findById/001 指向云函数 template/db_api/pub/findById?_id=001 + "^findById/(.+)": "template/db_api/pub/findById?_id=$1" + }, + "config": { + // 当设置为true时,只有符合url重写规则内的云函数才可以被url化访问。 + "accessOnlyInRule": false + } +}; diff --git a/uniCloud-aliyun/database/JQL查询.jql b/uniCloud-aliyun/database/JQL查询.jql new file mode 100644 index 0000000..35d21de --- /dev/null +++ b/uniCloud-aliyun/database/JQL查询.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.html#limit +// 详细JQL语法,请参考:https://uniapp.dcloud.net.cn/uniCloud/jql.html + +// 下面示例查询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 0000000..744924b --- /dev/null +++ b/uniCloud-aliyun/database/db_init.json @@ -0,0 +1,892 @@ +// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/cf-database?id=db_init + +// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据 + +{ + "vk-test": { + "data": [ + + ], + "index": [ + { + "IndexName": "location", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "location","Direction": "2dsphere"}],"MgoIsUnique": false} + }, + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-users": { + "data": [ + { + "_id":"001", + "username": "admin", + "password": "03caebb36670995fc261a275d212cad65e4bbebd", + "register_date": 1596416400000, + "register_ip": "127.0.0.1", + "nickname": "超级管理员", + "role":["admin"], + "token": [], + "allow_login_background":true + } + ], + "index": [ + { + "IndexName": "username", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "username","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "mobile", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "mobile","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "email", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "email","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "wx_openid.app-plus", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "wx_openid.app-plus","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "wx_openid.mp-weixin", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "wx_openid.mp-weixin","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "wx_unionid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "wx_unionid","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "ali_openid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "ali_openid","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "my_invite_code", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "my_invite_code","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "inviter_uid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "inviter_uid","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "invite_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "invite_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "role", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "role","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "register_date", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "register_date","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-verify-codes": { + "data": [], + "index": [ + { + "IndexName": "mobile", + "MgoKeySchema": { + "MgoIndexKeys": [{ + "Name": "mobile", + "Direction": "1" + }, { + "Name": "code", + "Direction": "1" + }], + "MgoIsUnique": false + } + }, + { + "IndexName": "email", + "MgoKeySchema": { + "MgoIndexKeys": [{ + "Name": "email", + "Direction": "1" + }, { + "Name": "code", + "Direction": "1" + }], + "MgoIsUnique": false + } + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "state", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "state","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-tempdata": { + "data": [ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "expired", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "expired","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-open-data": { + "data": [ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "expired", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "expired","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-log":{ + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-roles":{ + "data": [ + { + "_id": "001", + "_add_time": 1596416400000, + "enable":true, + "role_id":"admin", + "role_name": "超级管理员", + "comment":"系统内置角色 - 请勿修改", + "permission": [] + }, + { + "_id": "005", + "_add_time": 1596416400000, + "enable":true, + "role_id":"query-all", + "role_name": "boss", + "comment":"系统内置角色 - 请勿修改", + "permission": [] + }, + { + "_id": "006", + "_add_time": 1596416400000, + "enable":true, + "role_id":"custom-role-1", + "role_name": "自定义角色-1", + "comment":"更细粒化的自定义角色权限示例", + "permission": [] + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "role_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "role_id","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "permission", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "permission","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "role_name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "role_name","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "uni-id-permissions":{ + "data": [ + { + "_id": "sys-permission", + "_add_time": 1596416400000, + "permission_id":"sys-permission", + "permission_name": "系统内置权限", + "comment":"系统内置权限", + "url": "", + "sort": 103, + "enable":true + }, + { + "_id": "sys-permission-add", + "_add_time": 1596416400000, + "permission_id":"sys-permission-add", + "permission_name": "系统内置 - 增", + "comment":"所有函数名以add开头的云函数", + "url": ["*/add*"], + "icon":"vk-icon-add", + "sort": 1, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":1, + "level":3 + }, + { + "_id": "sys-permission-delete", + "_add_time": 1596416400000, + "permission_id":"sys-permission-delete", + "permission_name": "系统内置 - 删", + "comment":"所有函数名以delete开头的云函数", + "url": ["*/delete*"], + "icon":"vk-icon-delete", + "sort": 2, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":2, + "level":4 + }, + { + "_id": "sys-permission-update", + "_add_time": 1596416400000, + "permission_id":"sys-permission-update", + "permission_name": "系统内置 - 改", + "comment":"所有函数名以update开头的云函数", + "url": ["*/update*"], + "icon":"el-icon-edit", + "sort": 3, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":3, + "level":3 + }, + { + "_id": "sys-permission-read", + "_add_time": 1596416400000, + "permission_id":"sys-permission-read", + "permission_name": "系统内置 - 查", + "comment":"包含所有的查询操作", + "url": ["*/get*","*/find*","*/select*"], + "icon":"vk-icon-text", + "sort": 4, + "parent_id":"sys-permission", + "enable":true, + "match_mode":1, + "curd_category":4, + "level":3 + }, + { + "_id": "sys-manage", + "_add_time": 1596416400000, + "permission_id":"sys-manage", + "permission_name": "用户角色权限菜单", + "comment":"", + "sort": 101, + "enable":true + }, + { + "_id": "sys-manage-user", + "_add_time": 1596416400000, + "permission_id":"sys-manage-user", + "permission_name": "系统 - 用户管理", + "comment":"", + "url": ["admin/system/user/sys/*"], + "sort": 1, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-role", + "_add_time": 1596416400000, + "permission_id":"sys-manage-role", + "permission_name": "系统 - 角色管理", + "comment":"", + "url": ["admin/system/role/sys/*"], + "sort": 2, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-permission", + "_add_time": 1596416400000, + "permission_id":"sys-manage-permission", + "permission_name": "系统 - 权限管理", + "comment":"", + "url": ["admin/system/permission/sys/*"], + "sort": 3, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-menu", + "_add_time": 1596416400000, + "permission_id":"sys-manage-menu", + "permission_name": "系统 - 菜单管理", + "comment":"", + "url": ["admin/system/menu/sys/*"], + "sort": 4, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-app", + "_add_time": 1596416400000, + "permission_id":"sys-manage-app", + "permission_name": "系统 - 应用管理", + "comment":"", + "url": ["admin/system/app/sys/*"], + "sort": 5, + "enable":true, + "match_mode":1, + "parent_id":"sys-manage" + }, + { + "_id": "sys-manage-app-upgrade-center", + "_add_time": 1596416400000, + "permission_id": "sys-manage-app-upgrade-center", + "permission_name": "系统 - App升级中心", + "comment":"", + "url": ["admin/system/app-upgrade-center/sys/*"], + "sort": 6, + "enable": true, + "match_mode": 1, + "parent_id": "sys-manage" + }, + { + "_id": "system-uni", + "_add_time": 1596416400000, + "permission_id":"system-uni", + "permission_name": "系统设置", + "comment":"", + "sort": 102, + "enable":true + }, + { + "_id": "system-uni-uni-id-files", + "_add_time": 1596416400000, + "permission_id":"system-uni-uni-id-files", + "permission_name": "系统 - 素材管理", + "comment":"", + "url": ["admin/system_uni/uni-id-files/*"], + "sort": 1, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-vk-global-data", + "_add_time": 1596416400000, + "permission_id":"system-uni-vk-global-data", + "permission_name": "系统 - 缓存管理", + "comment":"", + "url": ["admin/system_uni/global-data/sys/*"], + "sort": 2, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-vk-components-dynamic", + "_add_time": 1596416400000, + "permission_id":"system-uni-vk-components-dynamic", + "permission_name": "系统 - 动态组件数据管理", + "comment":"", + "url": ["admin/system_uni/components-dynamic/sys/*"], + "sort": 3, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-uni-id-log", + "_add_time": 1596416400000, + "permission_id":"system-uni-uni-id-log", + "permission_name": "系统 - 用户登录日志管理", + "comment":"", + "url": ["admin/system_uni/uni-id-log/sys/*"], + "sort": 4, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + }, + { + "_id": "system-uni-opendb-admin-log", + "_add_time": 1596416400000, + "permission_id":"system-uni-opendb-admin-log", + "permission_name": "系统 - 操作日志管理", + "comment":"", + "url": ["admin/system_uni/admin-log/sys/*"], + "sort": 5, + "enable":true, + "match_mode":1, + "parent_id":"system-uni" + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "permission_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "permission_id","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "parent_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "parent_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "url", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "url","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-admin-menus":{ + "data": [ + { + "_id": "sys-admin", + "_add_time": 1596416400000, + "menu_id":"sys-admin", + "name": "用户角色权限", + "icon":"el-icon-s-tools", + "url": "", + "comment":"系统内置", + "sort": 100, + "enable":true + }, + { + "_id": "sys-user-manage", + "_add_time": 1596416400000, + "menu_id":"sys-user-manage", + "name": "用户管理", + "icon":"el-icon-s-custom", + "url": "/pages_plugs/system/user/list", + "comment":"1个角色可以分配多个角色", + "sort": 1, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-role-manage", + "_add_time": 1596416400000, + "menu_id":"sys-role-manage", + "name": "角色管理", + "icon":"el-icon-user", + "url": "/pages_plugs/system/role/list", + "comment":"1个角色可以分配多个权限和菜单", + "sort": 2, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-permission-manage", + "_add_time": 1596416400000, + "menu_id":"sys-permission-manage", + "name": "权限管理", + "icon":"vk-icon-lock", + "url": "/pages_plugs/system/permission/list", + "comment":"1个权限可以匹配多个云函数", + "sort": 3, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-menus-manage", + "_add_time": 1596416400000, + "menu_id":"sys-menus-manage", + "name": "菜单管理", + "icon":"el-icon-tickets", + "url": "/pages_plugs/system/menu/list", + "comment":"控制admin左侧菜单的显示和隐藏", + "sort": 4, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-app-manage", + "_add_time": 1596416400000, + "menu_id":"sys-app-manage", + "name": "应用管理", + "icon":"el-icon-cloudy", + "url": "/pages_plugs/system/app/list", + "comment":"应用管理", + "sort": 5, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "sys-app-upgrade-center", + "_add_time": 1596416400000, + "menu_id":"sys-app-upgrade-center", + "name": "App升级中心", + "icon":"vk-icon-shengji3-xianxing", + "url": "/pages_plugs/system/app-upgrade-center/list", + "comment":"管理和发布新的app版本", + "sort": 6, + "parent_id":"sys-admin", + "enable":true + }, + { + "_id": "system-uni", + "_add_time": 1596416400000, + "enable": true, + "icon": "el-icon-s-tools", + "menu_id": "system-uni", + "name": "系统设置", + "sort": 110 + }, + { + "_id": "system-uni-uni-id-files", + "sort": 1, + "url": "/pages_plugs/system_uni/uni-id-files/list", + "_add_time": 1596416400000, + "enable": true, + "icon": "el-icon-folder-opened", + "menu_id": "system-uni-uni-id-files", + "name": "素材管理", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-vk-global-data", + "enable": true, + "icon": "", + "menu_id": "system-uni-vk-global-data", + "name": "系统缓存管理", + "parent_id": "system-uni", + "sort": 2, + "url": "/pages_plugs/system_uni/vk-global-data", + "_add_time": 1596416400000 + }, + { + "_id": "system-uni-vk-components-dynamic", + "sort": 3, + "url": "/pages_plugs/system_uni/vk-components-dynamic", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-vk-components-dynamic", + "name": "动态组件数据", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-vk-pay-orders", + "sort": 4, + "url": "/pages_plugs/system_uni/vk-pay-orders", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-vk-pay-orders", + "name": "支付订单明细", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-uni-id-log", + "sort": 8, + "url": "/pages_plugs/system_uni/uni-id-log", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-uni-id-log", + "name": "用户登录日志", + "parent_id": "system-uni" + }, + { + "_id": "system-uni-opendb-admin-log", + "sort": 9, + "url": "/pages_plugs/system_uni/opendb-admin-log", + "_add_time": 1596416400000, + "enable": true, + "icon": "", + "menu_id": "system-uni-opendb-admin-log", + "name": "系统操作日志", + "parent_id": "system-uni" + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "menu_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "menu_id","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "parent_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "parent_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "url", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "url","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "opendb-app-list": { + "data": [ + { + "_id":"001", + "appid": "__UNI__01F080F", + "type": "client", + "name": "用户端", + "description": "此为用户端应用", + "create_date": 1596416400000, + "_add_time": 1596416400000, + "_add_time_str": "2020-08-03 09:00:00" + }, + { + "_id":"002", + "appid": "__UNI__570A7FB", + "type": "admin", + "name": "管理端", + "description": "此为管理端应用", + "create_date": 1596416400000, + "_add_time": 1596416400000, + "_add_time_str": "2020-08-03 09:00:00" + } + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "appid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "appid","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "name","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "create_date", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "create_date","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "enable_upgrade_center", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "enable_upgrade_center", "Direction": "1" }], "MgoIsUnique": false } + } + ] + }, + "opendb-app-versions": { + "data": [], + "index": [{ + "IndexName": "_add_time", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "_add_time", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "appid", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "appid", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "name", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "name", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "platform", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "platform", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "type", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "type", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "uni_platform", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "uni_platform", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "create_env", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "create_env", "Direction": "1" }], "MgoIsUnique": false } + }, + { + "IndexName": "stable_publish", + "MgoKeySchema": { "MgoIndexKeys": [{ "Name": "stable_publish", "Direction": "1" }], "MgoIsUnique": false } + } + ] + }, + "opendb-admin-log":{ + "data": [ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "title", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "title","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-components-dynamic":{ + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "data_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "data_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "title", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "title","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "show", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "show","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "name","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-global-data":{ + "data":[ + + ], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "key", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "key","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "expired_at", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "expired_at","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-files": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "user_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "status", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "status","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "type", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "type","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "display_name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "display_name","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "url", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "url","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-files-categories": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "name", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "name","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "sort", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "sort","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-pay-orders": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "out_trade_no", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "out_trade_no","Direction": "1"}],"MgoIsUnique": true} + }, + { + "IndexName": "user_order_success", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "user_order_success","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "transaction_id", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "transaction_id","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "total_fee", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "total_fee","Direction": "1"}],"MgoIsUnique": false} + }, + { + "IndexName": "pid", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "pid","Direction": "1"}],"MgoIsUnique": false} + } + ] + }, + "vk-pay-config": { + "data": [], + "index": [ + { + "IndexName": "_add_time", + "MgoKeySchema": {"MgoIndexKeys": [{"Name": "_add_time","Direction": "1"}],"MgoIsUnique": false} + } + ] + } +} diff --git a/uni_modules/uni-config-center/changelog.md b/uni_modules/uni-config-center/changelog.md new file mode 100644 index 0000000..57dbcb5 --- /dev/null +++ b/uni_modules/uni-config-center/changelog.md @@ -0,0 +1,6 @@ +## 0.0.3(2022-11-11) +- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug +## 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 0000000..bace866 --- /dev/null +++ b/uni_modules/uni-config-center/package.json @@ -0,0 +1,81 @@ +{ + "id": "uni-config-center", + "displayName": "uni-config-center", + "version": "0.0.3", + "description": "uniCloud 配置中心", + "keywords": [ + "配置", + "配置中心" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-function" + }, + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} diff --git a/uni_modules/uni-config-center/readme.md b/uni_modules/uni-config-center/readme.md new file mode 100644 index 0000000..03f7fc2 --- /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 0000000..00ba62f --- /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=vt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=vt(p,"Map"),J=vt(Object,"create"),K=function(){function t(){}return function(r){if(!xt(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=_t(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return _t(this,t).get(t)},Y.prototype.has=function(t){return _t(this,t).has(t)},Y.prototype.set=function(t,r){var e=_t(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 Ct(t)&&ct(t)==o}function ft(t){return!(!xt(t)||function(t){return!!U&&U in t}(t))&&(zt(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(!xt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=yt(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),xt(i))!function(t,r,e,n,o,i,u){var a=gt(t,e),f=gt(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=Ot(f),_=!p&&At(f),v=!p&&!_&&Ft(f);l=f,p||_||v?Ot(a)?l=a:Ct(j=a)&&mt(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)}}(pt);function jt(t,r){return t===r||t!=t&&r!=r}var wt=at(function(){return arguments}())?at:function(t){return Ct(t)&&F.call(t,"callee")&&!B.call(t,"callee")},Ot=Array.isArray;function mt(t){return null!=t&&Mt(t.length)&&!zt(t)}var At=G||function(){return!1};function zt(t){if(!xt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function Mt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function xt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function Ct(t){return null!=t&&"object"==typeof t}var Ft=b?function(t){return function(r){return t(r)}}(b):function(t){return Ct(t)&&Mt(t.length)&&!!s[ct(t)]};function Ut(t){return mt(t)?tt(t,!0):st(t)}var St,It=(St=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=St.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!xt(e))return!1;var n=typeof r;return!!("number"==n?mt(e)&&dt(r,e.length):"string"==n&&r in e)&&jt(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){if(!this._config){const t=this._getUserConfig();this._config=Array.isArray(t)?t:(this.customMerge||u)(this.defaultConfig,t)}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 一般uni-id升级大版本时为不兼容更新,从低版本迁移到高版本请参考:[uni-id迁移指南](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=migration) + +## 重要升级说明 + +**uni-id 3.x版本,搭配的uniCloud admin版本需大于1.2.10。** + +### 缓存角色权限 + +自`uni-id 3.0.0`起,支持在token内缓存用户的角色权限,默认开启此功能,各登录接口的needPermission参数不再生效。如需关闭请在config内配置`"removePermissionAndRoleFromToken": true`。 + +为什么要缓存角色权限?要知道云数据库是按照读写次数来收取费用的,并且读写数据库会拖慢接口响应速度。未配置`"removePermissionAndRoleFromToken": true`的情况下,可以在调用checkToken接口时不查询数据库获取用户角色权限。 + +详细checkToken流程如下: + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/ed45d350-5a4d-11eb-b997-9918a5dda011.jpg) + +可以看出,旧版token(removePermissionAndRoleFromToken为true时生成的)在checkToken时如需返回权限需要进行两次数据库查询。新版token不需要查库即可返回权限信息。 + +**注意** + +- 由于角色权限缓存在token内,可能会存在权限已经更新但是用户token未过期之前依然是旧版角色权限的情况。可以调短一些token过期时间来减少这种情况的影响。 +- admin角色token内不包含permission,如需自行判断用户是否有某个权限,要注意admin角色需要额外判断一下,写法如下 + ```js + const { + role, + permission + } = await uniID.checkToken(event.uniIdToken) + if(role.includes('admin') || permission.includes('your permission id')) { + // 当前角色拥有'your permission id'对应的权限 + } + ``` \ No newline at end of file diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/config.json b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/config.json new file mode 100644 index 0000000..6d67890 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/config.json @@ -0,0 +1,52 @@ +{ + "passwordSecret": "passwordSecret-demo", + "tokenSecret": "tokenSecret-demo", + "tokenExpiresIn": 7200, + "tokenExpiresThreshold": 600, + "passwordErrorLimit": 6, + "bindTokenToDevice": true, + "passwordErrorRetryTime": 3600, + "autoSetInviteCode": false, + "forceInviteCode": false, + "app-plus": { + "tokenExpiresIn": 2592000, + "oauth" : { + "weixin" : { + "appid" : "weixin appid", + "appsecret" : "weixin appsecret" + }, + "apple": { + "bundleId": "your APP bundleId" + } + } + }, + "mp-weixin": { + "oauth" : { + "weixin" : { + "appid" : "weixin appid", + "appsecret" : "weixin appsecret" + } + } + }, + "mp-alipay": { + "oauth" : { + "alipay" : { + "appid" : "alipay appid", + "privateKey" : "alipay privateKey" + } + } + }, + "service": { + "sms": { + "name": "DCloud", + "codeExpiresIn": 300, + "smsKey": "your sms key", + "smsSecret": "your sms secret" + }, + "univerify": { + "appid":"your appid", + "apiKey": "your apiKey", + "apiSecret": "your apiSecret" + } + } +} diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js new file mode 100644 index 0000000..5003d30 --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js @@ -0,0 +1 @@ +"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var t=e(require("crypto")),r=e(require("buffer")),n=e(require("stream")),i=e(require("util"));const o={PARAM_ERROR:{errCode:"param-error"},PARAM_REQUIRED:{errCode:"param-required"},USER_NOT_EXIST:{errCode:"user-not-exist"},ROLE_NOT_EXIST:{errCode:"role-not-exist"},PERMISSION_NOT_EXIST:{errCode:"permission-not-exist"},MULTI_USER_MATCHED:{errCode:"multi-user-matched"},USER_INFO_ERROR:{errCode:"user-info-error"},USER_ACCOUNT_CONFLICT:{errCode:"user-account-conflict"},USER_ACCOUNT_CLOSED:{errCode:"user-account-closed"},ACCOUNT_EXISTS:{errCode:"account-exists"},ACCOUNT_NOT_EXISTS:{errCode:"account-not-exists"},ACCOUNT_BOUND:{errCode:"account-bound"},UNBIND_FAILED:{errCode:"unbind-failed"},INVALID_INVITE_CODE:{errCode:"invalid-invite-code"},SET_INVITE_CODE_FAILED:{errCode:"set-invite-code-failed"},GET_THIRD_PARTY_ACCOUNT_FAILED:{errCode:"get-third-party-account-failed"},GET_THIRD_PARTY_USER_INFO_FAILED:{errCode:"get-third-party-user-info-failed"}},s={0:{errCode:0,errMsg:""},10001:{errCode:"account-banned"},10002:o.USER_NOT_EXIST,10003:o.MULTI_USER_MATCHED,10004:o.USER_INFO_ERROR,10005:o.USER_ACCOUNT_CONFLICT,10006:o.USER_ACCOUNT_CLOSED,10102:{errCode:"password-error"},10103:{errCode:"password-error-exceed-limit"},10201:o.ACCOUNT_EXISTS,10202:o.ACCOUNT_NOT_EXISTS,10203:o.INVALID_INVITE_CODE,10301:o.ACCOUNT_EXISTS,10302:o.ACCOUNT_NOT_EXISTS,10401:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10402:o.ACCOUNT_EXISTS,10403:o.ACCOUNT_NOT_EXISTS,10501:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10502:o.ACCOUNT_EXISTS,10503:o.ACCOUNT_NOT_EXISTS,10601:o.ACCOUNT_EXISTS,10602:o.ACCOUNT_NOT_EXISTS,10701:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10702:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10703:o.ACCOUNT_EXISTS,10704:o.ACCOUNT_NOT_EXISTS,10705:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10706:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10801:o.GET_THIRD_PARTY_ACCOUNT_FAILED,10802:o.ACCOUNT_EXISTS,10803:o.ACCOUNT_NOT_EXISTS,20101:o.PARAM_REQUIRED,20102:o.ACCOUNT_EXISTS,30101:o.PARAM_REQUIRED,30201:{errCode:"check-device-feature-failed"},30202:{errCode:"token-not-exist"},30203:{errCode:"token-expired"},30204:{errCode:"check-token-failed"},40201:o.USER_NOT_EXIST,40202:{errCode:"invalid-old-password"},50101:o.PARAM_REQUIRED,50102:o.PARAM_ERROR,50201:o.PARAM_REQUIRED,50203:o.PARAM_ERROR,50202:{errCode:"invalid-verify-code"},50301:{errCode:"send-sms-code-failed"},60101:o.ACCOUNT_BOUND,60201:o.ACCOUNT_BOUND,60301:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60302:o.ACCOUNT_BOUND,60401:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60402:o.ACCOUNT_BOUND,60501:o.GET_THIRD_PARTY_ACCOUNT_FAILED,60502:o.ACCOUNT_BOUND,70101:o.UNBIND_FAILED,70201:o.UNBIND_FAILED,70301:o.UNBIND_FAILED,70401:o.UNBIND_FAILED,70501:o.UNBIND_FAILED,80301:o.USER_NOT_EXIST,80401:o.SET_INVITE_CODE_FAILED,80402:o.SET_INVITE_CODE_FAILED,80501:o.INVALID_INVITE_CODE,80502:o.USER_NOT_EXIST,80503:{errCode:"modify-invite-code-is-not-allowed"},80601:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80602:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80701:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80702:o.GET_THIRD_PARTY_ACCOUNT_FAILED,80801:{errCode:"decrypt-weixin-data-failed"},80802:{errCode:"decrypt-weixin-data-failed"},80803:{errCode:"invalid-weixin-appid"},80804:o.PARAM_REQUIRED,80805:o.PARAM_REQUIRED,80806:o.PARAM_REQUIRED,80901:o.GET_THIRD_PARTY_USER_INFO_FAILED,90001:{errCode:"database-operation-failed"},90002:o.PARAM_REQUIRED,90003:o.PARAM_ERROR,90004:o.USER_NOT_EXIST,90005:o.ROLE_NOT_EXIST,90006:o.PERMISSION_NOT_EXIST};class a extends Error{constructor(e){super(e.message),this.errMsg=e.message||"",Object.defineProperties(this,{message:{get(){return`errCode: ${e.code||""} | errMsg: `+this.errMsg},set(e){this.errMsg=e}}})}}const c=Object.prototype.toString,u=Object.prototype.hasOwnProperty;function d(e,t){return u.call(e,t)}function p(e){return"[object Object]"===c.call(e)}function l(e){return"function"==typeof e}function f(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}function m(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}const h=/_(\w)/g,g=/[A-Z]/g;function y(e){return e.replace(h,(e,t)=>t?t.toUpperCase():"")}function w(e){return e.replace(g,e=>"_"+e.toLowerCase())}function v(e,t){let r,n;switch(t){case"snake2camel":n=y,r=h;break;case"camel2snake":n=w,r=g}for(const i in e)if(d(e,i)&&r.test(i)){const r=n(i);e[r]=e[i],delete e[i],p(e[r])?e[r]=v(e[r],t):Array.isArray(e[r])&&(e[r]=e[r].map(e=>v(e,t)))}return e}function _(e){return v(e,"snake2camel")}function b(e){return v(e,"camel2snake")}function T(e){return function(e,t="-"){e=e||new Date;const r=[];return r.push(e.getFullYear()),r.push(("00"+(e.getMonth()+1)).substr(-2)),r.push(("00"+e.getDate()).substr(-2)),r.join(t)}(e=e||new Date)+" "+function(e,t=":"){e=e||new Date;const r=[];return r.push(("00"+e.getHours()).substr(-2)),r.push(("00"+e.getMinutes()).substr(-2)),r.push(("00"+e.getSeconds()).substr(-2)),r.join(t)}(e)}function E(){"development"===process.env.NODE_ENV&&console.log(...arguments)}function C(e=6){let t="";for(let r=0;r-1?"&":"?"}access_token=${t.accessToken}`}return`${e}${r}`}class G{constructor(e){this.options=Object.assign({baseUrl:"https://api.weixin.qq.com",timeout:5e3},e)}async _requestWxOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};return await H({name:"auth."+e,url:`${this.options.baseUrl}${K(t,r)}`,data:r,options:n,defaultOptions:i})}async code2Session(e){return await this._requestWxOpenapi({name:"code2Session",url:"/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}async getOauthAccessToken(e){const t=await this._requestWxOpenapi({name:"getOauthAccessToken",url:"/sns/oauth2/access_token",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,code:e}});return t.expiresIn&&(t.expired=Date.now()+1e3*t.expiresIn),t}async getUserInfo({accessToken:e,openid:t}={}){const{nickname:r,headimgurl:n}=await this._requestWxOpenapi({name:"getUserInfo",url:"/sns/userinfo",data:{accessToken:e,openid:t,appid:this.options.appId,secret:this.options.secret,scope:"snsapi_userinfo"}});return{nickname:r,avatar:n}}}async function Q({name:e,url:t,data:r,options:n,defaultOptions:i}){let o;n=Object.assign({},i,n,{data:b(Object.assign({},r))});try{o=await uniCloud.httpclient.request(t,n)}catch(t){return function(e,t){throw new a({code:t.code||-2,message:t.message||e+" fail"})}(e,t)}let s=o.data;const c=o.headers["content-type"];if(!Buffer.isBuffer(s)||0!==c.indexOf("text/plain")&&0!==c.indexOf("application/json"))Buffer.isBuffer(s)&&(s={buffer:s,contentType:c});else try{s=JSON.parse(s.toString())}catch(e){s=s.toString()}return _(function(e,t){if(t.ret||t.error){const r=t.ret||t.error||t.errcode||-2,n=t.msg||t.error_description||t.errmsg||e+" fail";throw new a({code:r,message:n})}return delete t.ret,delete t.msg,delete t.error,delete t.error_description,delete t.errcode,delete t.errmsg,{...t,errMsg:e+" ok",errCode:0}}(e,s||{errCode:-2,errMsg:"Request failed"}))}class X{constructor(e){this.options=Object.assign({baseUrl:"https://graph.qq.com",timeout:5e3},e)}async _requestQQOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};var o,s;return await Q({name:"auth."+e,url:(o=this.options.baseUrl,s=t,/^https?:/.test(s)?s:o+s),data:r,options:n,defaultOptions:i})}async getOpenidByToken({accessToken:e}={}){const t=await this._requestQQOpenapi({name:"getOpenidByToken",url:"/oauth2.0/me",data:{accessToken:e,unionid:1,fmt:"json"}});if(t.clientId!==this.options.appId)throw new a({code:"APPID_NOT_MATCH",message:"appid not match"});return{openid:t.openid,unionid:t.unionid}}async code2Session({code:e}={}){return await this._requestQQOpenapi({name:"getOpenidByToken",url:"https://api.q.qq.com/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}}const Y={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};var z={code2Session:{returnValue:{openid:"userId"}}};class W extends class{constructor(e={}){if(!e.appId)throw new Error("appId required");if(!e.privateKey)throw new Error("privateKey required");const t={gateway:"https://openapi.alipay.com/gateway.do",timeout:5e3,charset:"utf-8",version:"1.0",signType:"RSA2",timeOffset:-(new Date).getTimezoneOffset()/60,keyType:"PKCS8"};e.sandbox&&(e.gateway="https://openapi.alipaydev.com/gateway.do"),this.options=Object.assign({},t,e);const r="PKCS8"===this.options.keyType?"PRIVATE KEY":"RSA PRIVATE KEY";this.options.privateKey=this._formatKey(this.options.privateKey,r),this.options.alipayPublicKey&&(this.options.alipayPublicKey=this._formatKey(this.options.alipayPublicKey,"PUBLIC KEY"))}_formatKey(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`}_formatUrl(e,t){let r=e;const n=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token"];for(const e in t)if(n.indexOf(e)>-1){const n=encodeURIComponent(t[e]);r=`${r}${r.includes("?")?"&":"?"}${e}=${n}`,delete t[e]}return{execParams:t,url:r}}_getSign(e,r){const n=r.bizContent||null;delete r.bizContent;const i=Object.assign({method:e,appId:this.options.appId,charset:this.options.charset,version:this.options.version,signType:this.options.signType,timestamp:T((o=this.options.timeOffset,new Date(Date.now()+6e4*((new Date).getTimezoneOffset()+60*(o||0)))))},r);var o;n&&(i.bizContent=JSON.stringify(b(n)));const s=b(i),a=Object.keys(s).sort().map(e=>{let t=s[e];return"[object String]"!==Array.prototype.toString.call(t)&&(t=JSON.stringify(t)),`${e}=${t}`}).join("&"),c=t.createSign(Y[this.options.signType]).update(a,"utf8").sign(this.options.privateKey,"base64");return Object.assign(s,{sign:c})}async _exec(e,t={},r={}){const n=this._getSign(e,t),{url:i,execParams:o}=this._formatUrl(this.options.gateway,n),{status:s,data:a}=await uniCloud.httpclient.request(i,{method:"POST",data:o,dataType:"text",timeout:this.options.timeout});if(200!==s)throw new Error("request fail");const c=JSON.parse(a),u=e.replace(/\./g,"_")+"_response",d=c[u],p=c.error_response;if(d){if(!r.validateSign||this._checkResponseSign(a,u)){if(!d.code||"10000"===d.code){return{errCode:0,errMsg:d.msg||"",..._(d)}}const e=d.sub_code?`${d.sub_code} ${d.sub_msg}`:""+(d.msg||"unkonwn error");throw new Error(e)}throw new Error("check sign error")}if(p)throw new Error(p.sub_msg||p.msg||"request fail");throw new Error("request fail")}_checkResponseSign(e,r){if(!this.options.alipayPublicKey||""===this.options.alipayPublicKey)return console.warn("options.alipayPublicKey is empty"),!0;if(!e)return!1;const n=this._getSignStr(e,r),i=JSON.parse(e).sign,o=t.createVerify(Y[this.options.signType]);return o.update(n,"utf8"),o.verify(this.options.alipayPublicKey,i,"base64")}_getSignStr(e,t){let r=e.trim();const n=e.indexOf(t+'"'),i=e.lastIndexOf('"sign"');return r=r.substr(n+t.length+1),r=r.substr(0,i),r=r.replace(/^[^{]*{/g,"{"),r=r.replace(/\}([^}]*)$/g,"}"),r}}{constructor(e){super(e),this._protocols=z}async code2Session(e){return await this._exec("alipay.system.oauth.token",{grantType:"authorization_code",code:e})}}function J(e){var t=e[0];return t<"0"||t>"7"?"00"+e:e}function Z(e){var t=e.toString(16);return t.length%2?"0"+t:t}function ee(e){if(e<=127)return Z(e);var t=Z(e);return Z(128+t.length/2)+t}function te(e,t){return e(t={exports:{}},t.exports),t.exports}var re=te((function(e,t){var n=r.Buffer;function i(e,t){for(var r in e)t[r]=e[r]}function o(e,t,r){return n(e,t,r)}n.from&&n.alloc&&n.allocUnsafe&&n.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=o),o.prototype=Object.create(n.prototype),i(n,o),o.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return n(e,t,r)},o.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=n(e);return void 0!==t?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}})),ne=(re.Buffer,re.Buffer);function ie(e){if(this.buffer=null,this.writable=!0,this.readable=!0,!e)return this.buffer=ne.alloc(0),this;if("function"==typeof e.pipe)return this.buffer=ne.alloc(0),e.pipe(this),this;if(e.length||"object"==typeof e)return this.buffer=e,this.writable=!1,process.nextTick(function(){this.emit("end",e),this.readable=!1,this.emit("close")}.bind(this)),this;throw new TypeError("Unexpected data type ("+typeof e+")")}i.inherits(ie,n),ie.prototype.write=function(e){this.buffer=ne.concat([this.buffer,ne.from(e)]),this.emit("data",e)},ie.prototype.end=function(e){e&&this.write(e),this.emit("end",e),this.emit("close"),this.writable=!1,this.readable=!1};var oe=ie,se=r.Buffer,ae=r.SlowBuffer,ce=ue;function ue(e,t){if(!se.isBuffer(e)||!se.isBuffer(t))return!1;if(e.length!==t.length)return!1;for(var r=0,n=0;n=128&&--n,n}var we={derToJose:function(e,t){e=ge(e);var r=me(t),n=r+1,i=e.length,o=0;if(48!==e[o++])throw new Error('Could not find expected "seq"');var s=e[o++];if(129===s&&(s=e[o++]),i-o0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var r=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*r;case"weeks":case"week":case"w":return 6048e5*r;case"days":case"day":case"d":return r*mt;case"hours":case"hour":case"hrs":case"hr":case"h":return r*ft;case"minutes":case"minute":case"mins":case"min":case"m":return r*lt;case"seconds":case"second":case"secs":case"sec":case"s":return r*pt;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(e);if("number"===r&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=mt)return gt(e,t,mt,"day");if(t>=ft)return gt(e,t,ft,"hour");if(t>=lt)return gt(e,t,lt,"minute");if(t>=pt)return gt(e,t,pt,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=mt)return Math.round(e/mt)+"d";if(t>=ft)return Math.round(e/ft)+"h";if(t>=lt)return Math.round(e/lt)+"m";if(t>=pt)return Math.round(e/pt)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function gt(e,t,r,n){var i=t>=1.5*r;return Math.round(e/r)+" "+n+(i?"s":"")}var yt=function(e,t){var r=t||Math.floor(Date.now()/1e3);if("string"==typeof e){var n=ht(e);if(void 0===n)return;return Math.floor(r+n/1e3)}return"number"==typeof e?r+e:void 0},wt=te((function(e,t){var r;t=e.exports=G,r="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},t.SEMVER_SPEC_VERSION="2.0.0";var n=Number.MAX_SAFE_INTEGER||9007199254740991,i=t.re=[],o=t.src=[],s=0,a=s++;o[a]="0|[1-9]\\d*";var c=s++;o[c]="[0-9]+";var u=s++;o[u]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var d=s++;o[d]="("+o[a]+")\\.("+o[a]+")\\.("+o[a]+")";var p=s++;o[p]="("+o[c]+")\\.("+o[c]+")\\.("+o[c]+")";var l=s++;o[l]="(?:"+o[a]+"|"+o[u]+")";var f=s++;o[f]="(?:"+o[c]+"|"+o[u]+")";var m=s++;o[m]="(?:-("+o[l]+"(?:\\."+o[l]+")*))";var h=s++;o[h]="(?:-?("+o[f]+"(?:\\."+o[f]+")*))";var g=s++;o[g]="[0-9A-Za-z-]+";var y=s++;o[y]="(?:\\+("+o[g]+"(?:\\."+o[g]+")*))";var w=s++,v="v?"+o[d]+o[m]+"?"+o[y]+"?";o[w]="^"+v+"$";var _="[v=\\s]*"+o[p]+o[h]+"?"+o[y]+"?",b=s++;o[b]="^"+_+"$";var T=s++;o[T]="((?:<|>)?=?)";var E=s++;o[E]=o[c]+"|x|X|\\*";var C=s++;o[C]=o[a]+"|x|X|\\*";var A=s++;o[A]="[v=\\s]*("+o[C]+")(?:\\.("+o[C]+")(?:\\.("+o[C]+")(?:"+o[m]+")?"+o[y]+"?)?)?";var I=s++;o[I]="[v=\\s]*("+o[E]+")(?:\\.("+o[E]+")(?:\\.("+o[E]+")(?:"+o[h]+")?"+o[y]+"?)?)?";var S=s++;o[S]="^"+o[T]+"\\s*"+o[A]+"$";var x=s++;o[x]="^"+o[T]+"\\s*"+o[I]+"$";var k=s++;o[k]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var O=s++;o[O]="(?:~>?)";var P=s++;o[P]="(\\s*)"+o[O]+"\\s+",i[P]=new RegExp(o[P],"g");var R=s++;o[R]="^"+o[O]+o[A]+"$";var j=s++;o[j]="^"+o[O]+o[I]+"$";var D=s++;o[D]="(?:\\^)";var q=s++;o[q]="(\\s*)"+o[D]+"\\s+",i[q]=new RegExp(o[q],"g");var N=s++;o[N]="^"+o[D]+o[A]+"$";var U=s++;o[U]="^"+o[D]+o[I]+"$";var L=s++;o[L]="^"+o[T]+"\\s*("+_+")$|^$";var V=s++;o[V]="^"+o[T]+"\\s*("+v+")$|^$";var M=s++;o[M]="(\\s*)"+o[T]+"\\s*("+_+"|"+o[A]+")",i[M]=new RegExp(o[M],"g");var B=s++;o[B]="^\\s*("+o[A]+")\\s+-\\s+("+o[A]+")\\s*$";var F=s++;o[F]="^\\s*("+o[I]+")\\s+-\\s+("+o[I]+")\\s*$";var $=s++;o[$]="(<|>)?=?\\s*\\*";for(var H=0;H<35;H++)r(H,o[H]),i[H]||(i[H]=new RegExp(o[H]));function K(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof G)return e;if("string"!=typeof e)return null;if(e.length>256)return null;if(!(t.loose?i[b]:i[w]).test(e))return null;try{return new G(e,t)}catch(e){return null}}function G(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof G){if(e.loose===t.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof G))return new G(e,t);r("SemVer",e,t),this.options=t,this.loose=!!t.loose;var o=e.trim().match(t.loose?i[b]:i[w]);if(!o)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>n||this.major<0)throw new TypeError("Invalid major version");if(this.minor>n||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>n||this.patch<0)throw new TypeError("Invalid patch version");o[4]?this.prerelease=o[4].split(".").map((function(e){if(/^[0-9]+$/.test(e)){var t=+e;if(t>=0&&t=0;)"number"==typeof this.prerelease[r]&&(this.prerelease[r]++,r=-2);-1===r&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},t.inc=function(e,t,r,n){"string"==typeof r&&(n=r,r=void 0);try{return new G(e,r).inc(t,n).version}catch(e){return null}},t.diff=function(e,t){if(J(e,t))return null;var r=K(e),n=K(t),i="";if(r.prerelease.length||n.prerelease.length){i="pre";var o="prerelease"}for(var s in r)if(("major"===s||"minor"===s||"patch"===s)&&r[s]!==n[s])return i+s;return o},t.compareIdentifiers=X;var Q=/^[0-9]+$/;function X(e,t){var r=Q.test(e),n=Q.test(t);return r&&n&&(e=+e,t=+t),e===t?0:r&&!n?-1:n&&!r?1:e0}function W(e,t,r){return Y(e,t,r)<0}function J(e,t,r){return 0===Y(e,t,r)}function Z(e,t,r){return 0!==Y(e,t,r)}function ee(e,t,r){return Y(e,t,r)>=0}function te(e,t,r){return Y(e,t,r)<=0}function re(e,t,r,n){switch(t){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e===r;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e!==r;case"":case"=":case"==":return J(e,r,n);case"!=":return Z(e,r,n);case">":return z(e,r,n);case">=":return ee(e,r,n);case"<":return W(e,r,n);case"<=":return te(e,r,n);default:throw new TypeError("Invalid operator: "+t)}}function ne(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof ne){if(e.loose===!!t.loose)return e;e=e.value}if(!(this instanceof ne))return new ne(e,t);r("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ie?this.value="":this.value=this.operator+this.semver.version,r("comp",this)}t.rcompareIdentifiers=function(e,t){return X(t,e)},t.major=function(e,t){return new G(e,t).major},t.minor=function(e,t){return new G(e,t).minor},t.patch=function(e,t){return new G(e,t).patch},t.compare=Y,t.compareLoose=function(e,t){return Y(e,t,!0)},t.rcompare=function(e,t,r){return Y(t,e,r)},t.sort=function(e,r){return e.sort((function(e,n){return t.compare(e,n,r)}))},t.rsort=function(e,r){return e.sort((function(e,n){return t.rcompare(e,n,r)}))},t.gt=z,t.lt=W,t.eq=J,t.neq=Z,t.gte=ee,t.lte=te,t.cmp=re,t.Comparator=ne;var ie={};function oe(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof oe)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new oe(e.raw,t);if(e instanceof ne)return new oe(e.value,t);if(!(this instanceof oe))return new oe(e,t);if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError("Invalid SemVer Range: "+e);this.format()}function se(e){return!e||"x"===e.toLowerCase()||"*"===e}function ae(e,t,r,n,i,o,s,a,c,u,d,p,l){return((t=se(r)?"":se(n)?">="+r+".0.0":se(i)?">="+r+"."+n+".0":">="+t)+" "+(a=se(c)?"":se(u)?"<"+(+c+1)+".0.0":se(d)?"<"+c+"."+(+u+1)+".0":p?"<="+c+"."+u+"."+d+"-"+p:"<="+a)).trim()}function ce(e,t,n){for(var i=0;i0){var o=e[i].semver;if(o.major===t.major&&o.minor===t.minor&&o.patch===t.patch)return!0}return!1}return!0}function ue(e,t,r){try{t=new oe(t,r)}catch(e){return!1}return t.test(e)}function de(e,t,r,n){var i,o,s,a,c;switch(e=new G(e,n),t=new oe(t,n),r){case">":i=z,o=te,s=W,a=">",c=">=";break;case"<":i=W,o=ee,s=z,a="<",c="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(ue(e,t,n))return!1;for(var u=0;u=0.0.0")),p=p||e,l=l||e,i(e.semver,p.semver,n)?p=e:s(e.semver,l.semver,n)&&(l=e)})),p.operator===a||p.operator===c)return!1;if((!l.operator||l.operator===a)&&o(e,l.semver))return!1;if(l.operator===c&&s(e,l.semver))return!1}return!0}ne.prototype.parse=function(e){var t=this.options.loose?i[L]:i[V],r=e.match(t);if(!r)throw new TypeError("Invalid comparator: "+e);this.operator=r[1],"="===this.operator&&(this.operator=""),r[2]?this.semver=new G(r[2],this.options.loose):this.semver=ie},ne.prototype.toString=function(){return this.value},ne.prototype.test=function(e){return r("Comparator.test",e,this.options.loose),this.semver===ie||("string"==typeof e&&(e=new G(e,this.options)),re(e,this.operator,this.semver,this.options))},ne.prototype.intersects=function(e,t){if(!(e instanceof ne))throw new TypeError("a Comparator is required");var r;if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),""===this.operator)return r=new oe(e.value,t),ue(this.value,r,t);if(""===e.operator)return r=new oe(this.value,t),ue(e.semver,r,t);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),i=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),o=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=re(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),c=re(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||i||o&&s||a||c},t.Range=oe,oe.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(" ").trim()})).join("||").trim(),this.range},oe.prototype.toString=function(){return this.range},oe.prototype.parseRange=function(e){var t=this.options.loose;e=e.trim();var n=t?i[F]:i[B];e=e.replace(n,ae),r("hyphen replace",e),e=e.replace(i[M],"$1$2$3"),r("comparator trim",e,i[M]),e=(e=(e=e.replace(i[P],"$1~")).replace(i[q],"$1^")).split(/\s+/).join(" ");var o=t?i[L]:i[V],s=e.split(" ").map((function(e){return function(e,t){return r("comp",e,t),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){r("caret",e,t);var n=t.loose?i[U]:i[N];return e.replace(n,(function(t,n,i,o,s){var a;return r("caret",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a="0"===n?">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":">="+n+"."+i+".0 <"+(+n+1)+".0.0":s?(r("replaceCaret pr",s),a="0"===n?"0"===i?">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+"-"+s+" <"+(+n+1)+".0.0"):(r("no pr"),a="0"===n?"0"===i?">="+n+"."+i+"."+o+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+" <"+(+n+1)+".0.0"),r("caret return",a),a}))}(e,t)})).join(" ")}(e,t),r("caret",e),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){var n=t.loose?i[j]:i[R];return e.replace(n,(function(t,n,i,o,s){var a;return r("tilde",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a=">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":s?(r("replaceTilde pr",s),a=">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0"):a=">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0",r("tilde return",a),a}))}(e,t)})).join(" ")}(e,t),r("tildes",e),e=function(e,t){return r("replaceXRanges",e,t),e.split(/\s+/).map((function(e){return function(e,t){e=e.trim();var n=t.loose?i[x]:i[S];return e.replace(n,(function(t,n,i,o,s,a){r("xRange",e,t,n,i,o,s,a);var c=se(i),u=c||se(o),d=u||se(s);return"="===n&&d&&(n=""),c?t=">"===n||"<"===n?"<0.0.0":"*":n&&d?(u&&(o=0),s=0,">"===n?(n=">=",u?(i=+i+1,o=0,s=0):(o=+o+1,s=0)):"<="===n&&(n="<",u?i=+i+1:o=+o+1),t=n+i+"."+o+"."+s):u?t=">="+i+".0.0 <"+(+i+1)+".0.0":d&&(t=">="+i+"."+o+".0 <"+i+"."+(+o+1)+".0"),r("xRange return",t),t}))}(e,t)})).join(" ")}(e,t),r("xrange",e),e=function(e,t){return r("replaceStars",e,t),e.trim().replace(i[$],"")}(e,t),r("stars",e),e}(e,this.options)}),this).join(" ").split(/\s+/);return this.options.loose&&(s=s.filter((function(e){return!!e.match(o)}))),s=s.map((function(e){return new ne(e,this.options)}),this)},oe.prototype.intersects=function(e,t){if(!(e instanceof oe))throw new TypeError("a Range is required");return this.set.some((function(r){return r.every((function(r){return e.set.some((function(e){return e.every((function(e){return r.intersects(e,t)}))}))}))}))},t.toComparators=function(e,t){return new oe(e,t).set.map((function(e){return e.map((function(e){return e.value})).join(" ").trim().split(" ")}))},oe.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new G(e,this.options));for(var t=0;t":0===t.prerelease.length?t.patch++:t.prerelease.push(0),t.raw=t.format();case"":case">=":r&&!z(r,t)||(r=t);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+e.operator)}}))}if(r&&e.test(r))return r;return null},t.validRange=function(e,t){try{return new oe(e,t).range||"*"}catch(e){return null}},t.ltr=function(e,t,r){return de(e,t,"<",r)},t.gtr=function(e,t,r){return de(e,t,">",r)},t.outside=de,t.prerelease=function(e,t){var r=K(e,t);return r&&r.prerelease.length?r.prerelease:null},t.intersects=function(e,t,r){return e=new oe(e,r),t=new oe(t,r),e.intersects(t)},t.coerce=function(e){if(e instanceof G)return e;if("string"!=typeof e)return null;var t=e.match(i[k]);if(null==t)return null;return K(t[1]+"."+(t[2]||"0")+"."+(t[3]||"0"))}})),vt=(wt.SEMVER_SPEC_VERSION,wt.re,wt.src,wt.parse,wt.valid,wt.clean,wt.SemVer,wt.inc,wt.diff,wt.compareIdentifiers,wt.rcompareIdentifiers,wt.major,wt.minor,wt.patch,wt.compare,wt.compareLoose,wt.rcompare,wt.sort,wt.rsort,wt.gt,wt.lt,wt.eq,wt.neq,wt.gte,wt.lte,wt.cmp,wt.Comparator,wt.Range,wt.toComparators,wt.satisfies,wt.maxSatisfying,wt.minSatisfying,wt.minVersion,wt.validRange,wt.ltr,wt.gtr,wt.outside,wt.prerelease,wt.intersects,wt.coerce,wt.satisfies(process.version,"^6.12.0 || >=8.0.0")),_t=["RS256","RS384","RS512","ES256","ES384","ES512"],bt=["RS256","RS384","RS512"],Tt=["HS256","HS384","HS512"];vt&&(_t.splice(3,0,"PS256","PS384","PS512"),bt.splice(3,0,"PS256","PS384","PS512"));var Et=/^\s+|\s+$/g,Ct=/^[-+]0x[0-9a-f]+$/i,At=/^0b[01]+$/i,It=/^0o[0-7]+$/i,St=/^(?:0|[1-9]\d*)$/,xt=parseInt;function kt(e){return e!=e}function Ot(e,t){return function(e,t){for(var r=-1,n=e?e.length:0,i=Array(n);++r-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991}(e.length)&&!function(e){var t=Ht(e)?qt.call(e):"";return"[object Function]"==t||"[object GeneratorFunction]"==t}(e)}function Ht(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function Kt(e){return!!e&&"object"==typeof e}var Gt=function(e,t,r,n){var i;e=$t(e)?e:(i=e)?Ot(i,function(e){return $t(e)?Vt(e):Mt(e)}(i)):[],r=r&&!n?function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||Kt(e)&&"[object Symbol]"==qt.call(e)}(e))return NaN;if(Ht(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Ht(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Et,"");var r=At.test(e);return r||It.test(e)?xt(e.slice(2),r?2:8):Ct.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(r):0;var o=e.length;return r<0&&(r=Lt(o+r,0)),function(e){return"string"==typeof e||!Ft(e)&&Kt(e)&&"[object String]"==qt.call(e)}(e)?r<=o&&e.indexOf(t,r)>-1:!!o&&function(e,t,r){if(t!=t)return function(e,t,r,n){for(var i=e.length,o=r+(n?1:-1);n?o--:++o-1},Qt=Object.prototype.toString;var Xt=function(e){return!0===e||!1===e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Boolean]"==Qt.call(e)},Yt=/^\s+|\s+$/g,zt=/^[-+]0x[0-9a-f]+$/i,Wt=/^0b[01]+$/i,Jt=/^0o[0-7]+$/i,Zt=parseInt,er=Object.prototype.toString;function tr(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var rr=function(e){return"number"==typeof e&&e==function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==er.call(e)}(e))return NaN;if(tr(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=tr(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Yt,"");var r=Wt.test(e);return r||Jt.test(e)?Zt(e.slice(2),r?2:8):zt.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e)},nr=Object.prototype.toString;var ir=function(e){return"number"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Number]"==nr.call(e)};var or=Function.prototype,sr=Object.prototype,ar=or.toString,cr=sr.hasOwnProperty,ur=ar.call(Object),dr=sr.toString,pr=function(e,t){return function(r){return e(t(r))}}(Object.getPrototypeOf,Object);var lr=function(e){if(!function(e){return!!e&&"object"==typeof e}(e)||"[object Object]"!=dr.call(e)||function(e){var t=!1;if(null!=e&&"function"!=typeof e.toString)try{t=!!(e+"")}catch(e){}return t}(e))return!1;var t=pr(e);if(null===t)return!0;var r=cr.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&ar.call(r)==ur},fr=Object.prototype.toString,mr=Array.isArray;var hr=function(e){return"string"==typeof e||!mr(e)&&function(e){return!!e&&"object"==typeof e}(e)&&"[object String]"==fr.call(e)},gr=/^\s+|\s+$/g,yr=/^[-+]0x[0-9a-f]+$/i,wr=/^0b[01]+$/i,vr=/^0o[0-7]+$/i,_r=parseInt,br=Object.prototype.toString;function Tr(e,t){var r;if("function"!=typeof t)throw new TypeError("Expected a function");return e=function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==br.call(e)}(e))return NaN;if(Er(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Er(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(gr,"");var r=wr.test(e);return r||vr.test(e)?_r(e.slice(2),r?2:8):yr.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e),function(){return--e>0&&(r=t.apply(this,arguments)),e<=1&&(t=void 0),r}}function Er(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var Cr=function(e){return Tr(2,e)},Ar=["RS256","RS384","RS512","ES256","ES384","ES512","HS256","HS384","HS512","none"];vt&&Ar.splice(3,0,"PS256","PS384","PS512");var Ir={expiresIn:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"expiresIn" should be a number of seconds or string representing a timespan'},notBefore:{isValid:function(e){return rr(e)||hr(e)&&e},message:'"notBefore" should be a number of seconds or string representing a timespan'},audience:{isValid:function(e){return hr(e)||Array.isArray(e)},message:'"audience" must be a string or array'},algorithm:{isValid:Gt.bind(null,Ar),message:'"algorithm" must be a valid string enum value'},header:{isValid:lr,message:'"header" must be an object'},encoding:{isValid:hr,message:'"encoding" must be a string'},issuer:{isValid:hr,message:'"issuer" must be a string'},subject:{isValid:hr,message:'"subject" must be a string'},jwtid:{isValid:hr,message:'"jwtid" must be a string'},noTimestamp:{isValid:Xt,message:'"noTimestamp" must be a boolean'},keyid:{isValid:hr,message:'"keyid" must be a string'},mutatePayload:{isValid:Xt,message:'"mutatePayload" must be a boolean'}},Sr={iat:{isValid:ir,message:'"iat" should be a number of seconds'},exp:{isValid:ir,message:'"exp" should be a number of seconds'},nbf:{isValid:ir,message:'"nbf" should be a number of seconds'}};function xr(e,t,r,n){if(!lr(r))throw new Error('Expected "'+n+'" to be a plain object.');Object.keys(r).forEach((function(i){var o=e[i];if(o){if(!o.isValid(r[i]))throw new Error(o.message)}else if(!t)throw new Error('"'+i+'" is not allowed in "'+n+'"')}))}var kr={audience:"aud",issuer:"iss",subject:"sub",jwtid:"jti"},Or=["expiresIn","notBefore","noTimestamp","audience","issuer","subject","jwtid"],Pr=function(e,t,r,n){var i;if("function"!=typeof r||n||(n=r,r={}),r||(r={}),r=Object.assign({},r),i=n||function(e,t){if(e)throw e;return t},r.clockTimestamp&&"number"!=typeof r.clockTimestamp)return i(new st("clockTimestamp must be a number"));if(void 0!==r.nonce&&("string"!=typeof r.nonce||""===r.nonce.trim()))return i(new st("nonce must be a non-empty string"));var o=r.clockTimestamp||Math.floor(Date.now()/1e3);if(!e)return i(new st("jwt must be provided"));if("string"!=typeof e)return i(new st("jwt must be a string"));var s,a=e.split(".");if(3!==a.length)return i(new st("jwt malformed"));try{s=it(e,{complete:!0})}catch(e){return i(e)}if(!s)return i(new st("invalid token"));var c,u=s.header;if("function"==typeof t){if(!n)return i(new st("verify must be called asynchronous if secret or public key is provided as a callback"));c=t}else c=function(e,r){return r(null,t)};return c(u,(function(t,n){if(t)return i(new st("error in secret or public key callback: "+t.message));var c,d=""!==a[2].trim();if(!d&&n)return i(new st("jwt signature is required"));if(d&&!n)return i(new st("secret or public key must be provided"));if(d||r.algorithms||(r.algorithms=["none"]),r.algorithms||(r.algorithms=~n.toString().indexOf("BEGIN CERTIFICATE")||~n.toString().indexOf("BEGIN PUBLIC KEY")?_t:~n.toString().indexOf("BEGIN RSA PUBLIC KEY")?bt:Tt),!~r.algorithms.indexOf(s.header.alg))return i(new st("invalid algorithm"));try{c=nt.verify(e,s.header.alg,n)}catch(e){return i(e)}if(!c)return i(new st("invalid signature"));var p=s.payload;if(void 0!==p.nbf&&!r.ignoreNotBefore){if("number"!=typeof p.nbf)return i(new st("invalid nbf value"));if(p.nbf>o+(r.clockTolerance||0))return i(new ct("jwt not active",new Date(1e3*p.nbf)))}if(void 0!==p.exp&&!r.ignoreExpiration){if("number"!=typeof p.exp)return i(new st("invalid exp value"));if(o>=p.exp+(r.clockTolerance||0))return i(new dt("jwt expired",new Date(1e3*p.exp)))}if(r.audience){var l=Array.isArray(r.audience)?r.audience:[r.audience];if(!(Array.isArray(p.aud)?p.aud:[p.aud]).some((function(e){return l.some((function(t){return t instanceof RegExp?t.test(e):t===e}))})))return i(new st("jwt audience invalid. expected: "+l.join(" or ")))}if(r.issuer&&("string"==typeof r.issuer&&p.iss!==r.issuer||Array.isArray(r.issuer)&&-1===r.issuer.indexOf(p.iss)))return i(new st("jwt issuer invalid. expected: "+r.issuer));if(r.subject&&p.sub!==r.subject)return i(new st("jwt subject invalid. expected: "+r.subject));if(r.jwtid&&p.jti!==r.jwtid)return i(new st("jwt jwtid invalid. expected: "+r.jwtid));if(r.nonce&&p.nonce!==r.nonce)return i(new st("jwt nonce invalid. expected: "+r.nonce));if(r.maxAge){if("number"!=typeof p.iat)return i(new st("iat required when maxAge is specified"));var f=yt(r.maxAge,p.iat);if(void 0===f)return i(new st('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));if(o>=f+(r.clockTolerance||0))return i(new dt("maxAge exceeded",new Date(1e3*f)))}if(!0===r.complete){var m=s.signature;return i(null,{header:u,payload:p,signature:m})}return i(null,p)}))},Rr=function(e,t,r,n){"function"==typeof r?(n=r,r={}):r=r||{};var i="object"==typeof e&&!Buffer.isBuffer(e),o=Object.assign({alg:r.algorithm||"HS256",typ:i?"JWT":void 0,kid:r.keyid},r.header);function s(e){if(n)return n(e);throw e}if(!t&&"none"!==r.algorithm)return s(new Error("secretOrPrivateKey must have a value"));if(void 0===e)return s(new Error("payload is required"));if(i){try{!function(e){xr(Sr,!0,e,"payload")}(e)}catch(e){return s(e)}r.mutatePayload||(e=Object.assign({},e))}else{var a=Or.filter((function(e){return void 0!==r[e]}));if(a.length>0)return s(new Error("invalid "+a.join(",")+" option for "+typeof e+" payload"))}if(void 0!==e.exp&&void 0!==r.expiresIn)return s(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));if(void 0!==e.nbf&&void 0!==r.notBefore)return s(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));try{!function(e){xr(Ir,!1,e,"options")}(r)}catch(e){return s(e)}var c=e.iat||Math.floor(Date.now()/1e3);if(r.noTimestamp?delete e.iat:i&&(e.iat=c),void 0!==r.notBefore){try{e.nbf=yt(r.notBefore,c)}catch(e){return s(e)}if(void 0===e.nbf)return s(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}if(void 0!==r.expiresIn&&"object"==typeof e){try{e.exp=yt(r.expiresIn,c)}catch(e){return s(e)}if(void 0===e.exp)return s(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}Object.keys(kr).forEach((function(t){var n=kr[t];if(void 0!==r[t]){if(void 0!==e[n])return s(new Error('Bad "options.'+t+'" option. The payload already has an "'+n+'" property.'));e[n]=r[t]}}));var u=r.encoding||"utf8";if("function"!=typeof n)return nt.sign({header:o,payload:e,secret:t,encoding:u});n=n&&Cr(n),nt.createSign({header:o,privateKey:t,payload:e,encoding:u}).once("error",n).once("done",(function(e){n(null,e)}))};let jr=[];class Dr{constructor(e){this.options=Object.assign({baseUrl:"https://appleid.apple.com",timeout:1e4},e)}async _fetch(e,t){const{baseUrl:r}=this.options;return uniCloud.httpclient.request(r+e,t)}async verifyIdentityToken(e){const t=e.split(".")[0],{kid:r}=JSON.parse(Buffer.from(t,"base64").toString());if(!jr.length)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}const n=this.getUsedKey(jr,r);if(!Object.keys(n).length&&!this.fetched)try{jr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}let i=null;try{i=Pr(e,function(e,t){var r=Buffer.from(e,"base64"),n=Buffer.from(t,"base64"),i=r.toString("hex"),o=n.toString("hex");i=J(i),o=J(o);var s=i.length/2,a=o.length/2,c=ee(s),u=ee(a),d="30"+ee(s+a+c.length/2+u.length/2+2)+"02"+c+i+"02"+u+o;return"-----BEGIN RSA PUBLIC KEY-----\n"+Buffer.from(d,"hex").toString("base64").match(/.{1,64}/g).join("\n")+"\n-----END RSA PUBLIC KEY-----\n"}(n.n,n.e),{algorithms:n.alg})}catch(e){return{code:10705,msg:e.message}}return{code:0,msg:i}}async getAuthKeys(){const{status:e,data:t}=await this._fetch("/auth/keys",{method:"GET",dataType:"json",timeout:this.options.timeout});if(200!==e)throw new Error("request https://appleid.apple.com/auth/keys fail");return t.keys}getUsedKey(e,t){let r={};for(let n=0;nvoid 0===e))return{code:N,messageValues:{param:this.t("dcloud-appid")}};const r=await P.doc(e).get(),n=r&&r.data&&r.data[0];if(!n)return{code:10002};const i=Object.keys(q).reduce((e,t)=>{const r=t,i=function(e,t){return t.split(".").reduce((e,t)=>e&&e[t],e)}(n,t);return i&&e.push({[r]:i}),e},[]);let o;const s={dcloud_appid:Mr.in(t),_id:Mr.neq(n._id)},a={dcloud_appid:Mr.exists(!1),_id:Mr.neq(n._id)};switch(i.length){case 0:return{code:10004};case 1:o=Mr.or([Mr.and([i[0],s]),Mr.and([i[0],a])]);break;default:o=Mr.or([Mr.and([Mr.or(i),s]),Mr.and([Mr.or(i),a])])}const c=await P.where(o).limit(1).get();return c&&c.data&&c.data[0]?{code:10005}:{code:0}}const Fr=uniCloud.database().command;const $r=uniCloud.database();const Hr=uniCloud.database();const Kr=uniCloud.database();async function Gr(e){const t=["apiKey","apiSecret"];for(let r=0,n=t.length;r0){u=a.and(a.or(c),a.or({dcloud_appid:a.in(s)},{dcloud_appid:a.exists(!1)}));if((await P.where(u).limit(1).get()).data.length>0)return{code:10201,messageValues:{type:this.t("username")}}}const d={role:o,nickname:t,dcloud_appid:s,register_date:Date.now()};if(e&&(d.username=e),r){const{passwordHash:e,version:t}=this.encryptPwd(r);d.password=e,t&&(d.password_secret_version=t)}return n&&(d.mobile=n,d.mobile_confirmed=1),i&&(d.email=i,d.email_confirmed=1),{code:0,uid:(await P.add(d)).id}},getUserInfo:async function({uid:e,field:t}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};let r;if(t&&t.length){const n={};for(let e=0;evoid 0===e.dcloud_appid||e.dcloud_appid.includes(this.context.APPID));if(0===i.length)return{code:10002};if(i.length>1)return{code:10005};const o=i[0]._id;return this.resetPwd({uid:o,password:r})},setAvatar:async function(e){return await P.doc(e.uid).update({avatar:e.avatar}),{code:0,msg:""}},updatePwd:async function(e){const t=await P.doc(e.uid).get();if(t&&t.data&&t.data.length>0){if(0===this._checkPwd(t.data[0],e.oldPassword).code){const{passwordHash:r,version:n}=this.encryptPwd(e.newPassword),i={password:r,token:[]};n&&(i.password_secret_version=n);return E("upRes",await P.doc(t.data[0]._id).update(i)),{code:0,msg:""}}return{code:40202}}return{code:40201}},updateUser:async function(e){const t=e.uid;if(!t)return{code:N,messageValues:{param:this.t("user-id")}};delete e.uid;const{username:r,email:n}=e,{usernameToLowerCase:i,emailToLowerCase:o}=this._getConfig();let s=r&&r.trim(),a=n&&n.trim();return s&&(i&&(s=s.toLowerCase()),e.username=s),a&&(o&&(a=a.toLowerCase()),e.email=a),E("update -> upRes",await P.doc(t).update(e)),{code:0,msg:""}},banAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:B})},unbanAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},closeAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:F})},openAccount:async function({uid:e}={}){return $.call(this,{uid:e,status:M})},_getAlipayApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.alipay)throw new Error(this.t("config-param-require",{param:e+".alipay"}));return["appid","privateKey"].forEach(r=>{if(!t.oauth.alipay[r])throw new Error(this.t("config-param-require",{param:`${e}.alipay.${r}`}))}),Ur({...t.oauth.alipay})},_getValidInviteCode:async function({inviteCode:e}){let t,r=10;e?(r=1,t=e):t=Vr();let n=!1;try{for(;r>0&&!n;){r--;if(0===(await P.where({my_invite_code:t}).get()).data.length){n=!0;break}t=Vr()}t=Vr()}catch(e){}return n?{code:0,inviteCode:t}:e?{code:80401}:{code:80402}},_addUser:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const n=this._getConfig(),i={...e,dcloud_appid:r?[this.context.APPID]:[],register_date:Date.now()},o=(await P.add(i)).id;let s;if(n.removePermissionAndRoleFromToken)s=await this.createToken({uid:o,needPermission:t});else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),s=await this.createToken({uid:o,role:t,permission:r})}const{token:a,tokenExpired:c}=s;return await P.doc(o).update({token:[a]}),{token:a,tokenExpired:c,uid:o,type:"register",userInfo:Object.assign({},i,{token:[a]})}},_loginExec:async function(e,t={}){if(e.status===B)return{code:10001};if(e.status===F)return{code:10006};const r=this._getConfig();let n=e.token||[];"string"==typeof n&&(n=[n]);const i=this._getExpiredToken(n);let o;if(n=n.filter(e=>-1===i.indexOf(e)),r.removePermissionAndRoleFromToken){const r=t.needPermission;o=await this.createToken({uid:e._id,needPermission:r})}else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),o=await this.createToken({uid:e._id,role:t,permission:r})}const{token:s,tokenExpired:a}=o;n.push(s),e.token=n;const c={last_login_date:Date.now(),last_login_ip:this.context.CLIENTIP,token:n,...t.extraData};await P.doc(e._id).update(c);const u=Object.assign({},e,c);return{code:0,msg:"",token:s,uid:u._id,username:u.username,type:"login",userInfo:u,tokenExpired:a}},_registerExec:async function(e,{needPermission:t,autoSetDcloudAppid:r=!0}={}){const{my_invite_code:n}=e;if(this._getConfig().autoSetInviteCode||n){const t=await this._getValidInviteCode({inviteCode:n});if(t.code)return t;e.my_invite_code=t.inviteCode}const{PLATFORM:i,appId:o,appid:s,APPID:a,uniPlatform:c,appName:u,appVersion:d,appVersionCode:p,channel:l,clientIP:f,CLIENTIP:m,OS:h,osName:g}=this.context;return e.register_env={appid:o||s||a||"",uni_platform:c||i||"",os_name:g||h||"",app_name:u||"",app_version:d||"",app_version_code:p||"",channel:l?l+"":"",client_ip:f||m||""},{code:0,msg:"",...await this._addUser(e,{needPermission:t,autoSetDcloudAppid:r})}},_getWeixinApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.weixin)throw new Error(this.t("config-param-require",{param:e+".weixin"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.weixin[r])throw new Error(this.t("config-param-require",{param:`${e}.weixin.${r}`}))}),qr({...t.oauth.weixin})},_getQQApi:function(){const e=this.context.PLATFORM,t=this._getConfig();if(!t.oauth||!t.oauth.qq)throw new Error(this.t("config-param-require",{param:e+".qq"}));return["appid","appsecret"].forEach(r=>{if(!t.oauth.qq[r])throw new Error(this.t("config-param-require",{param:`${e}.qq.${r}`}))}),Nr({...t.oauth.qq})},_getMatchedUser:function(e,t){if(0===e.length)return{code:10002};let r;const n={},i={};for(let r=e.length-1;r>=0;r--){const o=e[r];for(let s=0;s0?{code:10003,messageValues:{target:"用户"}}:{code:0,msg:"",userMatched:r,fieldMatched:s,isFallbackValueMatched:!!s&&i[s]}},_getCurrentAppUser:function(e){const t=this.context.APPID;return e.filter(e=>void 0===e.dcloud_appid||null===e.dcloud_appid||e.dcloud_appid.indexOf(t)>-1||e.dcloud_appid.indexOf(null)>-1)},_checkLoginUserList:function(e){if(e&&1!==e.length)return e[0].status===F?{code:10006}:{code:10005}},setAuthorizedAppLogin:async function({uid:e,dcloudAppidList:t}={}){if("array"!==m(t))return{code:U,messageValues:{param:"dcloudAppidList",reason:this.t("type-array-required",{param:this.t("dcloud-appid-list")})}};if(t&&0!==t.length){const r=await Br.bind(this)({uid:e,dcloudAppidList:t});if(r.code)return r}return await P.doc(e).update({dcloud_appid:Mr.set(t)}),{code:0}},authorizeAppLogin:async function({uid:e,dcloudAppid:t}={}){const r=await Br.bind(this)({uid:e,dcloudAppidList:[t]});return r.code?r:(await P.doc(e).update({dcloud_appid:Mr.push(t)}),{code:0})},forbidAppLogin:async function({uid:e,dcloudAppid:t}={}){return e?(await P.doc(e).update({dcloud_appid:Mr.pull(t)}),{code:0}):{code:N,messageValues:{param:this.t("user-id")}}},acceptInvite:async function({uid:e,inviteCode:t}){const r=await P.where({_id:Fr.neq(e),inviter_uid:Fr.not(Fr.all([e])),my_invite_code:t}).get();if(1!==r.data.length)return{code:80501,msg:"邀请码无效"};const n=[r.data[0]._id].concat(r.data[0].inviter_uid||[]),i=await P.doc(e).field({my_invite_code:!0,inviter_uid:!0}).get();if(0===i.data.length)return{code:80502};if(i.data[0].inviter_uid&&i.data[0].inviter_uid.length>0)return{code:80503,msg:"邀请码不可修改"};const o=Date.now();return await P.doc(e).update({inviter_uid:n,invite_time:o}),await P.where({inviter_uid:e}).update({inviter_uid:Fr.push(n)}),{code:0,msg:""}},getInvitedUser:async function({uid:e,level:t=1,limit:r=20,offset:n=0,needTotal:i=!1}){const o={code:0,msg:"",invitedUser:(await P.where({["inviter_uid."+(t-1)]:e}).field({_id:!0,username:!0,mobile:!0,invite_time:!0}).orderBy("invite_time","desc").skip(n).limit(r).get()).data};if(i){const r=await P.where({["inviter_uid."+(t-1)]:e}).count();o.total=r.total}return o},setUserInviteCode:async function({uid:e,myInviteCode:t}){const r=await this._getValidInviteCode({inviteCode:t});return r.code?r:(await P.doc(e).update({my_invite_code:r.inviteCode}),{code:0,msg:"",myInviteCode:r.inviteCode})},loginByAlipay:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,code:r,myInviteCode:n,role:i,type:o}=e,{openid:s}=await this._getAlipayApi().code2Session(r);if(!s)return{code:10501,messageValues:{account:this.t("alipay-account")}};let a=await P.where({ali_openid:s}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0){if("register"===o)return{code:10502,messageValues:{type:this.t("alipay-account")}};if(1!==a.length)return{code:10005};const e=a[0],r=await this._loginExec(e,{needPermission:t});if(0!==r.code)return r;const{userInfo:n}=r;return{...r,openid:s,mobileConfirmed:1===n.mobile_confirmed,emailConfirmed:1===n.email_confirmed}}{if("login"===o)return{code:10503,messageValues:{type:this.t("alipay-account")}};const e={ali_openid:s};e.my_invite_code=n,e.role=i;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:s,mobileConfirmed:!1,emailConfirmed:!1}}},loginByEmail:async function(e){let{email:t,code:r,password:n,myInviteCode:i,type:o,needPermission:s,role:a}=e||{};if(t=t&&t.trim(),!t)return{code:N,messageValues:{param:"邮箱"}};const{emailToLowerCase:c}=this._getConfig();let u=t;c&&(u=t.toLowerCase());const d=await this.verifyCode({email:u,code:r,type:o||"login"});if(0!==d.code)return d;let p={email:t,email_confirmed:1};const l={field:"email",value:t},f=$r.command;u!==t&&(p=f.or(p,{email:u,email_confirmed:1}),l.fallbackValue=u);let m=await P.where(p).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10301,messageValues:{type:"邮箱"}};const e=this._getMatchedUser(m,[l]);if(e.code)return e;const{userMatched:t}=e,r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,email:u}}{if("login"===o)return{code:10302,messageValues:{type:"邮箱"}};const e={email:u,email_confirmed:1},t=n&&n.trim();if(t){const{passwordHash:r,version:n}=this.encryptPwd(t);e.password=r,n&&(e.password_secret_version=n)}e.my_invite_code=i,e.role=a;const r=await this._registerExec(e,{needPermission:s});return 0!==r.code?r:{...r,email:u}}},loginBySms:async function({mobile:e,code:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){if(!(e=e&&e.trim()))return{code:N,messageValues:{param:this.t("mobile")}};const c=this._getConfig();if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const u=await this.verifyCode({mobile:e,code:t,type:o||"login"});if(0!==u.code)return u;const d={mobile:e,mobile_confirmed:1};let p=await P.where(d).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0){if("register"===o)return{code:10201,messageValues:{type:this.t("mobile")}};if(1!==p.length)return{code:10005};const t=p[0],r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,mobile:e}}{const t=Date.now();if("login"===o)return{code:10202,messageValues:{type:this.t("mobile")}};const u={mobile:e,mobile_confirmed:1,register_ip:this.context.CLIENTIP,register_date:t},d=r&&r.trim();if(d){const{passwordHash:e,version:t}=this.encryptPwd(d);u.password=e,t&&(u.password_secret_version=t)}if(n){const e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};u.inviter_uid=[e.data[0]._id].concat(e.data[0].inviter_uid||[]),u.invite_time=t}else if(c.forceInviteCode)return{code:10203};u.my_invite_code=i,u.role=a;const p=await this._registerExec(u,{needPermission:s});return 0!==p.code?p:{...p,mobile:e}}},loginByWeixin:async function(e){"string"==typeof e&&(e={code:e});const{needPermission:t,platform:r,code:n,myInviteCode:i,role:o,type:s}=e,a=r||this.context.PLATFORM,c="mp-weixin"===a,{openid:u,unionid:d,sessionKey:p,accessToken:l,refreshToken:f,expired:m}=await this._getWeixinApi()[c?"code2Session":"getOauthAccessToken"](n);if(!u)return{code:10401,messageValues:{account:"微信openid"}};let h;h=c?{sessionKey:p}:{accessToken:l,refreshToken:f,accessTokenExpired:m};const g=Hr.command,y=[{wx_openid:{[a]:u}}];d&&y.push({wx_unionid:d});let w=await P.where(g.or(...y)).get();if(w=this._getCurrentAppUser(w.data),w&&w.length>0){if("register"===s)return{code:10402,messageValues:{type:this.t("wechat-account")}};if(1!==w.length)return{code:10005};const e=w[0],r={wx_openid:{[a]:u}};d&&(r.wx_unionid=d);const n=await this._loginExec(e,{needPermission:t,extraData:r});if(0!==n.code)return n;const{userInfo:i}=n;return{...n,openid:u,unionid:d,...h,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===s)return{code:10403,messageValues:{type:this.t("wechat-account")}};const e={wx_openid:{[a]:u},wx_unionid:d};e.my_invite_code=i,e.role=o;const r=await this._registerExec(e,{needPermission:t});return 0!==r.code?r:{...r,openid:u,unionid:d,...h,mobileConfirmed:!1,emailConfirmed:!1}}},loginByQQ:async function({code:e,accessToken:t,myInviteCode:r,needPermission:n,role:i,type:o}={}){const s=this.context.PLATFORM,a="mp-qq"===s,{openid:c,unionid:u,sessionKey:d}=await this._getQQApi()[a?"code2Session":"getOpenidByToken"]({code:e,accessToken:t});if(!c)return{code:10801,messageValues:{account:"qq openid"}};const p={accessToken:t,sessionKey:d},l=Kr.command,f=[{qq_openid:{[s]:c}}];u&&f.push({qq_unionid:u});let m=await P.where(l.or(...f)).get();if(m=this._getCurrentAppUser(m.data),m&&m.length>0){if("register"===o)return{code:10802,messageValues:{type:this.t("qq-account")}};if(1!==m.length)return{code:10005};const e=m[0],t={qq_openid:{[s]:c}};u&&(t.qq_unionid=u);const r=await this._loginExec(e,{needPermission:n,extraData:t});if(0!==r.code)return r;const{userInfo:i}=r;return{...r,openid:c,unionid:u,...p,mobileConfirmed:1===i.mobile_confirmed,emailConfirmed:1===i.email_confirmed}}{if("login"===o)return{code:10803,messageValues:{type:this.t("qq-account")}};const e={qq_openid:{[s]:c},qq_unionid:u};e.my_invite_code=r,e.role=i;const t=await this._registerExec(e);return 0!==t.code?t:{...t,openid:c,unionid:u,...p,mobileConfirmed:!1,emailConfirmed:!1}}},loginByUniverify:async function({openid:e,access_token:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){const c=this._getConfig(),u=c&&c.service&&c.service.univerify;if(!u)throw new Error(this.t("uni-verify-config-required"));if(c.forceInviteCode&&!o)throw new Error(this.t("login-with-invite-type-required"));const d=await Gr.bind(this)({...u,openid:e,access_token:t});if(0!==d.code)return d;const p=String(d.phoneNumber);let l=await P.where({mobile:p,mobile_confirmed:1}).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){if("register"===o)return{code:10601,messageValues:{type:this.t("mobile")}};if(1!==l.length)return{code:10005};const e=l[0],t=await this._loginExec(e,{needPermission:s});return 0!==t.code?t:{...t,mobile:p}}if("login"===o)return{code:10602,messageValues:{type:this.t("mobile")}};const f=Date.now(),m={mobile:p,my_invite_code:i,mobile_confirmed:1,role:a},h=r&&r.trim();if(h){const{passwordHash:e,version:t}=this.encryptPwd(h);m.password=e,t&&(m.password_secret_version=t)}if(n){let e=await P.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10203};e=e.data[0],m.inviter_uid=[e._id].concat(e.inviter_uid||[]),m.invite_time=f}else if(c.forceInviteCode)return{code:10203};m.my_invite_code=i;const g=await this._registerExec(m,{needPermission:s});return 0!==g.code?g:{...g,mobile:p}},loginByApple:async function({nickName:e,fullName:t,identityToken:r,myInviteCode:n,type:i,needPermission:o,role:s}){const a=this._getConfig(),c=a&&a.oauth&&a.oauth.apple,u=c&&c.bundleId;if(!u)throw new Error(this.t("config-param-require",{param:"(app || app-plus).apple.bundleId"}));if(!r)return{code:N,messageValues:{param:"identityToken"}};t=e||(t&&Object.keys(t).length>0?t.familyName+t.givenName:"");const{code:d,msg:p}=await Lr().verifyIdentityToken(r);if(0!==d)return{code:d,msg:p,messageValues:{account:this.t("apple-account")}};const{iss:l,sub:f,aud:m,email:h}=p;if("https://appleid.apple.com"!==l)return{code:10706,messageValues:{account:this.t("apple-account")}};if(!f)return{code:10701,messageValues:{account:this.t("apple-account")}};if(u!==m)return{code:10702,messageValues:{account:this.t("apple-account")}};const g=t||"User-"+(h?h.split("@")[0]:Math.random().toString(32).slice(2));let y=await P.where({apple_openid:f}).get();if(y=this._getCurrentAppUser(y.data),y&&y.length>0){if("register"===i)return{code:10703,messageValues:{type:this.t("apple-account")}};if(1!==y.length)return{code:10005};const e=y[0],t=await this._loginExec(e,{needPermission:o});return 0!==t.code?t:{...t,openid:f}}if("login"===i)return{code:10704,messageValues:{type:this.t("apple-account")}};const w={nickname:g,apple_openid:f,my_invite_code:n,role:s},v=await this._registerExec(w,{needPermission:o});return 0!==v.code?v:{...v,openid:f}},login:async function({username:e,password:t,queryField:r=[],needPermission:n}){const i=Qr.command,o=[];r&&r.length||(r=["username"]),r.length>1&&console.warn(this.t("query-field-warning"));const{usernameToLowerCase:s,emailToLowerCase:a,passwordErrorLimit:c,passwordErrorRetryTime:u}=this._getConfig(),d={email:{email_confirmed:1},mobile:{mobile_confirmed:1}},p={},l=e&&e.trim();if(!l)return{code:N,messageValues:{param:this.t("username")}};s&&(p.username=l.toLowerCase()),a&&(p.email=l.toLowerCase());const f=[];r.forEach(t=>{o.push({[t]:e,...d[t]});const r={field:t,value:e};"username"===t&&p.username!==e?(o.push({[t]:p.username,...d[t]}),r.fallbackValue=p.username):"email"===t&&p.email!==e&&(o.push({[t]:p.email,...d[t]}),r.fallbackValue=p.email),f.push(r)});let m=await P.where(i.or(...o)).get();m=this._getCurrentAppUser(m.data);const h=this.context.CLIENTIP,g=this._getMatchedUser(m,f);if(g.code)return g;const{userMatched:y}=g;let w=y.login_ip_limit||[];w=w.filter(e=>e.last_error_time>Date.now()-1e3*u);let v=w.find(e=>e.ip===h);if(v&&v.error_times>=c)return{code:10103};const _=t&&t.trim();if(!_)return{code:N,messageValues:{param:"密码"}};const b=this._checkPwd(y,_);if(0===b.code){const e=w.indexOf(v);e>-1&&w.splice(e,1);const t={login_ip_limit:w},{passwordHash:r,passwordVersion:i}=b;r&&i&&(t.password=r,t.password_secret_version=i);const o=await this._loginExec(y,{needPermission:n,extraData:t});return o.code,o}return v?(v.error_times++,v.last_error_time=Date.now()):(v={ip:h,error_times:1,last_error_time:Date.now()},w.push(v)),await P.doc(y._id).update({login_ip_limit:w}),{code:10102,msg:"密码错误"}},register:async function(e){const t=[],r=[{name:"username",desc:this.t("username")},{name:"email",desc:this.t("email"),extraCond:{email_confirmed:1}},{name:"mobile",desc:this.t("mobile"),extraCond:{mobile_confirmed:1}}],{usernameToLowerCase:n,emailToLowerCase:i}=this._getConfig();r.forEach(r=>{const o=r.name;let s=e[o]&&e[o].trim();s?(("username"===r.name&&n||"email"===r.name&&i)&&(s=s.toLowerCase()),e[o]=s,t.push({[o]:s,...r.extraCond})):delete e[o]});const{username:o,email:s,mobile:a,myInviteCode:c,needPermission:u,autoSetDcloudAppid:d=!0}=e;if("needPermission"in e&&delete e.needPermission,"autoSetDcloudAppid"in e&&delete e.autoSetDcloudAppid,0===t.length)return{code:20101,messageValues:{param:this.t("user-unique-param")}};const p=Xr.command;let l=await P.where(p.or(...t)).get();if(l=this._getCurrentAppUser(l.data),l&&l.length>0){const t=l[0];if(t.status===F)return{code:10006};for(let n=0;nt[e]===i.extraCond[e])),t[i.name]===e[i.name]&&o)return{code:20102,messageValues:{type:i.desc}}}}const f=e.password&&e.password.trim();if(!f)return{code:N,messageValues:{param:this.t("password")}};const{passwordHash:m,version:h}=this.encryptPwd(f);e.password=m,h&&(e.password_secret_version=h),e.my_invite_code=c,delete e.myInviteCode;const g=await this._registerExec(e,{needPermission:u,autoSetDcloudAppid:d});return 0!==g.code?g:{...g,username:o,email:s,mobile:a}},logout:async function(e){const t=await this.checkToken(e);if(t.code)return t;const r=Yr.command;return await P.doc(t.uid).update({token:r.pull(e)}),{code:0,msg:""}},getRoleByUid:async function({uid:e}){if(!e)return{code:N,messageValues:{param:this.t("user-id")}};const t=await P.doc(e).get();return 0===t.data.length?{code:L}:{code:0,msg:"",role:t.data[0].role||[]}},getPermissionByRole:async function({roleID:e}){if(!e)return{code:N,messageValues:{param:"roleID"}};if("admin"===e){return{code:0,msg:"",permission:(await D.limit(1e3).get()).data.map(e=>e.permission_id)}}const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,msg:"",permission:t.data[0].permission||[]}},getPermissionByUid:async function({uid:e}={}){const t=await P.aggregate().match({_id:e}).project({role:!0}).unwind("$role").lookup({from:"uni-id-roles",localField:"role",foreignField:"role_id",as:"roleDetail"}).unwind("$roleDetail").replaceRoot({newRoot:"$roleDetail"}).end(),r=[],n=[];return t.data.forEach(e=>{n.push(e.role_id),r.push(...e.permission)}),{code:0,msg:"",role:n,permission:A(r)}},bindRole:async function({uid:e,roleList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.role=r?t:zr.push(t),await P.doc(e).update(n),{code:0,msg:""}},bindPermission:async function({roleID:e,permissionList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.permission=r?t:zr.push(t),await j.where({role_id:e}).update(n),{code:0,msg:""}},unbindRole:async function({uid:e,roleList:t}){return"string"==typeof t&&(t=[t]),await P.doc(e).update({role:zr.pull(zr.in(t))}),{code:0,msg:""}},unbindPermission:async function({roleID:e,permissionList:t}){return"string"==typeof t&&(t=[t]),await j.where({role_id:e}).update({permission:zr.pull(zr.in(t))}),{code:0,msg:""}},addRole:async function({roleID:e,roleName:t,comment:r,permission:n=[]}){return e?"admin"===e?{code:U,messageValues:{param:"roleID",reason:this.t("add-role-admin-is-not-allowed")}}:(await j.add({role_id:e,role_name:t,comment:r,permission:n,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},addPermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.add({permission_id:e,permission_name:t,comment:r,create_date:Date.now()}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},getRoleList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",roleList:(await j.skip(t).limit(e).get()).data};if(r){const{total:e}=await j.where({_id:zr.exists(!0)}).count();n.total=e}return n},getRoleInfo:async function(e){const t=await j.where({role_id:e}).get();return 0===t.data.length?{code:V}:{code:0,...t.data[0]}},updateRole:async function({roleID:e,roleName:t,comment:r,permission:n}){return e?(await j.where({role_id:e}).update({role_name:t,comment:r,permission:n}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("role-id")}}},deleteRole:async function({roleID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof roleID must be array or string");return await j.where({role_id:zr.in(e)}).remove(),await P.where({role:zr.elemMatch(zr.in(e))}).update({role:zr.pullAll(e)}),{code:0,msg:""}},getPermissionList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"",permissionList:(await D.skip(t).limit(e).get()).data};if(r){const{total:e}=await D.where({_id:zr.exists(!0)}).count();n.total=e}return n},getPermissionInfo:async function(e){const t=await D.where({permission_id:e}).get();return 0===t.data.length?{code:N,messageValues:{param:this.t("permission-id")}}:{code:0,...t.data[0]}},updatePermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.where({permission_id:e}).update({permission_name:t,comment:r}),{code:0,msg:""}):{code:N,messageValues:{param:this.t("permission-id")}}},deletePermission:async function({permissionID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("typeof permissionID must be array or string");return await D.where({permission_id:zr.in(e)}).remove(),await j.where({permission:zr.elemMatch(zr.in(e))}).update({permission:zr.pullAll(e)}),{code:0,msg:""}},bindAlipay:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,{openid:i}=await this._getAlipayApi({platform:n}).code2Session(t);if(!i)return{code:60401,messageValues:{account:this.t("alipay-account")}};let o=await P.where({ali_openid:i}).get();return o=this._getCurrentAppUser(o.data),o&&o.length>0?{code:60402,messageValues:{type:this.t("alipay-account")}}:(await P.doc(e).update({ali_openid:i}),{code:0,openid:i,msg:""})},bindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!r)return{code:N,messageValues:{param:this.t("email")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const{emailToLowerCase:i}=this._getConfig();i&&(r=r.toLowerCase());let o=await P.where({email:r,email_confirmed:1}).get();if(o=this._getCurrentAppUser(o.data),o&&o.length>0)return{code:60201,messageValues:{type:this.t("email")}};const s=await this.verifyCode({email:r,code:n,type:"bind"});return 0!==s.code?s:(await P.doc(t).update({email:r,email_confirmed:1}),{code:0,msg:"",email:r})},bindMobile:async function(e){let{uid:t,mobile:r,code:n,openid:i,access_token:o,type:s="sms"}=e||{};if("univerify"===s){const e=this._getConfig(),t=e&&e.service&&e.service.univerify;if(!t)throw new Error("请在config.json中配置service.univerify下一键登录相关参数");const n=await Gr.bind(this)({...t,openid:i,access_token:o});if(0!==n.code)return n;r=""+n.phoneNumber}let a=await P.where({mobile:r,mobile_confirmed:1}).get();if(a=this._getCurrentAppUser(a.data),a&&a.length>0)return{code:60101,messageValues:{type:"手机号"}};if("sms"===s&&"code"in e){if(!r)return{code:N,messageValues:{param:this.t("mobile")}};if(!n)return{code:N,messageValues:{param:this.t("verify-code")}};const e=await this.verifyCode({mobile:r,code:n,type:"bind"});if(0!==e.code)return e}return await P.doc(t).update({mobile:r,mobile_confirmed:1}),{code:0,msg:"",mobile:r}},bindWeixin:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,i="mp-weixin"===n,{openid:o,unionid:s,sessionKey:a,accessToken:c,refreshToken:u,expired:d}=await this._getWeixinApi({platform:n})[i?"code2Session":"getOauthAccessToken"](t);if(!o)return{code:60301,messageValues:{account:"微信openid"}};const p=Wr.command,l=[{wx_openid:{[n]:o}}];s&&l.push({wx_unionid:s});let f=await P.where(p.or(...l)).get();if(f=this._getCurrentAppUser(f.data),f&&f.length>0)return{code:60302,messageValues:{type:this.t("wechat-account")}};const m={wx_openid:{[n]:o}};let h;return s&&(m.wx_unionid=s),await P.doc(e).update(m),h=i?{sessionKey:a}:{accessToken:c,refreshToken:u,accessTokenExpired:d},{code:0,msg:"",openid:o,unionid:s,...h}},bindQQ:async function({uid:e,code:t,accessToken:r,platform:n}={}){const i=n||this.context.PLATFORM,o="mp-qq"===i,{openid:s,unionid:a,sessionKey:c}=await this._getQQApi()[o?"code2Session":"getOpenidByToken"]({code:t,accessToken:r});if(!s)return{code:60501,messageValues:{account:"qq openid"}};const u=Jr.command,d=[{qq_openid:{[i]:s}}];a&&d.push({qq_unionid:a});let p=await P.where(u.or(...d)).get();if(p=this._getCurrentAppUser(p.data),p&&p.length>0)return{code:60502,messageValues:{type:this.t("qq-account")}};const l={qq_openid:{[i]:s}};return a&&(l.qq_unionid=a),await P.doc(e).update(l),{code:0,msg:"",openid:s,unionid:a,...{accessToken:r,sessionKey:c}}},unbindAlipay:async function(e){const t=Zr.command,r=await P.doc(e).update({ali_openid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70401}},unbindEmail:async function(e){let{uid:t,email:r,code:n}=e||{};if(r=r&&r.trim(),!t||!r)return{code:N,messageValues:{param:t?this.t("email"):this.t("user-id")}};const{emailToLowerCase:i}=this._getConfig();if("code"in e){const e=await this.verifyCode({email:r,code:n,type:"unbind"});if(0!==e.code)return e}const o=en.command;let s={_id:t,email:r};if(i){const e=r.toLowerCase();e!==r&&(s=o.or(s,{_id:t,email:e}))}return 1===(await P.where(s).update({email:o.remove(),email_confirmed:o.remove()})).updated?{code:0,msg:""}:{code:70201}},unbindMobile:async function(e){const{uid:t,mobile:r,code:n}=e||{};if("code"in e){const e=await this.verifyCode({mobile:r,code:n,type:"unbind"});if(0!==e.code)return e}const i=tn.command;return 1===(await P.where({_id:t,mobile:r}).update({mobile:i.remove(),mobile_confirmed:i.remove()})).updated?{code:0,msg:""}:{code:70101}},unbindWeixin:async function(e){const t=rn.command,r=await P.doc(e).update({wx_openid:t.remove(),wx_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70301}},unbindQQ:async function(e){const t=nn.command,r=await P.doc(e).update({qq_openid:t.remove(),qq_unionid:t.remove()});return E("upRes:",r),1===r.updated?{code:0,msg:""}:{code:70501}},getSupportedLoginType:function({appid:e,platform:t}={}){if(!e||!t)throw new Error("Parameter appid and platform is required");const r=this._getConfig({appid:e,platform:t}),n=["username-password","mobile-password","email-password"];for(const e in on)on[e](r)&&n.push(e);return{supportedLoginType:n}},code2SessionAlipay:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getAlipayApi({platform:e}).code2Session(t.code);return r.openid?{code:0,msg:"",...r}:{code:80701,messageValues:{account:this.t("alipay-account")}}}catch(e){return console.error(e),{code:80702,messageValues:{account:this.t("alipay-account")}}}},code2SessionWeixin:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getWeixinApi({platform:e})["mp-weixin"===e?"code2Session":"getOauthAccessToken"](t.code);return r.openid?{code:0,msg:"",...r}:{code:80601,messageValues:{account:"微信openid"}}}catch(e){return console.error(e),{code:80602,messageValues:{account:"微信openid"}}}},verifyAppleIdentityToken:async function({identityToken:e,platform:t}){const r=t||this.context.PLATFORM,{code:n,msg:i}=await Lr({clientType:r}).verifyIdentityToken(e);return 0!==n?{code:n,msg:i}:{code:n,msg:"验证通过",...i}},wxBizDataCrypt:async function({code:e,sessionKey:r,encryptedData:n,iv:i}){if(!n)return{code:N,messageValues:{param:"encryptedData"}};if(!i)return{code:N,messageValues:{param:"iv"}};if(!e&&!r)return{code:N,messageValues:{param:"sessionKey"}};const o=this._getWeixinApi();if(!r){const t=await o.code2Session(e);if(!t.sessionKey)return{code:80801};r=t.sessionKey}r=Buffer.from(r,"base64"),n=Buffer.from(n,"base64"),i=Buffer.from(i,"base64");try{var s=t.createDecipheriv("aes-128-cbc",r,i);s.setAutoPadding(!0);var a=s.update(n,"binary","utf8");a+=s.final("utf8"),a=JSON.parse(a)}catch(e){return console.error(e),{code:80802}}return a.watermark.appid!==o.options.appId?{code:80803}:{code:0,msg:"",...a}},getWeixinUserInfo:async function({accessToken:e,openid:t}={}){const r=this.context.PLATFORM;if("app"!==r&&"app-plus"!==r)throw new Error(this.t("limit-client-platform"));try{return{code:0,msg:"",...await this._getWeixinApi().getUserInfo({accessToken:e,openid:t})}}catch(e){return console.error(e),{code:80901}}},encryptPwd:function(e,{value:r,version:n}={}){if(!(e=e&&e.trim()))throw new Error(this.t("param-required",{param:this.t("password")}));if(!r){const e=this._getConfig(),{passwordSecret:t}=e;if("array"===m(t)){const e=t.sort((e,t)=>e.version-t.version);r=e[e.length-1].value,n=e[e.length-1].version}else r=t}if(!r)throw new Error(this.t("param-error",{param:"passwordSecret",reason:"invalid passwordSecret"}));const i=t.createHmac("sha1",r.toString("ascii"));return i.update(e),{passwordHash:i.digest("hex"),version:n}},checkToken:async function(e,{needPermission:t,needUserInfo:r=!0}={}){const n=this._getConfig(),i=this._verifyToken(e);if(i.code)return i;const{uid:o,needPermission:s,role:a,permission:c,exp:u,iat:d,...p}=i,l=a&&c;t=void 0===t?s:t;const f=n.removePermissionAndRoleFromToken||!l||r,m=!n.removePermissionAndRoleFromToken&&!l||n.removePermissionAndRoleFromToken&&l||n.tokenExpiresThreshold&&u-Date.now()/1e3this._createTokenInternal({signContent:e,config:o})):this._createTokenInternal({signContent:a,config:o})},_updateToken:async function({uid:e,tokenList:t,removeToken:r=[],addToken:n=[]}={}){if(!t){const r=await P.doc(e).get(),n=r.data&&r.data[0];t=n&&n.token||[]}"string"==typeof t&&(t=[t]);const i=this._getExpiredToken(t);(t=t.filter(e=>-1===i.indexOf(e))).push(...n);for(let e=0;ee.version-t.version);let c;if(c=n?a.find(e=>e.version===n):a[0],!c)return{code:3};const u=a[a.length-1],{passwordHash:d}=this.encryptPwd(t,c);if(d===r){const e={code:0};if(c!==u){const{passwordHash:r,version:n}=this.encryptPwd(t,u);e.passwordHash=r,e.passwordVersion=n}return e}return{code:4,message:""}},_verifyToken:function(e){const t=this._getConfig();let r;try{r=Pr(e,t.tokenSecret)}catch(e){return"TokenExpiredError"===e.name?{code:30203,err:e}:{code:30204,err:e}}return t.bindTokenToDevice&&r.clientId&&r.clientId!==this._getClientUaHash()?{code:30201}:{code:0,message:"",...r}},_getExpiredToken:function(e){const t=this._getConfig(),r=[];return e.forEach(e=>{try{Pr(e,t.tokenSecret)}catch(t){r.push(e)}}),r},_getPermissionListByRoleList:async function(e){if(!Array.isArray(e))return[];if(0===e.length)return[];if(e.includes("admin")){return(await D.limit(500).get()).data.map(e=>e.permission_id)}const t=await j.where({role_id:sn.in(e)}).get(),r=[];return t.data.forEach(e=>{Array.prototype.push.apply(r,e.permission)}),A(r)},_getClientUaHash:function(){const e=t.createHash("md5"),r=/MicroMessenger/i.test(this.context.CLIENTUA)?this.context.CLIENTUA.replace(/(MicroMessenger\S+).*/i,"$1"):this.context.CLIENTUA;return e.update(r),e.digest("hex")},_createTokenInternal:function({signContent:e,config:t}){if(t.tokenExpiresIn&&t.tokenExpiresThreshold&&t.tokenExpiresIn<=t.tokenExpiresThreshold)throw new Error(this.t("token-expires-config-warning"));return"object"===m(e)&&e.uid?(t.bindTokenToDevice&&(e.clientId=this._getClientUaHash()),{token:Rr(e,t.tokenSecret,{expiresIn:t.tokenExpiresIn}),tokenExpired:Date.now()+1e3*t.tokenExpiresIn}):{code:30101,messageValues:{param:this.t("user-id")}}},setVerifyCode:async function({mobile:e,email:t,code:r,expiresIn:n,type:i}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50101,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50102,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};r||(r=C()),n||(n=180);const o=Date.now(),s={mobile:e,email:t,type:i,code:r,state:0,ip:this.context.CLIENTIP,created_at:o,expired_at:o+1e3*n};return await R.add(s),{code:0,mobile:e,email:t}},verifyCode:async function({mobile:e,email:t,code:r,type:n}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t)return{code:50201,messageValues:{param:"手机号或邮箱"}};if(e&&t)return{code:50203,messageValues:{param:"参数",reason:"手机号和邮箱不可同时存在"}};if(!r)return{code:50202,messageValues:{type:this.t(e?"sms":"email")}};const i=an.command,o=Date.now(),s={mobile:e,email:t,type:n,code:r,state:0,expired_at:i.gt(o)},a=await R.where(s).orderBy("created_at","desc").limit(1).get();if(a&&a.data&&a.data.length>0){const e=a.data[0];return await R.doc(e._id).update({state:1}),{code:0,msg:"验证通过"}}return{code:50202,messageValues:{type:this.t(e?"sms":"email")}}},sendSmsCode:async function({mobile:e,code:t,type:r,templateId:n}){if(!e)return{code:N,messageValues:{param:this.t("mobile")}};if(t||(t=C()),!r)return{code:N,messageValues:{param:this.t("verify-code-type")}};const i=this._getConfig();let o=i&&i.service&&i.service.sms;if(!o)throw new Error(this.t("config-param-required",{param:"service.sms"}));o=Object.assign({codeExpiresIn:300},o);const s=["smsKey","smsSecret"];for(let e=0,t=s.length;e=0?o:{code:0,msg:""}}catch(e){return console.error(e),{code:50301}}}});let un;try{un=require("uni-config-center")}catch(e){throw new Error("Plugin[uni-config-center] was not found")}class dn{constructor({context:e,clientInfo:t,config:r}={}){const n=un({pluginId:"uni-id"});this.pluginConfig=n,this.config=r||this._getConfigContent(),this._configCache={},Object.defineProperty(this,"context",{get(){let r;r=t?{OS:t.os,CLIENTIP:t.clientIP,CLIENTUA:t.userAgent,PLATFORM:t.platform,APPID:t.appId,LOCALE:t.locale,DEVICEID:t.deviceId}:Object.assign({},e||global.__ctx__||{});const n=["CLIENTIP","PLATFORM","APPID","LOCALE"];for(let e=0;ee.dcloudAppid===t)||e.find(e=>e.isDefaultConfig):e}_parseConfigContent(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getConfigContent(){if(this.pluginConfig&&this.pluginConfig.hasFile("config.json")){let e;try{e=this.pluginConfig.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseConfigContent(e)}{let e;try{e=require("./config.json")}catch(e){if("MODULE_NOT_FOUND"===e.code||"ENOENT"===e.code)throw new Error("uni-id config file[uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json] not found");throw e}return this._parseConfigContent(e)}}init(){throw new Error("uniID.init has been deprecated, use uniID.createInstance instead")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_getConfig({appid:e,platform:t}={}){const r=`${e=e||this.context.APPID}_${t=t||this.context.PLATFORM}`;if(this._configCache[r])return this._configCache[r];if(!(this.config&&0!==Object.keys(this.config).length))throw new Error(this.t("config-file-not-found"));const n=this._getAppConfig(this.config,e);"app"!==t&&"app-plus"!==t||(t=n.preferedAppPlatform||t),"web"!==t&&"h5"!==t||(t=n.preferedWebPlatform||t);const i=Object.assign(n,n[t])||{},o=Object.assign({bindTokenToDevice:!1,tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600,usernameToLowerCase:!0,emailToLowerCase:!0},i);return["passwordSecret","tokenSecret","tokenExpiresIn","passwordErrorLimit","passwordErrorRetryTime"].forEach(e=>{if(!o||!o[e])throw new Error(this.t("config-param-required",{param:e}))}),this._configCache[r]=o,o}}for(const e in cn)dn.prototype[e]=cn[e];function pn(e){const t=new dn(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(r=e[t],function(){const e=r.apply(this,arguments);return f(e)?e.then(e=>(x.bind(this)(e),e)):(x.bind(this)(e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var r}})}dn.prototype.createInstance=pn;var ln=pn();module.exports=ln; diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json new file mode 100644 index 0000000..93b2b8f --- /dev/null +++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json @@ -0,0 +1,16 @@ +{ + "name": "uni-id", + "version": "3.3.28", + "description": "uni-id for uniCloud", + "main": "index.js", + "homepage": "https://uniapp.dcloud.io/uniCloud/uni-id", + "repository": { + "type": "git", + "url": "git+https://gitee.com/dcloud/uni-id.git" + }, + "author": "", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/changelog.md b/uni_modules/vk-unicloud/changelog.md new file mode 100644 index 0000000..bd64556 --- /dev/null +++ b/uni_modules/vk-unicloud/changelog.md @@ -0,0 +1,1248 @@ +## 2.15.3(2023-09-25) +* 【修复】`短信发送` 接口当uni-id配置成多端隔离(数组形式)会报错的bug +* 【修复】`vk.importObject` 部分情况下会报错的问题 +* 【优化】如果当前运行的微信小程序是体验版,但没有点HBX的【发行】菜单发布,则提示开发者请点【发行】按钮 +* 【优化】`$hasRole`函数的功能 [传送门](https://vkdoc.fsq.pub/client/jsapi.html#hasrole) +* 【优化】`vk.pubfn.timeFormat` 支持显示时区,完整格式为 `yyyy-MM-ddThh:mm:ssZ` +* 【优化】其他细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.15.2(2023-08-15) +* 【重要】新增地图相关的API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/map.html) +* 【修复】`vk.baseDao.sample` 在腾讯云空间最大只能取20条的bug +* 【优化】`vk.pubfn.test` 新增参数 `allowEmpty` 控制是否允许为空 [传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-test-%E6%A3%80%E6%B5%8B%E6%96%87%E6%9C%AC%E6%A0%BC%E5%BC%8F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.15.1(2023-07-20) +* 1、【重要】为了安全性考虑,调整前端的 `vk.request` API,需要手动指定 `uniIdToken: true` 才会在请求头中自动添加 `uni-id-token` +* 2、【优化】前端 `vk.request` 当满足响应规范时,会自动保存 `token` 和 `userInfo` 以及token失效跳登录页面 +* 3、【优化】新增 `vk.baseDao.setById`(根据ID判断存在则修改,不存在则添加,此为原子操作,非查询再判断) +* 4、【优化】`user/pub/sendEmailCode` 发送邮件验证码新增针对同一个邮箱每天的次数限制(默认30次,可在函数内修改默认次数) +* 5、【优化】`user/pub/sendSmsCode` 发送短信验证码新增针对同一个手机号每天的次数限制(默认12次,可在函数内修改默认次数) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.15.0(2023-07-04) +* 1、【重要】注册接口统一去除前端的role参数(需替换目录 `router/service/user/pub`) +* 2、【修复】云端表单验证不支持a.b的问题 +* 3、【新增】`vk.sessionStorage` 本地会话缓存,仅h5可用 +* 4、【优化】`vk.uploadFile` 新增参数 `cloudPathAsRealPath` 默认为true,代表支持阿里云目录 +* 5、【优化】`vk.uploadFile` 新增参数 `cloudDirectory` 可以设置上传至指定的云端目录 +* 6、【优化】`vk.request` 新增 `interceptor` 参数(该参数仅前端调用时生效)[传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-request-%E8%AF%B7%E6%B1%82http%E6%8E%A5%E5%8F%A3) +* 7、【优化】发送邮件验证码新增参数判断 +* 8、【优化】云函数、云对象404时的错误提示 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.14.3(2023-06-09) +* 1、【新增】支付宝小程序api [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/alipay.html) +* 2、【修复】因 `2.14.2` 更新导致的支付宝小程序报错问题。 +* 3、【优化】注册接口前端全局防抖 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.14.2(2023-06-01) +* 1、【优化】`user/kh/addUploadRecord` 细节 +* 2、【优化】`vk.importObject` 支持 `importObjectOptions` 参数 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#uni-vk-importobject%E7%9A%84%E9%AB%98%E7%BA%A7%E7%94%A8%E6%B3%95) +* 3、【优化】vuex模块化支持多级目录 +* 4、【优化】微信公众号登录后不能跳回登录前页面的问题。 +* 5、【调整】`vk.pubfn.test(str, 'username')` 检测的长度调整为3-32位 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.14.1(2023-05-17) +* 1、【新增】QQ小程序API [详情](https://vkdoc.fsq.pub/client/uniCloud/plus/qq.html#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6) +* 2、【新增】抖音小程序API [详情](https://vkdoc.fsq.pub/client/uniCloud/plus/douyin.html) +* 3、【优化】`vk.pubfn.formValidate` [详情](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/formRules.html#rules%E8%AF%A6%E8%A7%A3) +* 4、【优化】`vk.crypto.aes.encrypt` 和 `vk.crypto.aes.decrypt` 新增 `mode` 参数,支持切换为加密算法,方便兼容java、php等后端语言加解密 [详情](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/crypto.html#%E5%9C%A8%E4%BA%91%E5%87%BD%E6%95%B0%E5%8A%A0%E5%AF%86-java%E6%88%96php%E7%AD%89%E5%85%B6%E4%BB%96%E5%90%8E%E7%AB%AF%E8%AF%AD%E8%A8%80%E8%A7%A3%E5%AF%86) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.6(2023-04-23) +* 1、【优化】`vk.baseDao.selects` 当getCount为false时,hasMore永远是false的bug +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.5(2023-03-20) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.4(2023-02-12) +* 1、【修复】云函数内调用 `vk.callFunction` 可能会报错的bug +* 2、【修复】微信公众号万能API不支持上传媒体图片的问题 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html#%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E4%B8%8A%E4%BC%A0%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%8E%A5%E5%8F%A3) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.3(2023-02-05) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.2(2023-01-19) +* 1、【调整】router云函数运行内存调整为512M(实测512M即可达到最优性能) +* 2、【新增】微信最新版头像和昵称获取示例,详见:/pages_template/uni-id/weixin/set-user-info.vue +* 3、【优化】升级微信小程序文本检测API `vk.openapi.weixin.security.msgSecCheck` 至2.0版本 [传送门 - 微信文档](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/msgSecCheck.html) +* 4、【修复】`微信公众号万能API调用接口` 在调用部分接口时可能会报错的问题 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.1(2022-12-29) +* 1、【调整】url化后token的请求头从 `uni_id_token` 改为 `uni-id-token`(新版阿里云不支持 `uni_id_token` 请求头) +* 2、【修复】`vk.openapi.weixin.h5.request` 接口无法在阿里云空间中自动使用代理的问题。 +* 3、【修复】`vk.pubfn.getOffsetTime` 接口在云端月偏移量计算在可能会出错的问题。 +* 4、【优化】其他一些兼容性问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.13.0(2022-12-29) +* 1、【调整】url化后token的请求头从 `uni_id_token` 改为 `uni-id-token`(新版阿里云不支持 `uni_id_token` 请求头) +* 2、【修复】`vk.openapi.weixin.h5.request` 接口无法在阿里云空间中自动使用代理的问题。 +* 3、【修复】`vk.pubfn.getOffsetTime` 接口在云端月偏移量计算在可能会出错的问题。 +* 4、【优化】其他一些兼容性问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.9(2022-12-13) +* 1、【优化】`vk.pubfn.getCommonTime()` API内部细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.8(2022-12-05) +* 1、【修复】let { weekStart } = vk.pubfn.getCommonTime(new Date()); weekStart一直是undefined的问题 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.7(2022-11-30) +* 1、【优化】新版阿里云空间通过代理请求微信公众号API细节处理 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.6(2022-11-24) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.5(2022-11-12) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.4(2022-11-12) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.3(2022-11-05) +* 1、【优化】新增 cancelAddTimeStr 配置,用于单独取消 _add_time_str +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/0092145a-8169-475d-83c5-c873ae8d0c05.png) +* 2、【优化】部分API的报错提示 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.2(2022-10-25) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.1(2022-10-10) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.12.0(2022-10-07) +* 1、【重要】vk实例初始化代码调整(因HBX更新导致本地运行时,不同的云函数环境目前没有隔离(云端无此问题,只有本地运行有此问题),从而导致HBX本地运行时,A云函数和B云函数复用了同一个vk实例,而更新后,vk实例在不同云函数内会隔离) + +`router/index.js` 代码修改(注意:如果你只使用一个router,则不修改也没有问题) + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vk = require('vk-unicloud'); // vk-unicloud 工具包 +vk.init(require('./config.js')); +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +修改为 + +```js +'use strict'; +// 注意:此为云函数路由入口文件,请勿修改此文件代码,你自己的云函数逻辑应写在service目录下 +const vkCloud = require('vk-unicloud'); // 引入 vk-unicloud +const vk = vkCloud.createInstance(require('./config.js')); // 通过 vkCloud.createInstance 创建 vk 实例 +exports.main = async (event, context) => { + return await vk.router({ event, context, vk }); +}; +``` + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.20(2022-09-29) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.19(2022-09-29) +* 1、【修复】升级HBX后带来的部分兼容性问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.18(2022-09-26) +* 1、【优化】`vk.pubfn.getCurrentPage()` API 在最新版HBX上的兼容性。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.17(2022-09-22) +* 1、【重要】微信公众号万能API调用接口支持在阿里云空间执行(自动使用阿里云代理模式)[传送门 - 阿里云固定IP设置](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.16(2022-09-18) +* 1、【修复】`vk.crypto.aes.encrypt`、`vk.crypto.aes.decrypt` 在非 `router` 目录结构的云函数中运行可能会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.15(2022-09-17) +* 1、【修复】`vk.crypto.aes.encrypt`、`vk.crypto.aes.decrypt` 在非 `router` 目录结构的云函数中运行可能会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.14(2022-09-16) +* 1、【修复】`vk.baseDao.getTableData` 的查询条件某个字段的值指定为null时,可能会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.13(2022-09-12) +* 1、【修复】`vk.baseDao.getTableData` 内使用 `_.geoNear` 无效的问题。 +* 2、【优化】前端使用 `vk.request` 请求时,若本地缓存中有 `uni_id_token`,则请求头会带上 `uni_id_token` 的值 +* 3、【优化】`router` 函数 `url化后`,若没有直接传 `uni_id_token` 参数,则会尝试从请求头中获取 `uni_id_token` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.12(2022-09-12) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.11(2022-09-11) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.10(2022-09-11) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.9(2022-09-08) +* 1、【修复】`vk.baseDao.getTableData` 内使用 `_.geoNear` 无效的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.8(2022-09-05) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.7(2022-08-29) +* 1、【重要】新增 `监听token更新` API [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220829#vk-onrefreshtoken-%E7%9B%91%E5%90%ACtoken%E6%9B%B4%E6%96%B0%E4%BA%8B%E4%BB%B6) +* 2、【优化】`云对象` 新增 `this.getUniCloudRequestId`(获取当前请求id)[传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getunicloudrequestid-%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E8%AF%B7%E6%B1%82id) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.6(2022-08-26) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.5(2022-08-25) +* 1、【优化】`vk.pubfn.getCommonTime` 更新文档 [传送门](https://vkdoc.fsq.pub/client/jsapi.html?t=20220825#vk-pubfn-getcommontime-%E8%8E%B7%E5%8F%96%E6%97%B6%E9%97%B4%E8%8C%83%E5%9B%B4) +* 2、【优化】其他细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.4(2022-08-23) +* 1、【修复】快手小程序自动跳登录页面的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.3(2022-08-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.2(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/a4ca3d72-358e-4437-8766-d0b14e269697.png) + +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 + +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` + +**特别注意** + +* 1、本次更新需要替换 `router/service/user/pub/` 目录 + +* 2、如果你使用了 `使用微信小程序绑定的手机号一键登录` 的API,则请看此处调整代码 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220822#vk-usercenter-loginbyweixinphonenumber-%E9%80%9A%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%91%E5%AE%9A%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%99%BB%E5%BD%95) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.1(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/a4ca3d72-358e-4437-8766-d0b14e269697.png) + +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 + +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` + +**特别注意** + +* 1、本次更新需要替换 `router/service/user/pub/` 目录 + +* 2、如果你使用了 `使用微信小程序绑定的手机号一键登录` 的API,则请看此处调整代码 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html?t=20220822#vk-usercenter-loginbyweixinphonenumber-%E9%80%9A%E8%BF%87%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%91%E5%AE%9A%E7%9A%84%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%99%BB%E5%BD%95) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.11.0(2022-08-22) +* 1、【重要】前端 `微信登录` 、 `微信获取openid` 等接口不再返回 `sessionKey` 取而代之的是返回 `encryptedKey`(加密后的数据,云函数解密后可获得 `sessionKey`) +* 2、【重要】新增配置 `vk.crypto.aes` 用于返回给前端加密数据时的加密密钥 +* 3、【新增】`vk.crypto.aes.encrypt` 用于加密数据 +* 4、【新增】`vk.crypto.aes.decrypt` 用于解密数据 +```js +// 加密数据 +let encryptedKey = vk.crypto.aes.encrypt({ + data: { + sessionKey: "XXXXX" + } +}); +console.log('encryptedKey: ', encryptedKey) + +// 解密 sessionKey 示例 +let decryptedRes = vk.crypto.aes.decrypt({ + data: encryptedKey, // 待解密的原文 +}); +console.log('decryptedRes: ', decryptedRes) +let sessionKey = decryptedRes.sessionKey; +console.log('sessionKey: ', sessionKey) +``` +**特别注意** + +本次更新需要替换 `router/service/user/pub/` 目录 + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.15(2022-08-20) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.14(2022-08-20) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.13(2022-08-19) +* 1、【优化】发送短信验证码接口和组件新增参数 `checkUserExist` : 是否需要检测手机号对应的账号是否存在,默认false:不检测 设置为true:会检测,如果检测到用户不存在,则不发短信。(如通过手机号找回密码的业务,如果手机号都未注册,则没有必要发短信)(需要替换文件:`router/service/user/pub/sendSmsCode.js`) +* 2、【修复】数据库API,`_.geoNear` 部分情况下会失效的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.12(2022-08-15) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.11(2022-08-15) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.10(2022-08-13) +* 1、【调整】根据手机验证码重置账号密码的短信验证 `type` 从 `reset` 改为 `reset-pwd`(与unicloud官方对齐) +* 2、【调整】根据邮箱验证码重置账号密码的邮件验证 `type` 从 `reset` 改为 `reset-pwd`(与unicloud官方对齐) +* 3、【修复】vk.pubfn.test("aaahttps://www.baidu.com","url") 会返回 true 的bug +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.9(2022-07-30) +* 1、【优化】云对象 `this.getCloudInfo()` 内增加 `functionName`、`functionType` [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getcloudinfo-%E8%8E%B7%E5%8F%96%E4%BA%91%E7%AB%AF%E4%BF%A1%E6%81%AF) +* 2、【优化】云对象 `this.getClientInfo()` 内增加 `source` [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#this-getclientinfo-%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BF%A1%E6%81%AF) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.8(2022-07-28) +* 1、【新增】`uni-id` 配置 `removeDcloudAppid` 默认false,若设置true,则注册成功后,会自动删除 `dcloud_appid` 字段,以达到禁用隔离不同端用户的功能。(需配合中间件registerInitFilter) +* 2、【新增】`vk.openapi.weixin.urllink.generate` 云函数生成小程序url链接API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E8%8E%B7%E5%8F%96%E5%B0%8F%E7%A8%8B%E5%BA%8Furl%E9%93%BE%E6%8E%A5) +* 3、【新增】`vk.userCenter.getWeixinMPurl` 前端直接生成小程序url链接API [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-getweixinmpurl-%E7%94%9F%E6%88%90%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8Furl%E9%93%BE%E6%8E%A5) +* 4、【优化】`vk.openapi.weixin.wxacode.getUnlimited` 和 `vk.openapi.weixin.urlscheme.generate` 支持参数 `env_version` [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E8%8E%B7%E5%8F%96%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%A0%81) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.7(2022-07-23) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.6(2022-07-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.5(2022-07-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.4(2022-07-21) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.3(2022-07-20) +* 1、【修复】`_.geoNear` 和 `lastWhereJson` 同时使用时报错的bug +* 2、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.2(2022-07-18) +* 1、`vk.pubfn.batchRun` 新增另外一种调用方式。[传送门](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-batchrun) +* 2、新增 `vk.uploadFile` 代替 `vk.callFunctionUtil.uploadFile`(保留旧写法) [传送门](https://vkdoc.fsq.pub/client/pages/uploadFile.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.1(2022-07-12) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.10.0(2022-07-09) +* 1、【优化】`vk.baseDao.update` `vk.baseDao.updateById` `vk.baseDao.updateAndReturn` API的 `dataJson` 参数若有 `_id`,则自动忽略 `_id`(因_id不可修改,原先是直接报错) +* 2、【优化】其他细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.12(2022-07-04) +* 1、【新增】微信小程序服务端万能API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B8%87%E8%83%BDapi%E8%B0%83%E7%94%A8%E6%8E%A5%E5%8F%A3) +* 2、【新增】微信公众号服务端万能API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.11(2022-06-28) +* 1、【优化】`万能连表` 支持使用数组下标对应的值进行连表,如用户表根据inviter_uid的第一个值进行连表达到只查出第一个上级用户信息的效果 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html#%E5%9C%BA%E6%99%AF11) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.10(2022-06-25) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.9(2022-06-22) +* 1、【重要】新增安全规则:未标记 `isCloudObject:true` 的对象定义为私有对象(如 `service/user/util/login_log.js`),前端禁止访问(只能被云函数/云对象 `require` 方式调用)。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.8(2022-06-22) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.7(2022-06-22) +* 1、【新增】数据库表内的字段重命名api [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%A6%82%E4%BD%95%E6%9B%B4%E6%94%B9%E5%AD%97%E6%AE%B5%E5%90%8D) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.6(2022-06-20) +* 1、【新增】云函数专用api `vk.pubfn.randomAsync`(异步)产生指定位数的不重复随机数(支持任意字符,s默认纯数字)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-randomasync) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.5(2022-06-17) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.4(2022-06-15) +* 1、【调整】`vk.getVuex` 当数据不存在时,返回值由 `undefined` 调整为 `空字符串`(undefined在部分平台会有问题) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.3(2022-06-11) +* 1、【重要】`uni-id` 新增配置参数 `"preferedWebPlatform": "h5",`,用于解决因HBX3.4.14版本导致的 `h5` 变为 `web` 带来的一系列问题。(完美兼容,你无需改自己的逻辑代码了) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.2(2022-06-10) +* 1、【调整】`vk.getVuex` 当数据不存在时,返回值由 `空字符串` 调整为 `undefined` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.1(2022-06-08) +* 1、【优化】`云对象` 的内置api `this.getClientInfo` 可以获取到更多信息(uni.getSystemInfo返回的客户端信息) +* 2、【优化】`云函数` 的 `originalParam.context` 可以获取到更多信息(uni.getSystemInfo返回的客户端信息) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.9.0(2022-06-07) +* 1、【新增】`vk.callFunction` api [点击查看详情](https://vkdoc.fsq.pub/client/question/question.html#%E4%BA%91%E5%87%BD%E6%95%B0-%E4%BA%91%E5%AF%B9%E8%B1%A1-%E4%B8%AD%E5%A6%82%E4%BD%95%E8%B0%83%E7%94%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BA%91%E5%87%BD%E6%95%B0-%E4%BA%91%E5%AF%B9%E8%B1%A1) +> * 1.1、支持在云对象中请求其他云对象内的函数。 +> * 1.2、支持在云对象中请求云函数。 +> * 1.3、支持在云函数内请求其他云函数。 +> * 1.4、支持在云函数内请求云对象内的函数。 +* 2、【优化】`pub` 类型的函数无需 `need_user_info:true`,也能从token中解析并获取到uid(无数据库请求,不影响性能) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.15(2022-06-02) +* 1、【优化】为了兼容DCloud推出的uniCloud响应体规范,请求后的返回值会自动加上errCode和errMsg,其中errCode=code,errMsg=msg +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.14(2022-06-02) +* 1、【优化】为了兼容DCloud推出的uniCloud响应体规范,请求后的返回值会自动加上errCode和errMsg,其中errCode=code,errMsg=msg +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.13(2022-05-30) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.12(2022-05-30) +* 1、【修复】`云对象` 模式下 `sys类型函数` 在非admin目录下时,请求会提示 `need_user_info` 的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.11(2022-05-28) +* 1、【修复】`interceptor.login` 前端自定义login拦截器,在某些情况下无法正常拦截的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.10(2022-05-27) +* 1、【修复】当 `云对象` 在 `service` 层根目录时,`pub.对象名.js` pub权限失效的问题。 +* 2、【优化】其他一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.9(2022-05-26) +* 1、【新增】`vk.baseDao.selects` 和 `vk.baseDao.getTableData` 新增 `lastSortArr` 参数,用于聚合后再排序。 +* 注意:`lastWhereJson` 和 `lastSortArr` 在数据量大的情况下是有性能问题的,(建议主表的where条件中先进行筛选,如只查本季度数据,只要主表过滤完后数据量不大,则没有性能问题。) +* 2、【修复】`lastWhereJson` 后,返回的 `total` 不准确的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.8(2022-05-25) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.7(2022-05-14) +* 1、【新增】`vk.pubfn.getFileType(url)` 根据文件url获取文件类型 +* 2、【新增】`vk.pubfn.getFileSuffix(url)` 根据文件url获取文件后缀名 +* 3、【新增】`vk.pubfn.checkFileSuffix(url,["png", "jpg", "jpeg", "gif", "bmp", "svg"])` 根据文件url判断是否满足指定后缀名中的任意1个 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.6(2022-05-13) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.5(2022-05-05) +* 1、【重要】vk实例对象已调整为页面内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uni.vk.xxx() 的方式来调用。 +* 2、【重要】vk实例对象已调整为云函数内置对象,vk实例对象内的api在任意地方都可以直接通过vk.xxx()使用,不再需要 this.vk.xxx() 或 uniCloud.vk.xxx() 的方式来调用。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.3(2022-04-28) +* 1、【新增】`vk.openapi.weixin.uniformMessage.send` 小程序转公众号消息模板接口 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%BD%AC%E5%85%AC%E4%BC%97%E5%8F%B7%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF) +* 2、【新增】`vk.openapi.weixin.h5.templateMessage.send` 公众号消息模板接口 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html#%E5%8D%95%E7%8B%AC%E5%85%AC%E4%BC%97%E5%8F%B7%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.2(2022-04-21) +* 1、【重要】`uni-id` 配置新增 `tokenMaxLimit` 每个账户的最大token数量,0为不限,淘汰策略:新的淘汰旧的(注意,即使设置为0,框架也会自动淘汰已过期的token)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) +* 2、【重要】微信登录支持多小程序:如果使用多小程序登录,则同一用户(同一个微信号)在不同小程序登录时,会分别创建不同的用户(除非小程序绑定在同一个开放平台下) +* 3、【新增】全局参数 `targetTimezone` 可设置默认时区(中国为8,8代表东8区,-8代表西8区) + +> [查看前端全局配置](https://vkdoc.fsq.pub/client/pages/config.html) + +> [查看云函数全局配置](https://vkdoc.fsq.pub/client/uniCloud/config/vk-unicloud.html) + +* 4、【新增】全局参数 `functionNameToUrl` 和 `isRequestDefault` [点击查看](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html#%E6%B3%A8%E6%84%8F-%E4%BA%91%E5%87%BD%E6%95%B0url%E5%8C%96%E6%96%B9%E5%BC%8F%E8%B0%83%E7%94%A8%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%E4%BD%A0%E7%9A%84%E4%BA%91%E5%87%BD%E6%95%B0url%E8%B7%AF%E5%BE%84%E5%9C%B0%E5%9D%80) +* 5、【优化】微信注册时支持新增自定义字段,如:nickname和avatar等。 +* 6、【优化】当云函数全局配置文件出错时,优化报错提示。 + +**本次更新除了常规升级框架外,还需要下载最新版框架示例项目,从最新版中复制 以下文件 替换 你项目中的对应文件。** + +* 1、`router/middleware/modules/returnUserInfoFilter.js` (此为用户登录注册全局中间件) +* 2、`router/service/user/pub/loginByWeixin.js` (此为微信登录云函数) + +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.1(2022-04-14) +* 1、【新增】前端请求多服务空间的极简方式(通过配置直接指定调用环境)[点击查看](https://vkdoc.fsq.pub/client/question/q9.html#%E6%96%B9%E5%BC%8F%E4%BA%8C) +* 2、【新增】`vk.userCenter.resetPasswordByEmail`(根据邮箱证码重置账号密码) [点击查看](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-resetpasswordbyemail-%E6%A0%B9%E6%8D%AE%E9%82%AE%E7%AE%B1%E8%AF%81%E7%A0%81%E9%87%8D%E7%BD%AE%E8%B4%A6%E5%8F%B7%E5%AF%86%E7%A0%81) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.8.0(2022-04-01) +* 1、【重要】新增 `云对象` 路由模式 [什么是云对象?](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html) +* 2、【重要】自此,在VK框架中,可以做到云对象和云函数同时存在。即在VK框架中,同时支持 `云对象路由模式` 和 `云函数路由模式`。 +* 3、【新增】本地运行支持云对象 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/cloudObject.html#%E6%9C%AC%E5%9C%B0%E8%BF%90%E8%A1%8C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.6(2022-03-26) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.5(2022-03-22) +* 1、【新增】`vk.userCenter.bindNewMobile` 换绑新的手机号接口 [查看详情](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-bindnewmobile-%E6%8D%A2%E7%BB%91%E6%89%8B%E6%9C%BA%E5%8F%B7) +* 2、【新增】`vk.userCenter.bindNewEmail` 换绑新的邮箱接口 [查看详情](https://vkdoc.fsq.pub/client/vk.userCenter.html#vk-usercenter-bindnewemail-%E6%8D%A2%E7%BB%91%E9%82%AE%E7%AE%B1) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.4(2022-03-21) +* 1、【优化】H5环境下,微信登录、微信绑定、微信解绑API,使之自动识别微信公众号环境(h5-weixin)的配置。 +注意:微信公众号的 `uni-id` 配置属性是 `h5-weixin`,非 `h5`。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.3(2022-03-18) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.7.2(2022-03-14) +* 1、【修复】`vk.navigateTo` 以 ./ 开头时 如:vk.navigateTo("./order-list") 判断是否需要登录不准确的问题。 +## 2.7.1(2022-03-14) +* 1、【优化】`app.config.js` 中的 `checkTokenPages` 检测页面是否需要登录支持 首页(启动页)的检测 +* 2、【优化】其他细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.7.0(2022-02-26) +###【重要】由于uni官方限制自定义表不可以用 `opendb-` 和 `uni-` 开头,故以下数据库表名只能进行调整 + +* 1、`opendb-components-dynamic` 改为 `vk-components-dynamic` +* 2、`opendb-global-data` 改为 `vk-global-data` +* 3、`uni-id-files` 改为 `vk-files` +* 4、`uni-id-files-categories` 改为 `vk-files-categories` + +___更改表名势必会对老项目产生影响。___ + +### 老项目更新注意事项: +* 1、老项目更新后,还需要从 `unicloud控制台` 把表名改成对应的新表名 +* 2、在项目代码中全局搜索旧表名,替换成新表名 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.15(2022-02-24) +* 1、【优化】`万能连表` 支持副表外键是数组类型(只要数组内任意元素与主表外键匹配即可)[点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html#%E5%9C%BA%E6%99%AF6) +* 2、【优化】其他一些细节 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.6.14(2022-01-20) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.13(2022-01-14) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.12(2022-01-08) +* 【修复】`vk.openapi.weixin.security.imgSecCheck` 图片安全检测失效的问题 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.11(2021-12-24) +* 1、【修复】`vk.pubfn.string2Number` 会将空字符串转为0的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.10(2021-12-17) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.9(2021-12-16) +* 1、【修复】`vk.pubfn.priceFilter` 、`vk.pubfn.percentageFilter` 、`vk.pubfn.discountFilter` 部分情况下,默认值不生效的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.8(2021-12-14) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.7(2021-12-14) +* 1、【优化】一些细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.6(2021-12-10) +* 1、【修复】少数情况下,http请求可能获取不到数据的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.5(2021-12-07) +* 1、【修复】公众号登录可能会获取不到昵称和头像的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.4(2021-12-07) +* 1、【优化】上传api的url自动去除原文件名的中文部分。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.3(2021-11-29) +* 1、【新增】`vk.baseDao` 内api支持连接其他服务空间的数据库 [点击查看](https://vkdoc.fsq.pub/client/question/q9.html#%E4%BA%91%E5%87%BD%E6%95%B0%E7%AB%AF%E8%AF%B7%E6%B1%82%E5%A4%9A%E6%9C%8D%E5%8A%A1%E7%A9%BA%E9%97%B4%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.2(2021-11-26) +* 1、【新增】`await vk.pubfn.batchRun` 批量循环并发执行异步函数(云函数内专用, 使用场景: 批量发送短信、邮件、消息通知等。)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-batchrun) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.1(2021-11-26) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.6.0(2021-11-19) +* 1、【重要】移除了内置的 `npm` 方式安装的 `uView` 组件库,开发者可以选择自己喜欢的组件库进行开发。[点击查看](https://vkdoc.fsq.pub/client/quickstart.html#%E8%87%AA-client%E7%AB%AF%E6%A1%86%E6%9E%B6-2-6-0-%E8%B5%B7-%E4%B8%8D%E5%86%8D%E5%86%85%E7%BD%AE%E4%BB%BB%E4%BD%95-ui-%E6%A1%86%E6%9E%B6-%E4%BD%A0%E5%8F%AF%E4%BB%A5%E9%80%89%E6%8B%A9%E8%87%AA%E5%B7%B1%E5%96%9C%E6%AC%A2%E7%9A%84-ui-%E7%BB%84%E4%BB%B6%E5%BA%93%E8%BF%9B%E8%A1%8C%E5%BC%80%E5%8F%91%E3%80%82) +* 2、【重要】移除内置组件 `vk-u-goods-sku-popup`(推荐 `vk-data-goods-sku-popup` 代替)[点击查看](https://ext.dcloud.net.cn/plugin?id=2848) +* 3、【重要】移除内置组件 `vk-u-number-box`(推荐 `u-number-box` 代替) +* 4、【重要】移除内置组件 `vk-u-grid-button` +* 5、【重要】移除内置组件 `vk-u-swiper` +* 6、【重要】重构内置组件 `vk-u-verification-code` 并改名为 `vk-data-verification-code` +* 如想要继续使用这些组件,可以把这些组件复制到项目根目录的 `components` 目录(没有则新建)(目录名和组件名需一致,如 `vk-u-grid-button/vk-u-grid-button`) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.6(2021-11-13) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.5(2021-11-11) +* 1、【新增】`vk.pubfn.getOffsetTime` 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getoffsettime-%E8%8E%B7%E5%BE%97%E6%8C%87%E5%AE%9A%E6%97%B6%E9%97%B4%E5%81%8F%E7%A7%BB-year%E5%B9%B4-month%E6%9C%88-day%E5%A4%A9-hours%E6%97%B6-minutes%E5%88%86-seconds%E7%A7%92%E5%89%8D%E6%88%96%E5%90%8E%E7%9A%84%E6%97%B6%E9%97%B4%E6%88%B3) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.4(2021-11-10) +* 1、【优化】前端请求云函数的一处细节。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.3(2021-11-09) +* 1、【优化】`vk.pubfn.base64ToFile` 支持 APP 环境执行 +* 2、【优化】`vk.pubfn.fileToBase64` 支持 APP 环境执行 +* 3、【修复】`vk.baseDao.selects` 当 `localKey` 为 `a.b.c` 这样的形式时会报错的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.2(2021-11-03) +* 1、【修复】`vk.baseDao.adds` 无返回值的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.1(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigateToHome` 跳转到首页 (app.config.js 的 index.url) +* 4、【新增】`vk.navigateToLogin` 跳转到登录页 (app.config.js 的 login.url) +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.5.0(2021-11-02) +* 1、【新增】`vk.h5` 前端API接口(H5专用的一些接口,只有H5环境时,才有该对象,不会增大小程序的包体积) +* 2、【新增】`vk.h5.wx`(wx为公众号js_sdk接口) [微信小程序环境内js_sdk文档](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) [微信公众号环境内js_sdk文档](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) +* 3、【新增】`vk.navigate.navigateToHome` 跳转到首页 +* 4、【新增】`vk.navigate.navigateToLogin` 跳转到登录页 +* 5、【修复】`vk.callFunctionUtil.updateRequestGlobalParam` 全局公共请求参数的一处逻辑问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.12(2021-10-30) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.11(2021-10-28) +* 1、【优化】`vk.pubfn.hidden(str, first, last);` 的 `first` 和 `last` 默认为0 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-hidden-%E5%B0%86%E6%89%8B%E6%9C%BA%E5%8F%B7%E3%80%81%E8%B4%A6%E5%8F%B7%E7%AD%89%E9%9A%90%E8%97%8F%E4%B8%AD%E9%97%B4%E5%AD%97%E6%AE%B5) +* 2、【优化】其他一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.10(2021-10-26) +* 【优化】在 `template` 模板中使用 `vk.pubfn`(可以用简写法 `$fn` 代替 `vk.pubfn`) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.9(2021-10-23) +* 【优化】`vk.userCenter` 接口细节,现在参数 `loading:true` 或 `loading:false` 均可以关闭 `loading提示框` +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.8(2021-10-16) +* 【优化】当配置文件编译错误时,增加对应的错误提示。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.7(2021-10-15) +* 【优化】当 `router/util/pubFunction.js` 内的代码出现编译错误时,控制台能打印编译错误信息。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.6(2021-10-07) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.4.5(2021-09-30) +* 1、【优化】`vk.pubfn.string2Number` 新增第二位参数option +```js +/** + * 将能转成数字的字符串转数字(支持字符串、对象、数组) + * @param {Any} obj + * @param {Object} option 哪些格式需要排除 + * 默认排除 + * mobile:true 手机号,如 15200000001 + * idCard:true 身份证,如 330154202109301214 + * startFrom0:true 第一位是0,且长度大于1的,同时第二位不是.的字符串 如 01,057189101254 + */ +vk.pubfn.string2Number(obj, option); +``` + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.3(2021-09-30) +* 1、【优化】`vk.pubfn.string2Number` 新增第二位参数option,默认排除手机号、身份证、第一位是0,且长度大于1的字符串(可自由设置) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.2(2021-09-30) +* 1、【新增】`vk.pubfn.string2Number` 将能转成数字的字符串值转Number类型(支持字符串、对象、数组)(深度遍历) +* 2、【优化】`vk.callFunctionUtil.updateRequestGlobalParam` 设置全局请求参数 `regExp` 参数支持数组(满足数组内任意正则即算匹配) [点击查看](https://vkdoc.fsq.pub/client/pages/updateRequestGlobalParam.html) + + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.1(2021-09-28) +* 1、【重要】支持微信公众号登录(有头像和昵称)详情见示例项目:`pages_template/openapi/h5-weixin/h5-weixin` +* 2、【优化】APP使用微信登录时,有头像和昵称 详情见示例项目:`pages_template/uni-id/weixin/weixin` + +公众号配置文件在 `uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json` + +```js +"h5-weixin": { + "oauth": { + "weixin": { + "appid": "微信公众号appid", + "appsecret": "微信公众号appsecret" + } + } +}, +``` +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.4.0(2021-09-28) +* 1、【重要】支持微信公众号登录(有头像和昵称)详情见示例项目:`pages_template/openapi/h5-weixin/h5-weixin` +* 2、【优化】APP使用微信登录时,有头像和昵称 详情见示例项目:`pages_template/uni-id/weixin/weixin` + +公众号配置文件在 `uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json` + +```js +"h5-weixin": { + "oauth": { + "weixin": { + "appid": "微信公众号appid", + "appsecret": "微信公众号appsecret" + } + } +}, +``` +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.29(2021-09-27) +* 1、【新增】`vk.pubfn.snake2camelJson` 对象内的属性名 - 蛇形转驼峰 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-snake2cameljson-%E5%AF%B9%E8%B1%A1%E5%86%85%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-%E8%9B%87%E5%BD%A2%E8%BD%AC%E9%A9%BC%E5%B3%B0) +* 2、【新增】`vk.pubfn.camel2snakeJson` 对象内的属性名 - 驼峰转蛇形 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-camel2snakejson-%E5%AF%B9%E8%B1%A1%E5%86%85%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D-%E9%A9%BC%E5%B3%B0%E8%BD%AC%E8%9B%87%E5%BD%A2) +* 3、【新增】`vk.pubfn.snake2camel` 字符串 - 蛇形转驼峰 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-snake2camel-%E5%AD%97%E7%AC%A6%E4%B8%B2-%E8%9B%87%E5%BD%A2%E8%BD%AC%E9%A9%BC%E5%B3%B0) +* 4、【新增】`vk.pubfn.camel2snake` 字符串 - 驼峰转蛇形 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-camel2snake-%E5%AD%97%E7%AC%A6%E4%B8%B2-%E9%A9%BC%E5%B3%B0%E8%BD%AC%E8%9B%87%E5%BD%A2) + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +##### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.3.28(2021-09-16) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.27(2021-09-14) +* 【优化】`vk.pubfn.dateDiff` 新增后缀参数 [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-datediff-%E5%B0%86%E6%97%B6%E9%97%B4%E6%98%BE%E7%A4%BA%E6%88%901%E7%A7%92%E5%89%8D%E3%80%811%E5%A4%A9%E5%89%8D) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.26(2021-09-14) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.25(2021-09-13) +* 1、【优化】文件上传逻辑 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.24(2021-09-08) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.23(2021-09-07) +* 1、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.22(2021-09-01) +* 1、【优化】文件上传逻辑 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.21(2021-08-31) +* 1、【新增】配置`vk.db.unicloud.getTableData.sortArr`,可以设置`vk.baseDao.getTableData`全局默认排序规则 +* 2、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.20(2021-08-26) +* 1、【新增】`app.config.js` 新增参数 `globalErrorCode` 可以修改全局异常的提示信息 [点击查看](https://vkdoc.fsq.pub/client/pages/config.html) +* 2、【新增】`javascript代码块提示.json` 最近新增的api的代码提示 [点击查看](https://vkdoc.fsq.pub/client/codeTips.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.19(2021-08-26) +* 1、【新增】`app.config.js` 新增参数 `globalErrorCode` 可以修改全局异常的提示信息 [点击查看](https://vkdoc.fsq.pub/client/pages/config.html) +* 2、【新增】`javascript代码块提示.json` 最近新增的api的代码提示 [点击查看](https://vkdoc.fsq.pub/client/codeTips.html) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.18(2021-08-24) +* 1、【修复】腾讯云的图片上传无法回显图片的问题。 +* 2、【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.17(2021-08-24) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.16(2021-08-24) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.15(2021-08-24) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.14(2021-08-23) +* 【修复】腾讯云的图片上传无法回显图片的问题。 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.13(2021-08-23) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.12(2021-08-23) +* 【优化】一些细节 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.11(2021-08-21) +* 【新增】`vk.pubfn.sleep` 进程等待(主要用于在云函数中需要故意等待几秒的情况)[点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-sleep-%E8%BF%9B%E7%A8%8B%E5%BC%BA%E5%88%B6%E7%AD%89%E5%BE%85-%E4%BC%91%E7%9C%A0) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.10(2021-08-21) +* 【优化】`vk.pubfn.timeFormat` 等API,当参数time为字符串时间戳时的特殊处理 +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.9(2021-08-21) +* 【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.8(2021-08-21) +* 【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.7(2021-08-21) +* 【新增】`vk.pubfn.getDayOffsetStartAndEnd` 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getdayoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%A4%A9%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getMonthOffsetStartAndEnd` 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getmonthoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E6%9C%88%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 【新增】`vk.pubfn.getYearOffsetStartAndEnd`获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) [点击查看](https://vkdoc.fsq.pub/client/jsapi.html#vk-pubfn-getyearoffsetstartandend-%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%AF%B9%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E7%9A%84%E5%81%8F%E7%A7%BB-count-%E5%B9%B4%E7%9A%84%E8%B5%B7%E6%AD%A2%E6%97%A5%E6%9C%9F) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.6(2021-08-19) +* 【优化】`vk.baseDao.selects`新增参数`addFields` [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%88%86%E7%BB%84count) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.5(2021-08-19) +* 【优化】`vk.baseDao.selects`新增参数`addFields` [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/question.html#%E5%88%86%E7%BB%84count) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.4(2021-08-19) +* 【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.3(2021-08-19) +* 【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.2(2021-08-19) +* 【新增】`vk.baseDao.updateAndReturn` API [点击查看](https://vkdoc.fsq.pub/client/uniCloud/db/api.html#%E6%9B%B4%E6%96%B0%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE-%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C) +* 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.1(2021-08-16) +####【重要】文档已搬家(gitee文档地址仅作为备用地址)[查看新版文档地址](https://vkdoc.fsq.pub/) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.3.0(2021-08-16) +####【重要】文档已搬家(gitee文档地址仅作为备用地址)[查看新版文档地址](https://vkdoc.fsq.pub/) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.13(2021-08-12) +#### 【优化】一些细节(为兼容Vue3做铺垫) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.12(2021-08-11) +#### 【优化】一些细节(为兼容Vue3做铺垫) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.11(2021-08-11) +#### 【优化】一些细节(为兼容Vue3做铺垫) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.10(2021-08-06) +#### 【优化】一些细节 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.9(2021-08-06) +#### 【优化】一些细节 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.8(2021-08-05) +### 更新内容 +#### 1、【修复】因`uni-id`配置隔离导致的微信`vk.openapi.weixin` API 兼容性问题。 +#### 2、【新增】`vk.pubfn.isArray` 判断变量是否是数组类型 +#### 3、【新增】`vk.pubfn.isObject` 判断变量是否是对象类型 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.2.7(2021-08-04) +### 更新内容 +#### 【优化】一些细节 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.6(2021-07-28) +### 更新内容 +#### 【新增】前端 `vk.callFunction` 支持请求其他服务空间的云函数 +```js +const myCloud = uniCloud.init({ + provider: 'aliyun', + spaceId: 'xxxx-yyy', + clientSecret: 'xxxx' +}); +vk.callFunction({ + url: 'template/db_api/pub/count', + title:'请求中...', + unicloud: myCloud, + success(data) { + console.log(data); + } +}); +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.2.4(2021-07-12) +### 更新内容 +####【修复】已知问题 +## 2.2.3(2021-07-12) +### 更新内容 +####【修复】首次使用框架,上传部署后访问云函数可能会出现 `createInstance is undefined` 的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.2.2(2021-07-12) +### 更新内容 +####【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.1(2021-07-12) +### 更新内容 +####【修复】连表查询时,因`lastWhereJson`而导致`getCount`错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.2.0(2021-07-09) +### 更新内容 +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) +#### 1、【重要调整】删除了`config`公共模块,升级为`uni-config-center`模式 [点击查看升级教程](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4219337&doc_id=975983) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.14(2021-07-07) +### 更新内容 +####【修复】已知bug +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.13(2021-07-05) +### 更新内容 +####【修复】已知bug +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.12(2021-06-28) +### 更新内容 +#### 1、【修复】`user/kh/getMenu`云函数获取菜单错误的bug。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.11(2021-06-22) +### 更新内容 +#### 1、【优化】`vk.pubfn.timeFormat` 若参数不符合规则,则原值显示。 +#### 2、【优化】`vk.pubfn.random` 新增第三个参数`arr` (产生的随机数不会和此数组的任意一项重复) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3268613&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.10(2021-06-22) +### 更新内容 +#### 1、【优化】`vk.pubfn.timeFormat` 若参数不符合规则,则原值显示。 +#### 2、【优化】`vk.pubfn.random` 新增第三个参数`arr` (产生的随机数不会和此数组的任意一项重复) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3268613&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.9(2021-06-16) +### 更新内容 +####【修复】`vk.baseDao.add` 因hbx 3.1.18版本导致的本地运行时 `_add_time_str` 错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.8(2021-06-12) +### 更新内容 +####【修复】`vk.pubfn.copyObject` 若参数值为undefined则会报异常的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.7(2021-06-10) +####【优化】`vk.callFunctionUtil.uploadFile` 自动识别文件类型,无需传`fileType`参数 +####【修复】已知问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.6(2021-06-04) +### 更新内容 +####【修复】`返回树状结构`时最后一级子节点没有继承主表`foreignDB`属性的bug。[查询返回树状结构文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.5(2021-06-04) +### 更新内容 +####【修复】`返回树状结构`时最后一级子节点没有继承主表`foreignDB`属性的bug。[查询返回树状结构文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.1.4(2021-06-03) +### 更新内容 +####【新增】`onActionIntercepted`(被中间件拦截时执行) 和 `onActionError`(云函数执行异常时执行) 类型中间件 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3035637&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.3(2021-06-03) +### 更新内容 +####【新增】`onActionIntercepted`(被中间件拦截时执行) 和 `onActionError`(云函数执行异常时执行) 类型中间件 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3035637&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.2(2021-05-31) +### 更新内容 +####【优化】过滤器 `timeFilter`、`dateDiff` 能正确识别10位数时间戳和13位时间戳。[点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3269404&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.1.1(2021-05-31) +### 更新内容 +####【优化】`云函数URL化` 路由模式下,URL重写支持只允许部分云函数可被访问。(可以做到只暴露指定的API接口,增加URL化后的安全性) +#### `router/util/urlrewrite.js`文件配置内容如下 [点击URL重写规则](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 2.0.11(2021-05-27) +### 更新内容 +#### 【优化】`vk.baseDao.select` 也支持 `getOne` 、 `getMain` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.10(2021-05-27) +### 更新内容 +#### 【修复】`vk.callFunctionUtil.uploadFile` 上传视频时后缀名可能会错误的问题。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.9(2021-05-26) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 中按距离查询的逻辑 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.8(2021-05-25) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.7(2021-05-25) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + + +## 2.0.6(2021-05-25) +### 更新内容 +#### 【优化】`vk.baseDao.selects` 新增两个属性`getOne` 、 `getMain` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4054561&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + + + +## 2.0.5(2021-05-21) +### 更新内容 +#### 【优化】`vk.baseDao.getTableData` 和 `vk.baseDao.selects` 连表查询逻辑。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.4(2021-05-21) +【调整】`vk.baseDao.getTableData` 默认排序规则调整为`_id`降序,之前是`_add_time`降序(因不是每个表都有`_add_time`字段) +## 2.0.3(2021-05-21) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】`vk.baseDao` API的查询性能。 + +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 + +## 2.0.2(2021-05-16) +### 更新内容 +#### 【优化】修复验证码发送的已知bug +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.1(2021-05-15) +### 更新内容 +#### 【优化】用户角色权限,支持admin使用 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003879&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 2.0.0(2021-05-15) +### 更新内容 +#### 【优化】用户角色权限,支持admin使用 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=4003879&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.4(2021-05-10) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】`vk.baseDao.selects` 支持分组查询,对应 `groupJson` 参数 [点击查看万能连表场景6](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +#### 2、【优化】`vk.globalDataCache.get` 支持如果缓存有值,则读取缓存,如果缓存无值,则执行函数,并将函数return的结果保存到缓存 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3442025&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.3(2021-04-23) +### 更新内容 +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +#### 1、【重要】【新增】 `pages-dev.json` 机制,写法与`pages.json` 相同,但里面的页面只有运行(开发)环境时才会被HBX打包,发行(正式)环境下不会被HBX打包进去。[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3928718&doc_id=975983) +```js +可以将一些测试页面写在 `pages-dev.json`内,这些测试页面在正式发布时是不会被HBX打包到源码里的。 +``` +#### 2、【重要】【新增】阿里云和unicloud短信聚合API (阿里云短信的实现不依赖阿里云SDK核心库,无需`npm install @alicloud/pop-core`)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/%E4%B8%8A%E4%BC%A0%20%E4%BA%91%E5%82%A8%E5%AD%98%E6%88%96%E9%98%BF%E9%87%8C%E4%BA%91OSS?sort_id=3673784) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.2(2021-04-19) +### 更新内容 +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +#### 【优化】`vk.selects` 支持主表外键是数组的情况下(如`uni-id-users`表的`role`字段)连表查出`roleList` [点击查看场景5](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +#### 1、【重要】【全网首家】`云函数url化` 支持以纯链接形式访问路由后的云函数 如: `https://xxx.bspapp.com/http/router/client/user/pub/findGoodsInfo?id=1` +#### 2、【重要】【全网首家】`云函数url化` 支持URL重写 [点击查看URL重写详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3916806&doc_id=975983) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.9.1(2021-04-16) +### 更新内容 +#### 【优化】`vk.selects` 支持主表外键是数组的情况下(如`uni-id-users`表的`role`字段)连表查出`roleList` [点击查看场景5](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) + +## 1.9.0(2021-04-15) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】`vk.selects` 支持返回树状结构 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3906510&doc_id=975983) +#### 2、【新增】`vk.pubfn.deepClone` 深度克隆(与`vk.pubfn.copyObject`的区别:可以克隆函数) +#### 3、【优化】`vk.setData` 内部逻辑 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.24(2021-04-13) +### 更新内容 +#### 1、【调整】`vk.request`默认的`header`与官方对其(之前默认是`{"content-type": "application/json; charset=UTF-8"}`) +#### 2、【优化】`uni-id` 模式调整为:兼容单实例多并发模式 +## 1.8.23(2021-04-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】云函数中 `vk.request`新增参数`needOriginalRes` 默认为`false`,若为`true`,则会返回原始数据(包含请求头等数据) +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.22(2021-04-07) +### 更新内容 +####【修复】`console.log`在小程序端可能会无法打印出代码所在位置的问题。 +## 1.8.21(2021-04-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +### 1、【优化】如需要在云函数中主动抛出异常,且能让前端框架自动识别后进行alert弹窗提示,则可使用以下方式 +```js +// 注意: 必须以msg:为前缀,否则框架无法识别(只支持字符串) +throw new Error("msg:这里是错误的提示"); +``` +#### 2、【新增】`app.config.js` 新增 `tokenExpiredAutoDelete` 属性,默认`true` 若设为`false`,则`token`失效时,依然保留前端的`token缓存`。 +``` +官方原生语法中,连表查询和非连表查询在使用`_.geoNear`时用较大差别; +而 vk.baseDao.selects(万能连表)写法跟 vk.baseDao.select(单表查询) 写法保持统一,使上手更简单。 +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.20(2021-03-29) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +####【优化】`vk.baseDao.selects` 支持`_.geoNear`API(将记录按照离给定点从近到远输出。)[点击查看万能连表场景4](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +``` +官方原生语法中,连表查询和非连表查询在使用`_.geoNear`时用较大差别; +而 vk.baseDao.selects(万能连表)写法跟 vk.baseDao.select(单表查询) 写法保持统一,使上手更简单。 +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.19(2021-03-27) +### 更新内容 +#### 1、【新增】`百度开放平台API接口` (营业执照识别、身份证识别等) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3803034&doc_id=975983) +#### 2、【优化】`kh`目录下的函数默认会获取 `userInfo`(当前登录用户信息),如果此云函数不需要用户信息,可以在前端多传一个参数`need_user_info:false` 可以减少一次数据库查询(加快响应速度)(快100ms左右) [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3790840&doc_id=975983) +#### 3、【优化】`returnUserInfoFilter` 过滤器的内部逻辑 +#### 4、【优化】`vk.callFunction` 新增参数 `needAlert`(默认为true) 来代替 `noAlert`(默认为false) 二选一即可(建议后面都使用`needAlert`参数,它更语义化) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.18(2021-03-24) +### 更新内容 +#### 1、【重要】`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3541759&doc_id=975983) +#### 2、【新增】`vk.pubfn.timeUtil.isLeapYear` 判断是否是闰年 +#### 3、【新增】`vk.pubfn.timeUtil.isQingming` 判断是否是清明节 +#### 4、【新增】清明节灰色页面实现方案 [点击查看](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3782115&doc_id=975983) +```js +/** + * 判断是否是闰年 + * @param {Number | Date} year 需要计算的年份或时间,默认使用当前时间的年份 + */ +vk.pubfn.timeUtil.isLeapYear(2021); +/** + * 判断是否是清明节 + * @param {Object} date 时间对象 + */ +vk.pubfn.timeUtil.isQingming(new Date()); +``` +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + + +## 1.8.17(2021-03-20) +### 更新内容 +#### 【优化】`vk.userCenter.code2SessionWeixin` 的内部逻辑。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.16(2021-03-20) +### 更新内容 +#### 1、【优化】`vk.callFunctionUtil.uploadFile` 新增参数 `suffix`,可直接自定义文件后缀名 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) + +## 1.8.15(2021-03-19) +### 更新内容 +#### 1、【修复】微信小程序服务端API在保存`token`时,缓存时间错误的问题。 +#### 2、【修复】`vk.callFunctionUtil.uploadFile` 上传视频返回`.png`的问题 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.14(2021-03-19) +### 更新内容 +#### 【新增】APP本机号码一键登录API `vk.userCenter.loginByUniverify` +## 1.8.13(2021-03-17) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【优化】在安装了`vuex`后,移除了名为`uni_id_user_info`的本地缓存(重复了)(`userInfo`使用`vk.getVuex('$user.userInfo')`获取) +#### 2、【修复】微信小程序服务端API在获取`token`时,没有正确使用缓存的问题。 + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.12(2021-03-12) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】现在可以在js文件中直接通过 `uni.vk` 来使用 `vk` 对象内的API +#### 2、【新增】`app.config.js` 新增参数 `checkSharePages` 控制页面是否可以被小程序分享 +#### 3、【优化】发行模式下,`console.log` 将不会打印任何日志。 +```js +若发行模式下需要强制打印,可用 `vk.log` 代替 `console.log` +``` +## 1.8.11(2021-03-10) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`vk.callFunctionUtil.uploadFile` 支持前端直传至`阿里云oss` [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673784&doc_id=975983) +#### 2、【新增】`app.config.js` 新增 `myfn` 参数,可用来拓展自定义公共函数 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3673929&doc_id=975983) + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) + +## 1.8.10(2021-03-06) +### 更新内容 +#### 【优化】`vk.setVuex` 和 `vk.setData` 的赋值逻辑 +```js +如数据源$data +{ + a:1, + b:"1", +}; +执行 vk.setVuex("$data.a.b.c",1); +结果: +{ + a:{ + b:{ + c:1 + } + }, + b:"1" +} +``` +## 1.8.9(2021-03-05) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【新增】`vk.openapi.weixin.subscribeMessage.send` 微信小程序发送订阅消息 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3569379&doc_id=975983) +#### 2、【优化】`vk.baseDao.add` 和 `vk.baseDao.adds` 新增参数 `cancelAddTime` 为`true`,则不会有`_add_time`和`_add_time_str`字段生成 +#### 3、【优化】`vk.baseDao.add` 和 `vk.baseDao.adds` 支持添加自定义 `_id` + +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.8(2021-03-04) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【重要】`vuex` 的使用方式有较大更新。(有性能提升)[点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3654596&doc_id=975983) + +## 1.8.7(2021-02-24) +### 更新内容 +#### 【修复】`vk.openapi.weixin.auth.code2Session` 会报`vk is not defined`的错误。 + +## 1.8.6(2021-02-24) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【修复】`vk.baseDao.deleteById` 会报`vk is not defined`的错误。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.5(2021-02-23) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【优化】`vk.baseDao.selects` 支持副表与副表的副表进行连表 [点击查看详情](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3028633&doc_id=975983) +``` +1.1、支持无限张副表和主表进行连接(横向无限张表) +1.2、支持副表与副表的副表进行连接(竖向无限层连接) +``` + + + +## 1.8.4(2021-02-16) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 微信小程序服务端API [点击查看文档](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=3569379&doc_id=975983) +#### 1、【新增】`获取AccessToken` : `vk.openapi.weixin.auth.getAccessToken` +#### 2、【新增】`code换取openid` : `vk.openapi.weixin.auth.code2Session` +#### 3、【新增】`获取微信绑定的手机号` : `vk.openapi.weixin.decrypt.getPhoneNumber` +#### 4、【新增】`文本违规检测` : `vk.openapi.weixin.security.msgSecCheck` +#### 5、【新增】`图片违规检测` : `vk.openapi.weixin.security.imgSecCheck` +#### 6、【新增】`获取小程序码` : `vk.openapi.weixin.wxacode.getUnlimited` +#### 7、【新增】`小程序Scheme码` : `vk.openapi.weixin.urlscheme.generate` + +## 1.8.3(2021-02-11) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 【优化】`main.js` 代码结构。 +#### 完整框架项目地址:`https://ext.dcloud.net.cn/plugin?id=2204`[点击查看](https://ext.dcloud.net.cn/plugin?id=2204) +## 1.8.2(2021-02-08) +### 支持 `uni-pay` 模块 +## 1.8.1(2021-02-08) +### 优化插件目录结构 +完整框架项目地址:https://ext.dcloud.net.cn/plugin?id=2204 +## 1.8.0(2021-02-07) +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】本次更新文件有重大改动,升级成功后将变成`uni_modules`版本,下次更新框架只需要在hbx编译器中一键更新。 +#### 3、【新增】【小程序API】`vk.userCenter.loginByWeixinPhoneNumber` 前端可以使用微信小程序一键进行手机号登录 +#### 4、【新增】【小程序API】`vk.userCenter.getPhoneNumber` 前端一键获取微信小程序绑定的手机号 +#### 5、【新增】【小程序API】`vk.openapi.weixin.decrypt.getPhoneNumber` 云函数解析微信小程序绑定的手机号 +#### 6、【新增】【小程序API】`vk.userCenter.getWeixinMPqrcode` 前端一键生成带参数的小程序码 +#### 7、【新增】【小程序API】`vk.userCenter.getWeixinMPscheme` 前端一键生成带参数的小程序scheme码(支持从手机短信跳转到小程序) +#### 8、【优化】`middleware/modules/returnUserInfoFilter` 中间件的处理逻辑。 +#### 9、【优化】`javascript代码块提示.json` 输入`vk.`可以快速提示代码块 `根目录/使用帮助/代码快捷提示` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 +### uniCloud 云函数路由研究群:22466457 如有问题或建议可以在群内讨论。 +### 更新内容 +#### 1、【重要】升级至`uni_modules`版本 [点击查看升级指南](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/1.8%E4%BB%A5%E4%B8%8B%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E8%87%B31.8%E5%8D%87%E7%BA%A7%E6%8C%87%E5%8D%97%20%E5%8D%87%E7%BA%A7%E6%88%90%20uni_modules%E7%89%88%E6%9C%AC?sort_id=3541759) +#### 2、【重要】本次更新文件有重大改动,升级成功后将变成`uni_modules`版本,下次更新框架只需要在hbx编译器中一键更新。 +#### 3、【新增】【小程序API】`vk.userCenter.loginByWeixinPhoneNumber` 前端可以使用微信小程序一键进行手机号登录 +#### 4、【新增】【小程序API】`vk.userCenter.getPhoneNumber` 前端一键获取微信小程序绑定的手机号 +#### 5、【新增】【小程序API】`vk.openapi.weixin.decrypt.getPhoneNumber` 云函数解析微信小程序绑定的手机号 +#### 6、【新增】【小程序API】`vk.userCenter.getWeixinMPqrcode` 前端一键生成带参数的小程序码 +#### 7、【新增】【小程序API】`vk.userCenter.getWeixinMPscheme` 前端一键生成带参数的小程序scheme码(支持从手机短信跳转到小程序) +#### 8、【优化】`middleware/modules/returnUserInfoFilter` 中间件的处理逻辑。 +#### 9、【优化】`javascript代码块提示.json` 输入`vk.`可以快速提示代码块 `根目录/使用帮助/代码快捷提示` + +#### 如有疑问,请加群:22466457 关于插件的问题包教包会! +### 你也可以在评论区发布留言交流心得。 \ No newline at end of file diff --git a/uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue b/uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue new file mode 100644 index 0000000..bc06dfd --- /dev/null +++ b/uni_modules/vk-unicloud/components/vk-data-verification-code/vk-data-verification-code.vue @@ -0,0 +1,320 @@ + + + + + diff --git a/uni_modules/vk-unicloud/index.js b/uni_modules/vk-unicloud/index.js new file mode 100644 index 0000000..63d85e3 --- /dev/null +++ b/uni_modules/vk-unicloud/index.js @@ -0,0 +1,7 @@ +/** + * vk-unicloud框架客户端(前端) + * author VK + */ +import vk from './vk_modules/vk-unicloud-page' + +export default vk; \ No newline at end of file diff --git a/uni_modules/vk-unicloud/package.json b/uni_modules/vk-unicloud/package.json new file mode 100644 index 0000000..ef506ef --- /dev/null +++ b/uni_modules/vk-unicloud/package.json @@ -0,0 +1,86 @@ +{ + "id": "vk-unicloud", + "displayName": "vk-unicloud-router开发框架核心库 - 已集成uni-id 框架内置了众多API。", + "version": "2.15.3", + "description": "此为vk-unicloud-router框架核心库(新手建议下载完整框架项目)已集成uni-id支持云函数url化。众多现成API,内置小白也能轻松上手的数据库API。使你项目刚起步进度就是百分之50", + "keywords": [ + "vk-unicloud-router", + "云函数路由、云对象路由", + "vk云开发", + "内置uni-id、uview、数据库baseDao", + "内置众多API、工具包" +], + "author": "VK", + "repository": "https://gitee.com/vk-uni/vk-uni-cloud-router", + "engines": { + "HBuilderX": "^3.1.0" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "370725567" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "https://vkdoc.fsq.pub/", + "type": "unicloud-template-function" + }, + "uni_modules": { + "dependencies": ["uni-config-center","uni-id"], + "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", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} diff --git a/uni_modules/vk-unicloud/readme.md b/uni_modules/vk-unicloud/readme.md new file mode 100644 index 0000000..231ce94 --- /dev/null +++ b/uni_modules/vk-unicloud/readme.md @@ -0,0 +1,572 @@ +### uniCloud云函数路由框架研究Q群:22466457 如有问题或建议可以在群内讨论。 +### 插件名称:`vk-unicloud-router` +### 作者:VK + +## 序 +##### 如果你热爱编程,想快速入门云开发,欢迎使用`vk-unicloud`系列开发框架 +##### 无需转变开发习惯,0成本上手云开发。 +##### 框架内置了众多API、工具包,为你的业务扫平障碍。使你的项目刚起步进度就是50%(微信登录、短信、验证码、缓存、生成小程序码等等) +##### 从此你又get一个新技能,只需用js,轻松搞定前后台整体业务。 +##### 完整框架项目地址: +##### `client端`框架地址: [https://ext.dcloud.net.cn/plugin?id=2204](https://ext.dcloud.net.cn/plugin?id=2204) +##### `admin端`框架地址:[https://ext.dcloud.net.cn/plugin?id=5043](https://ext.dcloud.net.cn/plugin?name=vk-unicloud-admin) +##### `client端`框架文档:[点击查看](https://vkdoc.fsq.pub/client/) +##### `admin端`框架文档:[点击查看](https://vkdoc.fsq.pub/admin/) +##### 框架学习Q群:`22466457` 欢迎萌新和大佬来使用和共同改进框架 + +## 主要功能 以及 对开发者的价值 +#### 1、实现云函数路由模式(同时支持对云对象的路由) +* 1.1、路由模式不使用任何第三方包,兼容性强,运行稳定 +* 1.2、减少云函数数量,云函数有个数限制(用一个云函数即可实现多个云函数效果) +* 1.3、部分通用的代码块可以放在公共区执行,具有公共函数的效果,增加代码复用率,便于维护。 +* 1.4、可以在开发环境和生产环境中任意切换,开发时,用开发环境,开发过程中不会影响到线上环境。(具体切换方法在文档最后) +* 1.5、美化云函数请求过程中的日志排版,使请求日志一目了然。(再也不用为日志分散,难找而头疼) +* 1.6、可以强制关闭云端服务(适用于需要临时关闭后端服务的情况,如腾讯云迁移数据到阿里云时需要先关闭服务,否则迁移过程中会有新数据产生) + +#### 2、实现 `全局过滤器`,过滤非法请求。您无需关心用户角色权限问题。 + +#### 3、众多现成的 `JS API`,让您无需重复造轮子。(持续增加中) + +#### 4、众多现成的 `云函数 API`,为您的业务扫平障碍,让您可以专注于自身业务开发。(微信登录、短信、验证码、缓存、生成小程序码等等)(持续增加中) + +#### 5、全面支持 `url化` 的云函数请求,您无需关心url化后参数的获取问题 + +#### 6、已集成 `uni-id` 当前版本: `3.3.28`(已支持真实发送邮箱验证码和短信验证码) +* 6.1、由于每个应用基本都会用上用户系统,官方建议所有 `uniCloud` 应用均使用 `uni-id` 作为用户体系, +有了统一的账户规范,并且围绕这套账户规范,有各种各样插件,那么开发者可以随意整合这些插件,让数据连同。 + +* 6.2、同时方便其他用户使用 `unicloud` 插件发布者发布的前后端一体插件,只需要导入一个云函数即可。 +(如导入一个社区插件,可能要导入几十个云函数,而使用此云函数路由后,只需导入一个云函数,且已集成 `uni-id`,打通账号体系)。 + +#### 7、在 `uni-id` 基础上升级为 `vk.userCenter` 用户中心API 通过this.vk.userCenter 即可调用 [传送门](https://vkdoc.fsq.pub/client/vk.userCenter.html) + +#### 8、封装 `uni.callFunction` 和 `uni.request` 使之合二为一 通过this.vk.callFunction 调用 + +#### 9、`vk.baseDao` 数据库API,使小白也能轻松上手对数据库的调用。 [传送门](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +#### 10、`vk.baseDao.selects` 数据库万能连表查询API [传送门](https://vkdoc.fsq.pub/client/uniCloud/db/selects.html) + +#### 11、`商品SKU选择器组件`(打造uni插件市场功能最全的SKU选择器组件)[传送门](https://ext.dcloud.net.cn/plugin?id=2848) + +#### 12、对 `Vuex` 进行了深度封装(支持持久化),现在可以很方便的使用Vuex进行读取和储存。[传送门](https://vkdoc.fsq.pub/client/pages/vuex.html) + +#### 13、自定义过滤器(在业务云函数执行之前(或之后),统一拦截,进行过滤后再放行,支持设置多个过滤器,并按指定顺序执行)[传送门](https://vkdoc.fsq.pub/client/uniCloud/middleware/filter.html) + +#### 14、支持设置需要登录的页面列表或不需要登录的页面列表(通过本地token检测,无网络请求,支持通配符写法)[传送门](https://vkdoc.fsq.pub/client/pages/config.html) + +#### 15、支持设置可以被分享的页面列表或禁止分享的页面列表(支持通配符写法)[传送门](https://vkdoc.fsq.pub/client/pages/config.html) + +#### 16、`vk.localStorage` 封装本地缓存的curd,同时具有监听缓存被更新和被删除的功能。[传送门](https://vkdoc.fsq.pub/client/pages/localStorage.html) + +#### 17、美化云函数请求过程中的日志排版,使请求日志一目了然。 + +![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-cf0c5e69-620c-4f3c-84ab-f4619262939f/4a44fbf8-6b5e-43a6-b443-51a108dec125.png) + +#### 18、可以 `强制关闭` 云端服务(适用于需要临时关闭后端服务的情况,如腾讯云迁移数据到阿里云时需要先关闭服务,否则迁移过程中会有新数据产生) + +#### 19、全局数据缓存API,现在可以很方便的在云函数中使用缓存。 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cache/cache.html) + +#### 20【全网首家】云函数URL化之URL重写 [传送门](https://vkdoc.fsq.pub/client/uniCloud/cloudfunctions/urlrewrite.html) + +#### 21、千人群交流开发心得,助你避坑,作者亲自在群内解答框架使用问题,让你轻松上手 `uniCloud云开发`。 + +#### 22、其他好处… + +### 目前已集成的服务端API + +#### 1、微信小程序服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin.html) + +#### 2、微信公众号服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/weixin-h5.html) + +#### 3、百度开放平台服务端API [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/baidu.html) + +#### 4、短信发送 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/sms.html) + +#### 5、邮箱发送 [传送门](https://vkdoc.fsq.pub/client/uniCloud/plus/mail.html) + +#### 6、Redis [传送门](https://vkdoc.fsq.pub/vk-redis/) + +##### 插件部分API功能体验地址 + +![插件首页体验地址](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-vk-cloud-router-test/51de83e0-e9ae-11ea-81ea-f115fe74321c.png?x-oss-process=image/resize,h_250 "插件首页体验地址") + +## 快速上手 - 安装步骤 + +## 后端(云函数端)安装步骤 +打开 `uniCloud/cloudfunctions` 目录 + +#### 前置工作:修改云函数全局配置文件(用到微信登录的必须要配置)[微信小程序配置详细教程](https://vkdoc.fsq.pub/client/question/q12.html) +#### 注意: +* 1、开发微信小程序和APP微信登录需要额外配置 manifest.json 以及 uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 这2个配置文件,且改动配置后需要重新上传 公共模块 和 router 函数。 +* 2、若你的电脑没有安装 Node.js,则无法使用 npm 命令。 +* 3、Node.js 安装包及源码下载地址为:[https://nodejs.org/en/download/](https://nodejs.org/en/download/) +* 4、Node.js 安装教程:[https://www.runoob.com/nodejs/nodejs-install-setup.html](https://www.runoob.com/nodejs/nodejs-install-setup.html) + +查看 `uni-id/config.json` 代码格式 [点击查看](https://vkdoc.fsq.pub/client/uniCloud/config/uni-id.html) + + +#### 正式安装 + +直接右键`uniCloud`目录 点击 `运行云服务空间初始化向导` 即可 + +## 前端(页面端)安装步骤 + +### Vue2.0版本 + +`main.js` 引入 `vk-unicloud-page` 库 + +```js +// 引入 vk框架前端 +import vk from './uni_modules/vk-unicloud'; +Vue.use(vk); +``` + +完整 `main.js` 示例 + +```js +import Vue from 'vue' +import App from './App' +import store from './store' +import config from '@/app.config.js' + +// 引入 vk框架前端 +import vk from './uni_modules/vk-unicloud'; +Vue.use(vk); + +// 初始化 vk框架 +Vue.prototype.vk.init({ + Vue, // Vue实例 + config, // 全局配置 +}); + +Vue.config.productionTip = false + +App.mpType = 'app' + +const app = new Vue({ + store, + ...App +}); +app.$mount(); + +``` + +### Vue3.0版本 + +`main.js` 引入 `vk-unicloud-page` 库 + +完整 `main.js` 示例 + +```js +import App from './App' +import store from './store' +import config from '@/app.config.js' + +// 引入 vk框架前端 +import vk from './uni_modules/vk-unicloud'; + +import { createSSRApp } from 'vue' + +export function createApp() { + const app = createSSRApp(App) + + // 使用 vuex + app.use(store) + + // 使用 vk框架前端 + app.use(vk); + + // 初始化 vk框架 + app.config.globalProperties.vk.init({ + Vue: app, // Vue实例 + config, // 配置 + }); + + return { app } +} +``` + +### 自 client端框架 2.6.0 起,不再内置任何 UI 框架,你可以选择自己喜欢的 UI 组件库进行开发。 + +### 集成 `vk-uview-ui`(vue2.0版) + +___若不想集成 `vk-uview-ui` 可跳过此处___ + +适合开发:H5、App(vue版本)、微信小程序、支付宝小程序(其他小程序未验证) + +> 插件市场导入 `vk-uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=6692) + +* 1、main.js 引入 vk-uview-ui + +```js +import uView from './uni_modules/vk-uview-ui'; +Vue.use(uView); +``` + +* 2、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 3、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/vk-uview-ui/theme.scss"; +``` + + +### 集成 `vk-uview-ui`(vue3.0版) + +___若不想集成 `vk-uview-ui` 可跳过此处___ + +适合开发:H5、App(vue版本)、微信小程序(其他小程序未验证) + +> 插件市场导入 `vk-uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=6692) + +不建议把老项目 升级到 Vue3.0 (升级非常麻烦,建议新项目才考虑是否使用Vue3.0) + +___注意:目前(2020-11-18) `uniapp` 的 `Vue3.0` 版本只兼容:H5、App、微信小程序___ + +* 1、前置步骤:修改 `manifest.json` 内的 `vue` 版本为 `vue3` +* 2、项目根目录新增 `index.html` 文件,文件代码为 +```html + + + + + + + + + + + + +
+ +
+ + + +``` + +* 3、main.js 引入 vk-uview-ui + +```js +// 引入 uView UI +import uView from './uni_modules/vk-uview-ui'; + +import { createSSRApp } from 'vue' + +export function createApp() { + const app = createSSRApp(App) + + // 使用 uView UI + app.use(uView) + + return { app } +} + +``` + +* 4、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 5、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/vk-uview-ui/theme.scss"; +``` + + +### 集成 `uview-ui`(nvue2.0版) + +___若不想集成 `uview-ui` 可跳过此处___ + +适合开发:App(nvue版本),如果你只开发App,推荐用这个UI + +> 插件市场导入 `uview-ui` 框架:[点击前往](https://ext.dcloud.net.cn/plugin?id=1593) + +* 1、main.js 引入 uview-ui + +```js +import uView from './uni_modules/uview-ui'; +Vue.use(uView); +``` + +* 2、App.vue 引入基础样式(注意style标签需声明scss属性支持) + +```html + +``` + +* 3、uni.scss 引入全局 scss 变量文件 + +```css +@import "@/uni_modules/uview-ui/theme.scss"; +``` + +### 集成 `uview-ui`(nvue3.0版) + +别想了,uniapp官方也还没支持。 + +### 组件库并不限制只能从以上选择,理论上支持任何UI组件库进行开发。 + +### 卸载 `uView1` 的步骤 + +* 1、main.js 删除 uView1 + +```js +import uView from 'uview-ui' +Vue.use(uView); +``` + +* 2、App.vue 删除基础样式 + +```html + +``` + +* 3、uni.scss 删除全局 scss 变量文件 + +```css +@import "uview-ui/theme.scss"; +``` + +* 4、pages.json 删除 easycom 规则 + +```js +"easycom": { + "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", +}, +``` + +* 5、package.json 删除 uview-ui 依赖 + +```js +"dependencies": { + "uview-ui": "^1.8.3" +}, +``` + +* 6、package-lock.json 删除 uview-ui 依赖 + +```js +"dependencies": { + "uview-ui": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.3.tgz", + "integrity": "sha512-DqKc+qRrOZLPcyfWv4b0HspSS9n1Cd6BbgKiYEv9rjTAnWoqJV7rXsvWqZdr5iKGP5EMNbNS741GLNw4sIHbpw==" + } +} +``` + +### 完整安装文档:[查看完整安装文档](https://vkdoc.fsq.pub/client/quickstart.html) + +## 云函数框架目录结构 + +``` +. +├── common─────────────────# 自定义官方公共模块包 +│ └── config──────────────────# 全局配置公共模块 +│ └── uni-id──────────────────# uni-id官方公共模块 +│ └── vk-unicloud─────────────# vk-unicloud公共模块 +├── router─────────────────# 正式环境云函数主入口(函数路由器) +│ └── dao──────────────────# dao层(数据库交互公共API) +│ └── middleware───────────# 中间层(过滤器、拦截器) +│ └── node_modules─────────# npm包 +│ └── service──────────────# 逻辑层(用于写业务逻辑) +│ ── └── 逻辑层目录结构在下方单独展示 +│ └── util─────────────────# 工具包 +│ ── └── pubFunction.js───────# 公共函数包 +│ ── └── smsUtil.js───────────# 全局过滤器 +│ └── config.js────────────# 入口函数初始化配置 +│ └── index.js─────────────# 入口函数 +│ └── package.json─────────# 第三方依赖配置文件(若使用npm,自动生成) +└─└── package-lock.json────# 第三方依赖配置文件(若使用npm,自动生成) +. +├── router-test───────────────# 函数路由(开发测试环境) +│ └── ...─────────# ... +│ └── ...─────────# ... +└── └── ...─────────# ... +``` + +### 逻辑层目录结构 +#### `router/service` 目录为逻辑层 +#### 以下的目录并非强制性,只是建议,便于统一开发规范。 + +``` +. +├── service──────────────────────# 逻辑层(用于写业务逻辑) +│ └── admin────────────────# 后台管理端逻辑(admin框架开发中。。。) +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── client───────────────# 客户端逻辑(H5、小程序、APP) +│ ── └── user─────────────────# 用户服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 用户服务专用的工具包 +│ ── └── order────────────────# 订单服务(自己系统的逻辑) +│ ──── └── kh───────────────────# kh函数为必须登录后才能访问的函数 +│ ──── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ──── └── util─────────────────# 订单服务专用的工具包 +│ ── └── xxxxxxxxxxxxxxx──────# +│ ── └── xxxxxxxxxxxxxxx──────# +│ └── common───────────────# 公共逻辑(公共接口) +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ ── └── xxxxxxxxxxxxxxxx─────# +│ └── user─────────────────# 统一用户中心服务(已集成uniID)(用户中心作为核心,且为了方便插件升级,故与admin和client平级) +│ ── └── kh───────────────────# kh函数为必须登录后才能访问的函数(客户端用户) +│ ── └── pub──────────────────# pub函数为所有人都可以访问,不限制 +│ ── └── sys──────────────────# sys函数为后端管理人员才能访问的函数(商家后台工作人员) +│ ── └── util─────────────────# 统一用户中心服务专用的工具包 +│ └── plugs───────────────# 插件逻辑(插件专用)(会陆续新增一些实用性插件给开发者使用,如微信小程序发送订阅消息等等) +│ ──└── plugs-A───────────────────# 插件A +│ ────└── admin───────────────────# 插件A admin端 +│ ────└── client──────────────────# 插件A client端 +│ ──└── plugs-B───────────────────# 插件B +│ ────└── admin───────────────────# 插件B admin端 +│ ────└── client──────────────────# 插件B client端 +│ └── template─────────────# 云函数模板(插件内的云函数写法模板) +│ ── └── db_api───────────────# 数据库接口调用模板 +│ └── muban.js─────────────# 云函数模板(新建一个云函数应复制粘贴这个文件) +│ └── muban_easy.js────────# 云函数模板(简易版) +└───────────────────────────────── +``` + + +## 云函数service模板文件示例 +```js +module.exports = { + /** + * 此函数名称 + * @url user/sys/test1 前端调用的url参数地址 + * @description 此函数描述 + * @param {Object} data 请求参数 + * @param {String} uniIdToken 用户token + * @param {String} userInfo 当前登录用户信息(同理,是可信任的)(只有kh函数才带此参数) + * @param {Object} util 公共工具包 + * @param {Object} filterResponse 过滤器返回的数据 + * @param {Object} originalParam 原始请求参数(包含了原始event和context) + * data 请求参数 说明 + * @param {String} uid 当前登录用户id,若用户已登录且token有效,则data中会带uid参数 + * (此参数是后端过滤器通过token获取并添加到data中的,是可信任的)(只有kh函数才带此参数) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + main: async (event) => { + let { data = {}, userInfo, util, filterResponse, originalParam } = event; + let { customUtil, uniID, config, pubFun, vk , db, _ } = util; + let { uid } = data; + let res = { code : 0, msg : '' }; + // 业务逻辑开始----------------------------------------------------------- + // 可写与数据库的交互逻辑等等 + + + // 业务逻辑结束----------------------------------------------------------- + return res; + } +} +``` +#### 成功时返回 +```js +// 注意:所有成功请求必须返回code:0 code为其他值,代表失败,如兑换失败,您的积分不足! +// 如成功时返回 res.code = 0 表示执行成功; +return { + code : 0, + msg : '兑换成功!' +} +``` +#### 失败时返回 +```js +return { + code : -1, + msg : '兑换失败,您的积分不足!' +} + +``` + +## this.vk.callFunction函数的参数说明 +```js +/** + * 云函数请求封装 - 统一入口 + * @description 通过云函数路由,1个云函数实现多个云函数的效果。 + * @param {String} url 请求路径,该路径实为router云函数的service目录下的路径 + * @param {Object} data 请求参数 + * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @param {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false + * @param {Boolean} needAlert 为true代表请求错误时,会有alert弹窗提示。默认为true + * @param {Function} success 请求成功时,执行的回调函数 + * @param {Function} fail 请求失败时,执行的回调函数 + * @param {Function} complete 无论请求成功与否,都会执行的回调函数 + */ +``` + + +## 前端调用云函数示例 + +```js + +this.vk.callFunction({ + url: 'user/kh/setAvatar', + title:'请求中...', + data:{ + avatar: "https://xxxxxxx.jpg" + }, + success(data) { + // 修改成功 + } +}); + +``` + +## 云函数url化方式调用云函数示例 + +[点击查看『云函数url化』方式调用云函数示例](https://vkdoc.fsq.pub/client/pages/callFunctionForUrl.html) + +## 前端非法token拦截器 + +[点击查看『前端非法token拦截器』](https://vkdoc.fsq.pub/client/pages/interceptor1.html) + +## vk.baseDao数据库API + +[点击查看『vk.baseDao』数据库API](https://vkdoc.fsq.pub/client/uniCloud/db/api.html) + +## 设置全局请求参数 + +[点击查看『设置全局请求参数』](https://vkdoc.fsq.pub/client/pages/updateRequestGlobalParam.html) + +## 列表渲染前后端一体模板 + +[点击查看『列表渲染』前后端一体模板](https://vkdoc.fsq.pub/client/pages/list.html) + +## 商品SKU选择器组件 + +[点击查看『商品SKU选择器组件』](https://gitee.com/vk-uni/vk-uni-cloud-router/wikis/pages?sort_id=2912199&doc_id=975983) + +## 如何切换 正式环境 和 开发环境 + +[点击查看如何『切换正式环境和开发环境』](https://vkdoc.fsq.pub/client/question/q1.html) + +## 本插件更新步骤 +[点击查看本插件『更新步骤』](https://vkdoc.fsq.pub/client/changeGuide.html) + +## uniCloud云函数路由框架研究Q群:`22466457` 如有问题或建议可以在群内讨论。 + +### 如果你觉得框架对你有用,可以在下方进行评论,也可以进行赞赏。 \ No newline at end of file diff --git a/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/LICENSE.md b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/LICENSE.md new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/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/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js new file mode 100644 index 0000000..4db5060 --- /dev/null +++ b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/index.js @@ -0,0 +1 @@ +"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var crypto$1=_interopDefault(require("crypto")),commonjsGlobal="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},util={regExpTest:function(e,t){let n=!1;if("string"==typeof e){new RegExp(e).test(t)&&(n=!0)}else if("object"==typeof e)for(let i=0;i{let{serviceParam:t,middlewareService:n=[]}=e,i={code:403,msg:"access denied",filterStack:[]},{url:a}=t;for(let e in n){let r=n[e],{mode:o="onActionExecuting",enable:s=!0}=r;if(s&&"onActionExecuting"===o&&util_1.regExpTest(r.regExp,a)){t.filterResponse=i;let e=await r.main(t);if(e.filterId=r.id,i.filterStack.push(e),0!==e.code){i=e;break}i=Object.assign(i,e)}}return i},onActionExecuted=async(e={})=>{let{serviceParam:t,middlewareService:n=[],serviceRes:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionExecuted"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},onActionIntercepted=async(e={})=>{let{serviceParam:t,middlewareService:n=[],filterResponse:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionIntercepted"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},onActionError=async(e={})=>{let{serviceParam:t,middlewareService:n=[],serviceRes:i}=e,{url:a}=t;for(let e in n){let r=n[e],{mode:o,enable:s=!0}=r;if(s&&"onActionError"===o&&util_1.regExpTest(r.regExp,a)){let e=await r.main(t,i);if(e){if(0!==e.code){i=e;break}i=Object.assign(i,e)}}}return i},checkIsLogin={main:async e=>{let{url:t,data:n={},util:i}=e,{uniID:a}=i,{need_user_info:r}=n,o={code:-1,msg:""};void 0===r&&(r=-1==t.indexOf("."));let s=0==t.indexOf("admin/");s&&(r=!0),(t.indexOf("sys.")>-1||t.indexOf("sys_")>-1||t.indexOf("/sys")>-1)&&(r=!0);let u=t.indexOf("/sys/")>-1,l=await a.checkToken(e.uniIdToken,{needPermission:u,needUserInfo:r});if(l.code&&l.code>0)return l;if(l.userInfo){let e=l.userInfo;e.permission=l.permission,delete e.token,delete e.password,o.userInfo=e}if(o.uid=l.uid,l.token&&(o.token=l.token,o.tokenExpired=l.tokenExpired),s){if(!o.userInfo)return{code:403,msg:"need_user_info必须为true"};{let e=o.userInfo.role||[];if(!o.userInfo.allow_login_background&&!e.includes("admin"))return{code:403,msg:"您无权限登录后台"}}}return o.code=0,o.msg="ok",o}},checkSysAuth={main:async e=>{let{url:t,util:n}=e,{uniID:i,config:a,pubFun:r,vk:o,db:s,_:u}=n,l={code:-1,msg:""};const c=checkIsLogin;if(l=await c.main(e),0!==l.code)return l;if(!l.userInfo)return{code:403,msg:"请去除need_user_info:false"};if(l.userInfo.role||(l.userInfo.role=[]),l.userInfo.role.includes("admin"))return l;if(!l.userInfo.allow_login_background&&0==t.indexOf("admin/"))return{code:403,msg:"您无权限登录后台"};let d=[];if(l.userInfo.role.includes("admin-lv3")){let e=await listPermission({whereJson:{level:u.in([1,2,3])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("admin-lv2")){let e=await listPermission({whereJson:{level:u.in([1,2])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("admin-lv1")){let e=await listPermission({whereJson:{level:u.in([1])},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}if(l.userInfo.role.includes("query-all")){let e=await listPermission({whereJson:{curd_category:4,level:u.neq(4)},justNeedID:!0},n);o.pubfn.isNotNull(e)&&(d=d.concat(e))}let p=await listRole({role:l.userInfo.role},n);for(let e in p){let{permission:t}=p[e];o.pubfn.isNotNull(t)&&(d=d.concat(t))}if(0==d.length)return{code:403,msg:"权限不足"};d=[...new Set(d)];let f=await listPermission({whereJson:{permission_id:u.in(d),match_mode:u.in([1,2])}},n),g=!1;for(let e=0;e0}async function listRole(e,t){let{vk:n,db:i,_:a}=t,{role:r}=e;return n.pubfn.isNull(r)?[]:(await n.baseDao.select({dbName:"uni-id-roles",whereJson:{role_id:a.in(r),enable:!0},fieldJson:{permission:!0}})).rows}var filterService=[{id:"pub",regExp:function(e=""){return"pub"===getType(e)},description:"pub函数为所有人都可以访问的函数",index:100,mode:"onActionExecuting",main:async function(e){let{url:t,data:n={},util:i}=e,{uniID:a}=i,r={};if(e.data.need_user_info)r=await checkIsLogin.main(e);else if(e.uniIdToken){let t=await a.checkToken(e.uniIdToken,{needPermission:!1,needUserInfo:!1});0===t.code&&(r.uid=t.uid)}return r.code=0,r.msg="ok",r}},{id:"kh",regExp:function(e=""){return"kh"===getType(e)},description:"kh函数为必须登录后才能访问的函数(客户端用户)",index:200,mode:"onActionExecuting",main:checkIsLogin.main},{id:"sys",regExp:function(e=""){return"sys"===getType(e)},description:"sys函数为后端管理人员才能访问的函数(商家后台工作人员)",index:300,mode:"onActionExecuting",main:checkSysAuth.main},{id:"access_denied",regExp:function(e=""){return"access denied"===getType(e)},description:"sys函数为后端管理人员才能访问的函数(商家后台工作人员)",index:100,mode:"onActionExecuting",main:function(){return{code:403,msg:"禁止访问私有函数!"}}}];function getType(e=""){let t="";return e.indexOf("/sys/")>-1?t="sys":e.indexOf("/kh/")>-1?t="kh":e.indexOf("/pub/")>-1&&(t="pub"),e.indexOf("/sys.")>-1||e.indexOf("/sys_")>-1||0===e.indexOf("sys.")||0===e.indexOf("sys_")?t="sys":e.indexOf("/kh.")>-1||e.indexOf("/kh_")>-1||0===e.indexOf("kh.")||0===e.indexOf("kh_")?t="kh":(e.indexOf("/pub.")>-1||e.indexOf("/pub_")>-1||0===e.indexOf("pub.")||0===e.indexOf("pub_"))&&(t="pub"),e.indexOf(".sys_")>-1?t="sys":e.indexOf(".kh_")>-1?t="kh":e.indexOf(".pub_")>-1&&(t="pub"),""==t&&e.indexOf(".")>-1&&(t="kh"),e.indexOf("._")>-1&&(t="access denied"),t}function getMiddleware(e){let t=[];if(e){let n=[...filterService,...e];n.sort((function(e,t){return e.index-t.index})),t=n.filter((e,t,i)=>{var a=[];return n.forEach((e,t)=>{a.push(e.id)}),a.indexOf(e.id)===t})}else t=filterService;return t}var getMiddleware_1=getMiddleware,filter={onActionExecuting:onActionExecuting,onActionExecuted:onActionExecuted,onActionIntercepted:onActionIntercepted,onActionError:onActionError,getMiddleware:getMiddleware_1},routerUtil={filterService:filter,getQueryStringParameters:function(e){let{event:t,vk:n}=e,i={};if(t.httpMethod){let{path:e=""}=t;if("/"===e[0]&&(e=e.substring(1)),e){let a,{urlrewrite:r={}}=n.getUnicloud(),{rule:o}=r,s=n.pubfn.getData(r,"config.accessOnlyInRule"),u=!1;if(o)for(let t in o){let i=o[t],r=n.pubfn.regExpExecToTemplate(e,t,i);if(r){u=!0;let t=r.split("?");e=t[0],a=n.pubfn.urlStringToJson(t[1]);break}}if(!u&&s)return{mpserverlessComposedResponse:!0,statusCode:403,code:403,headers:{"content-type":"application/json"},body:JSON.stringify({code:403,msg:"access denied"})};if(i={data:{}},n.pubfn.isNotNull(a)&&(i.data=Object.assign(i.data,a)),t.queryStringParameters){let e=t.queryStringParameters;"string"==typeof e&&(e=JSON.parse(e)),i.data=Object.assign(i.data,e)}if(t.body){let e=t.body,a=t.headers&&t.headers["content-type"]?t.headers["content-type"]:"";if(a.indexOf("multipart/form-data;")>-1)e=n.formDataUtil.formParser(t),i.data=Object.assign(i.data,e);else{t.isBase64Encoded&&(e=Buffer.from(e,"base64").toString("utf-8"));try{"string"==typeof e&&(e=JSON.parse(e)),i.data=Object.assign(i.data,e)}catch(e){}try{"string"==typeof e&&a.indexOf("x-www-form-urlencoded")>-1&&(e=n.pubfn.urlStringToJson(e),"object"==typeof e&&(e=n.pubfn.string2Number(e),i.data=Object.assign(i.data,e)))}catch(e){}}}i.$url||(i.data.$url?i.$url=i.data.$url:i.$url=e),i.data.uni_id_token&&(i.uni_id_token=i.data.uni_id_token,delete i.data.uni_id_token)}else{if(t.queryStringParameters){let e=t.queryStringParameters;"string"==typeof e.data&&(e.data=JSON.parse(e.data)),i=Object.assign(i,e)}if(t.body){let e=t.body;t.isBase64Encoded&&(e=Buffer.from(e,"base64").toString("utf-8"));try{"string"==typeof e&&(e=JSON.parse(e)),i=Object.assign(i,e)}catch(e){}}}try{let e=t.headers["uni-id-token"]||t.headers.uni_id_token;!i.uni_id_token&&e&&(i.uni_id_token=e)}catch(e){}}else i=JSON.parse(JSON.stringify(t));return i.data||(i.data={}),i.uniIdToken||(i.uniIdToken=i.uni_id_token),i.url=i.$url||"",i},returnError:returnError,filterInterception:async function({serviceParam:e,middlewareService:t,filterResponse:n}){try{n=await filter.onActionIntercepted({serviceParam:e,middlewareService:t,filterResponse:n})}catch(n){return await returnError({code:500,msg:`云函数 ${e.url} 的中间件 onActionIntercepted 运行异常!`,err:n,serviceParam:e,middlewareService:t})}return n},requireService:async function(e={}){let t,{vk:n,serviceParam:i}=e,{url:a,data:r,uniIdToken:o,util:s,filterResponse:u={},originalParam:l={}}=i;if(a.indexOf(".")>-1){let e,i=a.lastIndexOf("."),c=n.require("service/"+a.substring(0,i));if(t=n.pubfn.objectAssign({},c),!t.isCloudObject)throw new Error("msg:禁止访问私有对象内的函数!");let d=a.substring(i+1);if(0==d.indexOf("_"))throw new Error("msg:禁止访问私有函数!");if("function"!=typeof t[d]){try{l.event&&l.event.httpMethod&&l.event.path&&(a=l.event.path.substring(1))}catch(e){}throw{code:404,name:"cloudObject",message:`not found【${a}】`}}Object.assign(t,{vk:n,methodName:d,isCloudObject:!0,getClientInfo:function(){let{context:e={}}=l,t={...e,os:e.OS,appId:e.APPID,locale:e.LOCALE,clientIP:e.CLIENTIP,userAgent:e.CLIENTUA,platform:e.PLATFORM,deviceId:e.DEVICEID,source:e.SOURCE,uniIdToken:o,uid:u.uid,userInfo:u.userInfo,filterResponse:u,originalParam:l};return n.pubfn.objectKeySort(t)},getUserInfo:async function(){if(u.userInfo&&u.userInfo._id)return u.userInfo;if(!e&&u.uid){let t=await s.uniID.checkToken(o,{needUserInfo:!0});if(0!==t.code)throw new Error("msg:token失效:"+t.errMsg);t.userInfo&&t.userInfo._id&&(delete t.userInfo.token,delete t.userInfo.password,e=t.userInfo)}return e},getUtil:function(){return s},getMethodName:function(){return d},getParams:function(){return r},getCloudInfo:function(){let{SPACEINFO:e={},FUNCTION_NAME:t,FUNCTION_TYPE:n}=l.context||{},{provider:i,spaceId:a}=e;return{provider:i,spaceId:a,functionName:t,functionType:"cloudobject"}},getUniIdToken:function(){return o},getUniCloudRequestId:function(){return l.context.requestId},getHttpInfo:function(){return l.event}})}else t=n.require("service/"+a);return t},serviceRun:async function(e={}){let t,{serviceParam:n={},serviceMain:i}=e,{filterResponse:a}=n;if(a.uid&&(n.uid=a.uid),a.userInfo&&(n.userInfo=a.userInfo),i.isCloudObject){let{methodName:e="main"}=i;if("function"==typeof i._before){let e=await i._before();if("string"==typeof e)return{code:-1,msg:e};if("object"==typeof e&&0!==e.code)return{code:e.code,msg:e.msg};if("boolean"==typeof e&&!1===e)return{code:-1,msg:""}}if(t=await i[e](n.data),"function"==typeof i._after){let e=await i._after({res:t||{}});"object"==typeof e&&(t=e)}}else t=await i.main(n);return"object"==typeof t&&(void 0===t.vk_uni_token&&"object"==typeof a&&a.token&&void 0!==a.tokenExpired&&(t.vk_uni_token={token:a.token,tokenExpired:a.tokenExpired}),t=routerUtil.returnRes(t)),t},errorCatch:async function(e={}){let{err:t,type:n,serviceParam:i,middlewareService:a,serviceMain:r={}}=e,{url:o,originalParam:s={}}=i;t||(t={});let{code:u}=t,l=t.message||t.msg||t.errMsg||"";if("run"===n&&"function"==typeof r._after){let e=await r._after({err:t});if(e)return e}let c={code:500,msg:l,err:t,serviceParam:i,middlewareService:a};try{s.event&&s.event.httpMethod&&s.event.path&&(o=s.event.path.substring(1))}catch(t){}return"MODULE_NOT_FOUND"==u&&l.indexOf("service/")>-1||"ENOENT"==u&&l.indexOf("service")>-1||404==u&&["cloudFunction","cloudObject"].indexOf(t.name)>-1?(t.stack=`Error: not found【${o}】`,Object.assign(c,{code:404,msg:`not found【${o}】`})):"MODULE_NOT_FOUND"==u&&l.indexOf("Cannot find module")>-1?Object.assign(c,{code:500,msg:l}):"InternalServerError"==u&&l.indexOf("_id_ dup key")>-1?Object.assign(c,{code:500,msg:"vk.baseDao.add : _id不能重复添加"}):0===l.indexOf("Cannot read property 'mp-weixin' of undefined")?Object.assign(c,{code:501,msg:"请先绑定微信"}):l.indexOf("Response timeout for 10000ms")>-1?Object.assign(c,{code:502,msg:"timeout 请求超时,请重试!"}):l.indexOf("msg:token失效")>-1?Object.assign(c,{code:30202,errMsg:l,msg:l}):l.indexOf("msg:禁止访问私有对象内的函数")>-1||l.indexOf("msg:禁止访问私有函数")>-1?Object.assign(c,{code:403,msg:l.substring(4)}):0===l.indexOf("msg:")?Object.assign(c,{code:501,msg:l.substring(4)}):"ReferenceError"===t.name?Object.assign(c,{code:501,msg:`云函数 ${o} 变量引用错误:${l}`}):"TypeError"===t.name?Object.assign(c,{code:501,msg:`云函数 ${o} 运行异常,类型错误:${l}`}):"InternalServerError"==u?Object.assign(c,{code:"InternalServerError",msg:"内部错误"}):"Error"===t.name?Object.assign(c,{code:t.code,msg:l}):t.stack?Object.assign(c,{code:500,msg:"require"==n?`云函数 ${o} 编译异常!`:`云函数 ${o} 运行异常!`}):"string"==typeof t?Object.assign(c,{code:-1,msg:t}):Object.assign(c,t),await returnError(c)},returnRes:function(e={}){return"object"==typeof e&&(void 0!==e.code||void 0!==e.errCode&&(e.code=e.errCode,e.msg=e.errMsg)),e}},routerUtil_1=routerUtil;async function returnError(e={}){let{code:t,msg:n,err:i,serviceParam:a,middlewareService:r}=e;console.error(n);let o={code:t,msg:n};i&&(i.stack?(console.error(i.stack),o.err={message:i.message,stack:i.stack,code:i.code}):o.err=i);try{o.requestId=a.originalParam.context.requestId}catch(i){}let s=await filter.onActionError({serviceParam:a,middlewareService:r,serviceRes:o});return routerUtil.returnRes(s)}try{process.env.TZ="Asia/Shanghai"}catch(e){}async function main(e){let{event:t,context:n,vk:i}=e;!i&&this&&(i=this);let{config:a,uniID:r,uniPay:o,db:s,middlewareService:u,pubFun:l,customUtil:c,crypto:d}=i.getUnicloud();if(i.pubfn.getData(a,"vk.system.serviceShutdown"))return routerUtil_1.returnRes({code:405,msg:i.pubfn.getData(a,"vk.system.serviceShutdownDescription")});if(["h5","web"].indexOf(n.PLATFORM)>-1){let e=i.pubfn.getUniIdConfig(a,"preferedWebPlatform","h5");n.PLATFORM=e}else if(["app-plus","app"].indexOf(n.PLATFORM)>-1){let e=i.pubfn.getUniIdConfig(a,"preferedAppPlatform","app-plus");n.PLATFORM=e}let p={event:t,context:n},f=routerUtil_1.getQueryStringParameters(e),{url:g,data:m,uniIdToken:b}=f;if([403].indexOf(f.code)>-1)return routerUtil_1.returnRes(f);if(g&&"function"==typeof g.trim&&(g=g.trim()),m){m.vk_appId&&(n.APPID=m.vk_appId),m.vk_appid&&(n.APPID=m.vk_appid),m.vk_platform&&(n.PLATFORM=m.vk_platform),m.vk_locale&&(n.LOCALE=m.vk_locale);let e={};if("object"==typeof t.headers&&(t.headers["vk-appId"]&&(e.appId=t.headers["vk-appId"]),t.headers["vk-appid"]&&(e.appid=t.headers["vk-appid"]),t.headers["vk-platform"]&&(e.platform=t.headers["vk-platform"]),t.headers["vk-locale"]&&(e.locale=t.headers["vk-locale"]),t.headers["vk-device-id"]&&(e.deviceId=t.headers["vk-device-id"]),t.headers["vk-client-ip"]&&(e.clientIP=t.headers["vk-client-ip"]),t.headers["vk-os"]&&(e.os=t.headers["vk-os"])),"object"==typeof m.vk_context&&(e=i.pubfn.objectAssign(e,m.vk_context),delete m.vk_context),"object"==typeof e&&i.pubfn.isNotNull(e)&&(e.appId&&(n.APPID=e.appId),e.appid&&(n.APPID=e.appid),e.platform&&(n.PLATFORM=e.platform),e.locale&&(n.LOCALE=e.locale),e.clientIP&&!n.CLIENTIP&&(n.CLIENTIP=e.clientIP),e.os&&(n.OS=e.os),e.deviceId&&(n.DEVICEID=e.deviceId),"function"===n.SOURCE&&(e.clientIP&&(n.CLIENTIP=e.clientIP),e.userAgent&&(n.CLIENTUA=e.userAgent))),i.pubfn.isNullOne(n.APPID,n.PLATFORM)){let e=i.pubfn.getData(a,"vk.context");i.pubfn.isNotNull(e)&&(n.APPID||(n.APPID=e.APPID),n.PLATFORM||(n.PLATFORM=e.PLATFORM),n.LOCALE||(n.LOCALE=e.LOCALE),n.CLIENTIP||(n.CLIENTIP=e.CLIENTIP))}}const h=r.createInstance({context:n});s.command.$=s.command.aggregate;let y={vk:i,config:a,pubFun:l,uniID:h,uniPay:o,db:s,_:s.command,$:s.command.aggregate,customUtil:c,crypto:d,env:{APPID:n.APPID,CLIENTIP:n.CLIENTIP,DEVICEID:n.DEVICEID,LOCALE:n.LOCALE,OS:n.OS,PLATFORM:n.PLATFORM,CLIENTUA:n.CLIENTUA}};try{uniCloud.vk=i,uniCloud.env=y.env,uniCloud.context=n}catch(e){}let w={url:g,data:m,uniIdToken:b,util:y,originalParam:p};const _=routerUtil_1.filterService.getMiddleware(u);try{let e=await routerUtil_1.filterService.onActionExecuting({serviceParam:w,middlewareService:_});if(0!==e.code)return routerUtil_1.returnRes(await routerUtil_1.filterInterception({serviceParam:w,middlewareService:_,filterResponse:e}));delete m.uid,e.uid&&(m.uid=e.uid),w.filterResponse=e}catch(e){return await routerUtil_1.returnError({code:500,msg:`云函数 ${g} 的中间件 onActionExecuting 运行异常!`,err:e,serviceParam:w,middlewareService:_})}let k,v;try{k=await routerUtil_1.requireService({vk:i,serviceParam:w})}catch(e){return await routerUtil_1.errorCatch({err:e,type:"require",serviceParam:w,middlewareService:_})}try{v=await routerUtil_1.serviceRun({serviceParam:w,serviceMain:k})}catch(e){return await routerUtil_1.errorCatch({err:e,type:"run",serviceParam:w,middlewareService:_,serviceMain:k})}try{v=await routerUtil_1.filterService.onActionExecuted({serviceParam:w,middlewareService:_,serviceRes:v})}catch(e){return await routerUtil_1.returnError({code:500,msg:`云函数 ${g} 的中间件 onActionExecuted 运行异常!`,err:e,serviceParam:w,middlewareService:_})}return routerUtil_1.returnRes(v)}var router=main,md5=function(e){return crypto$1.createHash("md5").update(e).digest("hex")},util$1={},baseDao={init:function(e){util$1=e},add:async function(e){let{db:t,_:n,vk:i,config:a}=util$1,{dbName:r,dataJson:o,db:s,cancelAddTime:u,cancelAddTimeStr:l}=e;if(i.pubfn.isNull(r))throw new Error("vk.baseDao.add 中 dbName 不能为空");if(i.pubfn.isNull(o))throw new Error("vk.baseDao.add 中 dataJson 不能为空");let c=s||t;if(!o._add_time){let e=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTime");void 0===u&&e&&(u=e);let t=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTimeStr");if(void 0===l&&t&&(l=t),!u){let e=new Date;o._add_time=e.getTime(),l||(o._add_time_str=i.pubfn.timeFormat(e,"yyyy-MM-dd hh:mm:ss"))}}let d=await c.collection(r).add(o);return d.id?d.id:null},adds:async function(e){let{db:t,_:n,vk:i,config:a}=util$1,{dbName:r,dataJson:o,db:s,cancelAddTime:u,cancelAddTimeStr:l}=e;if(i.pubfn.isNull(r))throw new Error("vk.baseDao.adds 中 dbName 不能为空");if(i.pubfn.isNull(o))throw new Error("vk.baseDao.adds 中 dataJson 不能为空");if("[object Array]"!==Object.prototype.toString.call(o))throw new Error("vk.baseDao.adds 中 dataJson 必须是数组对象");let c=s||t,d=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTime");void 0===u&&d&&(u=d);let p=i.pubfn.getData(a,"vk.db.unicloud.cancelAddTimeStr");if(void 0===l&&p&&(l=p),!u){let e=new Date,t=e.getTime(),n=i.pubfn.timeFormat(e,"yyyy-MM-dd hh:mm:ss");for(let e in o)o[e]._add_time||(o[e]._add_time=t,l||(o[e]._add_time_str=n))}let f=await c.collection(r).add(o);return f.ids?f.ids:f.id?f.id:null},del:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,db:o}=e,s=o||n,u=0;if(t.pubfn.isNotNull(r)){let e=await s.collection(a).where(r).remove();e?u=e.deleted:(console.error(e.errMsg),u=-1)}else console.error("whereJson条件不能为空");return u},delete:async function(e){return await baseDao.del(e)},remove:async function(e){return await baseDao.del(e)},deleteById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,db:o}=e,s=o||n,u=0;if(t.pubfn.isNull(r))throw new Error("deleteById的id不能为空,且必须是字符串");let l=await s.collection(a).doc(r).remove();return l?u=l.deleted:(console.error(l.errMsg),u=0),u},update:async function(e){let t,{vk:n,db:i,_:a}=util$1,{dbName:r,whereJson:o,dataJson:s,db:u}=e,l=u||i,c=0;if(n.pubfn.isNull(o))throw new Error("update的whereJson不能为空,且必须是对象形式");if(n.pubfn.isNull(s))throw new Error("update的dataJson不能为空,且必须是对象形式");return s._id&&delete s._id,t=void 0===o?await l.collection(r).update(s):await l.collection(r).where(o).update(s),t?c=t.updated:console.error(t.errMsg),c},updateById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,dataJson:o,getUpdateData:s,db:u}=e,l=u||n,c=0;if(t.pubfn.isNull(r))throw new Error("updateById的id不能为空,且必须是字符串");if(t.pubfn.isNull(o))throw new Error("updateById的dataJson不能为空,且必须是对象形式");o._id===r&&delete o._id;let d=await l.collection(a).doc(r).update(o);return s?d?await baseDao.findById({db:l,dbName:a,id:r}):null:(d?c=d.updated:(console.error(d.errMsg),c=0),c)},updateAndReturn:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,whereJson:o,dataJson:s,db:u}=e,l=u||n;if(t.pubfn.isNullAll(r,o))throw new Error("updateAndReturn的id和whereJson两者不能都为空");if(t.pubfn.isNull(s))throw new Error("updateAndReturn的dataJson不能为空,且必须是对象形式");if(s._id&&delete s._id,t.pubfn.isNotNull(r)){return(await l.collection(a).doc(r).updateAndReturn(s)).doc}if(t.pubfn.isNotNull(o)){return(await l.collection(a).where(o).updateAndReturn(s)).doc}throw new Error("updateAndReturn的id和whereJson两者不能都为空")},setById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,dataJson:o,db:s}=e,u=s||n;if(t.pubfn.isNull(o))throw new Error("setById的dataJson不能为空,且必须是对象形式");if(t.pubfn.isNullAll(r,o._id))throw new Error("id或dataJson._id不能均为空");if(t.pubfn.isNotNullAll(r,o._id)&&r!==o._id)throw new Error("id和dataJson._id必须一致");t.pubfn.isNotNull(o._id)&&(r=o._id,delete o._id);let l=await u.collection(a).doc(r).set(o);return l.updated>0?l.type="update":(l.type="add",l.id=l.upsertedId),l},select:async function(e={}){let{vk:t,db:n,_:i}=util$1;"string"==typeof e.pageIndex&&(e.pageIndex=parseInt(e.pageIndex)),"string"==typeof e.pageSize&&(e.pageSize=parseInt(e.pageSize));let{dbName:a,whereJson:r,pageSize:o=10,getOne:s=!1,getMain:u=!1}=e;if(o<=0&&(o=999999999),o>500)return await baseDao.selectAll(e);let l=await baseDao.getSelectData(e),{result:c,hasMore:d,total:p,getCount:f,pageIndex:g,fieldJson:m}=l;return c=c.skip((g-1)*o).limit(o),t.pubfn.isNotNull(m)&&(c=c.field(m)),c.get().then(e=>{let t={};return f?(t.total=p,t.hasMore=d):(t.total=e.data?e.data.length:0,t.hasMore=t.total>=o),t.rows=e.data,t.code=0,t.msg="查询成功",t.pagination={pageIndex:g,pageSize:o},s&&(t.rows=t.rows[0]),u?t.rows:t})},findById:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,id:r,fieldJson:o,db:s}=e,u=(s||n).collection(a).doc(r);o&&(u=u.field(o));let l=await u.get();return"[object Array]"===Object.prototype.toString.call(l.data)?l.data[0]:l.data},findByWhereJson:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,fieldJson:o,sortArr:s,db:u}=e,l=u||n;if(t.pubfn.isNotNull(r)){let e=l.collection(a).where(r);if(s)for(let t in s){let n=s[t],i=n.name,a=n.type;null!=a&&""!=a||(a="asc"),e=e.orderBy(i,a)}o&&(e=e.field(o));let t=await e.limit(1).get();if(t.data&&t.data.length>0)return t.data[0]}else console.error("whereJson条件不能为空");return null},count:async function(e){let t,{vk:n,db:i,_:a}=util$1,{dbName:r,whereJson:o,foreignDB:s,foreignKey:u,groupJson:l,lastWhereJson:c,db:d}=e,p=d||i;if(n.pubfn.isNotNull(s)||n.pubfn.isNotNull(l)){let e=p.collection(r).aggregate();return n.pubfn.isNotNull(o)&&e.match(o),n.pubfn.isNotNull(l)&&e.group(l),n.pubfn.isNotNull(s)&&(e=baseDao.addForeignDB({foreignDB:s,foreignKey:u,result:e})),n.pubfn.isNotNull(c)&&(e=e.match(c)),e=await e.count("total").end(),e.data[0]?e.data[0].total:0}return t=n.pubfn.isNotNull(o)?await p.collection(r).where(o).count():await p.collection(r).count(),t.total},getSelectData:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,pageIndex:o=1,pageSize:s=10,getCount:u=!1,db:l}=e;s<0&&(o=1,s=999999999,u=!0);let c=l||n,d=e.sortArr,p=e.fieldJson,f=0,g=!1;if(u){let e;e=t.pubfn.isNotNull(r)?await c.collection(a).where(r).count():await c.collection(a).count(),f=e.total,o1e3&&(u=1e3));let l=await baseDao.getSelectData(e),{result:c,hasMore:d,total:p,getCount:f,pageIndex:g,pageSize:m,fieldJson:b}=l;m>0&&!p&&!f&&(p=m),i.pubfn.isNotNull(b)&&(c=c.field(b));let h={};if(f&&0===p)h={data:[]};else{let t=p;mr&&(n=r-t);let o=c.skip(t).limit(n).get();i.push(o)}try{h=(await Promise.all(i)).reduce((e,t)=>({data:e.data.concat(t.data),errMsg:e.errMsg}))}catch(t){throw console.error("vk.baseDao.select-异常",e,t),new Error("msg:vk.baseDao.select-异常")}}let y={};return y.total=f?p:h.data?h.data.length:0,y.hasMore=d,y.rows=h.data,y.code=0,y.msg="查询成功",y.pagination={pageIndex:g,pageSize:m},o&&(y.rows=y.rows[0]),s?y.rows:y},sum:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.sum("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:0},avg:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.avg("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},max:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.max("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},min:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,fieldName:r,whereJson:o,db:s}=e,u=s||n;const l=u.command.aggregate;let c=u.collection(a).aggregate();t.pubfn.isNotNull(o)&&c.match(o),c.group({_id:null,num:l.min("$"+r)});let d=await c.end();return d.data&&d.data[0]?d.data[0].num:null},sample:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,size:o,fieldJson:s,db:u}=e,l=u||n;l.command.aggregate;let c=l.collection(a).aggregate();return t.pubfn.isNotNull(r)&&c.match(r),c.sample({size:o}).limit(o),t.pubfn.isNotNull(s)&&c.project(s),(await c.end()).data},selects:async function(e={}){let{vk:t,db:n,_:i}=util$1;if(t.pubfn.isNotNull(e.treeProps))return await baseDao.tree(e);"string"==typeof e.pageIndex&&(e.pageIndex=parseInt(e.pageIndex)),"string"==typeof e.pageSize&&(e.pageSize=parseInt(e.pageSize));let{db:a,dbName:r,foreignKey:o="_id",pageIndex:s=1,pageSize:u=10,getCount:l=!1,getOne:c=!1,getMain:d=!1,whereJson:p={},unwindJson:f,groupJson:g,sortArr:m=[],foreignDB:b=[],lastWhereJson:h,lastSortArr:y=[],fieldJson:w={},addFields:_}=e,k=a||n;-1==u&&(s=1,u=999999999,l=!1),c&&(u=1,l=!1);let v,x=0,N=!1;if(t.pubfn.isNotNull(p))for(let e in p)p[e]&&"object"==typeof p[e]&&"geoNear"===p[e].operator&&(v=t.pubfn.copyObject(p[e]),v.keyName=e,v.limit=s*u,delete p[e]);if(l){if(t.pubfn.isNullAll(g,f,h)){let e;e=t.pubfn.isNotNull(p)?await k.collection(r).where(p).count():await k.collection(r).count(),x=e.total}else{let e=k.collection(r).aggregate();t.pubfn.isNotNull(p)&&(t.pubfn.isNotNull(v)?e=baseDao.getGeoNearJson({runDB:k,result:e,geoNearJson:v,whereJson:p}):e.match(p)),t.pubfn.isNotNull(f)&&(e=baseDao.getTnwind({result:e,unwindJson:f})),t.pubfn.isNotNull(g)&&e.group(g),t.pubfn.isNotNull(h)&&(t.pubfn.isNotNull(b)&&(e=baseDao.addForeignDB({foreignDB:b,foreignKey:o,result:e})),e.match(h)),e=await e.count("total").end(),x=e.data[0]?e.data[0].total:0}s=u),$.rows=O,$.code=0,$.msg="查询成功",$.pagination={pageIndex:s,pageSize:u},c&&($.rows=$.rows[0]),d?$.rows:$},listToObjectByLimit1:function(e){let{vk:t,db:n,_:i}=util$1,{list:a,foreignDB:r}=e;if(t.pubfn.isNotNull(r))for(let e in a)for(let n in r){let{as:i,limit:o,foreignDB:s,dbName:u}=r[n];i||(i=u),t.pubfn.isNotNull(s)&&(a[e][i]=baseDao.listToObjectByLimit1({list:a[e][i],foreignDB:s})),1===o&&(t.pubfn.isArray(a[e][i])?a[e][i]&&a[e][i].length>0?a[e][i]=a[e][i][0]:a[e][i]={}:void 0===a[e][i]&&(a[e][i]={}))}return a},addForeignDB:function(e){let{vk:t,db:n,_:i}=util$1,{foreignDB:a,foreignKey:r,result:o}=e;const s=i.aggregate;for(let e in a){let n,{dbName:u,foreignKey:l,localKey:c,localKeyType:d="",foreignKeyType:p="",as:f,limit:g,getOne:m,whereJson:b,fieldJson:h,sortArr:y,foreignDB:w,addFields:_}=a[e];f||(f=u),n=t.pubfn.isNotNull(c)?c:"object"==typeof r?r[e]:r;let k,v="string"==typeof n?"$"+n:n,x="string"==typeof l?"$"+l:l,N="$$foreignKey"+baseDao.getForeignKeyName(n),$="foreignKey"+baseDao.getForeignKeyName(n);k="array"===d.toLowerCase()?[s.cond({if:s.isArray(N),then:s.in([x,N]),else:s.eq([x,N])})]:"array"===p.toLowerCase()?[s.cond({if:s.isArray(x),then:s.in([N,x]),else:s.eq([x,N])})]:[s.eq([x,N])];let D=s.pipeline().match(i.expr(s.and(k)));if(t.pubfn.isNotNull(b)&&(D=D.match(b)),t.pubfn.isNotNull(y)){let e={};for(let t in y){let n=y[t],i=n.name,a=n.type;a=null==a||""==a||"asc"==a?1:-1,e[i]=a}D=D.sort(e)}g&&(D=D.limit(g)),t.pubfn.isNotNull(w)&&(D=baseDao.addForeignDB({foreignDB:w,result:D})),t.pubfn.isNotNull(h)&&(h=baseDao.foreignDBToProject({fieldJson:h,foreignDB:w}),D=D.project(h)),t.pubfn.isNotNull(_)&&(D=D.addFields(_)),D=D.done();let T={};T[$]=v;let O={from:u,let:T,pipeline:D,as:f};o=o.lookup(O),(1===g&&!1!==m||!0===m)&&(o=o.unwind({path:"$"+f,preserveNullAndEmptyArrays:!0}))}return o},getForeignKeyName:function(e){return"string"==typeof e?e.replace(new RegExp("\\.","g"),"__"):"__vk__foreignKey1"},addWhereJson:function(e,t={},n="whereJson"){let{vk:i,db:a,_:r}=util$1,{formData:o,columns:s}=e;for(let e in s){let a,u=s[e],{key:l,mode:c,defaultValue:d,type:p="",lastWhereJson:f,auxiliary:g=!0,trim:m=!0,isNumber:b=!1}=u;if("lastWhereJson"===n&&!f)continue;if("lastWhereJson"!==n&&f)continue;let h=l;if(i.pubfn.isNotNull(u.fieldName)&&(h=u.fieldName),a=i.pubfn.isNotNull(u.value)?u.value:o[l],i.pubfn.isNull(a)&&i.pubfn.isNotNull(d)&&(a=d),i.pubfn.isNull(c)&&(c=["address","province","city","area"].indexOf(p)>-1?"address":"[object Array]"===Object.prototype.toString.call(a)&&a.length>=2?"[]":"="),i.pubfn.isNotNull(a))if("string"==typeof a&&m&&"function"==typeof a.trim&&(a=a.trim()),b&&!isNaN(a)&&(a=Number(a)),"custom"===c);else if("%%"===c)try{t[h]=new RegExp(a)}catch(e){}else if("%*"===c)try{t[h]=new RegExp("^"+a)}catch(e){}else if("*%"===c)try{t[h]=new RegExp(a+"$")}catch(e){}else if(">"===c)t[h]=t[h]?t[h].gt(a):r.gt(a);else if(">="===c)t[h]=t[h]?t[h].gte(a):r.gte(a);else if("<"===c)t[h]=t[h]?t[h].lt(a):r.lt(a);else if("<="===c)t[h]=t[h]?t[h].lte(a):r.lte(a);else if("in"===c)t[h]=r.in(a);else if("nin"===c)t[h]=r.nin(a);else if("!="===c)t[h]=r.neq(a);else if("[]"===c)t[h]=r.gte(a[0]).lte(a[1]);else if("[)"===c)t[h]=r.gte(a[0]).lt(a[1]);else if("(]"===c)t[h]=r.gt(a[0]).lte(a[1]);else if("()"===c)t[h]=r.gt(a[0]).lt(a[1]);else if("address"===c){let e={};a.province&&a.province.code&&(e["province.code"]=a.province.code),a.city&&a.city.code&&(e["city.code"]=a.city.code),a.area&&a.area.code&&(e["area.code"]=a.area.code),t[h]=e}else t[h]=g?"___empty-array___"===a?[]:"___empty-object___"===a?{}:"___non-existent___"===a?r.exists(!1):"___existent___"===a?r.exists(!0):a:a}return t},addLastWhereJson:function(e,t={}){return baseDao.addWhereJson(e,t,"lastWhereJson")},getTableData:async function(e){let{vk:t,db:n,_:i,config:a}=util$1,{db:r,dbName:o,data:s={},getCount:u=!0,getMain:l,whereJson:c,unwindJson:d,fieldJson:p,sortArr:f,treeProps:g,groupJson:m,foreignKey:b,foreignDB:h,lastWhereJson:y,lastSortArr:w,addFields:_}=e,{pageIndex:k,pageSize:v,pagination:x,sortRule:N,lastSortRule:$,formData:D,columns:T}=s;x&&(k=x.pageIndex,v=x.pageSize);let O,A={},I={},S=[],E={};if(t.pubfn.isNotNull(f))S=f;else{let e=t.pubfn.getData(a,"vk.db.unicloud.getTableData.sortArr");t.pubfn.isNotNull(e)?S=e:S.push({name:"_id",type:"desc"})}if(t.pubfn.isNotNull(N)&&(S=N),t.pubfn.isNotNull($)&&(w=$),I=baseDao.addWhereJson(s),E=baseDao.addLastWhereJson(s),t.pubfn.isNotNull(c)&&(c.operator&&c.operands&&["or","and"].indexOf(c.operator)>-1?I=i.and([I,c]):t.pubfn.objectAssign(I,c)),t.pubfn.isNotNull(p)&&t.pubfn.objectAssign(A,p),t.pubfn.isNotNull(y)&&t.pubfn.objectAssign(E,y),t.pubfn.isNotNull(I))for(let e in I)"object"==typeof I[e]&&I[e]&&"geoNear"===I[e].operator&&(O=!0);return t.pubfn.isNullAll(h,m,g,d,O)?await t.baseDao.select({db:r,dbName:o,getMain:l,getCount:u,pageIndex:k,pageSize:v,fieldJson:A,whereJson:I,sortArr:S}):await t.baseDao.selects({db:r,dbName:o,foreignKey:b,getMain:l,getCount:u,pageIndex:k,pageSize:v,whereJson:I,unwindJson:d,fieldJson:A,sortArr:S,treeProps:g,groupJson:m,foreignDB:h,lastWhereJson:E,lastSortArr:w,addFields:_})},startTransaction:async function(e){let{vk:t,db:n,_:i}=util$1;return await n.startTransaction()},rollbackTransaction:async function(e){let{db:t,msg:n="【异常】操作失败",tips:i="事务已回滚。",err:a={},code:r=-1}=e;console.error("transaction error",a);let o={code:r,msg:n,tips:i};await t.rollback();let s={message:a.message,stack:a.stack};try{s.body=JSON.parse(a.message),"object"==typeof s.body&&void 0!==s.body.code&&(s.body.msg,1)&&(o.msg=s.body.msg)}catch(e){}return console.error("transaction errJson",s),o.err=s,o},group:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r,groupJson:o,sortArr:s,pageIndex:u=1,pageSize:l=10,getCount:c=!1,lookupJson:d,db:p}=e,f=p||n;l<=0&&(l=999999999);i.aggregate;let g,m=f.collection(a).aggregate();if(t.pubfn.isNotNull(r)&&(m=m.match(r)),t.pubfn.isNotNull(o)&&(m=m.group(o)),t.pubfn.isNotNull(s)){let e={};for(let t in s){let n=s[t],i=n.name,a=n.type;a=null==a||""==a||"asc"==a?1:-1,e[i]=a}m=m.sort(e)}m=m.skip((u-1)*l).limit(l),t.pubfn.isNotNull(d)&&(g=d.returnObject,delete d.returnObject,m=m.lookup(d)),m=await m.end();let b,h=m.data;if(g)for(let e in h)h[e][d.as]=h[e][d.as][0];let y=!1;if(c){let e=f.collection(a).aggregate();t.pubfn.isNotNull(r)&&(e=e.match(r)),t.pubfn.isNotNull(o)&&(e=e.group(o));let n=await e.count("total").end();b=n.data[0]?n.data[0].total:0,u=l;return{hasMore:y,total:b,rows:h,code:0,key:1,pageIndex:u,pageSize:l}},tree:async function(e){let{vk:t,db:n,_:i}=util$1,{dbName:a,whereJson:r={},pageIndex:o=1,pageSize:s=10,getCount:u=!1,sortArr:l=[],fieldJson:c={},lastWhereJson:d,treeProps:p={}}=e;e.foreignDB||(e.foreignDB=[]);let{id:f="_id",parent_id:g="parent_id",children:m="children",level:b=10,limit:h=500}=p;if(b<1||b>20)throw new Error("msg:treeProps.level的范围必须在[1,20]");delete e.treeProps,e.whereJson||(e.whereJson={[g]:null}),e.foreignDB.unshift({dbName:a,localKey:f,foreignKey:g,as:m,limit:h,whereJson:p.whereJson,fieldJson:p.fieldJson||e.fieldJson,sortArr:p.sortArr,foreignDB:t.pubfn.copyObject(e.foreignDB)});let y=t.pubfn.copyObject(e.foreignDB);for(let n=1;n{"[object object]"===Object.prototype.toString.call(e.content)&&(e.content=JSON.stringify(e.content)),void 0===e.dataType&&(e.dataType="json"),"default"!=e.dataType&&""!==e.dataType||delete e.dataType,e.useContent&&(e.content=JSON.stringify(e.data)),e.method||(e.method="POST"),e.method=e.method.toUpperCase(),void 0===e.headers&&void 0!==e.header&&(e.headers=e.header);let t=await uniCloud.httpclient.request(e.url,e);return!e.needOriginalRes&&t&&t.data?t.data:t};var vk_request=request;const callFunction=async(e={})=>{let{name:t,url:n,data:i={},uniIdToken:a,clientInfo:r={},event:o={},uniCloud:s}=e;if(o&&o.originalParam&&o.originalParam.context){let e=o.originalParam.context;a=o.uniIdToken,r={...e,appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,os:e.OS,userAgent:e.CLIENTUA,deviceId:e.DEVICEID,uniIdToken:a}}let u,l=s||uniCloud;u=l.$context&&l.$context.FUNCTION_NAME?l.$context.FUNCTION_NAME:l.$options&&l.$options.context&&l.$options.context.FUNCTION_NAME?l.$options.context.FUNCTION_NAME:"router",a||r.uniIdToken&&(a=r.uniIdToken);let c={...i,vk_context:{appId:r.appId,platform:r.platform,locale:r.locale,clientIP:r.clientIP,os:r.os,userAgent:r.userAgent,deviceId:r.deviceId}};t||(t=u);let d=await l.callFunction({name:t,data:{$url:n,uniIdToken:a,data:c}});return d&&d.result};var vk_callFunction=callFunction,util$2={formValidateItem:function(e,t,n){let i={code:0,msg:"ok"},a=getData(e,t);void 0===a&&(a=e[t]);for(let e in n){let r=n[e];if(void 0===a&&r.required){i={type:"undefined",code:-1,msg:"字段:"+t+" 名称错误,请检查!",key:t,value:a};break}if(r.required&&(null==a||null==a||""===a||0==a.length)){i={type:"required",code:-1,msg:r.message,key:t,value:a};break}if(r.type&&void 0!==a){if(Object.prototype.toString.call(a).toLowerCase().toLowerCase()!==`[object ${r.type}]`.toLowerCase()){i={type:"type",code:-1,msg:r.message,key:t,value:a};break}}if(r.len&&a.length!=r.len){i={type:"len",code:-1,msg:r.message,key:t,value:a};break}if(r.min&&isNotNull(a))if("number"==r.type){if(ar.max){i={type:"max",code:-1,msg:r.message,key:t,value:a};break}}else if(a.length>r.max){i={type:"max",code:-1,msg:r.message,key:t,value:a};break}if("function"==typeof r.validator){let e,n,o=0,s=r.validator(r,a,(function(e){return n||(n=e),e}));if(n||(n=s),void 0!==n&&!0!==n&&(o=-1,"object"==typeof n?e||(e=n.message||n.msg,n.code&&(o=n.code)):"string"==typeof n&&(e||(e=n))),o){i={type:"validator",code:o,msg:e||r.message,key:t,value:a};break}}}return i}},formValidate=function(e={}){let t={code:0,msg:"ok"},{data:n,rules:i}=e;if(i)for(let e in i){let a=i[e];if(t=util$2.formValidateItem(n,e,a),0!=t.code)break}return t};function isNotNull(e){return-1===[void 0,null,""].indexOf(e)}function getData(e,t,n){let i=JSON.parse(JSON.stringify(e));t=t.replace(/\s+/g,"")+".";let a="";for(let e=0;e0&&(n=util$3.treeToArrayFn(l[o],t,n,l[a])),s&&delete l[o]}return n},util$3.arrayToTree=function(e,t){let n=deepClone(e),{id:i="_id",parent_id:a="parent_id",children:r="children",deleteParentId:o=!1,need_field:s}=t,u=[],l={};for(let e=0;e=10&&(e=Number(e)),"number"==typeof e)10==e.toString().length&&(e*=1e3),n=new Date(e);else if("object"==typeof e)n=new Date(e.getTime());else if("string"==typeof e){let i=t=util$4.getTargetTimezone(t),a=t>=0?"+":"";t>=0&&t<10?i="0"+t:t<0&&t>-10&&(i="-0"+-1*t);let r,o=e.split(" "),s=o[0]||"",u=o[1]||"";r=s.indexOf("-")>-1?s.split("-"):s.split("/");let l=u.split(":"),c={year:Number(r[0]),month:Number(r[1])||1,day:Number(r[2])||1,hour:Number(l[0])||0,minute:Number(l[1])||0,second:Number(l[2])||0};for(let e in c)c[e]>=0&&c[e]<10&&(c[e]="0"+c[e]);let d=`${c.year}-${c.month}-${c.day}T${c.hour}:${c.minute}:${c.second}${a}${i}:00`;n=new Date(d)}return n},getTimeByTimeZone:function(e,t){let n=util$4.getDateObject(e);t=util$4.getTargetTimezone(t);let i=60*n.getTimezoneOffset()*1e3+60*t*60*1e3,a=n.getTime()+i;return n=new Date(a),n},timeFormat:function(e,t="yyyy-MM-dd hh:mm:ss",n){try{if(!e)return"";n=util$4.getTargetTimezone(n);let i=util$4.getTimeByTimeZone(e,n),a={"M+":i.getMonth()+1,"d+":i.getDate(),"h+":i.getHours(),"m+":i.getMinutes(),"s+":i.getSeconds(),"q+":Math.floor((i.getMonth()+3)/3),S:i.getMilliseconds(),Z:`${n>=0?"+":"-"}${Math.abs(n).toString().padStart(2,"0")}:00`};/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(i.getFullYear()+"").substr(4-RegExp.$1.length)));for(let e in a)new RegExp("("+e+")").test(t)&&(t=t.replace(RegExp.$1,1==RegExp.$1.length?a[e]:("00"+a[e]).substr((""+a[e]).length)));return t}catch(e){return time}},getDateInfo:function(e=new Date,t){let n=util$4.getTimeByTimeZone(e,t),i=n.getFullYear()+"",a=n.getMonth()+1<10?"0"+(n.getMonth()+1):n.getMonth()+1,r=n.getDate()<10?"0"+n.getDate():n.getDate(),o=n.getHours()<10?"0"+n.getHours():n.getHours(),s=n.getMinutes()<10?"0"+n.getMinutes():n.getMinutes(),u=n.getSeconds()<10?"0"+n.getSeconds():n.getSeconds(),l=n.getMilliseconds(),c=n.getDay(),d=Math.floor((n.getMonth()+3)/3);return{year:Number(i),month:Number(a),day:Number(r),hour:Number(o),minute:Number(s),second:Number(u),millisecond:Number(l),week:Number(c),quarter:Number(d)}},getCommonTime:function(e=new Date,t){let n={},i=util$4.getDateObject(e);t=util$4.getTargetTimezone(t);const a=60*i.getTimezoneOffset()*1e3+60*t*60*1e3,{year:r,month:o,day:s,hour:u,minute:l,second:c,millisecond:d,week:p,quarter:f}=util$4.getDateInfo(i,t);n.now={year:r,month:o,day:s,hour:u,minute:l,second:c,millisecond:d,week:p,quarter:f,date_str:util$4.timeFormat(i,"yyyy-MM-dd hh:mm:ss",t),date_day_str:util$4.timeFormat(i,"yyyy-MM-dd",t),date_month_str:util$4.timeFormat(i,"yyyy-MM",t)};let g=new Date(r,o,0).getDate(),m=new Date(r,12,0).getDate();n.todayStart=new Date(`${r}/${o}/${s}`).getTime()-a,n.today12End=new Date(`${r}/${o}/${s}`).getTime()+43199999-a,n.todayEnd=new Date(`${r}/${o}/${s}`).getTime()+86399999-a,n.monthStart=new Date(`${r}/${o}/1`).getTime()-a,n.monthEnd=new Date(`${r}/${o}/${g}`).getTime()+86399999-a,n.yearStart=new Date(r+"/1/1").getTime()-a,n.yearEnd=new Date(`${r}/12/${m}`).getTime()+86399999-a,n.hourStart=new Date(`${r}/${o}/${s} ${u}:00:00`).getTime()-a,n.hourEnd=new Date(`${r}/${o}/${s} ${u}:59:59`).getTime()-a;let b=r,h=o-1;0===h&&(h=12,b=r-1);let y=new Date(b,h,0).getDate();n.lastMonthStart=new Date(`${b}/${h}/1`).getTime()-a,n.lastMonthEnd=new Date(`${b}/${h}/${y}`).getTime()+86399999-a,n.yesterdayStart=n.todayStart-864e5,n.yesterday12End=n.today12End-864e5,n.yesterdayEnd=n.todayEnd-864e5;let w=util$4.getWeekOffsetStartAndEnd(0,i,t);n.weekStart=w.startTime,n.weekEnd=w.endTime,n.months=[],n.months[0]={startTime:n.monthStart,endTime:n.monthEnd,startTimeStr:util$4.timeFormat(n.monthStart,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(n.monthEnd,"yyyy-MM-dd hh:mm:ss",t),monthStart:n.monthStart,monthEnd:n.monthEnd};for(let e=1;e<=12;e++){let i=new Date(r,e,0).getDate(),o=new Date(`${r}/${e}/1`).getTime()-a,s=new Date(`${r}/${e}/${i}`).getTime()+86399999-a;n.months[e]={startTime:o,endTime:s,startTimeStr:util$4.timeFormat(o,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(s,"yyyy-MM-dd hh:mm:ss",t),monthStart:o,monthEnd:s}}n.days=[],n.days[0]={startTime:n.todayStart,endTime:n.todayEnd,startTimeStr:util$4.timeFormat(n.todayStart,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(n.todayEnd,"yyyy-MM-dd hh:mm:ss",t)};for(let e=1;e<=g;e++){let i=n.monthStart+864e5*(e-1),{startTime:a,endTime:r}=util$4.getDayOffsetStartAndEnd(0,i,t);n.days[e]={startTime:a,endTime:r,startTimeStr:util$4.timeFormat(a,"yyyy-MM-dd hh:mm:ss",t),endTimeStr:util$4.timeFormat(r,"yyyy-MM-dd hh:mm:ss",t)}}for(let e in n)"number"==typeof n[e]&&13===n[e].toString().length&&(n[e+"Str"]=util$4.timeFormat(n[e],"yyyy-MM-dd hh:mm:ss",t));return n},getMonthStartAndEnd:function(e,t){t=util$4.getTargetTimezone(t);let n={startTime:null,endTime:null},{year:i,month:a}=e;if(i>0&&a>0){const e=60*(new Date).getTimezoneOffset()*1e3+60*t*60*1e3;let r=new Date(i,a,0).getDate();n.startTime=new Date(`${i}/${a}/1`).getTime()-e,n.endTime=new Date(`${i}/${a}/${r}`).getTime()+86399999-e}return n},getHourOffsetStartAndEnd:function(e=0,t=new Date,n){let i=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);let a={};const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;i=new Date(i.getTime()+36e5*e);let o=util$4.getDateInfo(i);return a.startTime=new Date(`${o.year}/${o.month}/${o.day} ${o.hour}:00:00`).getTime()-r,a.endTime=new Date(`${o.year}/${o.month}/${o.day} ${o.hour}:00:00`).getTime()+3599999-r,a},getDayOffsetStartAndEnd:function(e=0,t=new Date,n){let i=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);let a={};const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;i=new Date(i.getTime()+864e5*e);let o=util$4.getDateInfo(i);return a.startTime=new Date(`${o.year}/${o.month}/${o.day}`).getTime()-r,a.endTime=new Date(`${o.year}/${o.month}/${o.day}`).getTime()+86399999-r,a},getWeekOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=0===a.getDay()?7:a.getDay();a.setDate(a.getDate()-o+1+7*e);let s=util$4.getDateInfo(a);a.setDate(a.getDate()+7);let u=util$4.getDateInfo(a);return i.startTime=new Date(`${s.year}/${s.month}/${s.day}`).getTime()-r,i.endTime=new Date(`${u.year}/${u.month}/${u.day}`).getTime()-1-r,i},getMonthOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t),r=util$4.getDateInfo(a),o=r.month+e,s=r.year;o>12?(s+=Math.floor(o/12),o=Math.abs(o)%12):o<=0&&(s=s-1-Math.floor(Math.abs(o)/12),o=12-Math.abs(o)%12);let u=new Date(s,o,0).getDate();return i.startTime=util$4.getDateObject(`${s}/${o}/01`,n).getTime(),i.endTime=util$4.getDateObject(`${s}/${o}/${u}`,n).getTime()+86399999,i},getQuarterOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);a.setMonth(a.getMonth()+3*e),n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=util$4.getDateInfo(a).month;[1,2,3].indexOf(o)>-1?o=1:[4,5,6].indexOf(o)>-1?o=4:[7,8,9].indexOf(o)>-1?o=7:[10,11,12].indexOf(o)>-1&&(o=10),a.setMonth(o-1);let s=util$4.getDateInfo(a);a.setMonth(a.getMonth()+3);let u=util$4.getDateInfo(a);return i.startTime=new Date(`${s.year}/${s.month}/1`).getTime()-r,i.endTime=new Date(`${u.year}/${u.month}/1`).getTime()-1-r,i},getYearOffsetStartAndEnd:function(e=0,t=new Date,n){let i={},a=util$4.getDateObject(t);n=util$4.getTargetTimezone(n);const r=60*a.getTimezoneOffset()*1e3+60*n*60*1e3;let o=util$4.getDateInfo(a).year+e;return i.startTime=new Date(o+"/1/1").getTime()-r,i.endTime=new Date(o+"/12/31").getTime()+86399999-r,i},getOffsetTime:function(e=new Date,t,n){let i=util$4.getDateObject(e),a=util$4.getDateInfo(i);n=util$4.getTargetTimezone(n);const r=60*i.getTimezoneOffset()*1e3+60*n*60*1e3;let o=t.year||t.y||0,s=t.month||t.m||0,u=t.day||t.d||0,l=t.hour||t.hours||t.hh||0,c=t.minute||t.minutes||t.mm||0,d=t.second||t.seconds||t.ss||0,{mode:p="after"}=t;"before"==p&&(o*=-1,s*=-1,u*=-1,l*=-1,c*=-1,d*=-1);let f={year:a.year+o,month:a.month+s,day:a.day+u,hour:a.hour+l,minute:a.minute+c,second:a.second+d};return i=new Date(f.year,f.month-1,f.day,f.hour,f.minute,f.second),i.getTime()-r},isLeapYear:function(e){if(void 0===e){let{now:t}=util$4.getCommonTime();e=t.year}else if("object"==typeof e){let{now:t}=util$4.getCommonTime(e);e=t.year}return e%4==0&&e%100!=0||e%400==0},isQingming:function(e=new Date){let{now:t}=util$4.getCommonTime(e),{year:n,month:i,day:a}=t,r=!1;return util$4.isLeapYear(n)||util$4.isLeapYear(n-1)?4===i&&4===a&&(r=!0):4===i&&5===a&&(r=!0),r},getFullTime:function(e,t=0,n){if(!e)return"";n=util$4.getTargetTimezone(n);let i=util$4.getDateObject(e);const a=60*i.getTimezoneOffset()*1e3+60*n*60*1e3,r=i.getTime()+a;i=new Date(r);let o=i.getFullYear()+"",s=i.getMonth()+1<10?"0"+(i.getMonth()+1):i.getMonth()+1,u=i.getDate()<10?"0"+i.getDate():i.getDate(),l=i.getHours()<10?"0"+i.getHours():i.getHours(),c=i.getMinutes()<10?"0"+i.getMinutes():i.getMinutes(),d=i.getSeconds()<10?"0"+i.getSeconds():i.getSeconds();return 2===t?{YYYY:Number(o),MM:Number(s),DD:Number(u),hh:Number(l),mm:Number(c),ss:Number(d),year:Number(o),month:Number(s),day:Number(u),hour:Number(l),minute:Number(c),second:Number(d)}:1===t?o+""+s+u+l+c+d:o+"-"+s+"-"+u+" "+l+":"+c+":"+d}},timeUtil=util$4,pubfn={};pubfn.formValidate=formValidate,pubfn.treeUtil=treeUtil,pubfn.timeUtil=timeUtil,pubfn.sleep=e=>new Promise(t=>setTimeout(t,e)),pubfn.timeFormat=pubfn.timeUtil.timeFormat,pubfn.getDateInfo=pubfn.timeUtil.getDateInfo,pubfn.getFullTime=pubfn.timeUtil.getFullTime,pubfn.getCommonTime=pubfn.timeUtil.getCommonTime,pubfn.getOffsetTime=pubfn.timeUtil.getOffsetTime,pubfn.getHourOffsetStartAndEnd=pubfn.timeUtil.getHourOffsetStartAndEnd,pubfn.getDayOffsetStartAndEnd=pubfn.timeUtil.getDayOffsetStartAndEnd,pubfn.getWeekOffsetStartAndEnd=pubfn.timeUtil.getWeekOffsetStartAndEnd,pubfn.getWeekStartAndEnd=pubfn.timeUtil.getWeekOffsetStartAndEnd,pubfn.getMonthOffsetStartAndEnd=pubfn.timeUtil.getMonthOffsetStartAndEnd,pubfn.getQuarterOffsetStartAndEnd=pubfn.timeUtil.getQuarterOffsetStartAndEnd,pubfn.getYearOffsetStartAndEnd=pubfn.timeUtil.getYearOffsetStartAndEnd,pubfn.getMonthStartAndEnd=pubfn.timeUtil.getMonthStartAndEnd,pubfn.validator=function(e){return function(t,n,i){let a=pubfn.test(n,e);return"function"!=typeof i||!a&&n?i(!1):void i()}},pubfn.test=function(e,t="",n=!1){let i;if(t=t.toLowerCase(),n&&(""===e||null==e))return!0;switch(t){case"mobile":return new RegExp(/^1[3|4|5|6|7|8|9][0-9]{9}$/).test(e);case"tel":return new RegExp(/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/).test(e);case"card":return new RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(e);case"mobilecode":return new RegExp(/^[0-9]{6}$/).test(e);case"username":return new RegExp(/^[a-zA-Z]([-_a-zA-Z0-9]{2,31})$/).test(e);case"pwd":case"password":return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(e);case"paypwd":return new RegExp(/^[0-9]{6}$/).test(e);case"postal":return new RegExp(/[1-9]\d{5}(?!\d)/).test(e);case"qq":return new RegExp(/^[1-9][0-9]{4,9}$/).test(e);case"email":return new RegExp(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/).test(e);case"money":return new RegExp(/^\d*(?:\.\d{0,2})?$/).test(e);case"url":return new RegExp(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/).test(e);case"ip":return new RegExp(/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/).test(e);case"date":return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/).test(e);case"time":return new RegExp(/^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(e);case"datetime":return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(e);case"english+number":return new RegExp(/^[a-zA-Z0-9]+$/).test(e);case"english+number+_":return new RegExp(/^[a-zA-Z0-9_]+$/).test(e);case"english+number+_-":return new RegExp(/^[a-zA-Z0-9_-]+$/).test(e);case"version":return new RegExp(/^([1-9]\d|[1-9])(.([1-9]\d|\d)){2}$/).test(e);case"number":return new RegExp(/^[0-9]+$/).test(e);case"english":return new RegExp(/^[a-zA-Z]+$/).test(e);case"chinese":return new RegExp(/^[\u4e00-\u9fa5]+$/gi).test(e);case"lower":return new RegExp(/^[a-z]+$/).test(e);case"upper":return new RegExp(/^[A-Z]+$/).test(e);case"html":return new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(e);case"image":return i=e.split("?")[0],new RegExp(/\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)$/).test(i);case"video":return i=e.split("?")[0],new RegExp(/\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8|3gp)$/).test(i);case"audio":return i=e.split("?")[0],new RegExp(/\.(mp3)$/).test(i);default:return!0}},pubfn.checkStr=pubfn.test,pubfn.priceFilter=function(e,t=""){return pubfn.isNull(e)?t:isNaN(e)?e:("string"==typeof e&&(e=parseFloat(e)),(e/100).toFixed(2))},pubfn.priceLeftFilter=function(e){let t="";return e&&(t=pubfn.priceFilter(e).split(".")[0]),t},pubfn.priceRightFilter=function(e){let t="";return e&&(t=pubfn.priceFilter(e).split(".")[1]),t},pubfn.percentageFilter=function(e,t=!0,n=""){return pubfn.isNull(e)?n:(isNaN(e)||("string"==typeof e&&(e=parseFloat(e)),e=parseFloat((100*e).toFixed(2)),t&&(e+="%")),e)},pubfn.discountFilter=function(e,t=!0,n=""){return pubfn.isNull(e)?n:isNaN(e)?e:("string"==typeof e&&(e=parseFloat(e)),(e=parseFloat((10*e).toFixed(2)))>10?"折扣不可以大于原价":10==e?"原价":0==e?"免费":e<0?"折扣不可以小于0":(t&&(e+=" 折"),e))},pubfn.objectDeleteInvalid=function(e){return Object.keys(e).forEach(t=>{void 0===e[t]&&delete e[t]}),e},pubfn.objectAssign=function(e,t,n=!0){return n&&pubfn.objectDeleteInvalid(t),Object.assign(e,t)},pubfn.copyObject=function(e){return void 0!==e?JSON.parse(JSON.stringify(e)):e},pubfn.deepClone=function(e){if([null,void 0,NaN,!1].includes(e))return e;if("object"!=typeof e&&"function"!=typeof e)return e;let t="[object Array]"===Object.prototype.toString.call(e)?[]:{};for(let n in e)e.hasOwnProperty(n)&&(t[n]="object"==typeof e[n]?pubfn.deepClone(e[n]):e[n]);return t},pubfn.formAssign=function(e,t){let n=pubfn.copyObject(e);return pubfn.objectAssign(n,t)},pubfn.arr_concat=function(e,t,n){n||(n="id"),e||(e=[]),t||(t=[]);let i=e.concat(t),a=[];if(-1!=n){let e=[];for(let t in i)-1==e.indexOf(i[t][n])&&(e.push(i[t][n]),a.push(i[t]))}else a=i;return a},pubfn.getData=function(e,t,n){let i=JSON.parse(JSON.stringify(e));t=t.replace(/\s+/g,"")+".";let a="";for(let e=0;ee[t])},pubfn.random=function(e,t,n){let i;if(pubfn.isNull(n))i=pubfn.randomFn(e,t);else{let a=0,r=1e5;do{a++,i=pubfn.randomFn(e,t)}while(n.indexOf(i)>-1&&ae){n+="0123456789"[i[e].charCodeAt()%10]}else n="0"+n;return n},pubfn.hidden=function(e="",t=0,n=0){let i=e.length-t-n,a="";for(let e=0;e-1&&(n=!0);return n},pubfn.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},pubfn.isObject=function(e){return"[object Object]"===Object.prototype.toString.call(e)},pubfn.calcFreights=function(e,t){return pubfn.calcFreightDetail(e,t).total_amount},pubfn.calcFreightDetail=function(e,t){let{first_weight:n,first_weight_price:i,continuous_weight:a,continuous_weight_price:r,max_weight:o}=e;o||(o=1e9);let s=t,u=0,l=o,c=!1,d=0;for(;t>0;)c?(d++,t-=a,l-=a):(c=!0,u++,l=o,t-=n,l-=n),l<=0&&(c=!1);let p=i*u+r*d;return{weight:s,first_weight:n,first_weight_price:i,first_weight_count:u,continuous_weight:a,continuous_weight_price:r,continuous_weight_count:d,first_weight_amount:u*i,continuous_weight_amount:r*d,total_amount:p,formula:`${i} * ${u} + ${r} * ${d} = ${p}`}},pubfn.getNewObject=function(e,t){let n=pubfn.copyObject(e),i={};if(t&&t.length>0)for(let e in t){let a=t[e];pubfn.isNotNull(n[a])&&(i[a]=n[a])}else i=n;return i},pubfn.deleteObjectKeys=function(e,t=[]){var n={};if(e)for(let i in e)-1==t.indexOf(i)&&(n[i]=e[i]);return n},pubfn.arrayToTree=pubfn.treeUtil.arrayToTree,pubfn.treeToArray=pubfn.treeUtil.treeToArray,pubfn.wildcardTestOne=function(e,t){if(!t)return!1;let n=t.replace(new RegExp("\\*"),"(.*)"),i=0!==t.indexOf("*")?"^":"",a="*"!==t[t.length-1]?"$":"";return new RegExp(i+n+a).test(e)},pubfn.wildcardTest=function(e,t){let n=0;if("string"==typeof t)pubfn.wildcardTestOne(e,t)&&n++;else if("object"==typeof t)for(let i=0;i0?l=r+"天":o>0?l=o+"小时":s>0?l=s+"分钟":u>0&&(l=u+"秒"),l+=t},pubfn.dateDiff2=function(e,t="1秒"){if(!e)return"";"string"!=typeof e||isNaN(e)||(e=Number(e)),"number"==typeof e&&(10==e.toString().length&&(e*=1e3),e=new Date(e),e=pubfn.timeFormat(e)),"string"==typeof e&&(e=e=e.replace("T"," "),e=new Date(e.replace(/-/g,"/")));var n=new Date,i=864e5,a=36e5,r=e.getTime()-n.getTime(),o=Math.floor(r/i),s=Math.floor(r%i/a),u=Math.floor(r%i%a/6e4),l=Math.round(r%i%a%6e4/1e3),c=t;return o>0?c=o+"天":s>0?c=s+"小时":u>0?c=u+"分钟":l>0&&(c=l+"秒"),c},pubfn.numStr=function(e){"string"==typeof e&&(e=parseFloat(e));var t=e;if(e<1e3)t=e;else if(e<1e4){t=Math.floor(e/100)/10+"千"}else if(e<1e6){t=Math.floor(e/1e3)/10+"万"}else if(e<1e7){t=Math.floor(e/1e6)+"百万"}else if(e<1e8){t=Math.floor(e/1e7)+"千万"}else if(e>=1e8){t=Math.floor(e/1e7)/10+"亿"}return t},pubfn.calcSize=function(e=0,t,n,i=2,a="auto"){let r=0,o="";if((e=parseFloat(e))parseObjectKeys(e,t)))}return e}pubfn.snake2camel=function(e){return e.replace(isSnakeCase,(e,t)=>t?t.toUpperCase():"")},pubfn.camel2snake=function(e){return e.replace(isCamelCase,e=>"_"+e.toLowerCase())},pubfn.snake2camelJson=function(e){return parseObjectKeys(e,"snake2camel")},pubfn.camel2snakeJson=function(e){return parseObjectKeys(e,"camel2snake")},pubfn.string2Number=function(e,t={}){switch(Object.prototype.toString.call(e).slice(8,-1).toLowerCase()){case"string":if(e&&!isNaN(e)){let{mobile:n=!0,idCard:i=!0,startFrom0:a=!0,maxLength:r=14}=t;return e.length>r||(n&&pubfn.test(e,"mobile")||i&&pubfn.test(e,"card")||a&&e.length>1&&0===e.indexOf("0")&&1!==e.indexOf("."))?e:Number(e)}return e;case"object":const n=Object.keys(e);for(let t=0;t-1&&(t=e.substring(n+1)),t},pubfn.checkFileSuffix=function(e,t){let n=!1,i=pubfn.getFileSuffix(e);for(let e=0;e-1){n=!0;break}return n},pubfn.splitArray=function(e,t){let n=[];for(let i=0;i-1){var o=a.indexOf('"',r),s=a.substring(r,o);if(o>r){var u=a.indexOf("---",o),l=a.substring(o+1,u).trim();n[s]=l}}}return n},pubfn.getPlatform=function(e){return"web"===e?e="h5":"app"===e&&(e="app-plus"),e},pubfn.getClientUAByContext=function(e={}){return e.ua||e.CLIENTUA},pubfn.getPlatformForUniId=function(e={}){let t=e.PLATFORM;if(t=pubfn.getPlatform(t),"h5"===t){pubfn.getClientUAByContext(e).toLowerCase().indexOf("micromessenger")>-1&&(t="h5-weixin")}return t},pubfn.getUniCloudContext=function(){let e;try{e=uniCloud.context}catch(e){}return e},pubfn.getUniCloudFunctionName=function(){let e;try{let t=pubfn.getUniCloudContext();e=t.FUNCTION_NAME||t.function_name}catch(e){}return e},pubfn.getUniCloudProvider=function(){let e;try{e=uniCloud.context.SPACEINFO.provider}catch(e){}return e},pubfn.getUniCloudRequestId=function(){let e;try{e=pubfn.getUniCloudContext().requestId}catch(e){}return e},pubfn.getUniIdConfig=function(e={},t,n){const i=e.uni;let a;if(pubfn.isArray(i)){let e=uniCloud.env&&uniCloud.env.APPID?uniCloud.env.APPID:uniCloud.$context.APPID;a=pubfn.getListItem(i,"dcloudAppid",e),pubfn.isNull(a)&&(a=pubfn.getListItem(i,"isDefaultConfig",!0))}else a=i;if(pubfn.isNotNull(t)){let e=pubfn.getData(a,t);return pubfn.isNull(e)?n:e}return a},pubfn.batchRun=async function(e){let{main:t,data:n=[],concurrency:i=50}=e;if(pubfn.isArray(t))return pubfn.batchRun2(e);let a=n.length,r=[];if(0==a)return{stack:r,total:a};if(1===i){for(let e=0;e=a)break;let u=t(n[s],s);e.push(u)}try{await Promise.all(e).then(e=>{r=r.concat(e)})}catch(e){console.error(e)}}return{stack:r,total:a}}},pubfn.batchRun2=async function(e){let{main:t,concurrency:n=100}=e,i=t.length,a=[];if(0==i)return{stack:a,total:i};if(1===n){for(let e=0;e=i)break;let s=(0,t[o])();e.push(s)}try{await Promise.all(e).then(e=>{a=a.concat(e)})}catch(e){console.error(e)}}return{stack:a,total:i}}},pubfn.randomAsync=async function(e,t,n,i=500){let a;if("function"==typeof n){let r=0;do{r++,a=pubfn.randomFn(e,t)}while(!await n(a)&&r0?(new Date).getTime()+1e3*n:0};dataCache[e]=i},util$5.del=function(e){delete dataCache[e]},util$5.clear=function(e){if(e)for(let t in dataCache)0==t.indexOf(e)&&delete dataCache[t];else dataCache={}},util$5.isExpired=function(e){let t=!0,n=dataCache[e];return n&&(0==n.expired||n.expired>(new Date).getTime())&&(t=!1),t},util$5.getAll=function(e){let t={};if(e)for(let n in dataCache)0==n.indexOf(e)&&(t[e]=dataCache[e]);else t=dataCache;for(let e in t)util$5.isExpired(e)&&(delete t[e],delete dataCache[e]);return t};var temporaryCache=util$5,globalDataCache={},util$6={},globalDataDao={};globalDataCache.init=function(e){globalDataDao=(util$6=e).vk.system.globalDataDao},globalDataCache.get=async function(e,t=0,n,i=!0){return"function"==typeof n?globalDataCache.autoGet(e,t,n,i):globalDataCache._get(e)},globalDataCache.autoGet=async function(e,t=0,n,i=!0){let a,{vk:r}=util$6;try{a=await globalDataCache._get(e),r.pubfn.isNull(a)&&"function"==typeof n&&(a=await n(),void 0!==a&&i&&await r.globalDataCache.set(e,a,t))}catch(e){return}return a},globalDataCache._get=async function(e){let t;try{let n=await globalDataDao.find(e);if(n){let{value:i,expired_at:a}=n;globalDataCache.isExpired(n)?await globalDataCache.del(e):t=i}}catch(e){return}return t},globalDataCache.set=async function(e,t,n=0,i){let a;e&&void 0!==e.key&&void 0!==e.value?(a=e.key,t=e.value,n=e.second,i=e.comment):a=e;let r={code:0,msg:"ok"};try{if(!a)return{code:-1,msg:"key值不能为空"};let e=n>0?(new Date).getTime()+1e3*n:0;r=await globalDataDao.set({key:a,value:t,expired_at:e,comment:i})}catch(e){return console.error(e),{code:-1,msg:"异常"}}return r},globalDataCache.del=async function(e){await globalDataDao.del(e)},globalDataCache.clear=async function(e){if(e)return await globalDataDao.deleteByWhere({key:new RegExp("^"+e)})},globalDataCache.list=async function(e){return await globalDataDao.list(e)},globalDataCache.count=async function(e){return await globalDataDao.count(e)},globalDataCache.isExpired=function(e){let t=!0;return e&&(!e.expired_at||0==e.expired_at||e.expired_at>(new Date).getTime())&&(t=!1),t},globalDataCache.inc=async function(e,t=1,n=0){let i;e&&void 0!==e.key&&void 0!==e.value?(i=e.key,t=e.value,n=e.second):i=e;let a={code:0,msg:"ok"};try{if(!i)return{code:-1,msg:"key值不能为空"};let e=n>0?(new Date).getTime()+1e3*n:0;a=await globalDataDao.inc({key:i,value:t,expired_at:e})}catch(e){return{code:-1,msg:"异常",err:e}}return a},globalDataCache.uniqueAdd=async function(e,t=1,n=5){let{vk:i}=util$6,a={code:0,msg:"ok"};try{if(!e)return{code:-1,msg:"key值不能为空"};let r=n>0?(new Date).getTime()+1e3*n:0;await i.globalDataCache.deleteExpired(e);a.id=await globalDataDao.add({key:e,value:t,expired_at:r})}catch(e){return console.error(e),{code:-1,msg:"异常"}}return a},globalDataCache.deleteExpired=async function(e){await globalDataDao.deleteExpired(e)};var globalDataCache_1=globalDataCache,util$7={aes:{}};const aesKey="5fb2cd73c7b53918728417c50762e6d45fb2cd73c7b53918728417c50762e6d4",AESMODE={AES192:"aes192",AES256ECB:"aes-256-ecb"};util$7.aes.MODE=AESMODE,util$7.aes.encrypt=function(e){let{data:t,key:n,mode:i=AESMODE.AES192}=e,a=uniCloud.vk,{crypto:r,config:o}=a.getUnicloud();if(n||(n=a.pubfn.getData(o.vk,"crypto.aes",aesKey)),"object"==typeof t&&(t=JSON.stringify(t)),i===AESMODE.AES256ECB)return encryptUseAes256Ecb(t,n);if(i===AESMODE.AES192)return encryptUseAes192(t,n);throw new Error(`msg:不支持 ${i} 加密算法`)},util$7.aes.decrypt=function(e){let{data:t,key:n,mode:i=AESMODE.AES192}=e,a=uniCloud.vk,{crypto:r,config:o}=a.getUnicloud();if(a.pubfn.isNull(t))throw new Error("msg:待解密原文不能为空");if(n||(n=a.pubfn.getData(o.vk,"crypto.aes",aesKey)),i===AESMODE.AES256ECB)return decryptUseAes256Ecb(t,n);if(i===AESMODE.AES192)return decryptUseAes192(t,n);throw new Error(`msg:不支持 ${i} 加密算法`)};var crypto=util$7;function encryptUseAes192(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud();const a=i.createCipher(AESMODE.AES192,t);let r=a.update(e,"utf8","hex");return r+=a.final("hex"),r}function decryptUseAes192(e,t){let n,i=uniCloud.vk,{crypto:a}=i.getUnicloud();try{const i=a.createDecipher(AESMODE.AES192,t);n=i.update(e,"hex","utf8"),n+=i.final("utf8");try{n=JSON.parse(n)}catch(e){}}catch(e){throw"msg:解密失败"}return n}function encryptUseAes256Ecb(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud(),a=Buffer.from(e),r=t;r.length>32&&(r=r.substring(0,32)),r=Buffer.from(r);const o=i.createCipheriv(AESMODE.AES256ECB,r,"");o.setAutoPadding(!1);const s=16-a.length%16,u=Buffer.alloc(s,s);a=Buffer.concat([a,u]);let l=o.update(a,null,"base64");return l+=o.final("base64"),l}function decryptUseAes256Ecb(e,t){let n=uniCloud.vk,{crypto:i}=n.getUnicloud(),a=t;a.length>32&&(a=a.substring(0,32)),a=Buffer.from(a);try{const t=i.createDecipheriv(AESMODE.AES256ECB,a,"");t.setAutoPadding(!1);let n=t.update(e,"base64");n+=t.final();const r=n.charCodeAt(n.length-1);n=n.slice(0,n.length-r);try{n=JSON.parse(n)}catch(e){}return n}catch(e){throw"解密失败"}}var alipay={},ALIPAY_ALGORITHM_MAPPING={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};alipay.sign=function(e,t,n){let i=JSON.parse(JSON.stringify(t)),a=Object.assign({method:e,app_id:n.appid,charset:n.charset||"utf-8",version:n.version||"1.0",sign_type:n.signType||"RSA2"},i);n.appCertSn&&n.alipayRootCertSn&&(a=Object.assign({app_cert_sn:n.appCertSn,alipay_root_cert_sn:n.alipayRootCertSn},a));const r=i.bizContent||i.biz_content;r&&(a.biz_content=JSON.stringify(r));const o=alipay.sortObj(a);let s=alipay.objectToUrl(o);const u="PKCS8"===(n.keyType||"PKCS8")?"PRIVATE KEY":"RSA PRIVATE KEY";let l=alipay.formatKey(n.privateKey,u);const c=crypto$1.createSign(ALIPAY_ALGORITHM_MAPPING[a.sign_type]).update(s,"utf8").sign(l,"base64");return Object.assign(o,{sign:c})},alipay.formatUrl=function(e,t="https://openapi.alipay.com/gateway.do"){let n=t;const i=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token","ws_service_url"];for(const t in e)if(i.indexOf(t)>-1){const i=encodeURIComponent(e[t]);n=`${n}${n.includes("?")?"&":"?"}${t}=${i}`,delete e[t]}return{execParams:e,url:n}},alipay.sortObj=function(e){new Array;let t=Object.keys(e).sort(),n={};for(let i in t)n[t[i]]=e[t[i]];return n},alipay.objectToUrl=function(e){let t="";for(let n in e)e[n]&&(t+=`&${n}=${e[n]}`);return t&&(t=t.substring(1)),t},alipay.formatKey=function(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`},alipay.getRequestRes=function(e,t){return e[t.replace(new RegExp("\\.","g"),"_")+"_response"]||e.error_response};var util$8=alipay,alipay$1={},util$9={};const serviceUrl="https://openapi.alipay.com/gateway.do",configKey="mp-alipay.oauth.alipay";function returnRes(e){return e.code=e.sub_code||e.code||0,e.msg=e.sub_msg||e.msg||"",e}alipay$1.init=function(e){util$9=e},alipay$1.getConfig=function(){let{vk:e,config:t}=util$9;return e.pubfn.getUniIdConfig(t)},alipay$1.request=async function(e={}){let{vk:t}=util$9,{method:n,data:i={},successText:a}=e,r=alipay$1.auth.getAppidInfo(e),o=Date.now(),s={timestamp:t.pubfn.timeFormat(o,"yyyy-MM-dd hh:mm:ss"),...i};const u=util$8.sign(n,s,r),{url:l,execParams:c}=util$8.formatUrl(u,serviceUrl);let d=await t.request({url:l,method:"POST",data:c}),p=await util$8.getRequestRes(d,n);return p.code&&"10000"!==p.code||(p.code=0,p.msg=a),p=returnRes(p),p},alipay$1.auth={},alipay$1.auth.getAppidInfo=function(e={}){let{appid:t,privateKey:n}=e,{vk:i,config:a}=util$9;const r=alipay$1.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.alipay.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.privateKey,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 privateKey 请先在 uni-config-center/vk-unicloud/index.js 中配置支付宝小程序(vk.oauth.alipay.list)的appid和privateKey`)}}else{let e=i.pubfn.getData(r,configKey)||{};if(t=e.appid,n=e.privateKey,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error(`请先在 uni-config-center/uni-id/config.json 中配置支付宝小程序(${configKey})的appid和privateKey`)}return{appid:t,privateKey:n}},alipay$1.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$9,{platform:i,needKey:a=!1}=e;i||(i="mp-alipay");let r=await alipay$1.auth.code2SessionMp(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.privateKey,r.platform=i,r.openid=r.userId,r},alipay$1.auth.code2SessionMp=async function(e={}){let{appid:t}=alipay$1.auth.getAppidInfo(e),n=e.code||e.js_code,{vk:i}=util$9,a=await alipay$1.request({method:"alipay.system.oauth.token",data:{code:n,grant_type:"authorization_code"}});return{...i.pubfn.snake2camelJson(a),appid:t,code:0,msg:"ok"}},alipay$1.security={},alipay$1.security.msgSecCheck=async function(e={}){return{code:-1,msg:"支付宝未提供此API"}},alipay$1.security.imgSecCheck=async function(e={}){return{code:-1,msg:"支付宝未提供此API"}},alipay$1.acode={},alipay$1.acode.getMiniCode=async function(e={}){let{page:t,scene:n="miniCode=1",line_color:i}=e,a={url_param:t,query_param:n,describe:"推广",color:i};return await alipay$1.request({method:"alipay.open.app.qrcode.create",data:{biz_content:a},successText:"生成成功"})},alipay$1.subscribeMessage={},alipay$1.subscribeMessage.send=async function(e={}){let{touser:t,form_id:n,template_id:i,page:a,data:r}=e,{appid:o}=alipay$1.auth.getAppidInfo(e),s={to_user_id:t,form_id:n,user_template_id:i,page:a,data:r};return await alipay$1.request({method:"alipay.open.app.mini.templatemessage.send",data:{biz_content:s},successText:"发送成功"})};var alipay_1=alipay$1,baidu={},util$a={};baidu.init=function(e){util$a=e},baidu.open={},baidu.open.auth={},baidu.open.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$a;if(!t){let e=i.pubfn.getData(a,"vk.service.openapi.baidu")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw new Error("请在uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js中配置并检查百度开放平台的appid和appsecret是否正确,参数路径:vk.service.openapi.baidu");return{appid:t,appsecret:n}},baidu.open.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=baidu.open.auth.getAppidInfo(e),{vk:i,config:a}=util$a,r=await i.request({url:`https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${t}&client_secret=${n}`,method:"GET"});return r.error_code?(console.error("getAccessToken失败:",r),{code:r.error_code,msg:r.error_msg,err:r}):{...r,code:0,msg:"ok"}},baidu.open.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=baidu.open.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$a,o="openapi-baidu-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await baidu.open.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,n.expires_in-3600),await r.globalDataCache.deleteExpired())}return t},baidu.open.ocr={},baidu.open.ocr.business_license=async function(e={}){let{image:t,url:n}=e;return await baidu.open.request({...e,action:"ocr/v1/business_license",actionVersion:"2.0",data:{image:t,url:n}})},baidu.open.ocr.idcard=async function(e={}){let{image:t,url:n,id_card_side:i,detect_risk:a,detect_photo:r}=e;return await baidu.open.request({...e,action:"ocr/v1/idcard",actionVersion:"2.0",data:{image:t,url:n,id_card_side:i,detect_risk:a,detect_photo:r}})},baidu.open.request=async function(e={}){let{vk:t}=util$a,n=await baidu.open.auth.getAccessToken(e);if(!n)return{code:-1,msg:"获取access_token失败,请检查vk-unicloud配置下vk.service.openapi.baidu配置的appid和appsecret是否正确"};let{action:i,actionVersion:a="2.0",header:r={"content-type":"application/x-www-form-urlencoded"},data:o}=e,s=await t.request({url:`https://aip.baidubce.com/rest/${a}/${i}?access_token=${n}`,method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},data:o});return s.error_code?{code:s.error_code,msg:s.error_msg,err:s}:{...s,code:0,msg:"ok"}};var baidu_1=baidu,douyin={},util$b={};const serviceUrl$1="https://developer.toutiao.com",configKey$1="mp-toutiao.oauth.toutiao";function returnRes$1(e){return e.code=e.err_no||0,e.msg=e.err_tips||"",e}douyin.init=function(e){util$b=e},douyin.getConfig=function(){let{vk:e,config:t}=util$b;return e.pubfn.getUniIdConfig(t)},douyin.request=async function(e={}){let{vk:t}=util$b,{url:n,data:i={}}=e,{appid:a,appsecret:r}=douyin.auth.getAppidInfo(e);if(!0===i.access_token){let t=await douyin.auth.getAccessToken(e);if(!t)return{code:-1,msg:`获取access_token失败,请检查uni-id配置${configKey$1}配置下的appid和appsecret是否正确`};i.access_token=t}-1===n.indexOf("http")&&(n=`${serviceUrl$1}/${n}`);let o=await t.request({contentType:"json",dataType:"json",...e,url:n});return o=returnRes$1(o),o},douyin.auth={},douyin.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$b;const r=douyin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.toutiao.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置抖音小程序(vk.oauth.toutiao.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,configKey$1)||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error(`请先在 uni-config-center/uni-id/config.json 中配置抖音小程序(${configKey$1})的appid和appsecret`)}return{appid:t,appsecret:n}},douyin.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=douyin.auth.getAppidInfo(e),{vk:i,config:a}=util$b,r=await i.request({url:serviceUrl$1+"/api/apps/v2/token",method:"POST",data:{appid:t,secret:n,grant_type:"client_credential"},contentType:"json",dataType:"json"});return r.err_no?(console.error("getAccessToken失败:",r),{code:r.err_no,msg:r.err_tips,err:r}):{code:0,msg:"ok",access_token:r.data.access_token,expires_in:r.data.expires_in}},douyin.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=douyin.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$b,o="mp-toutiao-access_token-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await douyin.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},douyin.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$b,{platform:i,needKey:a=!1}=e;i||(i="mp-toutiao");let r=await douyin.auth.code2SessionMp(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.appsecret,r.platform=i,r},douyin.auth.code2SessionMp=async function(e={}){let{appid:t,appsecret:n}=douyin.auth.getAppidInfo(e),i=e.code||e.js_code,a=e.anonymousCode,{vk:r}=util$b,o=await douyin.request({url:"api/apps/v2/jscode2session",method:"POST",data:{appid:t,secret:n,code:i,anonymous_code:a}});return o.code?(40018!==o.code&&40019!==o.code||(o.msg="无效code,请重新获取"),o):{...r.pubfn.snake2camelJson(o.data),appid:t,appsecret:n,code:0,msg:"ok"}},douyin.security={},douyin.security.msgSecCheck=async function(e={}){let{content:t,tasks:n}=e,{appid:i,appsecret:a}=douyin.auth.getAppidInfo(e),r=await douyin.auth.getAccessToken(e);if(!r)return{code:-1,msg:`获取access_token失败,请检查uni-id配置${configKey$1}配置下的appid和appsecret是否正确`};n||(n=[{content:t}]);let o=await douyin.request({url:"api/v2/tags/text/antidirt",method:"POST",header:{"X-Token":r},data:{tasks:n}});try{let e,t;o.data.map((n,i)=>{n.predicts.map((n,a)=>{n.hit&&(e||(e=!0,t=i))})}),e?(o.taskIndex=t,o.code=87014):o.code=0}catch(e){}return 40001===o.code&&(o.msg="access_token错误"),87014===o.code&&(o.msg="内容含有违法违规内容,请检查!"),0===o.code&&(o.msg="ok"),o},douyin.security.imgSecCheck=async function(e={}){let{image:t,access_token:n=!0}=e,i=e.base64||e.image_data,{appid:a,appsecret:r}=douyin.auth.getAppidInfo(e);if(i){let e=i.indexOf("base64,");e>-1&&(i=i.substring(e+"base64,".length))}let o=await douyin.request({url:"api/apps/censor/image",method:"POST",data:{app_id:a,access_token:n,image:t,image_data:i}});try{let e;o.predicts.map((t,n)=>{t.hit&&(e=!0)}),o.code=e?87014:0}catch(e){}return 87014===o.code&&(o.msg="内容含有违法违规内容,请检查!"),0===o.code&&(o.msg="ok"),o},douyin.acode={},douyin.acode.getMiniCode=async function(e={}){let{path:t,appname:n="douyin",width:i,line_color:a,background:r,set_icon:o,access_token:s=!0}=e,{appid:u,appsecret:l}=douyin.auth.getAppidInfo(e),c=await douyin.request({url:"api/apps/qrcode",method:"POST",data:{access_token:s,appname:n,path:t,width:i,line_color:a,background:r,set_icon:o},dataType:"default",useContent:!0,header:{"content-type":"application/json;charset=utf8"}});if(c.length<500){let e=c.toString();try{return e=JSON.parse(e),{code:e.errcode,msg:e.errmsg}}catch(e){}return{code:-1,err:err}}return c},douyin.subscribeMessage={},douyin.subscribeMessage.send=async function(e={}){let{touser:t,template_id:n,page:i,data:a,access_token:r=!0}=e,{appid:o,appsecret:s}=douyin.auth.getAppidInfo(e);return await douyin.request({url:"api/apps/subscribe_notification/developer/v1/notify",method:"POST",data:{access_token:r,app_id:o,tpl_id:n,open_id:t,data:a,page:i}})};var douyin_1=douyin,qq={},util$c={};const serviceUrl$2="https://api.q.qq.com",configKey$2="mp-qq.oauth.qq";function returnRes$2(e){return e.code=e.errcode||e.errCode||0,e.msg=e.errmsg||e.errMsg||"",e}qq.init=function(e){util$c=e},qq.getConfig=function(){let{vk:e,config:t}=util$c;return e.pubfn.getUniIdConfig(t)},qq.request=async function(e={}){let{vk:t}=util$c,{url:n,method:i,data:a={}}=e;if(-1===n.indexOf("http")&&(n=`${serviceUrl$2}/${n}`),!0===a.access_token){delete a.access_token;let t=await qq.auth.getAccessToken(e);if(!t)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+t}let r=await t.request({...e,url:n});return r=returnRes$2(r),r},qq.auth={},qq.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$c;const r=qq.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.qq.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置QQ小程序(vk.oauth.qq.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,configKey$2)||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置QQ小程序(mp-qq.oauth.qq)的appid和appsecret")}return{appid:t,appsecret:n}},qq.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=qq.auth.getAppidInfo(e),{vk:i,config:a}=util$c,r=await i.request({url:`https://api.q.qq.com/api/getToken?grant_type=client_credential&appid=${t}&secret=${n}`,method:"GET"});return r.errcode?(console.error("getAccessToken失败:",r),{code:r.errcode,msg:r.errmsg,err:r}):{code:0,msg:"ok",access_token:r.access_token,expires_in:r.expires_in}},qq.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=qq.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$c,o="mp-qq-access_token-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await qq.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},qq.auth.code2Session=async function(e={}){let{vk:t,uniID:n}=util$c,{platform:i,needKey:a=!1}=e;i||(i="mp-qq");let r=await qq.auth.code2SessionMpWeixin(e);try{let e=t.crypto.aes.encrypt({data:r});r.encryptedKey=e}catch(e){}return a||(delete r.sessionKey,delete r.accessToken,delete r.refreshToken),delete r.appsecret,r.platform=i,r},qq.auth.code2SessionMpWeixin=async function(e={}){let{appid:t,appsecret:n}=qq.auth.getAppidInfo(e),i=e.code||e.js_code,{vk:a}=util$c,r=await qq.request({url:`sns/jscode2session?appid=${t}&secret=${n}&js_code=${i}&grant_type=authorization_code`,method:"GET"});return r.code?(-101600007===r.code&&(r.msg="appid错误"),-101222100===r.code&&(r.msg="appsecret错误"),-2100===r.code&&(r.msg="无效code,请重新获取"),r):(r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"})},qq.security={},qq.security.msgSecCheck=async function(e={}){let{content:t,access_token:n=!0}=e,{appid:i,appsecret:a}=qq.auth.getAppidInfo(e),r=await qq.request({url:"api/json/security/MsgSecCheck",method:"POST",data:{access_token:n,appid:i,content:t}});return 40001===r.code&&(r.msg="access_token错误"),87014===r.code&&(r.msg="内容含有违法违规内容,请检查!"),r},qq.security.imgSecCheck=async function(e={}){let{vk:t}=util$c,{dataBuffer:n,formData:i,base64:a}=e,{appid:r,appsecret:o}=qq.auth.getAppidInfo(e),s=await qq.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};if(a&&!n){let e="base64,",t=a.indexOf(e);t>-1&&(a=a.substring(t+e.length)),n=new Buffer(a,"base64")}n&&!i&&(i=new t.formDataUtil.FormData,i.append("appid",r),i.append("media",n,{filename:Date.now()+".png",contentType:"image/png"}));let u=await qq.request({url:"api/json/security/ImgSecCheck?access_token="+s,content:i.getBuffer(),headers:i.getHeaders()});switch(u.code){case 40001:u.msg="access_token错误";break;case 87014:u.msg="图片内容含有违法违规内容,请检查!";break;case 40006:u.msg="图片大小不能超过1M"}return u},qq.acode={},qq.acode.getMiniCode=async function(e={}){let{path:t,access_token:n=!0}=e,{appid:i,appsecret:a}=qq.auth.getAppidInfo(e),r=await qq.request({url:"api/json/qqa/CreateMiniCode",method:"POST",data:{access_token:n,appid:i,path:t},dataType:"default",useContent:!0,header:{"content-type":"application/json;charset=utf8"}});if(r.length<500){let e=r.toString();try{e=JSON.parse(e)}catch(e){}return r=returnRes$2(e),40001===r.code&&(r.msg="access_token错误"),41030===r.code&&(r.msg="小程序页面不存在!"),r}return r},qq.subscribeMessage={},qq.subscribeMessage.send=async function(e={}){let{vk:t}=util$c,{touser:n,template_id:i,page:a,data:r,emphasis_keyword:o,oac_appid:s,use_robot:u}=e,l=await qq.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-qq配置的appid和appsecret是否正确"};let c=await t.request({url:`${serviceUrl$2}/api/json/subscribe/SendSubscriptionMessage?access_token=${l}`,method:"POST",data:{touser:n,template_id:i,page:a,data:r,emphasis_keyword:o,oac_appid:s,use_robot:u},useContent:!0,header:{"content-type":"application/json;charset=utf8"}});switch(c=returnRes$2(c),c.code){case 40003:c.msg="touser字段openid为空或者不正确";break;case 40037:c.msg="订阅模板id为空不正确";break;case 43101:c.msg="用户未订阅该消息";break;case 40036:c.msg="您的小程序不支持发送长期订阅消息";break;case 47003:c.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:c.msg="page路径不正确,需要保证在现网版本小程序中存在"}return c};var qq_1=qq,weixin={},util$d={};function returnRes$3(e){return e.code=e.errcode||0,e.msg=e.errmsg||"",e}weixin.init=function(e){util$d=e},weixin.getConfig=function(){let{vk:e,config:t}=util$d;return e.pubfn.getUniIdConfig(t)},weixin.request=async function(e={}){let{vk:t}=util$d,{url:n,method:i,data:a,access_token:r}=e;if(r||(r=await weixin.auth.getAccessToken(e)),!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};-1===n.indexOf("http")&&(n="https://api.weixin.qq.com/"+n),i||(i=t.pubfn.isNull(a)?"GET":"POST"),i&&"POST"===i.toUpperCase()&&void 0===e.useContent&&(e.useContent=!0),n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+r;let o=await t.request({...e,url:n});return o=returnRes$3(o),o},weixin.decrypt={},weixin.decrypt.getPhoneNumber=async function(e={}){let{vk:t}=util$d,{code:n}=e;if(!n&&e.encryptedData)return await weixin.decrypt.getPhoneNumberByEncryptedData(e);let i={code:0,msg:"ok"},a=t.pubfn.isNullOneByObject({code:n});if(a)return{code:-1,msg:a+"不能为空"};let r=await t.openapi.weixin.request({method:"POST",url:"wxa/business/getuserphonenumber",data:{code:n}});return 0!==r.code?r:(i.data=r.phone_info,i.phone=i.data.phoneNumber,i.mobile=i.data.phoneNumber,i)},weixin.decrypt.getPhoneNumberByEncryptedData=async function(e={}){let t,{vk:n}=util$d,{encryptedData:i,iv:a,sessionKey:r,encryptedKey:o,code:s}=e,u={code:0,msg:"ok"},l=n.pubfn.isNullOneByObject({encryptedData:i,iv:a});if(l)return{code:-1,msg:l+"不能为空"};if(o){let e=n.crypto.aes.decrypt({data:o});t=e.appid,r=e.sessionKey}else{t=weixin.auth.getAppidInfo(e).appid}return u.data=weixin.decrypt.decryptData({appid:t,encryptedData:i,iv:a,sessionKey:r}),u.phone=u.data.phoneNumber,u.mobile=u.data.phoneNumber,u},weixin.decrypt.decryptData=function(e={}){let t,{appid:n,encryptedData:i,iv:a,sessionKey:r}=e,{vk:o,crypto:s}=util$d,u=new Buffer(r,"base64"),l=new Buffer(i,"base64"),c=new Buffer(a,"base64");try{let e=s.createDecipheriv("aes-128-cbc",u,c);e.setAutoPadding(!0),t=e.update(l,"binary","utf8"),t+=e.final("utf8"),t=JSON.parse(t)}catch(e){throw new Error(e)}return t.watermark.appid!==n?{code:-1,msg:"appid不一致"}:t},weixin.auth={},weixin.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};if(t=r.appid,n=r.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",e),new Error(`你使用了多小程序登录模式,但未找到${t}对应的 appsecret 请先在 uni-config-center/vk-unicloud/index.js 中配置微信小程序(vk.oauth.weixin.list)的appid和appsecret`)}}else{let e=i.pubfn.getData(r,"mp-weixin.oauth.weixin")||{};if(t=e.appid,n=e.appsecret,i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置微信小程序(mp-weixin)的appid和appsecret")}return{appid:t,appsecret:n}},weixin.auth.getAccessTokenFn=async function(e={}){let{appid:t,appsecret:n}=weixin.auth.getAppidInfo(e),{vk:i,config:a}=util$d,r=await i.request({url:`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${t}&secret=${n}`,method:"GET"});return r.errcode?(console.error("getAccessToken失败:",r),{code:r.errcode,msg:r.errmsg,err:r}):{code:0,msg:"ok",access_token:r.access_token,expires_in:r.expires_in}},weixin.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=weixin.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$d,o="mp-weixin-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await weixin.auth.getAccessTokenFn(e);0===n.code&&(t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired())}return t},weixin.auth.code2Session=async function(e={}){let t,{vk:n,uniID:i}=util$d,{platform:a,context:r,needKey:o=!1}=e;a||(a=n.pubfn.getPlatformForUniId(r)||"mp-weixin"),t="mp-weixin"===a?await weixin.auth.code2SessionMpWeixin(e):"h5-weixin"===a?await weixin.h5.auth.code2Session(e):await i.code2SessionWeixin(e);try{let e=n.crypto.aes.encrypt({data:t});t.encryptedKey=e}catch(e){}return o||(delete t.sessionKey,delete t.accessToken,delete t.refreshToken),delete t.appsecret,t.platform=a,t},weixin.auth.code2SessionMpWeixin=async function(e={}){let{appid:t,appsecret:n}=weixin.auth.getAppidInfo(e),i=e.code||e.js_code,{vk:a}=util$d,r=await a.request({url:`https://api.weixin.qq.com/sns/jscode2session?appid=${t}&secret=${n}&js_code=${i}&grant_type=authorization_code`,method:"GET"});if(r.errcode){let e=r.errmsg;return 40163===r.errcode&&(e="该code已被使用,请重新获取"),40029===r.errcode&&(e="无效code,请重新获取"),{...r,code:r.errcode,msg:e}}return r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"}},weixin.wxacode={},weixin.wxacode.getUnlimited=async function(e={}){let{vk:t}=util$d,{access_token:n,page:i,scene:a,check_path:r,env_version:o,width:s,auto_color:u,line_color:l,is_hyaline:c}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+n,method:"POST",data:{page:i,scene:a,check_path:r,env_version:o,width:s,auto_color:u,line_color:l,is_hyaline:c},dataType:"default",useContent:!0,headers:{encoding:null}});if(d.length<500){let e=d.toString();try{e=JSON.parse(e)}catch(e){}return d=returnRes$3(e),40001===d.code&&(d.msg="access_token错误"),41030===d.code&&(d.msg="小程序页面不存在!"),d}return Buffer.isBuffer(d)?d:returnRes$3(d)},weixin.urlscheme={},weixin.urlscheme.generate=async function(e={}){let{vk:t}=util$d,{access_token:n,jump_wxa:i,is_expire:a,expire_time:r,expire_type:o,expire_interval:s}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/wxa/generatescheme?access_token="+n,method:"POST",data:{jump_wxa:i,is_expire:a,expire_time:r,expire_type:o,expire_interval:s},useContent:!0});return u=returnRes$3(u),40001===u.code&&(u.msg="access_token错误"),40165===u.code&&(u.msg="小程序页面不存在!"),u},weixin.urllink={},weixin.urllink.generate=async function(e={}){let{vk:t}=util$d,{access_token:n,path:i,query:a,is_expire:r,expire_type:o,expire_time:s,expire_interval:u,cloud_base:l,env_version:c}=e;if(n||(n=await weixin.auth.getAccessToken(e)),!n)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/generate_urllink?access_token="+n,method:"POST",data:{path:i,query:a,is_expire:r,expire_type:o,expire_time:s,expire_interval:u,cloud_base:l,env_version:c},useContent:!0});return d=returnRes$3(d),40001===d.code&&(d.msg="access_token错误"),40165===d.code&&(d.msg="小程序页面不存在!"),d},weixin.security={},weixin.security.msgSecCheck=async function(e={}){let{vk:t}=util$d,{content:n,version:i,scene:a,openid:r,title:o,nickname:s,signature:u}=e,l=await weixin.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let c=await t.request({url:"https://api.weixin.qq.com/wxa/msg_sec_check?access_token="+l,method:"POST",data:{content:n,version:i,scene:a,openid:r,title:o,nickname:s,signature:u},useContent:!0});return c=returnRes$3(c),40001===c.code&&(c.msg="access_token错误"),87014===c.code&&(c.msg="内容含有违法违规内容,请检查!"),2===i&&c.result&&100!==c.result.label&&(c.code=c.result.label,c.msg="内容含有违法违规内容,请检查!"),c},weixin.security.imgSecCheck=async function(e={}){let{vk:t}=util$d,{dataBuffer:n,formData:i,base64:a}=e,r=await weixin.auth.getAccessToken(e);if(!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(a&&!n){let e="base64,",t=a.indexOf(e);t>-1&&(a=a.substring(t+e.length)),n=new Buffer(a,"base64")}n&&!i&&(i=new t.formDataUtil.FormData,i.append("media",n,{filename:Date.now()+".png",contentType:"image/png"}));let o=await t.request({url:"https://api.weixin.qq.com/wxa/img_sec_check?access_token="+r,content:i.getBuffer(),headers:i.getHeaders()});switch(o=returnRes$3(o),o.code){case 40001:o.msg="access_token错误";break;case 87014:o.msg="图片内容含有违法违规内容,请检查!";break;case 40006:o.msg="图片大小不能超过1M"}return o},weixin.riskControl={},weixin.riskControl.getUserRiskRank=async function(e={}){let{vk:t}=util$d,{appid:n,openid:i,scene:a,mobile_no:r,client_ip:o,email_address:s,extended_info:u,is_test:l}=e,c=await weixin.auth.getAccessToken(e);if(!c)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let d=await t.request({url:"https://api.weixin.qq.com/wxa/getuserriskrank?access_token="+c,method:"POST",data:{appid:n,openid:i,scene:a,mobile_no:r,client_ip:o,email_address:s,extended_info:u,is_test:l},useContent:!0});return d=returnRes$3(d),40001===d.code&&(d.msg="access_token错误"),d},weixin.subscribeMessage={},weixin.subscribeMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,page:a,data:r,miniprogram_state:o="formal",lang:s="zh_CN"}=e,u=await weixin.auth.getAccessToken(e);if(!u)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};let l=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+u,method:"POST",data:{touser:n,template_id:i,page:a,data:r,miniprogram_state:o,lang:s},useContent:!0});switch(l=returnRes$3(l),l.code){case 40003:l.msg="touser字段openid为空或者不正确";break;case 40037:l.msg="订阅模板id为空不正确";break;case 43101:l.msg="用户未订阅该消息";break;case 47003:l.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:l.msg="page路径不正确,需要保证在现网版本小程序中存在"}return l},weixin.uniformMessage={},weixin.uniformMessage.send=async function(e={}){let{vk:t}=util$d,{appid:n,touser:i,template_appid:a,template_id:r,url:o,miniprogram:s,data:u}=e,l=await weixin.auth.getAccessToken(e);if(!l)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(!a){a=weixin.h5.auth.getAppidInfo({appid:a}).appid}let c=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token="+l,method:"POST",data:{touser:i,mp_template_msg:{appid:a,template_id:r,url:o,miniprogram:s,data:u}},useContent:!0});switch(c=returnRes$3(c),c.code){case 40003:c.msg="touser字段openid为空或者不正确";break;case 40037:c.msg="订阅模板id为空不正确";break;case 43101:c.msg="用户未订阅该消息";break;case 47003:c.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:c.msg="page路径不正确,需要保证在现网版本小程序中存在"}return c},weixin.livebroadcast={},weixin.livebroadcast.getLiveInfo=async function(e={}){let{vk:t}=util$d,{pageIndex:n=1,pageSize:i=100}=e,a=await weixin.auth.getAccessToken(e);if(!a)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的mp-weixin配置的appid和appsecret是否正确"};if(n<=0)return{code:-1,msg:"pageIndex必须是大于0的整数"};let r=(n-1)*i,o=i,s=await t.request({url:"https://api.weixin.qq.com/wxa/business/getliveinfo?access_token="+a,method:"POST",data:{start:r,limit:o},useContent:!0});switch(s=returnRes$3(s),s.code){case 941e4:s.msg="直播间列表为空"}return s},weixin.app={},weixin.app.auth={},weixin.app.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};t=r.appid,n=r.appsecret}}else{let e=i.pubfn.getData(r,"app-plus.oauth.weixin")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先在 uni-config-center/uni-id/config.json 中配置微信app登录(app-plus)的appid和appsecret");return{appid:t,appsecret:n}},weixin.app.auth.getAccessToken=async function(e={}){let{appid:t,appsecret:n}=weixin.app.auth.getAppidInfo(e),{vk:i,config:a}=util$d,{code:r}=e,o=await i.request({url:`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${t}&secret=${n}&code=${r}&grant_type=authorization_code`,method:"GET"});return o.errcode?(console.error("getAccessToken失败:",o),{code:o.errcode,msg:o.errmsg,err:o}):{...o,code:0,msg:"ok"}},weixin.app.auth.getUserInfo=async function(e={}){let{vk:t,config:n}=util$d,{access_token:i,openid:a,lang:r="zh-CN"}=e;if(!i)return{code:-1,msg:"access_token不能为空"};let o=await t.request({url:`https://api.weixin.qq.com/sns/userinfo?access_token=${i}&openid=${a}$lang=${r}`,method:"GET"});return o.errcode?(console.error("getUserInfo失败:",o),{code:o.errcode,msg:o.errmsg,err:o}):{...o,code:0,msg:"ok",avatar:o.headimgurl,gender:o.sex}},weixin.h5={},weixin.h5.request=async function(e={}){let{vk:t}=util$d,{url:n,method:i,data:a,access_token:r}=e;if(r||(r=await weixin.h5.auth.getAccessToken(e)),!r)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};-1===n.indexOf("http")&&(n="https://api.weixin.qq.com/"+n),i||(i=t.pubfn.isNull(a)?"GET":"POST"),i&&"POST"===i.toUpperCase()&&void 0===e.useContent&&(e.useContent=!0),n+=-1===n.indexOf("?")?"?":"&",n+="access_token="+r;let o=await t.request({...e,url:n});return o=returnRes$3(o),o},weixin.h5.auth={},weixin.h5.auth.getAppidInfo=function(e={}){let{appid:t,appsecret:n}=e,{vk:i,config:a}=util$d;const r=weixin.getConfig();if(t){if(!n){let e=i.pubfn.getData(a,"vk.oauth.weixin.list")||[],r=i.pubfn.getListItem(e,"appid",t)||{};t=r.appid,n=r.appsecret}}else{let e=i.pubfn.getData(r,"h5-weixin.oauth.weixin")||{};t=e.appid,n=e.appsecret}if(i.pubfn.isNullOne(t,n))throw console.log("config",r),new Error("请先配置微信公众号appid和appsecret");return{appid:t,appsecret:n}},weixin.h5.auth.code2Session=async function(e={}){let{appid:t,appsecret:n}=weixin.h5.auth.getAppidInfo(e),{code:i}=e,{vk:a}=util$d,r=await a.request({url:`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${t}&secret=${n}&code=${i}&grant_type=authorization_code`,method:"GET"});if(r.errcode){let e=r.errmsg;return 40163===r.errcode&&(e="该code已被使用,请重新获取"),40029===r.errcode&&(e="无效code,请重新获取"),{...r,code:r.errcode,msg:e}}return r=a.pubfn.snake2camelJson(r),{appid:t,appsecret:n,...r,code:0,msg:"ok"}},weixin.h5.auth.getAccessToken=async function(e={}){let t,{appid:n,appsecret:i}=weixin.h5.auth.getAppidInfo(e),{cache:a=!0}=e,{vk:r}=util$d,o="h5-weixin-"+n;if(a&&(t=await r.globalDataCache.get(o)),r.pubfn.isNull(t)){let n=await weixin.h5.auth.getAccessTokenFn(e);if(0===n.code)t=n.access_token,await r.globalDataCache.set(o,t,240),await r.globalDataCache.deleteExpired();else if(console.log("获取微信公众号access_token失败:",n),40164===n.code)throw{code:n.code,msg:"请将固定IP全部加入微信公众号IP白名单,详见搜索文档:固定ip",err:n}}return t},weixin.h5.auth.getAccessTokenFn=async function(e={}){let t,{appid:n,appsecret:i}=weixin.h5.auth.getAppidInfo(e),{vk:a,config:r}=util$d;if("aliyun"===a.pubfn.getUniCloudProvider()){let e=await uniCloud.httpProxyForEip.get("https://api.weixin.qq.com/cgi-bin/token",{grant_type:"client_credential",appid:n,secret:i});if("string"==typeof e)try{e=JSON.parse(e)}catch(e){t={errcode:-1,errmsg:"异常"+e.message}}t="object"==typeof e?e.body:{errcode:-1,errmsg:"异常:getRes未获取到值"}}else t=await a.request({url:`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${n}&secret=${i}`,method:"GET"});return t.errcode?(console.error("getAccessToken失败:",t),{code:t.errcode,msg:t.errmsg,err:t}):{code:0,msg:"ok",access_token:t.access_token,expires_in:t.expires_in}},weixin.h5.subscribeMessage={},weixin.h5.subscribeMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,page:a,data:r,miniprogram:o}=e,s=await weixin.h5.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token="+s,method:"POST",data:{touser:n,template_id:i,page:a,data:r,miniprogram:o},useContent:!0});switch(u=returnRes$3(u),u.code){case 40003:u.msg="touser字段openid为空或者不正确";break;case 40037:u.msg="订阅模板id为空不正确";break;case 43101:u.msg="用户未订阅该消息";break;case 47003:u.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:u.msg="page路径不正确,需要保证在现网版本小程序中存在"}return u},weixin.h5.templateMessage={},weixin.h5.templateMessage.send=async function(e={}){let{vk:t}=util$d,{touser:n,template_id:i,url:a,miniprogram:r,data:o}=e,s=await weixin.h5.auth.getAccessToken(e);if(!s)return{code:-1,msg:"获取access_token失败,请检查uni-id配置下的h5-weixin配置的appid和appsecret是否正确"};let u=await t.request({url:"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+s,method:"POST",data:{touser:n,template_id:i,url:a,miniprogram:r,data:o},useContent:!0});switch(u=returnRes$3(u),u.code){case 40003:u.msg="touser字段openid为空或者不正确";break;case 40037:u.msg="订阅模板id为空不正确";break;case 43101:u.msg="用户未订阅该消息";break;case 47003:u.msg="模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错";break;case 41030:u.msg="page路径不正确,需要保证在现网版本小程序中存在"}return u},weixin.loginByWeixin=async function(e={},t,n){let i,a,r;e.context?(i=e.data||{},a=e.context,r=e.custom,e.appid&&(i.appid=e.appid),e.appsecret&&(i.appsecret=e.appsecret)):(i=e,a=t,r=n);let o,s,{vk:u,uniID:l,_:c}=util$d,{code:d,platform:p,type:f,appid:g}=i;if(p||(p=u.pubfn.getPlatformForUniId(a),i.platform=p),g&&["mp-weixin","h5-weixin","app-plus"].indexOf(p)>-1){let e;"mp-weixin"===p?e=weixin.auth.getAppidInfo(i):"h5-weixin"===p?e=weixin.h5.auth.getAppidInfo(i):"app-plus"===p&&(e=weixin.app.auth.getAppidInfo(i));let{appid:t,appsecret:n}=e,r=u.pubfn.copyObject(weixin.getConfig());u.pubfn.setData(r,p+".oauth.weixin",{appid:t,appsecret:n}),i.platform=p,s=l.createInstance({context:a,config:r})}s||(s=l);try{delete i.role,o=await s.loginByWeixin(i);try{if(o.uid&&!o.msg&&(o.msg="register"===o.type?"注册成功":"登录成功"),o.uid&&"register"===o.type){let e={},t={last_login_date:Date.now(),last_login_ip:a.CLIENTIP};if(["h5-weixin","app-plus"].indexOf(p)>-1){let t=await u.openapi.weixin.app.auth.getUserInfo({access_token:o.accessToken,openid:o.openid});e={nickname:t.nickname,avatar:t.headimgurl}}["mp-weixin"].indexOf(p)>-1&&(e={nickname:i.nickname,avatar:i.avatar}),u.pubfn.isNotNull(r)&&(e=u.pubfn.objectAssign(e,r)),u.pubfn.isNotNull(t)&&(e=u.pubfn.objectAssign(e,t)),u.pubfn.isNotNull(e)&&(o.userInfo=await u.baseDao.updateAndReturn({dbName:"uni-id-users",whereJson:{_id:o.uid||"___",nickname:c.exists(!1)},dataJson:e}))}}catch(e){console.error("保存用户头像昵称异常:",e)}if(0===o.code)try{let t=u.crypto.aes.encrypt({data:{code:0,sessionKey:o.sessionKey,openid:o.openid,unionid:o.unionid,uid:o.uid,accessToken:o.accessToken,accessTokenExpired:o.accessTokenExpired,refreshToken:o.refreshToken}});o.encryptedKey=t,e.needKey||(delete o.sessionKey,delete o.accessToken,delete o.refreshToken)}catch(e){}}catch(e){console.error("loginByWeixin异常:",e);let t=e.message||"";throw e.message.indexOf("code been used")>-1&&(t="该code已被使用,请重新获取"),e.message.indexOf("invalid code")>-1&&(t="无效code,请重新获取"),new Error("msg:"+t)}return o};var weixin_1=weixin,openapi={};openapi.alipay=alipay_1,openapi.baidu=baidu_1,openapi.douyin=douyin_1,openapi.qq=qq_1,openapi.weixin=weixin_1,openapi.init=function(e){openapi.alipay.init(e),openapi.baidu.init(e),openapi.douyin.init(e),openapi.qq.init(e),openapi.weixin.init(e)};var openapi_1=openapi,builder=class{constructor(){this._shouldUseCache=!1,this._cachedBuffer=null,this._lineBreak="\r\n",this._boundary="------FormDataBaseBoundary"+Math.random().toString(36).substring(2),this.dataList=[]}_addData(e){if(this._shouldUseCache=!1,0===this.dataList.length)return void this.dataList.push(e);const t=this.dataList[this.dataList.length-1];switch(`${Buffer.isBuffer(t)?"buffer":"other"}_${Buffer.isBuffer(e)?"buffer":"other"}`){case"buffer_buffer":this.dataList.push(this._lineBreak),this.dataList.push(e);break;case"buffer_other":this.dataList.push(this._lineBreak+e);break;case"other_buffer":this.dataList[this.dataList.length-1]=t+"\r\n",this.dataList.push(e);break;case"other_other":this.dataList[this.dataList.length-1]=t+"\r\n"+e}}append(e,t,n){this._addData("--"+this._boundary);let i=`Content-Disposition: form-data; name="${encodeURIComponent(e)}"`;if(Buffer.isBuffer(t)){if(!n.filename||!n.contentType)throw new Error("filename and contentType required");i+=`; filename="${encodeURIComponent(n.filename)}"`,this._addData(i),this._addData("Content-Type: "+n.contentType),this._addData(""),this._addData(t)}else this._addData(i),this._addData(""),this._addData(t)}getHeaders(e){const t={"Content-Type":"multipart/form-data; boundary="+this._boundary};return Object.assign(t,e)}getBuffer(){if(this._shouldUseCache)return this._cachedBuffer;this._shouldUseCache=!0;let e=Buffer.alloc(0);return this.dataList.forEach(t=>{e=Buffer.isBuffer(t)?Buffer.concat([e,t]):Buffer.concat([e,Buffer.from(""+t)])}),e=Buffer.concat([e,Buffer.from(`${this._lineBreak}--${this._boundary}--`)]),this._cachedBuffer=e,e}};const BOUNDARY_REG=/^multipart\/.+?(?:;\s*boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i,LEADING_REG=/Content-Disposition:\sform-data;\sname="(.+?)"(?:;\sfilename="(.+?)")?/i,TYPE_REG=/Content-Type:\s(.+?)$/i,lineBreak="\r\n";function split(e,t){let n=0,i=0,a=[];for(;-1!==(i=e.indexOf(t,n));)a.push(e.slice(n,i)),n=i+t.length,i=e.indexOf(t,n);return a}function readParam(e){let t=e.indexOf("\r\n")+"\r\n".length,n=t,i=e.lastIndexOf("\r\n"),a=[];for(;-1!==(n=e.indexOf("\r\n",t));)if(a.push(e.slice(t,n)),t=n+"\r\n".length,0===a[a.length-1].length){a.push(e.slice(t,i));break}return a}var parser=e=>{const t=(e.headers["content-type"]||e.headers["Content-Type"]).match(BOUNDARY_REG),n=t[1]||t[2],i=split(Buffer.from(e.body,"base64"),Buffer.from("--"+n)).map(e=>readParam(e).filter(e=>e.length>0)).filter(e=>2===e.length||3===e.length||4===e.length).map(e=>{const t={},n=e[0].toString().match(LEADING_REG);switch(t.name=decodeURIComponent(n[1]),e.length){case 2:t.value=e[1].toString();break;case 3:t.filename=decodeURIComponent(n[2]),t.contentType=e[1].toString().match(TYPE_REG)[1],t.fileContent=e[2];break;case 4:t.filename=decodeURIComponent(n[2]),t.contentType=e[1].toString().match(TYPE_REG)[1],t.fileContent=e[3]}return t}),a={};return i.forEach(e=>{const t=e.name;delete e.name,a[t]=e.fileContent?e:e.value}),a},formDataUtils={FormData:builder,formParser:parser};const dbName_role="uni-id-roles",dbName_menu="opendb-admin-menus",dbName_permission="uni-id-permissions";var dao={},util$e={};dao.init=function(e){util$e=e},dao.findRoleById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_role,whereJson:{role_id:e}}),t},dao.roleBindPermission=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{role_id:r="___",permissionList:o=[],reset:s=!1}=e;if(!s){let e=await dao.findRoleById(r),{permission:t=[]}=e;o=t.concat(o),o=[...new Set(o)]}return a.num=await t.baseDao.update({dbName:dbName_role,whereJson:{role_id:r},dataJson:{permission:i.set(o)}}),a},dao.roleBindMenu=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{role_id:r="___",menuList:o=[],reset:s=!1,addPermission:u=!1}=e,l=[],c=await dao.findRoleById(r),{menu:d=[],permission:p=[]}=c;if(s?l=compareArray(o,d):(o=d.concat(o),o=[...new Set(o)]),a.num=await t.baseDao.update({dbName:dbName_role,whereJson:{role_id:r},dataJson:{menu:i.set(o)}}),u){let e=await dao.findMenuByIdsToPermission(o),n=[];if(s&&t.pubfn.isNotNull(l)){n=compareArray(e,await dao.findMenuByIdsToPermission(l))}p=p.concat(e),p=compareArray(n,p),p=[...new Set(p)],dao.roleBindPermission({role_id:r,permissionList:p,reset:!0})}return a},dao.findPermissionById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_permission,whereJson:{permission_id:e}}),t},dao.findMenuByIdsToPermission=async e=>{let{vk:t,db:n,_:i}=util$e,a=await dao.findMenuByIds(e);if(t.pubfn.isNull(a))return[];let r=[];for(let e in a){let n=a[e].permission;t.pubfn.isNotNull(n)&&(r=r.concat(n))}return r=[...new Set(r)],r},dao.listPermissionToTree=async(e={})=>{let t,{vk:n,db:i,_:a}=util$e,{getCount:r=!1,pageSize:o=500,pageIndex:s=1,whereJson:u={parent_id:a.in([null,""])},sortArr:l=[{name:"sort",type:"asc"}],treeProps:c={}}=e,{level:d=3,limit:p=500,whereJson:f}=c;u&&!u.permission_id&&(u.permission_id=a.exists(!0)),t=await n.baseDao.selects({dbName:dbName_permission,pageIndex:s,pageSize:o,getCount:r,whereJson:u,sortArr:l,treeProps:{id:"permission_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:f,sortArr:l}});let g={id:"permission_id",parent_id:"parent_id",children:"children"},m=t.rows;m=n.pubfn.treeToArray(m,g),t.list=n.pubfn.copyObject(m);for(let e in m){let t=m[e],i="",a="";if(n.pubfn.isNotNull(t.level)){i=` - ${["未分类","子弹级","炸弹级","榴弹级","核弹级"][t.level]}(LV:${t.level})`}if(n.pubfn.isNotNull(t.curd_category)){a=" - "+["未分类","增","删","改","查","特殊"][t.curd_category]}m[e].label=`${t.permission_name}(${t.permission_id})${a}${i}`}return m=n.pubfn.arrayToTree(m,g),t.rows=m,t},dao.findMenuById=async(e="___")=>{let t,{vk:n,db:i,_:a}=util$e;return t=await n.baseDao.findByWhereJson({dbName:dbName_menu,whereJson:{menu_id:e}}),t},dao.findMenuByIds=async e=>{let t,{vk:n,db:i,_:a}=util$e;return n.pubfn.isNull(e)?[]:(t=(await n.baseDao.select({dbName:dbName_menu,pageIndex:1,pageSize:500,whereJson:{menu_id:a.in(e)}})).rows,t)},dao.listMenuByRole=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:"",menus:[],menuList:[]},{role:r,treeProps:o={}}=e,s=[],u={enable:!0},l={enable:!0};if(!(r.indexOf("admin")>-1)){if(t.pubfn.isNull(r))return a;let e=await t.baseDao.select({dbName:dbName_role,pageSize:500,whereJson:{role_id:i.in(r),enable:!0},fieldJson:{menu:!0}});for(let n in e.rows){let{menu:i}=e.rows[n];t.pubfn.isNotNull(i)&&(s=s.concat(i))}if(0==s.length)return a;s=[...new Set(s)],u.menu_id=i.in(s),l.menu_id=i.in(s)}u.parent_id=i.in([null,""]);let c=[{name:"sort",type:"asc"}],{level:d=3,limit:p=500}=o,f=await t.baseDao.selects({dbName:dbName_menu,pageIndex:1,pageSize:500,whereJson:u,sortArr:c,treeProps:{id:"menu_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:l,sortArr:c}});return a.menus=f.rows,a.menuList=t.pubfn.treeToArray(f.rows,{id:"menu_id",parent_id:"parent_id",children:"children"}),a},dao.menuBindPermission=async(e={})=>{let{vk:t,db:n,_:i}=util$e,a={code:0,msg:""},{menu_id:r="___",permissionList:o=[],reset:s=!1}=e;if(!s){let e=await dao.findMenuById(r),{permission:t=[]}=e;o=t.concat(o),o=[...new Set(o)]}return a.num=await t.baseDao.update({dbName:dbName_menu,whereJson:{menu_id:r},dataJson:{permission:i.set(o)}}),a},dao.listMenuToTree=async(e={})=>{let t,{vk:n,db:i,_:a}=util$e,{getCount:r=!1,pageSize:o=500,pageIndex:s=1,whereJson:u={parent_id:a.in([null,""]),menu_id:a.exists(!0)},sortArr:l=[{name:"sort",type:"asc"}],treeProps:c={}}=e,{level:d=3,limit:p=500,whereJson:f}=c;u&&!u.menu_id&&(u.menu_id=a.exists(!0)),t=await n.baseDao.selects({dbName:dbName_menu,pageIndex:s,pageSize:o,getCount:r,whereJson:u,sortArr:l,treeProps:{id:"menu_id",parent_id:"parent_id",children:"children",level:d,limit:p,whereJson:f,sortArr:l}});let g={id:"menu_id",parent_id:"parent_id",children:"children"},m=t.rows;m=n.pubfn.treeToArray(m,g),t.list=n.pubfn.copyObject(m);for(let e in m){let t=m[e];m[e].label=`${t.name}(${t.menu_id})`}return m=n.pubfn.arrayToTree(m,g),t.rows=m,t};var sysDao=dao;function compareArray(e,t){let n=new Set(e);return t.filter(e=>!n.has(e))}const dbName="vk-global-data";var dao$1={},util$f={};dao$1.init=function(e){util$f=e},dao$1.find=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.findById({dbName:dbName,id:e}),a},dao$1.del=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.deleteById({dbName:dbName,id:e}),a},dao$1.deleteByWhere=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.del({dbName:dbName,whereJson:e}),a},dao$1.deleteExpired=async e=>{let{vk:t,db:n,_:i}=util$f,a={},r={};"string"==typeof e?r._id=e:"object"==typeof e&&(r=e);let o=(new Date).getTime();return a=await t.baseDao.del({dbName:dbName,whereJson:{...r,expired_at:i.gt(0).lte(o)}}),a},dao$1.update=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{key:r,value:o,comment:s,expired_at:u}=e;return a=await t.baseDao.updateById({dbName:dbName,id:r,dataJson:{value:i.set(o),comment:s,expired_at:u}}),a},dao$1.add=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{key:r,value:o,comment:s,expired_at:u}=e;return a=await t.baseDao.add({dbName:dbName,dataJson:{_id:r,key:r,value:o,comment:s,expired_at:u}}),a},dao$1.count=async e=>{let{vk:t,db:n,_:i}=util$f,a={};return a=await t.baseDao.count({dbName:dbName,whereJson:e}),a},dao$1.set=async e=>{let{vk:t,db:n,_:i}=util$f,a={code:0,msg:"ok"},r=new Date;e._add_time=r.getTime(),e._add_time_str=t.pubfn.timeFormat(r,"yyyy-MM-dd hh:mm:ss");let o=await n.collection(dbName).doc(e.key).set(e);return o.upsertedId?(a.id=o.upsertedId,a.mode="add"):(a.mode="update",a.updated=o.updated),a.num=1,a},dao$1.inc=async e=>{let{vk:t,db:n,_:i}=util$f,{key:a,value:r,expired_at:o}=e,s={},u=await t.baseDao.updateById({dbName:dbName,id:a,dataJson:{value:i.inc(r),expired_at:o}});if(0==u){0===await dao$1.count({_id:a})&&(s.id=await dao$1.add(e),s.num=1,s.mode="add")}else s.num=u,s.mode="update";return s},dao$1.list=async e=>{let{vk:t,db:n,_:i}=util$f,a={},{pageIndex:r,pageSize:o,whereJson:s,sortArr:u}=e;return a=await t.baseDao.select({dbName:dbName,pageIndex:r,pageSize:o,whereJson:s,sortArr:u}),a};var globalDataDao$1=dao$1,util$g={},smsUtil={init:function(e){util$g=e}},aliyun={specialUrlEncode:function(e){return(e=encodeURIComponent(e)).replace(/\+/g,"%20").replace(/\*/g,"%2A").replace(/%7E/g,"~")},sign:function(e,t){let{crypto:n}=util$g;return n.createHmac("sha1",e).update(t).digest("base64")}};smsUtil.sendSms=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={};if("aliyun"===i){let i=t.pubfn.getData(n,"vk.service.sms.aliyun");t.pubfn.isNotNull(i)&&(r||(e.smsKey=i.accessKeyId),o||(e.smsSecret=i.accessKeySecret),s||(e.signName=i.signName)),d=await smsUtil.sendSmsByAliyun(e)}else{if("unicloud"!==i)return{code:-1,msg:`暂不支持${i}供应商`};{let i=t.pubfn.getUniIdConfig(n,"service.sms");t.pubfn.isNotNull(i)&&(r||(e.smsKey=i.smsKey),o||(e.smsSecret=i.smsSecret),s||(e.signName=i.signName)),d=await smsUtil.sendSmsByUnicloud(e)}}return d.requestParam={provider:i,phone:u},d},smsUtil.sendSmsByAliyun=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={code:0,msg:""};try{if(t.pubfn.isNullOne(r,o))return{code:-1,msg:"阿里云短信配置错误,请检查vk-unicloud配置下的vk.service.sms.aliyun配置的accessKeyId和accessKeySecret是否正确"};let e="https://dysmsapi.aliyuncs.com",n=t.pubfn.timeFormat(new Date,"yyyy-MM-ddThh:mm:ssZ",0),i=(new Date).getTime().toString().substring(7)+t.pubfn.random(30);"object"==typeof c&&(c=JSON.stringify(c));let a={SignatureMethod:"HMAC-SHA1",SignatureNonce:i,AccessKeyId:r,SignatureVersion:"1.0",Timestamp:n,Format:"json",Action:"SendSms",Version:"2017-05-25",PhoneNumbers:u,SignName:s,TemplateParam:c,TemplateCode:l};delete a.Signature;let p=[];for(let e in a)p.push(e);p.sort();let f=!1,g="";for(let e in p){let t=p[e];g+="&"+aliyun.specialUrlEncode(t)+"="+aliyun.specialUrlEncode(a[t])}g=g.substring(1);let m="GET&"+aliyun.specialUrlEncode("/")+"&"+aliyun.specialUrlEncode(g),b=aliyun.sign(o+"&",m),h=aliyun.specialUrlEncode(b),y="Signature="+h+"&"+g;f&&(console.log("\r\n随机数\r\n"),console.log(a.SignatureNonce),console.log("\r\n=========\r\n"),console.log(a.Timestamp),console.log("\r\n====sortedQueryString====\r\n"),console.log(g),console.log("\r\n=====stringToSign====\r\n"),console.log(m),console.log("\r\n=====sign====\r\n"),console.log(b),console.log("\r\n=====signature====\r\n"),console.log(h),console.log("\r\n=========\r\n"),console.log(e+"/?"+y));t.pubfn.urlStringToJson(y);let w=await t.request({url:`${e}?${y}`,method:"GET"});return d="OK"===w.Code?{code:0,msg:"ok",requestRes:w}:{code:-1,msg:w.Message,requestRes:w},d}catch(e){return{code:-1,msg:"短信发送失败",err:{message:e.message,stack:e.stack}}}},smsUtil.sendSmsByUnicloud=async function(e){let{vk:t,config:n}=util$g,{provider:i,appid:a,smsKey:r,smsSecret:o,signName:s,phone:u,templateId:l,data:c}=e,d={code:0,msg:""};try{if(t.pubfn.isNullOne(r,o))return{code:-1,msg:"unicloud短信配置错误,请检查uni-id配置下的service.sms配置的smsKey和smsSecret是否正确"};let e=await uniCloud.sendSms({smsKey:r,smsSecret:o,phone:u,templateId:l,data:c});d=0==e.code||0==e.errCode?{code:0,msg:"ok",requestRes:e}:{code:-1,msg:e.errMessage||e.errMsg,requestRes:e}}catch(e){return{code:-1,msg:"短信发送失败",err:{message:e.message,stack:e.stack}}}return d},smsUtil.sendSmsVerifyCode=async function(e){let t,{vk:n,config:i,uniID:a}=util$g,{provider:r,phone:o,code:s,type:u,expiresIn:l=180}=e,c={code:0,msg:""};if("unicloud"===r){t=n.pubfn.getUniIdConfig(i,"service.sms.templateId");let e=n.pubfn.getUniIdConfig(i,"service.sms.codeExpiresIn");e&&(l=e);let a=n.pubfn.getUniIdConfig(i,"service.sms.name"),u=Math.ceil(l/60).toString();c=await n.system.smsUtil.sendSms({provider:r,phone:o,templateId:t,data:{code:s,name:a,action:"身份验证",expMinute:u}})}else t=n.pubfn.getData(i,`vk.service.sms.${r}.templateCode.verifyCode`),c=await n.system.smsUtil.sendSms({provider:r,phone:o,templateId:t,data:{code:s}});return 0===c.code&&await a.setVerifyCode({mobile:o,code:s,expiresIn:l,type:u}),c};var smsUtil_1=smsUtil,system={};system.sysDao=sysDao,system.globalDataDao=globalDataDao$1,system.smsUtil=smsUtil_1,system.init=function(e){let t=["sysDao","globalDataDao","smsUtil"];for(let n in t){let i=t[n];"function"==typeof system[i].init&&system[i].init(e)}};var system_1=system,vkunicloud={};class VK{constructor(e){this.router=router,this.md5=md5,this.baseDao=vkBaseDao,this.request=vk_request,this.callFunction=vk_callFunction,this.pubfn=_function,this.temporaryCache=temporaryCache,this.globalDataCache=globalDataCache_1,this.crypto=crypto,this.openapi=openapi_1,this.formDataUtil=formDataUtils,this.system=system_1,this.baseDir=null,e&&this.init(e)}require(e){return vkunicloud.requireFn(this.baseDir+"/"+e)}requireFn(e){try{return vkunicloud.requireFn(e)}catch(e){let{message:t=""}=e;return void(-1==t.indexOf("Cannot find module")&&-1==t.indexOf("no such file or directory")&&console.error(e))}}use(e,t){for(let n in e)e[n]&&"function"==typeof e[n].init&&e[n].init(t),this[n]=e[n]}getGlobalObject(){return"object"==typeof globalThis?globalThis:"object"==typeof self?self:"object"==typeof window?window:"object"==typeof commonjsGlobal?commonjsGlobal:void 0}init(e={}){let t=this;if(e.requireFn&&(vkunicloud.requireFn=e.requireFn),e.baseDir&&(t.baseDir=e.baseDir),e.configCenter||(e.configCenter=t.requireFn("uni-config-center")),e.uniID||(e.uniID=t.requireFn("uni-id")),e.uniPay||(e.uniPay=t.requireFn("uni-pay")),e.middlewareService||(e.middlewareService=t.requireFn("./middleware/index")),e.daoCenter||(e.daoCenter=t.requireFn("./dao/index")),e.crypto||(e.crypto=t.requireFn("crypto")),e.urlrewrite||(e.urlrewrite=t.requireFn("./util/urlrewrite")),e.config||(e.config=e.configCenter({pluginId:"vk-unicloud"}).requireFile("index.js")),!e.config)throw new Error("配置文件:uniCloud/cloudfunctions/common/uni-config-center/vk-unicloud/index.js \n编译错误,请检查!");if(!e.db)try{e.db=uniCloud.database()}catch(e){}if(t.vkPay=t.requireFn("vk-uni-pay"),e.pubFun||(e.pubFun=t.requireFn("./util/pubFunction")),e.pubFun&&(t.myfn=e.pubFun),e.redis||(e.redis=t.requireFn("vk-redis")),e.redis)t.redisUtil=e.redis,t.redis=e.redis.redis,t.newRedis=e.redis.newRedis;else try{t.redis=uniCloud.redis}catch(e){}e.uniMap||(e.uniMap=t.requireFn("uni-map-common")),e.uniMap&&(t.uniMap=e.uniMap),e.db&&(vkunicloud.db=e.db,vkunicloud._=e.db.command),vkunicloud.pubfn=t.pubfn,e.configCenter&&(vkunicloud.configCenter=e.configCenter),e.config&&(vkunicloud.config=e.config),e.uniID&&(vkunicloud.uniID=e.uniID),e.uniPay&&(vkunicloud.uniPay=e.uniPay),e.middlewareService&&(vkunicloud.middlewareService=e.middlewareService),e.pubFun&&(vkunicloud.pubFun=e.pubFun),e.customUtil&&(vkunicloud.customUtil=e.customUtil),e.crypto&&(vkunicloud.crypto=e.crypto),e.urlrewrite&&(vkunicloud.urlrewrite=e.urlrewrite);const n={vk:t,...vkunicloud};t.use({daoCenter:e.daoCenter,baseDao:t.baseDao,openapi:t.openapi,globalDataCache:t.globalDataCache,system:t.system,pubFun:e.pubFun},n);try{let n=t.getGlobalObject();"object"==typeof n&&e.middlewareService&&(n.vk=t)}catch(e){}}getUnicloud(){return vkunicloud}createInstance(e){return new VK(e)}}var src=new VK;module.exports=src; diff --git a/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json new file mode 100644 index 0000000..cb547fc --- /dev/null +++ b/uni_modules/vk-unicloud/uniCloud/cloudfunctions/common/vk-unicloud/package.json @@ -0,0 +1,16 @@ +{ + "name": "vk-unicloud", + "version": "2.15.3", + "description": "【云函数端SDK】VK云函数路由模式uniCloud开发框架,在router目录下执行 npm i vk-unicloud 进行安装和升级", + "main": "index.js", + "homepage": "https://gitee.com/vk-uni/vk-uni-cloud-router.git", + "repository": { + "type": "git", + "url": "git+https://gitee.com/vk-uni/vk-uni-cloud-router.git" + }, + "files": [ + "dist" + ], + "author": "VK", + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js new file mode 100644 index 0000000..e3eebe7 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/index.js @@ -0,0 +1,190 @@ +/** + * vk-unicloud框架客户端(前端) + * author VK + */ +import userCenter from './libs/vk-unicloud/vk-unicloud-user-center' +import callFunctionUtil from './libs/vk-unicloud/vk-unicloud-callFunctionUtil' +import pubfn from './libs/function/index' +import modal from './libs/function/modal' +import navigate from './libs/function/vk.navigate' +import localStorage from './libs/function/vk.localStorage' +import sessionStorage from './libs/function/vk.sessionStorage' +import aliyunOSSUtil from './libs/function/aliyunOSSUtil' +import openapi from './libs/openapi/index' +import requestUtil from './libs/function/vk.request' +import importObject from './libs/function/vk.importObject' + +import filters from './libs/function/vk.filters' +import mixin from './libs/mixin/mixin.js' +import initPermission from './libs/function/permission' +import storeMixin from './libs/store/mixin/mixin' +import initGlobalError from './libs/store/libs/error' +import consoleLog from './libs/install/console.log' +import updateManager from './libs/function/updateManager.js' +// #ifdef H5 +import h5 from './libs/function/vk.h5' +// #endif + + + +var vk = { + userCenter, + callFunctionUtil, + /** + * 发起一个云函数请求 + */ + callFunction: callFunctionUtil.callFunction, + getToken: callFunctionUtil.getToken, + checkToken: callFunctionUtil.checkToken, + uploadFile: callFunctionUtil.uploadFile, + getConfig: callFunctionUtil.getConfig, + emitRefreshToken: callFunctionUtil.emitRefreshToken, + onRefreshToken: callFunctionUtil.onRefreshToken, + offRefreshToken: callFunctionUtil.offRefreshToken, + pubfn, + + // #ifdef H5 + h5, + // #endif + + alert: modal.alert, + toast: modal.toast, + confirm: modal.confirm, + prompt: modal.prompt, + showActionSheet: modal.showActionSheet, + showLoading: modal.showLoading, + hideLoading: modal.hideLoading, + setLoading: modal.setLoading, + + navigate, + // 保留当前页面,并进行页面跳转 + navigateTo: navigate.navigateTo, + // 关闭当前页面,并进行页面跳转 + redirectTo: navigate.redirectTo, + // 并关闭所有页面,并进行页面跳转 + reLaunch: navigate.reLaunch, + // 并关闭所有非tab页面,并进行tab面跳转 + switchTab: navigate.switchTab, + // 页面返回 + navigateBack: navigate.navigateBack, + // 跳转到首页 + navigateToHome: navigate.navigateToHome, + // 跳转到登录页 + navigateToLogin: navigate.navigateToLogin, + // 跳转到小程序 + navigateToMiniProgram: navigate.navigateToMiniProgram, + // 触发全局的自定义事件,附加参数都会传给监听器回调函数。 + $emit: navigate.$emit, + // 监听全局的自定义事件,事件由 uni.$emit 触发,回调函数会接收事件触发函数的传入参数。 + $on: navigate.$on, + // 触发全局的自定义事件,附加参数都会传给监听器回调函数。 + $once: navigate.$once, + // 移除全局自定义事件监听器。 + $off: navigate.$off, + // 本地持久 + localStorage: localStorage, + // 本地会话缓存 + sessionStorage: sessionStorage, + + // 获取应用语言列表 + getLocaleList: pubfn.getLocaleList, + // 获取应用当前语言 + getLocale: pubfn.getLocale, + // 获取应用当前语言对象 + getLocaleObject: pubfn.getLocaleObject, + // 设置应用当前语言 + setLocale: pubfn.setLocale, + + + // 本地持久缓存 + ...localStorage, + // 本地会话缓存 + ...sessionStorage, + // 阿里云oss + aliyunOSSUtil, + // 更新管理器 + updateManager, + // 开放API + openapi, + // 请求库 + requestUtil, + // 发起URL请求 + request: requestUtil.request, + // 导出云对象 + importObject +}; +// vk实例初始化 +vk.init = function(obj = {}) { + let { + Vue, // Vue实例 + config, // 配置 + store, // vuex简写法则(新版本无需传store) + } = obj; + if (typeof store !== "undefined") { + // 兼容旧版本 + Vue.use(store); + } else { + // 新版本无需传store + Vue.mixin(storeMixin); + if (config.globalError) { + Vue.use(initGlobalError); + } + } + // 自定义云函数路由配置 + vk.callFunctionUtil.setConfig(config); + // 重写 console.log + Vue.use(consoleLog); +}; + +vk.getGlobalObject = function() { + if (typeof globalThis === "object") return globalThis; + if (typeof self === "object") return self; + if (typeof window === "object") return window; + if (typeof global === "object") return global; +}; +// 加载拓展功能 +vk.use = function(obj, util) { + for (let name in obj) { + if (obj[name] && typeof obj[name].init === "function") { + obj[name].init(util); + } + vk[name] = obj[name]; + } +}; + +const install = Vue => { + // 全局混入 + Vue.mixin(mixin); + // #ifndef VUE3 + // 加载全局过滤器开始 + for (let i in filters) { + Vue.filter(i, filters[i]); + } + Vue.prototype.vk = vk; + Vue.prototype.$fn = vk.pubfn; + + // #endif + + // #ifdef VUE3 + // 将vk挂载到Vue实例 + Vue.config.globalProperties.vk = vk; + Vue.config.globalProperties.$fn = vk.pubfn; + // #endif + + // 将vk挂载到uni对象 + if (typeof uni == "object") uni.vk = vk; + // 将vk挂载到全局 + let vkGlobalThis = vk.getGlobalObject(); + if (typeof vkGlobalThis == "object") vkGlobalThis.vk = vk; + let util = { vk }; + // 加载插件 + vk.use({ + callFunctionUtil: vk.callFunctionUtil, + openapi: vk.openapi + }, util); + initPermission(Vue); +} + +export default { + install +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js new file mode 100644 index 0000000..6ec7911 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/aliyunOSSUtil.js @@ -0,0 +1,274 @@ +/** + * 阿里云oss工具类 + */ +var aliyunOSSUtil = {}; +var counterNum = 0; + +/** + * 上传至阿里云oss +vk.callFunctionUtil.uploadFile({ + filePath:tempFilePath, + fileType:"image", + provider:"aliyun", + index, + onUploadProgress:function(res){ + // 上传过程中 + if (res.progress > 0) { + if(list[index]){ + list[index].progress = res.progress; + + } + } + }, + success:function(res){ + // 上传成功 + + }, + fail:function(res){ + // 上传失败 + + } +}); + */ +aliyunOSSUtil.uploadFile = function(obj) { + let { + filePath, + fileType = "image", + name = "file", + header = { + "x-oss-forbid-overwrite": true, + }, + index = 0, + file = {}, + needSave = false, + category_id, + title, + cloudPathRemoveChinese = true, // 删除文件名中的中文 + cloudDirectory, + } = obj; + let vk = getApp().globalData.vk; + if (title) vk.showLoading(title); + let fileNameObj = createFileName(obj); + let aliyunOSS = getConfig(); + let fileName = fileNameObj.fileFullName; + let formData = vk.pubfn.copyObject(aliyunOSS.uploadData); + formData["key"] = fileName; // 存储在oss的文件路径 + /** + * 特别说明 + * 若已知本地图片,则使用formData["name"] = filePath + * 若已知base64,则是用formData["file"] = file;// file base64字符串转成blob对象 + */ + if (filePath.indexOf(";base64,") > -1) { + formData["file"] = dataURLtoBlob(filePath); + } else { + formData["name"] = filePath; + } + let Logger = {}; + Logger.startTime = new Date().getTime(); + Logger.filePath = filePath; + return new Promise((resolve, reject) => { + let uploadTask = uni.uploadFile({ + url: aliyunOSS.action, + filePath, + name, + header, + formData: formData, + success: function(res) { + if (title) vk.hideLoading(); + if (![200, 201].includes(res.statusCode)) { + if (typeof obj.fail === "function") obj.fail(res); + Logger.error = res; + } else { + // 上传成功 + res.fileID = fileNameObj.url; + res.url = fileNameObj.url; + Logger.result = res; + if (typeof obj.success === "function") obj.success(res); + resolve(res); + if (needSave) { + // 保存文件记录到数据库 + vk.userCenter.addUploadRecord({ + data: { + url: res.fileID, + name: file.name, + size: file.size, + file_id: res.fileID, + provider: "aliyun", + category_id + }, + filePath, + fileType, + success: function() { + if (typeof obj.addSuccess == "function") obj.addSuccess(res); + }, + fail: function(res) { + if (typeof obj.addFail === "function") obj.addFail(res); + } + }); + } + } + }, + fail: function(res) { + if (title) vk.hideLoading(); + Logger.error = res; + if (res.errMsg && res.errMsg.indexOf('fail url not in domain list') > -1) { + vk.toast('上传域名未在白名单中'); + } + if (typeof obj.fail === "function") obj.fail(res); + }, + complete: function() { + let vk = getApp().globalData.vk; + let config = vk.callFunctionUtil.config; + if (config.debug) { + Logger.endTime = new Date().getTime(); + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + console.log("%c--------【开始】【阿里云oss文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + console.log("【本地文件】: ", Logger.filePath); + console.log("【返回数据】: ", Logger.result); + console.log("【预览地址】: ", Logger.result.fileID); + console.log("【上传耗时】: ", Logger.runTime, "毫秒"); + console.log("【上传时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) console.error("【error】:", Logger.error); + console.log("%c--------【结束】【阿里云oss文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + } + } + }); + uploadTask.onProgressUpdate((res) => { + if (res.progress > 0) { + if (typeof obj.onUploadProgress === "function") obj.onUploadProgress(res); + } + }); + }); +}; + + +export default aliyunOSSUtil; + + +// 获取配置 +function getConfig() { + let vk = getApp().globalData.vk; + let aliyunOSS = vk.getConfig("service.aliyunOSS"); + let configData = {}; + if (aliyunOSS && aliyunOSS.uploadData && aliyunOSS.uploadData.OSSAccessKeyId) { + try { + // 只有开启按userId分组且开启了vk的vuex功能,才可以自动按userId分组 + if (aliyunOSS.groupUserId && typeof vk.getVuex === "function") { + let userInfo = vk.getVuex("$user.userInfo"); + if (vk.pubfn.isNotNull(userInfo) && userInfo._id) { + aliyunOSS.dirname += `/${userInfo._id}`; + } + } + } catch (err) {} + configData = { + uploadData: { + OSSAccessKeyId: aliyunOSS.uploadData.OSSAccessKeyId, + policy: aliyunOSS.uploadData.policy, + signature: aliyunOSS.uploadData.signature, + success_action_status: 200, + key: "test.png" + }, + action: aliyunOSS.action, + dirname: aliyunOSS.dirname, + host: aliyunOSS.host, + }; + } + return configData; +} +// 生成文件名 +function createFileName(obj = {}) { + let { + file, + filePath, + index = 0, + cloudPathRemoveChinese = true, + cloudDirectory + } = obj; + let vk = getApp().globalData.vk; + let aliyunOSS = getConfig(); + let dirname = aliyunOSS.dirname; + let host = aliyunOSS.host; + let fileObj = {}; + + let suffix = getFileSuffix(obj); + let oldName = index + "." + suffix; + if (file && file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) oldName = file.name; + // 只保留["数字","英文",".","-"] + if (cloudPathRemoveChinese) { + oldName = oldName.replace(/[^a-zA-Z.-d]/g, ''); + } + if (oldName.indexOf(".") == 0) oldName = "0" + oldName; + } + let date = new Date(); + let dateYYYYMMDD = vk.pubfn.timeFormat(date, "yyyy/MM/dd"); + let dateTime = date.getTime().toString(); // 时间戳 + // 时间戳后8位 + let dateTimeEnd8 = dateTime.substring(dateTime.length - 8, dateTime.length); + let randomNumber = vk.pubfn.random(8); // 8位随机数 + // 文件路径 = 固定路径名 + 业务路径 + + // 业务路径 + let servicePath = ""; + if (cloudDirectory) { + // 如果自定义了上传目录,则使用自定义的上传目录 + if (cloudDirectory.lastIndexOf("/") !== cloudDirectory.length-1) { + cloudDirectory = cloudDirectory + "/"; + } + servicePath = cloudDirectory; + } else { + // 否则,使用年月日作为上传目录 + servicePath = dateYYYYMMDD + "/"; + } + // 文件名 = 时间戳后8位 - 随机数8位 + 后缀名 + let fileNickName = dateTimeEnd8 + randomNumber + "-" + oldName; + // 文件相对路径 = 业务目录 + 文件名 + let fileRelativePath = servicePath + fileNickName; + // 文件名全称(包含文件路径) = 根目录 + 文件相对路径 + let fileFullName = dirname + "/" + fileRelativePath; + // 外网地址 = 外网域名 + 文件名全称 + let url = host + "/" + fileFullName; + fileObj.url = url; + fileObj.fileFullName = fileFullName; + fileObj.fileNickName = fileNickName; + return fileObj; +} + +function getFileSuffix(obj = {}) { + let { + file, + filePath, + suffix = "png" + } = obj; + if (filePath) { + let suffixName = filePath.substring(filePath.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file) { + if (file.path) { + let suffixName = file.path.substring(file.path.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + } + return suffix; +} + +function dataURLtoBlob(dataurl) { + let arr = dataurl.split(','), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), + n = bstr.length, + u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js new file mode 100644 index 0000000..485521e --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/debounce.js @@ -0,0 +1,34 @@ +let timeoutArr = []; +/** + * 防抖函数 + * 防抖原理:一定时间内,只有最后一次或第一次调用,回调函数才会执行 + * @param {Function} fn 要执行的回调函数 + * @param {Number} time 延时的时间 + * @param {Boolean} isImmediate 是否立即执行 默认true + * @param {String} timeoutName 定时器ID + * @return null +vk.pubfn.debounce(() => { + +}, 1000); + */ +function debounce(fn, time = 500, isImmediate = true, timeoutName = "default") { + // 清除定时器 + if(!timeoutArr[timeoutName]) timeoutArr[timeoutName] = null; + if (timeoutArr[timeoutName] !== null) clearTimeout(timeoutArr[timeoutName]); + // 立即执行一次 + if (isImmediate) { + var callNow = !timeoutArr[timeoutName]; + timeoutArr[timeoutName] = setTimeout(() => { + timeoutArr[timeoutName] = null; + }, time); + if (callNow){ + if(typeof fn === 'function') return fn(); + } + } else { + // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时time毫秒后执行fn回调方法 + timeoutArr[timeoutName] = setTimeout(() => { + if(typeof fn === 'function') return fn(); + }, time); + } +} +export default debounce diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js new file mode 100644 index 0000000..3db999a --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepClone.js @@ -0,0 +1,23 @@ +// 判断arr是否为一个数组,返回一个bool值 +function isArray (arr) { + return Object.prototype.toString.call(arr) === '[object Array]'; +} + +// 深度克隆 +function deepClone (obj) { + // 对常见的“非”值,直接返回原来值 + if([null, undefined, NaN, false].includes(obj)) return obj; + if(typeof obj !== "object" && typeof obj !== 'function') { + //原始类型直接返回 + return obj; + } + var o = isArray(obj) ? [] : {}; + for(let i in obj) { + if(obj.hasOwnProperty(i)){ + o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i]; + } + } + return o; +} + +export default deepClone; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js new file mode 100644 index 0000000..81d2d18 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/deepMerge.js @@ -0,0 +1,30 @@ +import deepClone from "./deepClone"; + +// JS对象深度合并 +function deepMerge(target = {}, source = {}) { + target = deepClone(target); + if (typeof target !== 'object' || typeof source !== 'object') return false; + for (var prop in source) { + if (!source.hasOwnProperty(prop)) continue; + if (prop in target) { + if (typeof target[prop] !== 'object') { + target[prop] = source[prop]; + } else { + if (typeof source[prop] !== 'object') { + target[prop] = source[prop]; + } else { + if (target[prop].concat && source[prop].concat) { + target[prop] = target[prop].concat(source[prop]); + } else { + target[prop] = deepMerge(target[prop], source[prop]); + } + } + } + } else { + target[prop] = source[prop]; + } + } + return target; +} + +export default deepMerge; \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js new file mode 100644 index 0000000..dbd1091 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/index.js @@ -0,0 +1,2430 @@ +/** + * 通用公共函数 + */ +var pubfn = {}; +// 防抖 +import debounce from './debounce.js' +// 限流 +import throttle from './throttle.js' +// url参数 +import queryParams from './queryParams.js' +// H5版本的复制 +import setClipboardData from './setClipboardData.js' +// 时间 +import timeUtil from './timeUtil.js' +// 树形结构转换 +import treeUtil from './treeUtil.js' + +/** + * 树形结构转换 + */ +pubfn.treeUtil = treeUtil; +/** + * 时间工具类 + */ +pubfn.timeUtil = timeUtil; +/** + * 防抖函数 + */ +pubfn.debounce = debounce; +/** + * 节流函数 + */ +pubfn.throttle = throttle; +/** + * 对象转url参数 + * @param {*} data,对象 + * @param {*} isPrefix,是否自动加上"?" + * 此函数参考uView + * vk.pubfn.queryParams(json); + */ +pubfn.queryParams = queryParams; +/** + * 设置剪贴板 + */ +pubfn.setClipboardData = setClipboardData; + +/** + * 休眠,等待(单位毫秒) + * @param {Number} ms 毫秒 + * await vk.pubfn.sleep(1000); + */ +pubfn.sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); + +/** + * 日期格式化 + * @param {Date || Number} date 需要格式化的时间 + * vk.pubfn.timeFormat(new Date(),"yyyy-MM-dd hh:mm:ss"); + */ +pubfn.timeFormat = pubfn.timeUtil.timeFormat; +/** + * 解析日期对象属性 + * @param {Date || Number} date 需要转换的时间 + * vk.pubfn.getDateInfo(new Date()); + */ +pubfn.getDateInfo = pubfn.timeUtil.getDateInfo; + +/** + * 日期对象转换(此API已弃用,建议用vk.pubfn.timeFormat代替) + * @param {Date || Number} date 需要转换的时间 + * @param {Number} type 转换方式 + * type = 0 返回 2020-08-03 12:12:12 + * type = 1 返回 20200803121212 + * type = 2 返回 { YYYY, MM, DD, hh, mm, ss } + */ +pubfn.getFullTime = pubfn.timeUtil.getFullTime; + +/** + * 获取时间范围 + * @param {Date} date 日期对象 可以指定时间计算节点,默认使用当前时间进行计算 + * 返回的是时间戳(防止时区问题) + * 返回数据如下: + { + todayStart 今日开始时间 + todayEnd 今日结束时间 + today12End 今日上午结束时间 + monthStart 本月开始时间 + monthEnd 本月结束时间 + yearStart 本年开始时间 + yearEnd 本年结束时间 + weekStart 本周开始时间 + weekEnd 本周结束时间 + now 现在的时间点(含月年日时分秒) + months 本年度每月的开始和结束时间 months[1] 代表1月 + } + * vk.pubfn.getCommonTime(); + */ +pubfn.getCommonTime = pubfn.timeUtil.getCommonTime; + +/** + * 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 + * 返回时间戳形式 +vk.pubfn.getOffsetTime(new Date(), { + year:0, + month:0, + day:0, + hours:0, + minutes:0, + seconds:0, + mode:"after", // after 之后 before 之前 +}); + */ +pubfn.getOffsetTime = pubfn.timeUtil.getOffsetTime; + +/** + * 获得相对当前时间的偏移 count 小时的起止日期(小时的开始和结束) + * @param {Number} count 默认0 (0代表当前小时 为-1代表上一个小时 为1代表下一个小时以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getHourOffsetStartAndEnd(0); + */ +pubfn.getHourOffsetStartAndEnd = pubfn.timeUtil.getHourOffsetStartAndEnd; + + +/** + * 获得相对当前时间的偏移 count 天的起止日期(日的开始和结束) + * @param {Number} count 默认0 (0代表今日 为-1代表昨日 为1代表明日以此类推) + * @param {Date || Number} date 指定从那天开始计算 + * vk.pubfn.getDayOffsetStartAndEnd(0); + */ +pubfn.getDayOffsetStartAndEnd = pubfn.timeUtil.getDayOffsetStartAndEnd; + +/** + * 获得相对当前周addWeekCount个周的起止日期 + * @param {Number} addWeekCount 默认0 (0代表本周 为-1代表上周 为1代表下周以此类推 为2代表下下周) + * vk.pubfn.getWeekOffsetStartAndEnd(0); + */ +pubfn.getWeekOffsetStartAndEnd = pubfn.timeUtil.getWeekOffsetStartAndEnd; // 新版写法 +pubfn.getWeekStartAndEnd = pubfn.timeUtil.getWeekOffsetStartAndEnd; // 兼容老版本写法 + +/** + * 获得相对当前时间的偏移 count 月的起止日期(月的开始和结束) + * @param {Number} count 默认0 (0代表本月 为-1代表上月 为1代表下月以此类推) + * @param {Date || Number} date 指定从那天开始计算 + * vk.pubfn.getMonthOffsetStartAndEnd(0); + */ +pubfn.getMonthOffsetStartAndEnd = pubfn.timeUtil.getMonthOffsetStartAndEnd; + +/** + * 获得相对当前时间的偏移 count 个季度的起止日期(季度的开始和结束时间戳) + * @param {Number} count 默认0(0代表本季度 -1代表上个季度 1代表下个季度以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getQuarterOffsetStartAndEnd(0); + */ +pubfn.getQuarterOffsetStartAndEnd = pubfn.timeUtil.getQuarterOffsetStartAndEnd; + + +/** + * 获得相对当前时间的偏移 count 年的起止日期(年的开始和结束) + * @param {Number} count 默认0 (0代表今年 为-1代表去年 为1代表明年以此类推) + * @param {Date || Number} date 指定从那天开始计算 + * vk.pubfn.getYearOffsetStartAndEnd(0); + */ +pubfn.getYearOffsetStartAndEnd = pubfn.timeUtil.getYearOffsetStartAndEnd; + +/** + * 获得指定年份和月份后的该月的开始时间和结束时间 + * 返回数据如下:(时间戳形式) + { + startTime 该月开始时间 + endTime 该月结束时间 + } +vk.pubfn.getMonthStartAndEnd({ + year:2021 + month:1 +}); + */ +pubfn.getMonthStartAndEnd = pubfn.timeUtil.getMonthStartAndEnd; + +/** + * Vue 全局表单验证器扩展 +rules: { + receiver_mobile:[ + { validator:vk.pubfn.validator("mobile"), message: '手机号格式错误', trigger: 'blur' } + ], +}, + */ +pubfn.validator = function(type) { + return function(rule, value, callback) { + let key = pubfn.test(value, type); + if (typeof callback === "function") { + if (key || !value) { + callback(); + } else { + return callback(false); + } + } else { + return callback(false); + } + } +}; + +/** + * 检测文本是否满足指定格式 + * @param {String} str 需要检测的文本 + * @param {String} type 检测类型(忽略大小写) + * @param {Boolean} allowEmpty 是否允许为空 + * 包含 + * mobile 手机号码 + * tel 座机 + * card 身份证 + * mobileCode 6位数字验证码 + * username 账号以字母开头,长度在3~32之间,只能包含字母、数字和下划线 + * pwd 密码长度在6~18之间,只能包含字母、数字和下划线 + * password 与pwd效果一致,密码长度在6~18之间,只能包含字母、数字和下划线 + * paypwd 支付密码 6位纯数字 + * postal 邮政编码 + * qq QQ号 + * email 邮箱 + * money 金额(小数点只允许2位) + * url 网址 + * ip IP地址 + * date 日期 2020-08-03 + * time 时间 12:12:12 + * dateTime 日期+时间 2020-08-03 12:12:12 + * number 纯数字 + * english 纯英文 + * chinese 纯中文 + * english+number 英文+数字 + * english+number+_ 英文+数字+_ + * english+number+_- 英文+数字+_- + * lower 小写 + * upper 大写 + * version 版本号 xx.xx.xx (xx必须是数字) + * html html格式 + * image 图片 + * video 视频 + * audio 音频 + * vk.pubfn.test(str, type, allowEmpty); + */ +pubfn.test = function(str, type = "", allowEmpty=false) { + type = type.toLowerCase(); + let newStr; + if (allowEmpty && (str === "" || str === null || str === undefined)) { + return true; + } + switch (type) { + case 'mobile': //手机号码 + return new RegExp(/^1[3|4|5|6|7|8|9][0-9]{9}$/).test(str); + case 'tel': //座机 + return new RegExp(/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/).test(str); + case 'card': //身份证 + return new RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(str); + case 'mobilecode': //6位数字验证码 + return new RegExp(/^[0-9]{6}$/).test(str); + case 'username': //账号以字母开头,长度在3~32之间,只能包含字母、数字和下划线 + return new RegExp(/^[a-zA-Z]([-_a-zA-Z0-9]{2,31})$/).test(str) + case 'pwd': //密码长度在6~18之间,只能包含字母、数字和下划线和@ + return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(str) + case 'password': //密码长度在6~18之间,只能包含字母、数字和下划线和@ + return new RegExp(/^([a-zA-Z0-9_@]){6,18}$/).test(str) + case 'paypwd': //支付密码 6位纯数字 + return new RegExp(/^[0-9]{6}$/).test(str) + case 'postal': //邮政编码 + return new RegExp(/[1-9]\d{5}(?!\d)/).test(str); + case 'qq': //QQ号 + return new RegExp(/^[1-9][0-9]{4,9}$/).test(str); + case 'email': //邮箱 + return new RegExp(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/).test(str); + case 'money': //金额(小数点2位) + return new RegExp(/^\d*(?:\.\d{0,2})?$/).test(str); + case 'url': //网址 + return new RegExp(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/).test(str); + case 'ip': //IP + return new RegExp(/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/).test( + str); + case 'date': //日期 2014-01-01 + return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/).test(str); + case 'time': //时间 12:00:00 + return new RegExp(/^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(str); + case 'datetime': //日期+时间 2014-01-01 12:00:00 + return new RegExp(/^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/).test(str); + case 'english+number': //英文+数字(空字符串算通过) + return new RegExp(/^[a-zA-Z0-9]+$/).test(str); + case 'english+number+_': //英文+数字+_(空字符串算通过) + return new RegExp(/^[a-zA-Z0-9_]+$/).test(str); + case 'english+number+_-': //英文+数字+_-(空字符串算通过) + return new RegExp(/^[a-zA-Z0-9_-]+$/).test(str); + case 'version': //版本号 xx.xx.xx(xx必须是数字) + return new RegExp(/^([1-9]\d|[1-9])(.([1-9]\d|\d)){2}$/).test(str); + case 'number': //数字(空字符串算通过) + return new RegExp(/^[0-9]+$/).test(str); + case 'english': //英文(空字符串算通过) + return new RegExp(/^[a-zA-Z]+$/).test(str); + case 'chinese': //中文(空字符串算通过) + return new RegExp(/^[\u4e00-\u9fa5]+$/gi).test(str); + case 'lower': //小写(空字符串算通过) + return new RegExp(/^[a-z]+$/).test(str); + case 'upper': //大写(空字符串算通过) + return new RegExp(/^[A-Z]+$/).test(str); + case 'html': //HTML标记 + return new RegExp(/<("[^"]*"|'[^']*'|[^'">])*>/).test(str); + case 'image': //是否图片格式 + newStr = str.split("?")[0]; + return new RegExp(/\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)$/).test(newStr); + case 'video': //是否视频格式 + newStr = str.split("?")[0]; + return new RegExp(/\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8|3gp)$/).test(newStr); + case 'audio': //是否音频格式 + newStr = str.split("?")[0]; + return new RegExp(/\.(mp3)$/).test(newStr); + default: + return true; + } +}; +// 保留之前的函数名 +pubfn.checkStr = pubfn.test; +/** + * 删除对象中所有值为无效值的属性(如:undefined) + * @param {Object} obj + * vk.pubfn.objectDeleteInvalid(obj); + */ +pubfn.objectDeleteInvalid = function(obj = {}) { + Object.keys(obj).forEach(item => { + if (obj[item] === undefined) { + delete obj[item]; + } + }); + return obj; +}; +/** + * 对象属性拷贝(浅拷贝) + * @description 将 obj2 的属性赋值给 obj1(如果obj1中有对应的属性,则会被obj2的属性值覆盖) + * @param {Object} obj1 + * @param {Object} obj2 + * vk.pubfn.objectAssign(obj1, obj2); + * vk.pubfn.objectAssign(obj1, obj2, true); + * vk.pubfn.objectAssign(obj1, obj2, false); + */ +pubfn.objectAssign = function(obj1, obj2, deleteInvalid = true) { + if (deleteInvalid) pubfn.objectDeleteInvalid(obj2); + return Object.assign(obj1, obj2); +}; +/** + * 复制一份对象-没有映射关系 + * @description 主要用于解除映射关系(不支持克隆函数) + * @param {Object} obj + * let newObj = vk.pubfn.copyObject(obj); + */ +pubfn.copyObject = function(obj) { + if (typeof obj !== "undefined") { + return JSON.parse(JSON.stringify(obj)); + } else { + return obj; + } +}; +/** + * 深度克隆一个对象-没有映射关系 + * @description 主要用于解除映射关系(支持克隆函数) + * @param {Object} obj + * let newObj = vk.pubfn.deepClone(obj); + */ +pubfn.deepClone = function(obj) { + // 对常见的“非”值,直接返回原来值 + if ([null, undefined, NaN, false].includes(obj)) return obj; + if (typeof obj !== "object" && typeof obj !== 'function') { + //原始类型直接返回 + return obj; + } + let o = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {}; + for (let i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = typeof obj[i] === "object" ? pubfn.deepClone(obj[i]) : obj[i]; + } + } + return o; +}; +/** + * 表单自动填充数据 + * @description 主要用于表单修改时,数据库没有默认字段会报错的问题 + * @param {Object} defaultData 默认数据 + * @param {Object} itemData 当前数据 + * that.form1 = vk.pubfn.formAssign(defaultData,itemData); + */ +pubfn.formAssign = function(defaultData, itemData) { + let newDefaultData = pubfn.copyObject(defaultData); + return pubfn.objectAssign(newDefaultData, itemData); +}; + + +/** + * 两个(元素为对象)的数组合并,并去除重复的数据 + * @param {Array} arr1 第一个数组(arr1和aar2没有顺序要求) + * @param {Array} aar2 第二个数组 + * @param {String} flag 判断标识,默认用id来判断,若flag传-1,代表不去除重复数据 + * let arr = vk.pubfn.arr_concat(arr1, arr2, "_id"); + */ +pubfn.arr_concat = function(arr1, arr2, flag) { + if (!flag) flag = "id"; // 默认用id来判断是否是同一个对象元素 + if (!arr1) arr1 = []; + if (!arr2) arr2 = []; + let arr3 = arr1.concat(arr2); // 新旧数据合并 + let arr = []; // 定义一个临时数组 存放对象 + if (flag != -1) { + let arr_id = []; // 定义一个临时数组 存放id + for (let i in arr3) { // 循环遍历当前数组 + // 判断当前数组下标为i的元素是否已经保存到临时数组 + // 如果已保存,则跳过,否则将此元素保存到临时数组中 + if (arr_id.indexOf(arr3[i][flag]) == -1) { + arr_id.push(arr3[i][flag]); // 添加id到数组 + arr.push(arr3[i]); // 添加对象到数组 + } + } + } else { + arr = arr3; + } + return arr; +}; +/** + * 自动根据字符串路径获取对象中的值支持.和[] , 且任意一个值为undefined时,不会报错,会直接返回undefined + * @param {Object} dataObj 数据源 + * @param {String} name 支持a.b 和 a[b] + * @param {String} defaultValue undefined时的默认值 + * vk.pubfn.getData(dataObj, name); + */ +pubfn.getData = function(dataObj, name, defaultValue) { + let newDataObj; + if (pubfn.isNotNull(dataObj)) { + newDataObj = JSON.parse(JSON.stringify(dataObj)); + let k = "", + d = ".", + l = "[", + r = "]"; + name = name.replace(/\s+/g, k) + d; + let tstr = k; + for (let i = 0; i < name.length; i++) { + let theChar = name.charAt(i); + if (theChar != d && theChar != l && theChar != r) { + tstr += theChar; + } else if (newDataObj) { + if (tstr != k) newDataObj = newDataObj[tstr]; + tstr = k; + } + } + } + if (typeof newDataObj === "undefined" && typeof defaultValue !== "undefined") newDataObj = defaultValue; + return newDataObj; +}; +/** + * 自动根据字符串路径设置对象中的值 支持.和[] + * @param {Object} dataObj 数据源 + * @param {String} name 支持a.b 和 a[b] + * @param {String} value 值 + * vk.pubfn.setData(dataObj, name, value); + */ +pubfn.setData = function(dataObj, name, value) { + // 通过正则表达式 查找路径数据 + let dataValue; + if (typeof value === "object") { + dataValue = pubfn.copyObject(value); + } else { + dataValue = value; + } + let regExp = new RegExp("([\\w$-]+)|\\[(:\\d)\\]", "g"); + const patten = name.match(regExp); + // 遍历路径 逐级查找 最后一级用于直接赋值 + for (let i = 0; i < patten.length - 1; i++) { + let keyName = patten[i]; + if (typeof dataObj[keyName] !== "object") dataObj[keyName] = {}; + dataObj = dataObj[keyName]; + } + // 最后一级 + dataObj[patten[patten.length - 1]] = dataValue; +}; + +/** + * 检测参数是否为空 其中 undefined、null、{}、[]、"" 均为空值 true 空值 false 有值 + * vk.pubfn.isNull(value); + */ +pubfn.isNull = function(value) { + let key = false; + if ( + typeof value == "undefined" || + Object.prototype.toString.call(value) == "[object Null]" || + JSON.stringify(value) == "{}" || + JSON.stringify(value) == "[]" || + value === "" || + JSON.stringify(value) === undefined + ) { + key = true; + } + return key; +}; +/** + * 检测参数是否不为空 结果与 vk.pubfn.isNull 相反 + * vk.pubfn.isNotNull(value); + */ +pubfn.isNotNull = function(value) { + return !pubfn.isNull(value); +}; +/** + * 检测所有参数 - 是否至少有一个为空 + * vk.pubfn.isNullOne(value1,value2,value3); + */ +pubfn.isNullOne = function(...strS) { + let key = false; + for (let i = 0; i < strS.length; i++) { + let str = strS[i]; + if (pubfn.isNull(str)) { + key = true; + break; + } + } + + return key; +}; +/** + * 检测整个对象是否没有一个属性是空值,如果有空值,则返回首个是空值的属性名 + let nullKey = vk.pubfn.isNullOneByObject({ value1,value2,value3 }); + if(nullKey) return { code : -1, msg : `${nullKey}不能为空` }; + */ +pubfn.isNullOneByObject = function(obj) { + let key; + for (let name in obj) { + let val = obj[name]; + if (pubfn.isNull(val)) { + key = name; + break; + } + } + return key; +}; +/** + * 检测所有参数 - 是否全部为空 + * vk.pubfn.isNullAll(value1,value2,value3); + */ +pubfn.isNullAll = function(...strS) { + let key = true; + for (let i = 0; i < strS.length; i++) { + let str = strS[i]; + if (pubfn.isNotNull(str)) { + key = false; + break; + } + } + return key; +}; + +/** + * 检测所有参数 - 是否全部都不为空 + * vk.pubfn.isNotNullAll(value1,value2,value3); + */ +pubfn.isNotNullAll = function(...strS) { + return !pubfn.isNullOne(...strS); +}; +/** + * 获取对象数组中的某一个item,根据指定的键名和键值 + * @description 主要用于在一个对象数组中快速获取 _id = 1 的对象 + * @param {Array} list 数据源 + * @param {String} key 键名(不可为空) + * @param {String} value 键值 (不可为空) + * vk.pubfn.getListItem(list, key, value); + */ +pubfn.getListItem = function(list, key, value) { + let item; + for (let i = 0; i < list.length; i++) { + if (list[i][key] === value) { + item = list[i]; + break; + } + } + return item; +}; +/** + * 获取对象数组中某个元素的index,根据指定的键名和键值 + * @description 主要用于在一个对象数组中快速获取 _id = 1 的index + * @param {Array} list 数据源 + * @param {String} key 键名 + * @param {String} value 键值 + * vk.pubfn.getListIndex(list, key, value); + */ +pubfn.getListIndex = function(list, key, value) { + let index = -1; + for (let i = 0; i < list.length; i++) { + if (list[i][key] === value) { + index = i; + break; + } + } + return index; +}; +/** + * 获取对象数组中某个元素的index,根据指定的键名和键值 + * @description 主要用于在一个对象数组中快速获取 _id = 1 的index + * @param {Array} list 数据源 + * @param {String} key 键名 + * @param {String} value 键值 + * vk.pubfn.getListItemIndex(list, key, value); + */ +pubfn.getListItemIndex = function(list, key, value) { + let obj = {}; + let item; + let index = -1; + for (let i = 0; i < list.length; i++) { + if (list[i][key] === value) { + index = i; + item = list[i]; + break; + } + } + obj = { + item, + index + } + return obj; +}; +/** + * 数组转对象 - 将对象数组转成json + * 如[{"_id":"001","name":"name1","sex":1},{"_id":"002","name":"name2","sex":2}] + * 转成 + * {"001",{"_id":"001","name":"name1","sex":1},"002":{"_id":"002","name":"name2","sex":2}} + * vk.pubfn.arrayToJson(list, "_id"); + */ +pubfn.arrayToJson = function(list, key) { + let json = {}; + for (let i in list) { + let item = list[i]; + json[item[key]] = item; + } + return json; +}; +pubfn.listToJson = pubfn.arrayToJson; + +/** + * 从数组中提取指定字段形式成为新的数组 + * 如[{"_id":"001","name":"name1","sex":1},{"_id":"002","name":"name2","sex":2}] + * 提取_id字段转成 + * ["001","002"] + * let idArr = vk.pubfn.arrayObjectGetArray(list, "_id"); + */ +pubfn.arrayObjectGetArray = function(list, key) { + return list.map(obj => { return obj[key] }); +}; + +/** + * 产生指定位数的随机数(支持任意字符,默认纯数字) + * @param {Number} length 随机数固定位数 + * @param {String} range 指定的字符串中随机范围 + * @param {Array} arr 产生的随机数不会和此数组的任意一项重复 + * vk.pubfn.random(6); + * vk.pubfn.random(6, "abcdefghijklmnopqrstuvwxyz0123456789"); + * vk.pubfn.random(1,"12",["1","2"]); + */ +pubfn.random = function(length, range, arr) { + let s; + if (pubfn.isNull(arr)) { + s = pubfn.randomFn(length, range); + } else { + let i = 0; + let maxForCount = 100000; + do { + i++; + s = pubfn.randomFn(length, range); + } while (arr.indexOf(s) > -1 && i < maxForCount); + if (i === maxForCount) { + s = undefined; + } + } + return s; +}; +/** + * 产生指定位数的随机数(支持任意字符,默认纯数字) + * @param {Number} length 随机数固定位数 + * @param {String} range 指定的字符串中随机范围 + * vk.pubfn.random(6); + * vk.pubfn.random(6, "abcdefghijklmnopqrstuvwxyz0123456789"); + */ +pubfn.randomFn = function(length, range) { + let s = ""; + let list = "123456789"; + //0123456789QWERTYUIPASDFGHJKLZXCVBNM + if (pubfn.isNotNull(range)) { + if (range == "a-z,0-9") { + range = "abcdefghijklmnopqrstuvwxyz0123456789"; + } else if (range == "A-Z,0-9") { + range = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + } else if (range == "a-z,A-Z,0-9" || range == "A-Z,a-z,0-9") { + range = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + } + list = range; + } + for (let i = 0; i < length; i++) { + let code = list[Math.floor(Math.random() * list.length)]; + s += code; + } + return s; +}; + +/** + * 将字符串id转化为指定位数的纯数字字符串id(会重复) + * vk.pubfn.stringIdToNumberId(uid,8); + */ +pubfn.stringIdToNumberId = function(str, length) { + let s = ""; + let list = "0123456789"; + for (let i = 0; i < length; i++) { + if (str.length > i) { + let index = str[i].charCodeAt() % 10; + s += list[index]; + } else { + s = "0" + s; + } + } + return s; +}; + +/** + * 将手机号,账号等隐藏中间字段 + * @param {String} str 需要转换的字符串 + * @param {Number} first 前面显示的字符数量 + * @param {Number} last 后面显示的字符数量 + * vk.pubfn.hidden(str, first, last); + */ +pubfn.hidden = function(str = "", first = 0, last = 0) { + let len = str.length - first - last; + let xing = ''; + for (let i = 0; i < len; i++) { + xing += '*'; + } + return str.substring(0, first) + xing + str.substring(str.length - last); +}; +/** + * 判断常量数组A是否至少有一个元素在常量数组B中存在(两数组有交集) + * @param {Array} arr1 数组A + * @param {Array} arr2 数组B + * vk.pubfn.checkArrayIntersection(arr1, arr2); + */ +pubfn.checkArrayIntersection = function(arr1 = [], arr2 = []) { + let checkKey = false; + for (let i = 0; i < arr2.length; i++) { + if (arr1.indexOf(arr2[i]) > -1) { + checkKey = true; + } + } + return checkKey; +}; +/** + * 检测数据源是否满足表达式规则 + * @param {Object} data 数据源 + * @param {String} expText 表达式文本 + * vk.pubfn.checkDataExpText(data, expText); + */ +pubfn.checkDataExpText = function(data = {}, expText) { + expText = expText.replace(new RegExp("\\s", "g"), ""); + //console.log("expText:",expText); + let orArr = expText.split("||"); + //console.log("orArr",orArr); + let checkKey = false; + for (let index1 = 0; index1 < orArr.length; index1++) { + let orItem = orArr[index1]; + let andArr = orItem.split("&&"); + //console.log("andArr",andArr); + let itemKey = true; + for (let index2 = 0; index2 < andArr.length; index2++) { + let andItem = andArr[index2]; + //console.log("andItem",andItem); + if (andItem.indexOf("!=") > -1) { + let andItemArr = andItem.split("!="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + + itemKey = String(formValue) !== value ? true : false; + + } else if (andItem.indexOf("==") > -1) { + let andItemArr = andItem.split("=="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + + itemKey = String(formValue) == value ? true : false; + + } else if (andItem.indexOf(">=") > -1) { + let andItemArr = andItem.split(">="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (isNaN(value)) { + if (typeof formValue !== "undefined") itemKey = String(formValue) >= value ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } else { + if (typeof formValue !== "undefined") itemKey = formValue >= Number(value) ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } + } else if (andItem.indexOf(">") > -1) { + let andItemArr = andItem.split(">"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (isNaN(value)) { + if (typeof formValue !== "undefined") itemKey = String(formValue) > value ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } else { + if (typeof formValue !== "undefined") itemKey = formValue > Number(value) ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } + } else if (andItem.indexOf("<=") > -1) { + let andItemArr = andItem.split("<="); + let key = andItemArr[0]; + let value = andItemArr[1]; + if (isNaN(value)) { + if (typeof data[key] !== "undefined") itemKey = String(data[key]) <= value ? true : false; + if (typeof data[key] === "undefined" || data[key] === null) itemKey = false; + } else { + if (typeof data[key] !== "undefined") itemKey = data[key] <= Number(value) ? true : false; + if (typeof data[key] === "undefined" || data[key] === null) itemKey = false; + } + } else if (andItem.indexOf("<") > -1) { + let andItemArr = andItem.split("<"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (isNaN(value)) { + if (typeof formValue !== "undefined") itemKey = String(formValue) < value ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } else { + if (typeof formValue !== "undefined") itemKey = formValue < Number(value) ? true : false; + if (typeof formValue === "undefined" || formValue === null) itemKey = false; + } + } else if (andItem.indexOf("{in}") > -1) { + let andItemArr = andItem.split("{in}"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (Array.isArray(formValue)) { + let index = formValue.findIndex(item => { + return item.toString() === value.toString(); + }); + itemKey = index > -1 ? true : false; + } else { + itemKey = false; + } + //itemKey = (Array.isArray(formValue) && formValue.indexOf(value) > -1 ) ? true : false; + } else if (andItem.indexOf("{nin}") > -1) { + let andItemArr = andItem.split("{nin}"); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + if (Array.isArray(formValue)) { + let index = formValue.findIndex(item => { + return item.toString() === value.toString(); + }); + itemKey = index < 0 ? true : false; + } else { + itemKey = false; + } + //itemKey = (Array.isArray(formValue) && formValue.indexOf(value) < 0 ) ? true : false; + } else { + let andItemArr = andItem.split("="); + let key = andItemArr[0]; + let value = andItemArr[1]; + let formValue = pubfn.getData(data,key); + + itemKey = String(formValue) == value ? true : false; + + //console.log("key:",key,"value:",value,"formValue",formValue.toString(),"itemKey:",itemKey); + } + if (!itemKey) { + break; + } + } + if (itemKey) { + checkKey = true; + break; + } + } + return checkKey; +}; + +/** + * 判断变量是否是数组 + * vk.pubfn.isArray(value); + */ +pubfn.isArray = function(value) { + return Object.prototype.toString.call(value) === "[object Array]" ? true : false; +}; +/** + * 判断变量是否是对象 + * vk.pubfn.isObject(value); + */ +pubfn.isObject = function(value) { + return Object.prototype.toString.call(value) === "[object Object]" ? true : false; +}; + + + +/** + * 计算运费 + * @param {Object} freightItem 运费模板 + { + first_weight Number 首重(KG) + first_weight_price Number 首重 首重价格(100=1元) + continuous_weight Number 续重(KG) + continuous_weight_price Number 续重价格(100=1元) + max_weight Number 重量达到此值时(KG),会多计算首重的价格,并少一次续重的价格 倍乘(相当于拆分多个包裹) + } + * @param {Number} weight 运费重量 + * 返回值 + * @return {Number} 最终运费金额(100=1元) + * vk.pubfn.calcFreights(freightItem, weight); + */ +pubfn.calcFreights = function(freightItem, weight) { + let freightRes = vk.pubfn.calcFreightDetail(freightItem, weight); + return freightRes.total_amount; +}; + +/** + * 计算运费,返回细节 + * @param {Object} freightItem 运费模板 + { + first_weight Number 首重(KG) + first_weight_price Number 首重 首重价格(100=1元) + continuous_weight Number 续重(KG) + continuous_weight_price Number 续重价格(100=1元) + max_weight Number 重量达到此值时(KG),会多计算首重的价格,并少一次续重的价格 倍乘(相当于拆分多个包裹) + } + * @param {Number} weight 需要计算的商品重量 + * 返回值 + * @return {Number} weight 运费重量(KG) + * @return {Number} first_weight_price 首重金额(100=1元) + * @return {Number} continuous_weight_price 续重金额(100=1元) + * @return {Number} total_amount 最终运费金额(100=1元) + * @return {String} formula 运费计算公式字符串 + * let freightRes = vk.pubfn.calcFreightDetail(freightItem, weight); + */ +pubfn.calcFreightDetail = function(freightItem, weight) { + let { + first_weight, // 首重(KG) + first_weight_price, // 首重价格(元) + continuous_weight, // 续重(KG) + continuous_weight_price, // 续重价格(元) + max_weight, // 拆包裹,每个包裹最大重量(KG) + } = freightItem; + if (!max_weight) max_weight = 1000000000; + let originalWeight = weight; + let money = 0; // 运费 + let first_weight_count = 0; // 包裹数量 + let packagesSurplusWeight = max_weight; // 包裹剩余重量 + let first_weight_key = false; // 是否已减过首重 + let continuous_weight_count = 0; // 续重次数 + let logArr = []; + let logRun = false; + while (weight > 0) { + if (!first_weight_key) { + // 首重 + first_weight_key = true; + first_weight_count++; + packagesSurplusWeight = max_weight; // 还原包裹剩余重量 + weight -= first_weight; + packagesSurplusWeight -= first_weight; + } else { + // 续重 + continuous_weight_count++; + weight -= continuous_weight; + packagesSurplusWeight -= continuous_weight; + } + if (logRun) logArr.push({ + "总重量剩余": weight, + "当前包裹重量剩余": packagesSurplusWeight, + "当前第几个包裹": first_weight_count, + "续重计算次数": continuous_weight_count + }); + + if (packagesSurplusWeight <= 0) { + // 需要增加一个新的包裹 + first_weight_key = false; // 新包裹设置没有减过首重 + } + } + if (logRun) console.log(JSON.stringify(logArr)); + let total_amount = first_weight_price * first_weight_count + continuous_weight_price * continuous_weight_count; + let res = { + weight: originalWeight, // 商品重量(KG) + first_weight, // 首重步长 + first_weight_price, // 首重单价 + first_weight_count, // 首重计算次数 + continuous_weight, // 续重步长 + continuous_weight_price, // 续重单价 + continuous_weight_count, // 续重计算次数 + first_weight_amount: first_weight_count * first_weight_price, // 首重总金额 + continuous_weight_amount: continuous_weight_price * continuous_weight_count, // 续重总金额 + total_amount, // 最终运费金额 + formula: `${first_weight_price} * ${first_weight_count} + ${continuous_weight_price} * ${continuous_weight_count} = ${total_amount}`, // 运费计算公式 + }; + return res; +}; + + +/** + * 从一个对象中取多个属性,并生成一个全新的对象,会过滤空字符串,空数组,空对象 + * @param {Object} obj 对象 + * @param {Array} keys 键名数组 + * vk.pubfn.getNewObject(obj, keys); + */ +pubfn.getNewObject = function(obj, keys) { + let selectedObj = pubfn.copyObject(obj); + let newObject = {}; + if (keys && keys.length > 0) { + for (let i in keys) { + let key = keys[i]; + if (pubfn.isNotNull(selectedObj[key])) { + newObject[key] = selectedObj[key]; + } + } + } else { + newObject = selectedObj; + } + return newObject; +}; + +/** + * 对象删除指定的字段,返回新的对象 + * @param {Object} data 操作对象 + * @param {Array} deleteKeys 需要删除的键名(数组形式) + * vk.pubfn.deleteObjectKeys(data, deleteKeys); + */ +pubfn.deleteObjectKeys = function(data, deleteKeys = []) { + let newData = {}; + if (data) { + for (let key in data) { + if (deleteKeys.indexOf(key) == -1) { + newData[key] = data[key]; + } + } + } + return newData; +} + +/** + * 数组结构转树形结构 + * @param {Array} treeData 数据源 + * @param {Object} treeProps 树结构配置 + * { id:"_id", parent_id:"parent_id", children:"children",need_field:["_id","name"],deleteParentId:true } + * vk.pubfn.arrayToTree(treeData, treeProps); + */ +pubfn.arrayToTree = pubfn.treeUtil.arrayToTree; +/** + * 树形结构转数组结构 + * @param {Array} treeData 数据源 + * @param {Object} treeProps 树结构配置 + * { id:"_id", parent_id:"parent_id", children:"children", deleteChildren:true } + * vk.pubfn.treeToArray(treeData, treeProps); + */ +pubfn.treeToArray = pubfn.treeUtil.treeToArray; + +/** + * 通配符匹配 + * @param {String} text 被匹配的文本 + * @param {String} expText 通配符规则 + * vk.pubfn.wildcardTestOne(text, expText); + */ +pubfn.wildcardTestOne = function(text, expText) { + if (!expText) return false; + let regExpText = expText.replace(new RegExp("\\*"), "(.*)"); + let startText = expText.indexOf("*") !== 0 ? "^" : ""; + let endText = expText[expText.length - 1] !== "*" ? "$" : ""; + let regExp = new RegExp(startText + regExpText + endText); + return regExp.test(text); +}; +/** + * 通配符匹配 expText支持数组 + * @param {String} text 被匹配的文本 + * @param {String | Array} expText 通配符规则 + * vk.pubfn.wildcardTest(text, expText); + */ +pubfn.wildcardTest = function(text, expText) { + let matchNum = 0; // 被匹配的次数 + let regExp1 = new RegExp("\\*"); + if (typeof expText === "string") { + // 字符串 + if (pubfn.wildcardTestOne(text, expText)) { + matchNum++; + } + } else if (typeof expText === "object") { + // 数组 + for (let i = 0; i < expText.length; i++) { + let expTextItem = expText[i]; + if (pubfn.wildcardTestOne(text, expTextItem)) { + matchNum++; + } + } + } + return matchNum; +} + +/** + * 正则匹配 + * @param {String} text 被匹配的文本 + * @param {String} expText 正则表达式规则 + * vk.pubfn.regExpTestOne(text, expText); + */ +pubfn.regExpTestOne = function(text, expText) { + if (!expText) return false; + let regExp = new RegExp(expText); + return regExp.test(text); +}; + +/** + * 正则匹配 + * @param {String} text 被匹配的文本 + * @param {String || Array} wildcardExp 正则表达式规则 + * vk.pubfn.regExpTest(text, regExp); + */ +pubfn.regExpTest = function(text, expText) { + let matchNum = 0; // 被匹配的次数 + if (typeof expText === "string") { + // 字符串 + if (pubfn.regExpTestOne(text, expText)) { + matchNum++; + } + } else if (typeof expText === "object") { + // 数组 + for (let i = 0; i < expText.length; i++) { + let expTextItem = expText[i]; + if (pubfn.regExpTestOne(text, expTextItem)) { + matchNum++; + } + } + } + return matchNum; +} + +/** + * 产生订单号,不依赖数据库,高并发时性能高(理论上会重复,但概率非常非常低) + * @param {String} prefix 前缀 + * @param {Number} num 位数,建议在25-30之间,默认25 + * vk.pubfn.createOrderNo(); + */ +pubfn.createOrderNo = function(prefix = "", num = 25) { + // 获取当前时间字符串格式如20200803093000123 + let fullTime = vk.pubfn.timeFormat(new Date(), "yyyyMMddhhmmss"); + fullTime = fullTime.substring(2); + let randomNum = num - (prefix + fullTime).length; + return prefix + fullTime + pubfn.random(randomNum); +}; + +const isSnakeCase = new RegExp('_(\\w)', 'g'); +const isCamelCase = new RegExp('[A-Z]', 'g'); + +function parseObjectKeys(obj, type) { + let parserReg; + let parser; + switch (type) { + case 'snake2camel': + parser = pubfn.snake2camel + parserReg = isSnakeCase + break + case 'camel2snake': + parser = pubfn.camel2snake + parserReg = isCamelCase + break + } + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + if (parserReg.test(key)) { + const keyCopy = parser(key) + obj[keyCopy] = obj[key] + delete obj[key] + if (Object.prototype.toString.call((obj[keyCopy])) === '[object Object]') { + obj[keyCopy] = parseObjectKeys(obj[keyCopy], type) + } else if (Array.isArray(obj[keyCopy])) { + obj[keyCopy] = obj[keyCopy].map((item) => { + return parseObjectKeys(item, type) + }) + } + } + } + } + return obj +} +/** + * 字符串 - 蛇形转驼峰 + * @param {String} value + * vk.pubfn.snake2camel(value); + */ +pubfn.snake2camel = function(value) { + return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : '')) +} +/** + * 字符串 - 驼峰转蛇形 + * @param {String} value + * vk.pubfn.camel2snake(value); + */ +pubfn.camel2snake = function(value) { + return value.replace(isCamelCase, str => '_' + str.toLowerCase()) +} + +/** + * 对象内的属性名 - 蛇形转驼峰 + * @param {Object} obj + * vk.pubfn.snake2camelJson(obj); + */ +pubfn.snake2camelJson = function(obj) { + return parseObjectKeys(obj, 'snake2camel'); +}; +/** + * 对象内的属性名 - 驼峰转蛇形 + * @param {Object} obj + * vk.pubfn.camel2snakeJson(obj); + */ +pubfn.camel2snakeJson = function(obj) { + return parseObjectKeys(obj, 'camel2snake'); +}; + +/** + * 将能转成数字的字符串转数字(支持字符串、对象、数组) + * @param {Any} obj + * @param {Object} option 哪些格式需要排除 + * 默认排除 + * mobile:true 手机号,如 15200000001 + * idCard:true 身份证,如 330154202109301214 + * startFrom0:true 第一位是0,且长度大于1的,同时第二位不是.的字符串 如 01,057189101254 + * maxLength:14 超过此长度的字符串排除 + * vk.pubfn.string2Number(obj, option); + */ +pubfn.string2Number = function(obj, option = {}) { + const type = Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); + switch (type) { + case 'string': + if (obj && !isNaN(obj)) { + let { + mobile = true, + idCard = true, + startFrom0 = true, + maxLength = 14, + } = option; + if (obj.length > maxLength) { + return obj; + } else if (mobile && pubfn.test(obj, "mobile")) { + return obj; + } else if (idCard && pubfn.test(obj, "card")) { + return obj; + } else if (startFrom0 && obj.length > 1 && obj.indexOf("0") === 0 && obj.indexOf(".") !== 1) { + return obj; + } + return Number(obj); + } else { + return obj; + } + case 'object': + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + obj[key] = pubfn.string2Number(obj[key]); + } + return obj; + case 'array': + for (let i = 0; i < obj.length; i++) { + obj[i] = pubfn.string2Number(obj[i]); + } + return obj; + default: + return obj; + } +}; + +/** + * 保留小数 + * @param {Number} val 原值 + * @param {Number} precision 精度 + * vk.pubfn.toDecimal(val, 2); + */ +pubfn.toDecimal = function(val, precision = 0) { + if (typeof val === "string") val = Number(val); + return parseFloat(val.toFixed(precision)); +}; + +/** + * 判断文件url的类型 + * @param {String} url 文件的url路径 + * vk.pubfn.getFileType(url); + * 返回值为字符串 + * image 图片 + * video 视频 + * audio 音频 + * other 其他 + */ +pubfn.getFileType = function(url) { + let fileType; + if (pubfn.checkFileSuffix(url, ["png", "jpg", "jpeg", "gif", "bmp", "svg"])) { + fileType = "image"; + } else if (pubfn.checkFileSuffix(url, ["avi", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"])) { + fileType = "video"; + } else if (pubfn.checkFileSuffix(url, ["mp3"])) { + fileType = "audio"; + } else { + fileType = "other"; + } + return fileType; +}; +/** + * 获取文件url的后缀名 + * @param {String} url 文件的url路径,必须带 + * vk.pubfn.getFileSuffix(url); + */ +pubfn.getFileSuffix = function(url) { + let suffix; + let index = url.lastIndexOf("."); + if (index > -1) { + suffix = url.substring(index + 1); + } + return suffix; +}; + +/** + * 判断文件url是否在指定后缀名数组内 + * @param {String} url 文件的url路径 + * @param {Array} list 后缀名列表 + * vk.pubfn.checkFileSuffix(url,["png", "jpg", "jpeg", "gif", "bmp", "svg"]); + */ +pubfn.checkFileSuffix = function(url, list) { + let key = false; + let suffix = pubfn.getFileSuffix(url); + for (let i = 0; i < list.length; i++) { + if (list.indexOf(suffix) > -1) { + key = true; + break; + } + } + return key; +}; +// 前端专属开始 ----------------------------------------------------------- +/** + * 将时间显示成1秒前、1天前 + * @description 主要用于 文章最后回复时间: 1分钟前 + * @param {String || Number} startTime 需要计算的时间 如文章最后回复时间 + * vk.pubfn.dateDiff(startTime); + */ +pubfn.dateDiff = function(startTime, suffix = "前") { + if (!startTime) { + return ""; + } + if (typeof startTime === "string" && !isNaN(startTime)) startTime = Number(startTime); + if (typeof startTime == "number") { + if (startTime.toString().length == 10) startTime *= 1000; + startTime = new Date(startTime); + startTime = pubfn.timeFormat(startTime); + } + if (typeof startTime == "string") { + startTime = startTime.replace("T", " "); + startTime = startTime; + startTime = new Date(startTime.replace(/-/g, "/")); //将-转化为/,使用new Date + } + let endTime = new Date(); //获取当前时间 + let nd = 1000 * 24 * 60 * 60; //一天的毫秒数 + let nh = 1000 * 60 * 60; //一小时的毫秒数 + let nm = 1000 * 60; //一分钟的毫秒数 + let ns = 1000; //一秒钟的毫秒数long diff;try { + let diff = endTime.getTime() - startTime.getTime(); + let day = Math.floor(diff / nd); //计算差多少天 + let hour = Math.floor(diff % nd / nh); //计算差多少小时 + let min = Math.floor(diff % nd % nh / nm); //计算差多少分钟 + let sec = Math.round(diff % nd % nh % nm / ns); //计算差多少秒//输出结果 + let showStr = "1 秒"; + if (day > 0) { + showStr = day + "天"; + } else if (hour > 0) { + showStr = hour + "小时"; + } else if (min > 0) { + showStr = min + "分钟"; + } else if (sec > 0) { + showStr = sec + "秒"; + } + showStr += suffix; + return showStr; +} +/** + * 将时间显示成1秒、1天 + * @description 主要用于 到期时间剩余 : 3天 这样的场景 + * @param {String || Number} endTime 需要计算的时间 如到期时间 + * vk.pubfn.dateDiff2(endTime); + */ +pubfn.dateDiff2 = function(startTime, str = "1秒") { + if (!startTime) { + return ""; + } + if (typeof startTime === "string" && !isNaN(startTime)) startTime = Number(startTime); + if (typeof startTime == "number") { + if (startTime.toString().length == 10) startTime *= 1000; + startTime = new Date(startTime); + startTime = pubfn.timeFormat(startTime); + } + if (typeof startTime == "string") { + startTime = startTime.replace("T", " "); + startTime = startTime; + startTime = new Date(startTime.replace(/-/g, "/")); //将-转化为/,使用new Date + } + let endTime = new Date(); //获取当前时间 + let nd = 1000 * 24 * 60 * 60; //一天的毫秒数 + let nh = 1000 * 60 * 60; //一小时的毫秒数 + let nm = 1000 * 60; //一分钟的毫秒数 + let ns = 1000; //一秒钟的毫秒数long diff;try { + let diff = startTime.getTime() - endTime.getTime(); + let day = Math.floor(diff / nd); + let hour = Math.floor(diff % nd / nh); + let min = Math.floor(diff % nd % nh / nm); + let sec = Math.round(diff % nd % nh % nm / ns); + let showStr = str; + if (day > 0) { + showStr = day + "天"; + } else if (hour > 0) { + showStr = hour + "小时"; + } else if (min > 0) { + showStr = min + "分钟"; + } else if (sec > 0) { + showStr = sec + "秒"; + } + return showStr; +}; +/** + * 将大数字转中文 + * @description 主要用于展示浏览量等不需要非常精确显示的场景 + * 如: + * 3210 -> 3千 + * 31210 -> 3万 + * 1523412 -> 1百万 + * 15234120 ->1千万 + * @param {Number} n 需要转换的数字 + * vk.pubfn.numStr(n); + */ +pubfn.numStr = function(n) { + if (typeof n == "string") { + n = parseFloat(n); + } + let str = n; + if (n < 1000) { + str = n; + } else if (n < 10000) { + let n1 = Math.floor(n / 100); + str = n1 / 10 + "千" + } else if (n < 1000000) { + let n1 = Math.floor(n / 1000); + str = n1 / 10 + "万" + } else if (n < 10000000) { + let n1 = Math.floor(n / 1000000); + str = n1 + "百万" + } else if (n < 100000000) { + let n1 = Math.floor(n / 10000000); + str = n1 + "千万" + } else if (n >= 100000000) { + let n1 = Math.floor(n / 10000000); + str = n1 / 10 + "亿" + } + return str; +}; +/** + * 金额显示过滤器(已分为单位,将100 转成 1) + * @param {Number} money 金额 + * vk.pubfn.priceFilter(money); + */ +pubfn.priceFilter = function(money, defaultValue = "") { + if (pubfn.isNull(money)) { + return defaultValue; + } + if (isNaN(money)) { + return money; + } + if (typeof money == "string") { + money = parseFloat(money); + } + return (money / 100).toFixed(2); +}; +// 金额过滤器 - 只显示小数点左边 +pubfn.priceLeftFilter = function(n) { + let s = ""; + if (n) { + s = pubfn.priceFilter(n).split(".")[0]; + } + return s; +}; +// 金额过滤器 - 只显示小数点右边 +pubfn.priceRightFilter = function(n) { + let s = ""; + if (n) { + s = pubfn.priceFilter(n).split(".")[1]; + } + return s; +}; +/** + * 百分比过滤器 将 0.01 显示成 1% 1 显示成 100% + * @param {Number} value 百分比值 + * @param {Boolean} needShowSymbol 显示 % 这个符号 + * @param {String | Number} defaultValue value为空时的默认值 + * vk.pubfn.percentageFilter(money); + */ +pubfn.percentageFilter = function(value, needShowSymbol = true, defaultValue = "") { + if (pubfn.isNull(value)) { + return defaultValue; + } + if (isNaN(value)) { + return value; + } + if (typeof value == "string") { + value = parseFloat(value); + } + value = parseFloat((value * 100).toFixed(2)); + if (needShowSymbol) { + value += "%"; + } + return value; +}; +/** + * 折扣过滤器 将 0.1 显示成 1折 1 显示成 原价 0 显示成免费 + * @param {Number} value 折扣值 + * @param {Boolean} needShowSymbol 显示 折 这个中文字符 + * @param {String | Number} defaultValue value为空时的默认值 + * vk.pubfn.discountFilter(value); + */ +pubfn.discountFilter = function(value, needShowSymbol = true, defaultValue = "") { + if (pubfn.isNull(value)) { + return defaultValue; + } + if (isNaN(value)) { + return value; + } + if (typeof value == "string") { + value = parseFloat(value); + } + value = parseFloat((value * 10).toFixed(2)); + if (value > 10) { + return "折扣不可以大于原价"; + } + if (value == 10) { + return "原价"; + } + if (value == 0) { + return "免费"; + } + if (value < 0) { + return "折扣不可以小于0"; + } + if (needShowSymbol) { + value += " 折"; + } + return value; +}; +/** + * 将字符串格式的时间转为时间戳 + * @param {String} dateString 格式为:2020-08-08 12:12:12 + */ +pubfn.toTimeLong = function(dateString) { + if (!dateString) { + return ""; + } + dateString = dateString.substring(0, 19); + dateString = dateString.replace(new RegExp(/-/, "g"), '/'); + let time = new Date(dateString).getTime(); + if (isNaN(time)) { + time = ""; + } + return time; +}; + +/** + * 单位进制换算 + * length 换算前大小 + * arr 进制的数组,如["B","KB","MB","GB"] + * ary 进制,如KB-MB-GB,进制1024 + * precision 数值精度 + * vk.pubfn.calcSize(length,["B","KB","MB","GB"],1024,3); + */ +pubfn.calcSize = function(length = 0, arr, ary, precision = 2, showType = "auto") { + length = parseFloat(length); + let size = 0; + let type = ""; + if (length < ary || arr.length <= 1) { + type = arr[0]; + size = parseFloat(length.toFixed(precision)); + } else { + for (let i = 1; i < arr.length; i++) { + let currentType = arr[i]; + length = length / ary; + if (showType === "auto") { + if (length < ary) { + type = currentType; + size = parseFloat(length.toFixed(precision)); + break; + } + } else { + if (showType === currentType) { + type = currentType; + size = parseFloat(length.toFixed(precision)); + break; + } + } + } + } + return { + size: size, + type: type, + title: size + " " + type + } +}; + +/** + * 将一个大数组拆分成N个小数组(分割数组) + * @param {Array} array 大数组 + * @param {Number} size 小数组每组最大多少个 + * 代码示例 + * let newArray = vk.pubfn.splitArray(array, 2); + */ +pubfn.splitArray = function(array, size) { + let data = []; + for (let i = 0; i < array.length; i += size) { + data.push(array.slice(i, i + size)) + } + return data +}; + +/** + * 将对象内的属性按照ASCII字符顺序进行排序,返回排序后的对象 + * @param {Object} obj 需要排序对象 + * 代码示例 + * let newObj = vk.pubfn.objectKeySort(obj); + */ +pubfn.objectKeySort = function(obj) { + let keys = Object.keys(obj).sort(); + let newObject = {}; + for (let i in keys) { + newObject[keys[i]] = (obj[keys[i]]); + } + return newObject; +}; + +// 以下是前端专属API----------------------------------------------------------- + +/** + * 手机端长列表分页加载数据 2.0版本 + * @param {Vue页面对象} that 页面数据对象this + * @param {String} url 请求地址(云函数路径) + * @param {String} listName 后端返回的list数组的字段名称,默认rows(二选一即可) + * @param {String} listKey 后端返回的list数组的字段名称,默认rows(二选一即可) + * @param {String} formKey 表单请求的对象数据源字段名称,默认queryForm1 + * @param {Object} data 额外数据 + * @param {function} dataPreprocess 数据预处理函数 + * + * 代码示例 + vk.pubfn.getListData2({ + that : this, + url : "template/db_api/pub/select", + data : { + a : 1 + }, + dataPreprocess : function(list){ + return list; + } + }); + */ +pubfn.getListData2 = function(obj = {}) { + let vk = uni.vk; + let { + that, + listName, + listKey = "rows", + formKey = "queryForm1", + url, + dataPreprocess, + idKeyName = "_id" + } = obj; + if (listName) listKey = listName; + /** + * 2.0与1.0的区别 + * 2.0使用的queryForm1作为查询,而1.0是form1 + * 2.0云函数端是getTableData,而1.0是selects + */ + let queryForm1 = that[formKey] || that.queryForm1 || that.queryForm; + // 标记为请求中 + that.loading = true; + let hasMore = true; + if (queryForm1.pagination.pageIndex === 1) { + that.firstLoading = true; + } + vk.callFunction({ + url: url, + data: queryForm1, + success: function(data) { + let list = data[listKey] || []; + // 数据预处理 + if (typeof dataPreprocess == "function") { + list = dataPreprocess(list); + } + if (queryForm1.pagination.pageIndex > 1) { + // 翻页 + if (list.length == 0) { + // 无数据时 + hasMore = false; + queryForm1.pagination.pageIndex--; + list = that.data.list; + } else { + // 有数据时 + if (list.length < queryForm1.pagination.pageSize) { + hasMore = false; + } + // 数据合并 + list = vk.pubfn.arr_concat(that.data.list, list, idKeyName); + } + } else if (queryForm1.pagination.pageIndex == 1) { + // 第一页 + if (list.length < queryForm1.pagination.pageSize) { + hasMore = false; + } + if (list.length == 0) { + that.state.isEmpty = true; + } else { + that.state.isEmpty = false; + } + } + // 如果后端返回了hasMore,则使用后端的hasMore值 + if (typeof data.hasMore !== "undefined") { + hasMore = data.hasMore; + } + data = { + ...data, + total: data.total, + list: list, + hasMore: hasMore, + pageIndex: data.pageIndex, + pageSize: data.pageSize + }; + that.state.loadmore = hasMore ? "loadmore" : "nomore"; // 更新状态 + that.data = vk.pubfn.objectAssign(that.data, data); // 更新数据 + if (typeof obj.success == "function") obj.success(data); + }, + fail: function(err) { + that.state.loadmore = "loadmore"; + if (queryForm1.pagination.pageIndex > 1) { + queryForm1.pagination.pageIndex--; + } + if (typeof obj.fail == "function") { + obj.fail(data); + } else if (err && err.msg) { + vk.toast(err.msg, "none"); + } + }, + complete: function(res) { + that.loading = false; + if (queryForm1.pagination.pageIndex === 1) { + that.state.firstLoading = false; + } + if (typeof obj.complete == "function") obj.complete(res); + } + }); +}; + +/** + * 手机端长列表分页加载数据(1.0版本) + * @param {Vue页面对象} that 页面数据对象this + * @param {String} url 请求地址(云函数路径) + * @param {String} listName 后端返回的list数组的字段名称,默认rows + * @param {String} listKey 后端返回的list数组的字段名称,默认rows + * @param {String} formKey 表单请求的对象数据源字段名称,默认form1 + * @param {Object} data 额外数据 + * @param {function} dataPreprocess 数据预处理函数 + * + * 代码示例 + vk.pubfn.getListData({ + that : this, + url : "template/db_api/pub/select", + listKey : "rows", + formKey : "form1", + data : { + a : 1 + }, + dataPreprocess : function(list){ + return list; + } + }); + */ +pubfn.getListData = function(obj = {}) { + let { + that, + listName, + listKey = "rows", + formKey = "form1", + url, + dataPreprocess, + loading + } = obj; + let vk = uni.vk; + if (listName) listKey = listName; + let { data = {} } = that; + let form1 = that[formKey] || {}; + let { pageKey = true } = data; + if (!form1.pageIndex) form1.pageIndex = 1; + if (!form1.pageSize) form1.pageSize = 20; + let addTime = form1.addTime; + let endTime = form1.endTime; + if (endTime) endTime += " 23:59:59"; + if (!pageKey && form1.pageIndex > 1) { + form1.pageIndex--; + return false; + } + + if (addTime) form1.addTimeLong = pubfn.toTimeLong(addTime); + if (endTime) form1.endTimeLong = pubfn.toTimeLong(endTime); + if (obj.data && JSON.stringify(obj.data) != "{}") { + pubfn.objectAssign(form1, obj.data); + } + let title = obj.title; + if (typeof obj.title == "undefined" && !loading) { + title = form1.pageIndex == 1 ? "请求中..." : ""; + } + vk.callFunction({ + url: url, + data: form1, + title: title, + loading: loading, + success: function(data) { + let list = data[listKey] || []; + // 数据预处理 + if (typeof dataPreprocess == "function") { + list = dataPreprocess(list); + } + if (form1.pageIndex > 1) { + // 翻页 + if (list.length == 0) { + // 无数据时 + pageKey = false; + form1.pageIndex--; + list = that.data.list; + } else { + // 有数据时 + if (list.length < form1.pageSize) { + pageKey = false; + } + let oldList = that.data.list; + // 数据合并 + list = pubfn.arr_concat(oldList, list, "_id"); + } + } else if (form1.pageIndex == 1) { + if (list.length < form1.pageSize) { + pageKey = false; + } + } + //console.log(pageKey,list.length,form1.pageSize); + data = { + ...data, + total: data.total, + list: list, + pageKey: pageKey, + loadmore: pageKey ? "loadmore" : "nomore" // 更新状态 + }; + that.data = pubfn.objectAssign(that.data, data); // 更新数据 + if (typeof obj.success == "function") obj.success(data); + }, + fail: function(err) { + if (form1.pageIndex > 1) { form1.pageIndex--; } + if (typeof obj.fail == "function") { + obj.fail(data); + } else if (err && err.msg) { + vk.toast(err.msg, "none"); + } + }, + complete: function(res) { + if (typeof obj.complete == "function") obj.complete(res); + }, + }); +}; + +/** + * 动态组件数据获取 + * @description 主要用于动态组件的数据获取 + * @param {Vue页面对象} that 页面数据对象this + * @param {String} ids 动态数据组件的ID + * + * 代码示例 + * 如:放置一个动态数据的 公告组件 和 一个轮播图组件 + * view 核心:自定义组件接收一个 Object 类型的属性 datas + + + 在页面数据变量中新增 componentsDynamic + data() { + return { + // 动态组件数据集合 + componentsDynamic:{} + } + } + 在页面初始化方法中执行下面的函数 + this.vk.pubfn.getComponentsDynamicData({ + that : this, + ids : ["notice-bar-01","index-swiper-01"] + }); + */ +pubfn.getComponentsDynamicData = function(obj = {}) { + let { + that, + keyName = "componentsDynamic", + title, + url = "plugs/components_dynamic/client/pub/getComponentsDynamicData", + ids + } = obj; + let vk = uni.vk; + let form1 = { + ids: ids + }; + if (obj.data && JSON.stringify(obj.data) != "{}") { + pubfn.objectAssign(form1, obj.data); + } + // 读取缓存开始----------------------------------------------------------- + let cacheKey = "pub-componentsDynamic"; + let cacheData = uni.getStorageSync(cacheKey) || {}; + let cacheDataKey = JSON.stringify(ids); + if (cacheData[cacheDataKey]) { + // 渲染本地数据 + that[keyName] = cacheData[cacheDataKey]; + } + // 读取缓存结束----------------------------------------------------------- + vk.callFunction({ + url: url, + data: form1, + title: title, + success: function(data) { + if (JSON.stringify(cacheData[cacheDataKey]) !== JSON.stringify(data.componentsDynamic)) { + // 渲染服务器数据 + that[keyName] = data.componentsDynamic; + // 同时将组件数据进行缓存 + cacheData[cacheDataKey] = data.componentsDynamic; + uni.setStorageSync(cacheKey, cacheData); + } + if (typeof obj.success == "function") obj.success(data); + }, + fail: function(err) { + console.error(err); + if (typeof obj.fail == "function") obj.fail(data); + }, + complete: function() { + if (typeof obj.complete == "function") obj.complete(data); + }, + }); +}; + +/** + * 将../../ 形式的页面相对路径 转成 页面绝对路径 + * @param {String} url 需要转换的url + * vk.pubfn.getPageFullPath(url); + */ +pubfn.getPageFullPath = function(url) { + let fullPath = url; + if (fullPath.indexOf("/") !== 0) { + if (fullPath.indexOf("./") === 0) { + //fullPath = "." + fullPath; + fullPath = fullPath.substring(2); + } + let urlSplit = fullPath.split("../"); + // 向上目录级数,0:根目录 1:向上1级 + let level = urlSplit.length; + // 尾部路径 + let urlEnd = urlSplit[level - 1]; + // 获取当前页面的页面全路径 + let pages = getCurrentPages(); + let currentPage = pages[pages.length - 1]; + let currentPagePath = currentPage.route; + // 分割成目录,最后一段是页面名称 + let urlArr = currentPagePath.split("/"); + let urlSplicing = ""; + // 开始拼接 + for (let i = 0; i < urlArr.length - level; i++) { + urlSplicing += urlArr[i] + "/"; + } + // 完整页面路径 + fullPath = urlSplicing + urlEnd; + if (fullPath.indexOf("/") != 0) { + fullPath = "/" + fullPath; + } + } + return fullPath; +}; +/** + * 获取平台信息 + * let platform = vk.pubfn.getPlatform(); + */ +pubfn.getPlatform = function() { + let platform; + // #ifdef APP-PLUS || APP-NVUE || APP-PLUS-NVUE + platform = "app-plus"; + // #endif + // #ifdef H5 + platform = "h5"; + // #endif + // #ifdef MP-WEIXIN + platform = "mp-weixin"; + // #endif + // #ifdef MP-ALIPAY + platform = "mp-alipay"; + // #endif + // #ifdef MP-BAIDU + platform = "mp-baidu"; + // #endif + // #ifdef MP-TOUTIAO + platform = "mp-toutiao"; + // #endif + // #ifdef MP-QQ + platform = "mp-qq"; + // #endif + // #ifdef MP-360 + platform = "mp-360"; + // #endif + // #ifdef MP-KUAISHOU + platform = "mp-toutiao"; + // #endif + return platform; +}; +/** + * 获取当前页面实例 + * 返回数据 + * fullPath 当前打开页面的完整路径(带页面参数) + * pagePath 当前打开页面的路径(不含参数) + * options 当前打开页面的参数 + * route 当前打开页面路由地址 + * $vm 当前打开页面的vue实例 + * vk.pubfn.getCurrentPage(); + */ +pubfn.getCurrentPage = function() { + let res = {}; + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + if (page.route.indexOf("/") == 0) page.route = page.route.substring(1); + let pagePath = `/${page.route}`; + let fullPath = `/${page.route}`; + let options = page.options; + if (page.$page) { + if (typeof page.$page.fullPath !== "undefined") { + fullPath = page.$page.fullPath; + } else if (typeof options === "object") { + let optionsStr = pubfn.queryParams(options); + fullPath = pagePath + optionsStr; + } + } + res.fullPath = fullPath; + res.pagePath = pagePath; + res.options = options; + res.route = page.route; + res.$vm = page.$vm; + return res; +}; +/** + * 获取当前页面路由 + * vk.pubfn.getCurrentPageRoute(); + */ +pubfn.getCurrentPageRoute = function(removeSlash) { + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + if (removeSlash) { + return page.route; + } else { + return "/" + page.route; + } +}; +/** + * 文件转base64 + +方式一 + +vk.pubfn.fileToBase64({ + file:res.tempFiles[0], + success:function(base64){ + + } +}); + +方式二 + +vk.pubfn.fileToBase64({ file }).then(base64 => { + +}); + */ +pubfn.fileToBase64 = function(obj = {}) { + let { file } = obj; + let filePath = typeof file === "object" ? file.path : file; + return new Promise(function(resolve, reject) { + // #ifdef H5 + let reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function(res) { + let base64 = this.result; + if (base64.indexOf(";base64,") == -1) { + base64 = "data:image/jpeg;base64," + base64; + } + if (obj.success) obj.success(base64); + if (obj.complete) obj.complete(base64); + resolve(base64); + }; + reader.onerror = function(err) { + if (obj.fail) obj.fail(err); + if (obj.complete) obj.complete(err); + reject(err); + }; + // #endif + // #ifdef MP + uni.getFileSystemManager().readFile({ + filePath: filePath, + encoding: "base64", + success: function(res) { + let base64 = res.data; + if (base64.indexOf(";base64,") == -1) { + base64 = "data:image/jpeg;base64," + base64; + } + if (obj.success) obj.success(base64); + if (obj.complete) obj.complete(base64); + resolve(base64); + }, + fail: function(err) { + if (obj.fail) obj.fail(err); + reject(err); + }, + complete: obj.complete + }); + // let base64 = uni.getFileSystemManager().readFileSync(file.path, 'base64'); + // if(obj.success) obj.success(base64); + // if(obj.complete) obj.complete(base64); + // resolve(base64); + // #endif + // #ifdef APP-PLUS + plus.io.resolveLocalFileSystemURL(pubfn.getLocalFilePath(filePath), function(entry) { + entry.file(function(file) { + let fileReader = new plus.io.FileReader(); + fileReader.onload = function(data) { + if (obj.success) obj.success(data.target.result); + if (obj.complete) obj.complete(data.target.result); + resolve(data.target.result); + } + fileReader.onerror = function(err) { + if (obj.fail) obj.fail(err); + reject(err); + } + fileReader.readAsDataURL(file) + }, function(err) { + if (obj.fail) obj.fail(err); + reject(err); + }) + }, function(err) { + if (obj.fail) obj.fail(err); + reject(err); + }) + // #endif + }); +}; + +/** + * base64转文件 +方式一 + +vk.pubfn.base64ToFile({ + base64:base64, + success:function(file){ + + } +}); + +方式二 + +vk.pubfn.base64ToFile({ base64 }).then(file => { + +}); + */ +pubfn.base64ToFile = function(obj = {}) { + let { + base64 = "", + filePath + } = obj; + let extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/); + if (extName) { + extName = extName[1]; + } else { + reject(new Error('base64 error')); + } + if (!filePath) { + filePath = pubfn.random(32, "abcdefghijklmnopqrstuvwxyz0123456789") + '.' + extName; + } + let index = base64.indexOf("base64,"); + let base64Data = base64; + if (index > -1) { + base64Data = base64.substring(base64.indexOf("base64,") + 7); + } + let savePath; + return new Promise(function(resolve, reject) { + // #ifdef MP + savePath = wx.env.USER_DATA_PATH + '/' + filePath; + let fs = uni.getFileSystemManager(); + fs.writeFile({ + filePath: savePath, + data: base64Data, + encoding: "base64", + success: function(res) { + let file = { + path: savePath, + lastModifiedDate: new Date(), + name: filePath + }; + if (obj.success) obj.success(file); + resolve(file); + }, + fail: function(res) { + if (obj.fail) obj.fail(res); + reject(res); + }, + complete: obj.complete + }); + // #endif + // #ifdef H5 + savePath = filePath; + let blob = pubfn.base64toBlob(base64); + let file = pubfn.blobToFile(blob, savePath); + if (obj.success) obj.success(file); + if (obj.complete) obj.complete(file); + resolve(file); + // #endif + // #ifdef APP-PLUS + let fileName = filePath; + let basePath = '_user_resources'; + let dirPath = 'vk_temp'; + savePath = basePath + '/' + dirPath + '/' + fileName; + let bitmap = new plus.nativeObj.Bitmap(fileName); + bitmap.loadBase64Data(base64, function() { + bitmap.save(savePath, {}, function() { + bitmap.clear(); + let file = { + path: savePath, + lastModifiedDate: new Date(), + name: filePath + }; + if (obj.success) obj.success(file); + if (obj.complete) obj.complete(file); + resolve(file); + }, function(error) { + bitmap.clear(); + if (obj.fail) obj.fail(error); + reject(error); + }) + }, function(error) { + bitmap.clear(); + if (obj.fail) obj.fail(error); + reject(error); + }) + // #endif + }); +}; +/** + * 将base64转换为blob (H5独有) + vk.pubfn.base64toBlob(base64); + */ +pubfn.base64toBlob = function(base64) { + let arr = base64.split(','); + let mime = arr[0].match(/:(.*?);/)[1]; + let bstr = atob(arr[1]); + let n = bstr.length; + let u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); +}; +/** + * //将blob转换为file + vk.pubfn.blobToFile(base64); + */ +pubfn.blobToFile = function(blob, fileName) { + blob.lastModifiedDate = new Date(); + blob.name = fileName; + blob.path = URL.createObjectURL(blob); + return blob; +}; + +/** + * 小程序订阅消息 前端无需再写 #ifdef MP-WEIXIN + vk.pubfn.requestSubscribeMessage({ + tmplIds: ['NcspDBQpH6CGHos3mMADrrQpEv2gHmtfOPa5KTLs92E'] + }); + */ +pubfn.requestSubscribeMessage = function(obj) { + // #ifdef MP-WEIXIN + return uni.requestSubscribeMessage(obj); + // #endif +}; + +/** + * 检测是否需要登录 此方法目前为测试版 + * vk.pubfn.checkLogin(); + */ +pubfn.checkLogin = function(obj = {}) { + let vk = uni.vk; + let loginUrl = vk.getConfig("login.url"); + try { + let url; + try { + url = obj.url || vk.pubfn.getCurrentPageRoute(); + } catch (err) { + url = vk.getConfig("index.url") || "/pages/index/index"; + } + vk.navigate.checkNeedLogin({ + url: url, + success: function(res) { + if (res.needLogin) { + // 记录下原本要跳转的页面 + url = vk.pubfn.getPageFullPath(obj.fullPath || url); + vk.navigate.setOriginalPage({ url }); + if (obj.isOnLaunch) vk.navigate.isOnLaunchToLogin = true; // 标记为首次启动的页面需要登录 + uni.reLaunch({ + url: loginUrl, + success: () => { + // #ifdef MP-WEIXIN + setTimeout(() => { + uni.hideHomeButton(); + }, 400); + // #endif + } + }); + } else { + // #ifdef H5 + // 解决微信公众号登录无法跳回原页面的问题 + if (!obj.options || !obj.options.code || !obj.options.state) { + vk.navigate.setOriginalPage(null); + } + // #endif + // #ifndef H5 + vk.navigate.setOriginalPage(null); + // #endif + } + } + }); + } catch (err) { + console.error("catch", err); + uni.reLaunch({ + url: loginUrl + }); + // #ifdef MP-WEIXIN + uni.hideHomeButton(); + // #endif + } +}; +/** + * 获取文件本地路径 + * @param {Object} path + */ +pubfn.getLocalFilePath = function(path) { + if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) { + return path + } + if (path.indexOf('file://') === 0) { + return path + } + if (path.indexOf('/storage/emulated/0/') === 0) { + return path + } + if (path.indexOf('/') === 0 && typeof plus !== "undefined") { + let localFilePath = plus.io.convertAbsoluteFileSystem(path) + if (localFilePath !== path) { + return localFilePath + } else { + path = path.substr(1) + } + } + return '_www/' + path +}; + +/** + * 获取当前支持的应用语言 + * let localeList = vk.pubfn.getLocaleList(); + */ +pubfn.getLocaleList = function() { + let localeList = [ + { value: "zh-Hans", label: "简体中文" }, + { value: "zh-Hant", label: "繁體中文" }, + { value: "en", label: "English" } + ]; + return localeList; +}; +/** + * 获取当前应用语言 + * let locale = vk.pubfn.getLocale(); + */ +pubfn.getLocale = function() { + let localeValue; + if (typeof uni.getLocale === "function") { + localeValue = uni.getLocale(); + } else { + localeValue = "zh-Hans"; // 默认中文简体 + } + let localeObj = { + "zh_CN": "zh-Hans", // 中国大陆(简体) + "zh_HK": "zh-Hant", // 香港(繁体) + "zh_MO": "zh-Hant", // 澳门(繁体) + "zh_SG": "zh-Hans", // 新加坡(简体) + "zh_TW": "zh-Hant", // 台湾(繁体) + }; + if (localeObj[localeValue]) localeValue = localeObj[localeValue]; + return localeValue; +}; +/** + * 获取当前应用语言 + * let localeObj = vk.pubfn.getLocaleObject(); + */ +pubfn.getLocaleObject = function() { + let value = pubfn.getLocale(); + let list = pubfn.getLocaleList(); + return pubfn.getListItem(list, "value", value); +}; +/** + * 设置当前应用语言 + */ +pubfn.setLocale = function(...e) { + return uni.setLocale(...e); +}; + +/** + * 将obj2的数据赋值给obj1,并使vue双向绑定(vue2对象新增属性不会双向绑定) + * @description 将 obj2 的属性赋值给 obj1 (如果obj1中有对应的属性,则会被obj2的属性值覆盖) + * @param {Object} obj1 + * @param {Object} obj2 + * @param {Object} that 页面实例 + * vk.pubfn.objectAssignForVue(obj1, obj2, that); + */ +pubfn.objectAssignForVue = function(obj1, obj2, that) { + pubfn.objectDeleteInvalid(obj2); + for (let key in obj2) { + that.$set(obj1, key, obj2[key]); + } +}; + +// 前端专属结束 ----------------------------------------------------------- +export default pubfn; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js new file mode 100644 index 0000000..61ffb06 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/modal.js @@ -0,0 +1,297 @@ +/** + * 函数 - 弹窗 + */ +const localeObj = { + title: { + "zh-Hans": "提示", + "zh-Hant": "提示", + "en": "Tips" + }, + confirmText: { + "zh-Hans": "确定", + "zh-Hant": "確定", + "en": "OK" + }, + cancelText: { + "zh-Hans": "取消", + "zh-Hant": "取消", + "en": "Cancel" + }, + placeholderText: { + "zh-Hans": "请输入", + "zh-Hant": "請輸入", + "en": "Please enter" + } +}; +export default { + /** + vk.alert("内容"); + vk.alert("内容","提示","好的",function(){ + + }); + */ + alert: function(a = " ", b, c, d) { + let vk = uni.vk; + let locale = vk.getLocale(); + let obj = { + title: localeObj.title[locale], + confirmText: localeObj.confirmText[locale], + placeholderText: localeObj.placeholderText[locale], + content: a, + showCancel: false + }; + if (typeof d === 'function') { + obj.title = b; + obj.confirmText = c; + obj.success = d; + } else if (typeof c === 'function') { + obj.title = b; + obj.success = c; + } else if (typeof b === 'function') { + obj.success = b; + } else if (b != undefined) { + obj.title = b; + if (c != undefined) { + obj.confirmText = c; + } + } + if (typeof obj.content === 'number') { + obj.content = obj.content + ""; + } else if (typeof obj.content === 'object') { + obj.content = JSON.stringify(obj.content); + } + return uni.showModal(obj); + }, + /** + vk.confirm("内容","提示","确定","取消",(res) => { + if(res.confirm){ + + } + }); + */ + confirm: function(a, b, c, d, e) { + let vk = uni.vk; + let locale = vk.getLocale(); + let obj = { + showCancel: true, + cancelColor: "#999", + title: localeObj.title[locale], + confirmText: localeObj.confirmText[locale], + cancelText: localeObj.cancelText[locale], + placeholderText: localeObj.placeholderText[locale], + }; + if (typeof a === "object") { + obj = a; + } else { + if (typeof a === "string") { + obj.content = a; + } + if (typeof e === 'function') { + obj.title = b; + obj.confirmText = c; + obj.cancelText = d; + obj.success = e; + } else if (typeof d === 'function') { + obj.title = b; + obj.confirmText = c; + obj.success = d; + } else if (typeof c === 'function') { + obj.title = b; + obj.success = c; + } else if (typeof b === 'function') { + obj.success = b; + } else if (b != undefined) { + obj.title = b; + if (c != undefined) { + obj.confirmText = c; + } + } + } + return uni.showModal(obj); + }, + /** + vk.prompt("请输入","提示","确定","取消",function(res){ + if(res.confirm){ + console.log(res.content); + } + },"输入框内初始内容"); + */ + prompt: function(a, b, c, d, e, f) { + let vk = uni.vk; + let locale = vk.getLocale(); + let obj = { + showCancel: true, + editable: true, + cancelColor: "#999", + title: localeObj.title[locale], + confirmText: localeObj.confirmText[locale], + cancelText: localeObj.cancelText[locale], + placeholderText: localeObj.placeholderText[locale], + }; + if (typeof a === "object") { + obj = a; + } else { + if (typeof a === "string") { + obj.placeholderText = a; + } + if (typeof e === 'function') { + obj.title = b; + obj.confirmText = c; + obj.cancelText = d; + obj.success = e; + obj.content = f; + } else if (typeof d === 'function') { + obj.title = b; + obj.confirmText = c; + obj.success = d; + obj.content = e; + } else if (typeof c === 'function') { + obj.title = b; + obj.success = c; + obj.content = d; + } else if (typeof b === 'function') { + obj.success = b; + obj.content = c; + } + } + return uni.showModal(obj); + }, + /** + vk.toast("提示内容","none"); + */ + toast: function(a, b, c, d, e) { + let vk = uni.vk; + if (typeof a === 'number') { + a = a.toString(); + } else if (typeof a === 'object') { + a = JSON.stringify(a); + } + let title = a; + let icon = "none"; + let image = ""; + let mask = false; + let duration = 1500; + let fn; + + if (typeof e !== "undefined") { + if (typeof e == "function") fn = e; + if (typeof e == "number") duration = e; + if (typeof e == "boolean") mask = e; + } + if (typeof d !== "undefined") { + if (typeof d == "function") fn = d; + if (typeof d == "number") duration = d; + if (typeof d == "boolean") mask = d; + } + if (typeof c !== "undefined") { + if (typeof c == "function") fn = c; + if (typeof c == "number") duration = c; + if (typeof c == "boolean") mask = c; + } + + if (typeof b !== "undefined") { + if (typeof b == "function") fn = b; + if (typeof b == "number") duration = b; + if (typeof b == "boolean") mask = b; + if (typeof b == 'string') { + if (b == "ok") b = "success"; + if (b == "success" || b == "loading" || b == "none" || b == "error") { + icon = b; + } else { + image = b; + } + } + } + return uni.showToast({ + title: title, + icon: icon, + image: image, + mask: mask, + duration: duration, + success: function(res) { + if (typeof fn === 'function') { + setTimeout(function() { + fn(res); + }, duration); + } + } + }); + }, + /** + * 操作菜单 + vk.showActionSheet({ + title:"", + list:["位置","@好友"], + color:"rgb(0, 0, 0)", + success:function(res){ + if(res.index==0){ + + }else if(res.index==1){ + + } + } + }); + */ + showActionSheet: function(object) { + let vk = uni.vk; + let title = object.title; + let list = object.list; + let color = object.color || "#000000"; + let success = object.success; + let fail = object.fail; + let complete = object.complete; + return uni.showActionSheet({ + itemList: list, + itemColor: color, + success: function(res) { + let index = res.tapIndex; + let text = list[index]; + let g = { index, text }; + //console.log(g); + if (typeof success == "function") success(g); + }, + fail: function(res) { + //console.log(res); + if (typeof fail == "function") fail(res); + }, + complete: function(res) { + if (typeof complete == "function") complete(res); + } + }); + }, + showLoading: function(obj) { + if (typeof obj == "string") { + let title = obj; + obj = { + title: title, + mask: true + }; + } + uni.showLoading(obj); + }, + hideLoading: function() { + uni.hideLoading(); + }, + // 设置当前页面的loading变量的值 + setLoading: function(loading = true, obj = true) { + try { + let vk = uni.vk; + if (typeof obj === "boolean") { + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + let that = page.$vm; + that.loading = loading; + } else if (typeof obj === "object") { + let { data, name, that } = obj; + if (!data) data = that; + vk.pubfn.setData(data, name, loading); + } else if (typeof obj === "string") { + let pages = getCurrentPages(); + let page = pages[pages.length - 1]; + let that = page.$vm; + let name = obj; + vk.pubfn.setData(that, name, loading); + } + } catch (err) {} + }, +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js new file mode 100644 index 0000000..e79e439 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/permission.js @@ -0,0 +1,33 @@ +function $hasRole(...args) { + const userRoles = this.$store.state.$user.userInfo.role || []; + return args.some(arg => { + if (Array.isArray(arg)) { + return arg.every(role => userRoles.includes(role)); + } else { + return userRoles.includes(arg); + } + }); +} + +function $hasPermission(...args) { + const userPermission = this.$store.state.$user.permission || [] + return args.some(arg => { + if (Array.isArray(arg)) { + return arg.every(permission => userPermission.includes(permission)); + } else { + return userPermission.includes(arg); + } + }); +} + +export default function(Vue) { + // #ifndef VUE3 + Vue.prototype.$hasRole = $hasRole; + Vue.prototype.$hasPermission = $hasPermission; + // #endif + + // #ifdef VUE3 + Vue.config.globalProperties.$hasRole = $hasRole; + Vue.config.globalProperties.$hasPermission = $hasPermission; + // #endif +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js new file mode 100644 index 0000000..e2cc086 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/queryParams.js @@ -0,0 +1,60 @@ +/** + * 对象转url参数 + * @param {*} data,对象 + * @param {*} isPrefix,是否自动加上"?" + * 此函数参考uView + */ +function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') { + let newData = JSON.parse(JSON.stringify(data)); + let prefix = isPrefix ? '?' : '' + let _result = [] + if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'; + for (let key in newData) { + let value = newData[key] + // 去掉为空的参数 + if (['', undefined, null].indexOf(value) >= 0) { + continue; + } + // 如果值为数组,另行处理 + if (value.constructor === Array) { + // e.g. {ids: [1, 2, 3]} + switch (arrayFormat) { + case 'indices': + // 结果: ids[0]=1&ids[1]=2&ids[2]=3 + for (let i = 0; i < value.length; i++) { + _result.push(key + '[' + i + ']=' + value[i]) + } + break; + case 'brackets': + // 结果: ids[]=1&ids[]=2&ids[]=3 + value.forEach(_value => { + _result.push(key + '[]=' + _value) + }) + break; + case 'repeat': + // 结果: ids=1&ids=2&ids=3 + value.forEach(_value => { + _result.push(key + '=' + _value) + }) + break; + case 'comma': + // 结果: ids=1,2,3 + let commaStr = ""; + value.forEach(_value => { + commaStr += (commaStr ? "," : "") + _value; + }) + _result.push(key + '=' + commaStr) + break; + default: + value.forEach(_value => { + _result.push(key + '[]=' + _value) + }) + } + } else { + _result.push(key + '=' + value) + } + } + return _result.length ? prefix + _result.join('&') : '' +} + +export default queryParams; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js new file mode 100644 index 0000000..71d5773 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/setClipboardData.js @@ -0,0 +1,51 @@ + +// #ifdef H5 + uni.setClipboardData = function setClipboardData({ + data, + success, + fail, + complete + } = {}) { + try { + const x = window.scrollX + const y = window.scrollY + const input = document.createElement('input') + input.setAttribute('readonly', 'readonly') + input.setAttribute('value', data) + input.style.position = 'absolute' + input.style.width = '100px' + input.style.left = '-10000px' + document.body.appendChild(input) + input.focus() + window.scrollTo(x, y) + input.setSelectionRange(0, input.value.length) + document.execCommand('copy') + document.body.removeChild(input) + setTimeout(() => { + const res = { + errMsg: 'setClipboardData:ok', + data + } + success && success(res) + complete && complete(res) + }) + } catch (e) { + setTimeout(() => { + const res = { + errMsg: 'setClipboardData:fail' + } + fail && fail(res) + complete && complete(res) + }) + } + } + // #endif + +// JS对象深度合并 +function setClipboardData(obj = {}) { + uni.setClipboardData({ + ...obj + }); +} + +export default setClipboardData; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js new file mode 100644 index 0000000..60cd436 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/throttle.js @@ -0,0 +1,37 @@ +let timeoutArr = []; +let flagArr = []; +/** + * 节流函数 + * 节流原理:在一定时间内,只能触发一次 + * @param {Function} fn 要执行的回调函数 + * @param {Number} time 延时的时间 + * @param {Boolean} isImmediate 是否立即执行 + * @param {String} timeoutName 定时器ID + * @return null +vk.pubfn.throttle(function() { + +}, 1000); + */ +function throttle(fn, time = 500, isImmediate = true, timeoutName = "default") { + if(!timeoutArr[timeoutName]) timeoutArr[timeoutName] = null; + if (isImmediate) { + if (!flagArr[timeoutName]) { + flagArr[timeoutName] = true; + // 如果是立即执行,则在time毫秒内开始时执行 + if(typeof fn === 'function') fn(); + timeoutArr[timeoutName] = setTimeout(() => { + flagArr[timeoutName] = false; + }, time); + } + } else { + if (!flagArr[timeoutName]) { + flagArr[timeoutName] = true; + // 如果是非立即执行,则在time毫秒内的结束处执行 + timeoutArr[timeoutName] = setTimeout(() => { + flagArr[timeoutName] = false; + if(typeof fn === 'function') fn(); + }, time); + } + } +}; +export default throttle \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js new file mode 100644 index 0000000..dc2b4c3 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/timeUtil.js @@ -0,0 +1,642 @@ +/** + * 时间工具类 + */ +var util = {}; +util.getTargetTimezone = function(val) { + if (typeof val === "number") { + return val; + } + let vk = uni.vk; + let defaultValue = 8; + let targetTimezone = defaultValue; + try { + const config = vk.callFunctionUtil.getConfig(); + targetTimezone = config.targetTimezone; + if (typeof targetTimezone !== "number") { + targetTimezone = defaultValue; + } + } catch (err) {} + return targetTimezone; +}; + +// 尽可能的将参数转成正确的时间对象 +util.getDateObject = function(date, targetTimezone) { + if (!date) return ""; + let nowDate; + // 如果是字符串,且纯数字,则强制转数值 + if (typeof date === "string" && !isNaN(date) && date.length >= 10) date = Number(date); + if (typeof date === "number") { + if (date.toString().length == 10) date *= 1000; + nowDate = new Date(date); // 转时间对象 + } else if (typeof date === "object") { + nowDate = new Date(date.getTime()); // 新建一个时间对象 + } else if (typeof date === "string") { + targetTimezone = util.getTargetTimezone(targetTimezone); + let targetTimezoneStr = targetTimezone; + let targetTimezoneF = targetTimezone >= 0 ? "+" : ""; + if (targetTimezone >= 0 && targetTimezone < 10) { + targetTimezoneStr = `0${targetTimezone}`; + } else if (targetTimezone < 0 && targetTimezone > -10) { + targetTimezoneStr = `-0${targetTimezone*-1}`; + } + let arr1 = date.split(" "); + let arr1_1 = arr1[0] || ""; + let arr1_2 = arr1[1] || ""; + let arr2; + if (arr1_1.indexOf("-") > -1) { + arr2 = arr1_1.split("-"); + } else { + arr2 = arr1_1.split("/"); + } + let arr3 = arr1_2.split(":"); + let dateObj = { + year: Number(arr2[0]), + month: Number(arr2[1]) || 1, + day: Number(arr2[2]) || 1, + hour: Number(arr3[0]) || 0, + minute: Number(arr3[1]) || 0, + second: Number(arr3[2]) || 0, + }; + for (let key in dateObj) { + if (dateObj[key] >= 0 && dateObj[key] < 10) dateObj[key] = `0${dateObj[key]}`; + } + // 格式 2022-10-01T00:00:00+08:00 + let dateStr = `${dateObj.year}-${dateObj.month}-${dateObj.day}T${dateObj.hour}:${dateObj.minute}:${dateObj.second}${targetTimezoneF}${targetTimezoneStr}:00`; + nowDate = new Date(dateStr); + } + return nowDate; +}; + +// 获取时间在不同时区下的时间对象 +util.getTimeByTimeZone = function(date, targetTimezone) { + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + let timezoneOffset = nowDate.getTimezoneOffset(); + let offset = timezoneOffset * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let targetTime = nowDate.getTime() + offset; + nowDate = new Date(targetTime); + return nowDate; +}; + + +/** + * 日期格式化 + * @param {Date || Number} date 需要格式化的时间 + * vk.pubfn.timeFormat(new Date(),"yyyy-MM-dd hh:mm:ss"); + */ +util.timeFormat = function(date, fmt = 'yyyy-MM-dd hh:mm:ss', targetTimezone) { + try { + if (!date) return ""; + targetTimezone = util.getTargetTimezone(targetTimezone); + let nowDate = util.getTimeByTimeZone(date, targetTimezone); + let opt = { + "M+": nowDate.getMonth() + 1, //月份 + "d+": nowDate.getDate(), //日 + "h+": nowDate.getHours(), //小时 + "m+": nowDate.getMinutes(), //分 + "s+": nowDate.getSeconds(), //秒 + "q+": Math.floor((nowDate.getMonth() + 3) / 3), //季度 + "S": nowDate.getMilliseconds(), //毫秒 + "Z": `${targetTimezone >= 0 ? '+' : '-'}${Math.abs(targetTimezone).toString().padStart(2, '0')}:00` // 时区 + }; + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (nowDate.getFullYear() + "").substr(4 - RegExp.$1.length)); + } + for (let k in opt) { + if (new RegExp("(" + k + ")").test(fmt)) { + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (opt[k]) : (("00" + opt[k]).substr(("" + opt[k]).length))); + } + } + return fmt; + } catch (err) { + // 若格式错误,则原值显示 + return time; + } +}; + + +/** + * 解析日期对象属性 + * @param {Date || Number} date 需要转换的时间 + * vk.pubfn.getDateInfo(new Date()); + */ +util.getDateInfo = function(date = new Date(), targetTimezone) { + let nowDate = util.getTimeByTimeZone(date, targetTimezone); + let year = nowDate.getFullYear() + ''; + let month = (nowDate.getMonth() + 1 < 10 ? '0' + (nowDate.getMonth() + 1) : nowDate.getMonth() + 1); + let day = (nowDate.getDate() < 10 ? '0' + (nowDate.getDate()) : nowDate.getDate()); + let hour = (nowDate.getHours() < 10 ? '0' + (nowDate.getHours()) : nowDate.getHours()); + let minute = (nowDate.getMinutes() < 10 ? '0' + (nowDate.getMinutes()) : nowDate.getMinutes()); + let second = (nowDate.getSeconds() < 10 ? '0' + (nowDate.getSeconds()) : nowDate.getSeconds()); + let millisecond = nowDate.getMilliseconds(); //毫秒 + let week = nowDate.getDay(); // 周 + let quarter = Math.floor((nowDate.getMonth() + 3) / 3); //季度 + return { + year: Number(year), + month: Number(month), + day: Number(day), + hour: Number(hour), + minute: Number(minute), + second: Number(second), + millisecond: Number(millisecond), + week: Number(week), + quarter: Number(quarter), + }; +}; + + +/** + * 获取时间范围 + * @param {Date} date 日期对象 可以指定时间计算节点,默认使用当前时间进行计算 + * 返回的是时间戳 + * 返回数据如下: + { + todayStart 今日开始时间(时间戳) + todayEnd 今日结束时间(时间戳) + today12End 今日上午结束时间(时间戳) + monthStart 本月开始时间(时间戳) + monthEnd 本月结束时间(时间戳) + yearStart 本年开始时间(时间戳) + yearEnd 本年结束时间(时间戳) + weekStart 本周开始时间(时间戳) + weekEnd 本周结束时间(时间戳) + hourStart 当前小时开始时间(时间戳) + hourEnd 当前小时结束时间(时间戳) + yesterdayStart 昨天开始时间(时间戳) + yesterday12End 昨天上午结束时间(时间戳) + yesterdayEnd 昨天结束时间(时间戳) + lastMonthStart 上月开始时间(时间戳) + lastMonthEnd 上月结束时间(时间戳) + now 现在的时间点(含月年日时分秒) + months 本年度每月的开始和结束时间 months[1] 代表1月 + days 本月每天的开始和结束时间 days[1] 代表1日 + } + * vk.pubfn.getCommonTime(); + */ +util.getCommonTime = function(date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const { year, month, day, hour, minute, second, millisecond, week, quarter } = util.getDateInfo(nowDate, targetTimezone); + const oneDayTime = 24 * 60 * 60 * 1000; + // 现在的时间 + res.now = { + year, + month, + day, + hour, + minute, + second, + millisecond, + week, + quarter, + date_str: util.timeFormat(nowDate, "yyyy-MM-dd hh:mm:ss", targetTimezone), + date_day_str: util.timeFormat(nowDate, "yyyy-MM-dd", targetTimezone), + date_month_str: util.timeFormat(nowDate, "yyyy-MM", targetTimezone), + }; + // 获取本月最大天数 + let month_last_day = new Date(year, month, 0).getDate(); + // 获取今年12月最大天数 + let year_last_day = new Date(year, 12, 0).getDate(); + // 今日开始时间 + res.todayStart = new Date(`${year}/${month}/${day}`).getTime() - timeDif; + // 今日12点时间 + res.today12End = new Date(`${year}/${month}/${day}`).getTime() + (12 * 60 * 60 * 1000 - 1) - timeDif; + // 今日结束时间 + res.todayEnd = new Date(`${year}/${month}/${day}`).getTime() + (oneDayTime - 1) - timeDif; + // 本月开始时间 + res.monthStart = new Date(`${year}/${month}/1`).getTime() - timeDif; + // 本月结束时间 + res.monthEnd = new Date(`${year}/${month}/${month_last_day}`).getTime() + (oneDayTime - 1) - timeDif; + // 本年开始时间 + res.yearStart = new Date(`${year}/1/1`).getTime() - timeDif; + // 本年结束时间 + res.yearEnd = new Date(`${year}/12/${year_last_day}`).getTime() + (oneDayTime - 1) - timeDif; + // 当前小时开始时间 + res.hourStart = new Date(`${year}/${month}/${day} ${hour}:00:00`).getTime() - timeDif; + // 当前小时结束时间 + res.hourEnd = new Date(`${year}/${month}/${day} ${hour}:59:59`).getTime() - timeDif; + // 计算上月开始----------------------------------------------------------- + let year_last = year; + let month_last = month - 1; + if (month_last === 0) { + month_last = 12; + year_last = year - 1; + } + let month_last_day_last = new Date(year_last, month_last, 0).getDate(); + // 上月开始时间 + res.lastMonthStart = new Date(`${year_last}/${month_last}/1`).getTime() - timeDif; + // 上月结束时间 + res.lastMonthEnd = new Date(`${year_last}/${month_last}/${month_last_day_last}`).getTime() + (oneDayTime - 1) - timeDif; + // 计算上月结束----------------------------------------------------------- + + // 昨天开始时间 + res.yesterdayStart = res.todayStart - 1000 * 3600 * 24; + // 昨天上午结束时间 + res.yesterday12End = res.today12End - 1000 * 3600 * 24; + // 昨天结束时间 + res.yesterdayEnd = res.todayEnd - 1000 * 3600 * 24; + + let weekObj = util.getWeekOffsetStartAndEnd(0, nowDate, targetTimezone); + // 本周开始时间 + res.weekStart = weekObj.startTime; + // 本周结束时间 + res.weekEnd = weekObj.endTime; + // 本年1-12月的起止时间 + res.months = []; + res.months[0] = { + startTime: res.monthStart, + endTime: res.monthEnd, + startTimeStr: util.timeFormat(res.monthStart, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(res.monthEnd, "yyyy-MM-dd hh:mm:ss", targetTimezone), + monthStart: res.monthStart, // 兼容旧版 + monthEnd: res.monthEnd, // 兼容旧版 + }; + for (let i = 1; i <= 12; i++) { + // 获取此月最大天数 + let month_last_day = new Date(year, i, 0).getDate(); + // 此月开始时间 + let startTime = new Date(`${year}/${i}/1`).getTime() - timeDif; + // 此月结束时间 + let endTime = new Date(`${year}/${i}/${month_last_day}`).getTime() + (oneDayTime - 1) - timeDif; + res.months[i] = { + startTime, + endTime, + startTimeStr: util.timeFormat(startTime, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(endTime, "yyyy-MM-dd hh:mm:ss", targetTimezone), + monthStart: startTime, // 兼容旧版 + monthEnd: endTime, // 兼容旧版 + }; + } + // 本月1号到最后一天每天的起止时间 + res.days = []; + res.days[0] = { + startTime: res.todayStart, + endTime: res.todayEnd, + startTimeStr: util.timeFormat(res.todayStart, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(res.todayEnd, "yyyy-MM-dd hh:mm:ss", targetTimezone) + }; + for (let i = 1; i <= month_last_day; i++) { + let nowTime = res.monthStart + ((i - 1) * oneDayTime); + let { startTime, endTime } = util.getDayOffsetStartAndEnd(0, nowTime, targetTimezone); + res.days[i] = { + startTime, + endTime, + startTimeStr: util.timeFormat(startTime, "yyyy-MM-dd hh:mm:ss", targetTimezone), + endTimeStr: util.timeFormat(endTime, "yyyy-MM-dd hh:mm:ss", targetTimezone) + }; + } + for (let key in res) { + if (typeof res[key] === "number" && res[key].toString().length === 13) { + res[`${key}Str`] = util.timeFormat(res[key], "yyyy-MM-dd hh:mm:ss", targetTimezone); + } + } + return res; +}; + +/** + * 获得指定年份和月份后的该月的开始时间和结束时间 + * 返回数据如下:(时间戳形式) + { + startTime 该月开始时间 + endTime 该月结束时间 + } +vk.pubfn.getMonthStartAndEnd({ + year:2021 + month:1 +}); + */ +util.getMonthStartAndEnd = function(obj, targetTimezone) { + targetTimezone = util.getTargetTimezone(targetTimezone); + let res = { + startTime: null, + endTime: null + }; + let { year, month } = obj; + if (year > 0 && month > 0) { + const dif = new Date().getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let month_last_day = new Date(year, month, 0).getDate(); + // 开始时间 + res.startTime = new Date(`${year}/${month}/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${year}/${month}/${month_last_day}`).getTime() + (24 * 60 * 60 * 1000 - 1) - timeDif; + } + return res; +} + +/** + * 获得相对当前时间的偏移 count 小时的起止日期(返回小时的开始和结束时间戳) + * @param {Number} count 默认0(0代表当前小时 -1代表上一个小时 1代表下一个小时以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getHourOffsetStartAndEnd(0); + */ +util.getHourOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + let res = {}; + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + // 一天的毫秒数 + let offsetMillisecond = 1000 * 60 * 60; + // 相对于当前日期count个天的日期 + nowDate = new Date(nowDate.getTime() + (offsetMillisecond * 1 * count)); + let dateInfo = util.getDateInfo(nowDate); + // 获得当天的起始时间 + res.startTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day} ${dateInfo.hour}:00:00`).getTime() - timeDif; + // 获得当天的结束时间 + res.endTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day} ${dateInfo.hour}:00:00`).getTime() + (offsetMillisecond - 1) - timeDif; + return res; +} + + +/** + * 获得相对当前时间的偏移 count 天的起止日期(返回日的开始和结束) + * @param {Number} count 默认0(0代表今日 -1代表昨日 1代表明日以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getDayOffsetStartAndEnd(0); + */ +util.getDayOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + let res = {}; + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + // 一天的毫秒数 + let offsetMillisecond = 1000 * 60 * 60 * 24; + // 相对于当前日期count个天的日期 + nowDate = new Date(nowDate.getTime() + (offsetMillisecond * 1 * count)); + let dateInfo = util.getDateInfo(nowDate); + // 获得当天的起始时间 + res.startTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day}`).getTime() - timeDif; + // 获得当天的结束时间 + res.endTime = new Date(`${dateInfo.year}/${dateInfo.month}/${dateInfo.day}`).getTime() + (offsetMillisecond - 1) - timeDif; + return res; +} + +/** + * 获得相对当前周count个周的起止日期(返回周的开始和结束) + * @param {Number} count 默认0(0代表本周 -1代表上周 1代表下周以此类推) + * vk.pubfn.getWeekOffsetStartAndEnd(0); + */ +util.getWeekOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let nowDay = nowDate.getDay() === 0 ? 7 : nowDate.getDay(); + nowDate.setDate(nowDate.getDate() - nowDay + 1 + count * 7); + let dateInfo1 = util.getDateInfo(nowDate); + nowDate.setDate(nowDate.getDate() + 7); + let dateInfo2 = util.getDateInfo(nowDate); + // 开始时间 + res.startTime = new Date(`${dateInfo1.year}/${dateInfo1.month}/${dateInfo1.day}`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${dateInfo2.year}/${dateInfo2.month}/${dateInfo2.day}`).getTime() - 1 - timeDif; + return res; +} + +/** + * 获得相对当前时间的偏移 count 个月的起止日期(月的开始和结束时间戳) + * @param {Number} count 默认0(0代表本月 -1代表上月 1代表下月以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getMonthOffsetStartAndEnd(0); + */ +util.getMonthOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let dateInfo = util.getDateInfo(nowDate); + let month = dateInfo.month + count; + let year = dateInfo.year; + if (month > 12) { + year = year + Math.floor(month / 12); + month = Math.abs(month) % 12; + } else if (month <= 0) { + year = year - 1 - Math.floor(Math.abs(month) / 12); + month = 12 - Math.abs(month) % 12; + } + let month_last_day = new Date(year, month, 0).getDate(); + // 开始时间 + res.startTime = new Date(`${year}/${month}/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${year}/${month}/${month_last_day}`).getTime() + (24 * 60 * 60 * 1000 - 1) - timeDif; + return res; +} + + +/** + * 获得相对当前时间的偏移 count 个季度的起止日期(季度的开始和结束时间戳) + * @param {Number} count 默认0(0代表本季度 -1代表上个季度 1代表下个季度以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getQuarterOffsetStartAndEnd(0); + */ +util.getQuarterOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + nowDate.setMonth(nowDate.getMonth() + count * 3); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let dateInfo = util.getDateInfo(nowDate); + let month = dateInfo.month; + if ([1, 2, 3].indexOf(month) > -1) { + // 第1季度 + month = 1; + } else if ([4, 5, 6].indexOf(month) > -1) { + // 第2季度 + month = 4; + } else if ([7, 8, 9].indexOf(month) > -1) { + // 第3季度 + month = 7; + } else if ([10, 11, 12].indexOf(month) > -1) { + // 第4季度 + month = 10; + } + nowDate.setMonth(month - 1); // 因为0代表1月,所以这里要减1 + let dateInfo1 = util.getDateInfo(nowDate); + nowDate.setMonth(nowDate.getMonth() + 3); + let dateInfo2 = util.getDateInfo(nowDate); + // 开始时间 + res.startTime = new Date(`${dateInfo1.year}/${dateInfo1.month}/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${dateInfo2.year}/${dateInfo2.month}/1`).getTime() - 1 - timeDif; + return res; +} + +/** + * 获得相对当前时间的偏移 count 年的起止日期(年的开始和结束时间戳) + * @param {Number} count 默认0 (0代表今年 -1代表去年 1代表明年以此类推) + * @param {Date || Number} date 指定从哪个时间节点开始计算 + * vk.pubfn.getYearOffsetStartAndEnd(0); + */ +util.getYearOffsetStartAndEnd = function(count = 0, date = new Date(), targetTimezone) { + let res = {}; + let nowDate = util.getDateObject(date); + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + let dateInfo = util.getDateInfo(nowDate); + let year = dateInfo.year + count; + // 开始时间 + res.startTime = new Date(`${year}/1/1`).getTime() - timeDif; + // 结束时间 + res.endTime = new Date(`${year}/12/31`).getTime() + (24 * 60 * 60 * 1000 - 1) - timeDif; + return res; +}; + + +/** + * 获得指定时间偏移 year年 month月 day天 hours时 minutes分 seconds秒前或后的时间戳 + * 返回时间戳 +vk.pubfn.getOffsetTime(new Date(), { + year:0, + month:0, + day:0, + hours:0, + minutes:0, + seconds:0, + mode:"after", // after 之后 before 之前 +}); + +vk.pubfn.getOffsetTime(new Date(), { + y:0, + m:0, + d:0, + hh:0, + mm:0, + ss:0, + mode:"after" // after 之后 before 之前 +}); + */ +util.getOffsetTime = function(date = new Date(), obj, targetTimezone) { + let nowDate = util.getDateObject(date); + let dateInfo = util.getDateInfo(nowDate); + + targetTimezone = util.getTargetTimezone(targetTimezone); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + + let year = obj.year || obj.y || 0; + let month = obj.month || obj.m || 0; + let day = obj.day || obj.d || 0; + let hour = obj.hour || obj.hours || obj.hh || 0; + let minute = obj.minute || obj.minutes || obj.mm || 0; + let second = obj.second || obj.seconds || obj.ss || 0; + let { mode = "after" } = obj; + if (mode == "before") { + year *= -1; + month *= -1; + day *= -1; + hour *= -1; + minute *= -1; + second *= -1; + } + let offsetObj = { + year: dateInfo.year + year, + month: dateInfo.month + month, + day: dateInfo.day + day, + hour: dateInfo.hour + hour, + minute: dateInfo.minute + minute, + second: dateInfo.second + second + }; + nowDate = new Date(offsetObj.year, offsetObj.month - 1, offsetObj.day, offsetObj.hour, offsetObj.minute, offsetObj.second); + return nowDate.getTime() - timeDif; +} + +/** + * 判断是否是闰年 + * @param {Number | Date} year 需要计算的年份或时间,默认使用当前时间的年份 + * vk.pubfn.timeUtil.isLeapYear(year); + */ +util.isLeapYear = function(year) { + if (typeof year === "undefined") { + let { now } = util.getCommonTime(); + year = now.year; + } else if (typeof year === "object") { + let { now } = util.getCommonTime(year); + year = now.year; + } + if (((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)) { + return true; + } else { + return false; + } +} + + +/** + * 判断是否是清明节 + * @param {Date} date 日期对象 可以指定时间计算节点,默认使用当前时间进行计算 +vk.pubfn.timeUtil.isQingming(new Date()); + */ +util.isQingming = function(data = new Date()) { + let { now } = util.getCommonTime(data); + let { year, month, day } = now; + let key = false; + // 清明节的日期是不固定的,规律是:闰年开始的前2年是4月4日,闰年开始的第3年和第4年是4月5日 + if (util.isLeapYear(year) || util.isLeapYear(year - 1)) { + if (month === 4 && day === 4) { + key = true; + } + } else { + if (month === 4 && day === 5) { + key = true; + } + } + return key; +} + +/** + * 日期对象转换(已弃用,建议不要使用此API) + * @param {Date || Number} date 需要转换的时间 + * @param {Number} type 转换方式 + * type = 0 返回 2020-08-03 12:12:12 + * type = 1 返回 20200803121212 + * type = 2 返回 { YYYY, MM, DD, hh, mm, ss } + */ +util.getFullTime = function(date, type = 0, targetTimezone) { + if (!date) return ""; + targetTimezone = util.getTargetTimezone(targetTimezone); + let nowDate = util.getDateObject(date); + const dif = nowDate.getTimezoneOffset(); + const timeDif = dif * 60 * 1000 + (targetTimezone * 60 * 60 * 1000); + const east8time = nowDate.getTime() + timeDif; + nowDate = new Date(east8time); + + let YYYY = nowDate.getFullYear() + ''; + let MM = (nowDate.getMonth() + 1 < 10 ? '0' + (nowDate.getMonth() + 1) : nowDate.getMonth() + 1); + let DD = (nowDate.getDate() < 10 ? '0' + (nowDate.getDate()) : nowDate.getDate()); + let hh = (nowDate.getHours() < 10 ? '0' + (nowDate.getHours()) : nowDate.getHours()); + let mm = (nowDate.getMinutes() < 10 ? '0' + (nowDate.getMinutes()) : nowDate.getMinutes()); + let ss = (nowDate.getSeconds() < 10 ? '0' + (nowDate.getSeconds()) : nowDate.getSeconds()); + if (type === 2) { + return { + YYYY: Number(YYYY), + MM: Number(MM), + DD: Number(DD), + hh: Number(hh), + mm: Number(mm), + ss: Number(ss), + + year: Number(YYYY), + month: Number(MM), + day: Number(DD), + hour: Number(hh), + minute: Number(mm), + second: Number(ss), + }; + } else if (type === 1) { + return YYYY + "" + MM + "" + DD + "" + hh + "" + mm + "" + ss; + } else { + return YYYY + "-" + MM + "-" + DD + " " + hh + ":" + mm + ":" + ss; + } +}; + + +export default util; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js new file mode 100644 index 0000000..1853d13 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/treeUtil.js @@ -0,0 +1,93 @@ + +import deepClone from './deepClone' +var util = {}; +/** + * 将树形结构转成数组结构 + * @param {Array} treeData 数据源 + * @param {Object} treeProps 树结构配置 { id : "menu_id", children : "children" } + * vk.pubfn.treeToArray(treeData); + */ +util.treeToArray = function(treeData, treeProps) { + let newTreeData = deepClone(treeData); + return util.treeToArrayFn(newTreeData, treeProps); +}; +util.treeToArrayFn = function(treeData, treeProps = {}, arr=[], current_parent_id) { + let { id="_id", parent_id="parent_id", children = "children", deleteChildren = true } = treeProps; + for(let i in treeData){ + let item = treeData[i]; + if(current_parent_id) item[parent_id] = current_parent_id; + arr.push(item); + if(item[children] && item[children].length>0){ + arr = util.treeToArrayFn(item[children], treeProps, arr, item[id]); + } + if(deleteChildren){ + delete item[children]; + } + } + return arr; +}; +/** + * 数组结构转树形结构 +let tree = vk.pubfn.arrayToTree(arrayData,{ + id:"code", + parent_id:"parent_code", +}); + */ + +util.arrayToTree = function(originalArrayData,treeProps) { + let arrayData = deepClone(originalArrayData); + let { + id="_id", + parent_id="parent_id", + children = "children", + deleteParentId = false, + need_field + } = treeProps; + let result = []; + let temp = {}; + for (let i = 0; i < arrayData.length; i++) { + temp[arrayData[i][id]] = arrayData[i]; // 以id作为索引存储元素,可以无需遍历直接定位元素 + } + for (let j = 0; j < arrayData.length; j++) { + let currentElement = arrayData[j]; + let newCurrentElement = {}; + if(need_field){ + need_field = uniqueArr(need_field.concat([id,parent_id,children])); + for(let keyName in currentElement){ + if(need_field.indexOf(keyName) === -1){ + delete currentElement[keyName]; + } + } + } + let tempCurrentElementParent = temp[currentElement[parent_id]]; // 临时变量里面的当前元素的父元素 + if (tempCurrentElementParent) { + // 如果存在父元素 + if (!tempCurrentElementParent[children]) { + // 如果父元素没有chindren键 + tempCurrentElementParent[children] = []; // 设上父元素的children键 + } + if(deleteParentId){ + delete currentElement[parent_id]; + } + tempCurrentElementParent[children].push(currentElement); // 给父元素加上当前元素作为子元素 + } else { + // 不存在父元素,意味着当前元素是一级元素 + result.push(currentElement); + } + } + return result; +}; + +// 最简单数组去重法 +function uniqueArr(array) { + let n = []; //一个新的临时数组 + //遍历当前数组 + for (let i = 0; i < array.length; i++) { + //如果当前数组的第i已经保存进了临时数组,那么跳过, + //否则把当前项push到临时数组里面 + if (n.indexOf(array[i]) == -1) n.push(array[i]); + } + return n; +} + +export default util; \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js new file mode 100644 index 0000000..470e3fe --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/updateManager.js @@ -0,0 +1,61 @@ +var updateManager = {}; +/** + * 本API返回全局唯一的版本更新管理器对象: updateManager,用于管理小程序更新。 + * vk.updateManager.updateReady(); + */ +updateManager.updateReady = function(obj) { + // #ifdef MP + updateManagerByMP(obj); + // #endif +}; + + +export default updateManager; + + +function updateManagerByMP(obj = {}) { + let { + title = "更新提示", + content = "新版本已经准备好,点击更新!", + autoUpdate = true, + showCancel = false, + confirmText = "一键更新" + } = obj; + const updateManager = uni.getUpdateManager(); + + updateManager.onCheckForUpdate(function(res) { + // 请求完新版本信息的回调 + // console.log(res.hasUpdate); + }); + + updateManager.onUpdateReady(function(res) { + uni.showModal({ + title, + content, + showCancel, + confirmText, + success(res) { + if (res.confirm) { + if (typeof obj.success === "function") { + obj.success({ + applyUpdate: updateManager.applyUpdate + }); + } + if (typeof obj.complete === "function") obj.complete(); + if (autoUpdate) { + // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 + updateManager.applyUpdate(); + } + } + }, + + }); + }); + + updateManager.onUpdateFailed(function(res) { + // 新的版本下载失败 + console.error("onUpdateFailed", res); + if (typeof obj.fail === "function") obj.fail(res); + if (typeof obj.complete === "function") obj.complete(); + }); +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js new file mode 100644 index 0000000..1b338ff --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.filters.js @@ -0,0 +1,63 @@ +/** + * vk.filters + * 全局过滤器 + */ +import pubfn from './index.js' +var util = {}; +// 将时间显示成1秒前、1天前 +util.dateDiff = function(starttime, showType) { + return pubfn.dateDiff(starttime, showType); +} +util.dateDiff2 = function(starttime, showType) { + return pubfn.dateDiff2(starttime, showType); +}; +// 计数器1 +util.numStr = function(n) { + return pubfn.numStr(n); +}; + +util.timeStr = function(date) { + return pubfn.timeFormat(date); +}; +/** + * 日期对象转字符串 + * @description 最终转成 2020-08-01 12:12:12 + * @param {Date || Number} date 需要转换的时间 + * date参数支持 + * 支持:时间戳 + * 支持:2020-08 + * 支持:2020-08-24 + * 支持:2020-08-24 12 + * 支持:2020-08-24 12:12 + * 支持:2020-08-24 12:12:12 + */ +util.timeFilter = function(date, fmt) { + return pubfn.timeFormat(date, fmt); +}; +// 金额过滤器 +util.priceFilter = function(n, defaultValue = " - ") { + return pubfn.priceFilter(n, defaultValue); +}; +// 金额过滤器 - 只显示小数点左边 +util.priceLeftFilter = function(n) { + return pubfn.priceLeftFilter(n); +}; +// 金额过滤器 - 只显示小数点右边 +util.priceRightFilter = function(n) { + return pubfn.priceRightFilter(n); +}; +// 百分比过滤器 +util.percentageFilter = function(n, needShowSymbol, defaultValue = " - ") { + return pubfn.percentageFilter(n, needShowSymbol, defaultValue); +}; +// 折扣过滤器 +util.discountFilter = function(n, needShowSymbol, defaultValue = " - ") { + return pubfn.discountFilter(n, needShowSymbol, defaultValue); +}; +// 大小过滤器 sizeFilter(1024,3,["B","KB","MB","GB"]) +util.sizeFilter = function(...obj) { + let res = pubfn.calcSize(...obj); + return res.title; +}; + +export default util; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js new file mode 100644 index 0000000..d77d5b3 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.h5.js @@ -0,0 +1,60 @@ +// #ifdef H5 +/** + * H5专用的一些函数,会涉及到window等H5专用的内置对象。 + */ +var h5 = {}; + +// 引入 微信公众号 js_sdk 包 +import wx from './weixin-js-sdk' +h5.wx = wx; + +/** + * 获取当前H5所在的环境 + * let env = vk.h5.getEnv(); + */ +h5.getEnv = function() { + let ua = window.navigator.userAgent.toLowerCase(); + if (ua.match(/MicroMessenger/i) == 'micromessenger' && (ua.match(/miniprogram/i) == 'miniprogram')) { + // 微信小程序 + return "mp-weixin"; + } + if (ua.match(/MicroMessenger/i) == 'micromessenger') { + // 微信公众号 + return "h5-weixin"; + } + if (ua.match(/alipay/i) == 'alipay' && ua.match(/miniprogram/i) == 'miniprogram') { + return "mp-alipay"; + } + if (ua.match(/alipay/i) == 'alipay') { + return "h5-alipay"; + } + // 外部 H5 + return "h5"; +}; + +/** + * 获取当前项目根目录访问地址 + * https://www.aaa.com/pages/index/index?a=1&b=1 + * http://192.168.66.66:8080/pages/index/index?a=1&b=1 + * 获取当前H5的url地址的https://www.aaa.com 部分 + * let getRootPath = vk.h5.getRootPath(); + * let getRootPath = vk.h5.getRootPath({ projectName:true }); + */ +h5.getRootPath = function(obj={}) { + let { + projectName: _projectName = false + } = obj; + let wwwPath = window.location.href; + let pathName = window.location.pathname; + let pos = wwwPath.indexOf(pathName); + let localhostPaht = wwwPath.substring(0, pos); + let projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1); + let rootPath = localhostPaht; + if (_projectName) { + rootPath = localhostPaht + projectName; + } + return rootPath; +}; + +export default h5; +// #endif diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js new file mode 100644 index 0000000..a0fb08b --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.importObject.js @@ -0,0 +1,59 @@ +/** + * 导出云对象实例 + * @param {String} name 云对象路径,如:client/pub + * @example const pubObject = uni.vk.importObject('client/pub'); // 导入云对象 + * 注意,只能在声明 async 的函数内使用,如: +async test(){ + let res = await pubObject.getList({ + title: "请求中", + data: { + a: 1, + b: "2" + } + }); +} + */ +var importObject = function(name, importObjectOptions = {}) { + const newObj = new Proxy(importObject, { + get: function(target, key, receiver) { + /** + * 导出云对象内的某个方法 + * @param {Object} data 请求参数,如 { a:1, b:"2" } 云对象内可通过 let { a, b } = data; 获取参数 + * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @param {Boolean} needAlert 为true代表请求错误时,会有弹窗提示。默认为true + * @param {Object} loading 与title二选一,格式为 { name: "loading", that: that } name是变量名,that是数据源,当发起请求时,自动that[name] = true; 请求结束后,自动that[name] = false; + */ + return async function(options) { + // 如果importObjectOptions中指定了easy为true,代表options的值就是请求参数 + if (importObjectOptions.easy) { + options = { + data: options + } + } + // 如果importObjectOptions中指定了data,代表有默认请求参数,需要加到请求参数中 + if (importObjectOptions.data) { + if (typeof importObjectOptions.data === "function") { + options.data = Object.assign({}, importObjectOptions.data(), options.data) + } else { + options.data = Object.assign({}, importObjectOptions.data, options.data) + } + } + return uni.vk.callFunction({ + ...importObjectOptions, + ...options, + url: `${name}.${key}` + }); + } + }, + // set: function(target, key, value, receiver) { + // console.log("set"); + // console.log("target",target); + // console.log("key",key); + // console.log("value",value); + // console.log("receiver", receiver); + // }, + }); + return newObj; +}; + +export default importObject; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js new file mode 100644 index 0000000..63dca97 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.localStorage.js @@ -0,0 +1,131 @@ +/** + * vk依赖扩展 - localStorage 本地缓存 + * pub - 公共的可随时删除的缓存 + * kh - 跟登录账号有关联的缓存 + * sys - 系统级缓存 - 一般不删除 + * + * 储存缓存 + * vk.setStorageSync(key, data); + * 获取缓存 + * vk.getStorageSync(key); + */ +var localStorage = {}; +/** + * 将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。 + * @param {String} key 本地缓存中的指定的 key + * @param {Any} data 需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象 + */ +localStorage.setStorageSync = function(key, data) { + uni.setStorageSync(key, data); + watchLocalStorage({ type: "set", key, data }); +}; + +/** + * 从本地缓存中异步获取指定 key 对应的内容。 + * @param {String} key 本地缓存中的指定的 key + */ +localStorage.getStorageSync = function(key) { + let data = uni.getStorageSync(key); + // get 没有必要监听 + // watchLocalStorage({ type:"get", key, data }); + return data; +}; + +/** + * 同步获取当前 storage 的相关信息。 + */ +localStorage.getStorageInfoSync = function() { + let info = uni.getStorageInfoSync(); + let sizeInfo = calcSize(Number(info.currentSize), 1024, 3, ["KB", "MB", "GB"]); + info.sizeInfo = sizeInfo; + return info; +}; + +/** + * 从本地缓存中同步移除指定 key。 + * @param {String} key 本地缓存中的指定的 key + */ +localStorage.removeStorageSync = function(key) { + uni.removeStorageSync(key); + watchLocalStorage({ type: "remove", key }); +}; +/** + * 从本地缓存中异步移除指定 key。 + */ +localStorage.removeStorage = function(obj) { + uni.removeStorage({ + key: obj.key, + success: (res) => { + watchLocalStorage({ type: "remove", key: obj.key }); + if (obj.success) obj.success(res); + }, + fail: obj.fail, + complete: obj.complete + }); +}; + +/** + * 同步清理本地数据缓存。若key有值,则清除键值为指定字符串开头的缓存 + * @param {String} key 本地缓存中的指定的 key + * vk.clearStorageSync(); + */ +localStorage.clearStorageSync = function(key) { + if (key) { + let { keys } = uni.getStorageInfoSync(); + if (keys) { + keys.map((keyName) => { + if (keyName.indexOf(key) == 0) { + localStorage.removeStorage({ + key: keyName + }); + } + }); + } + } else { + uni.clearStorage(); + watchLocalStorage({ type: "clear" }); + } +}; + +export default localStorage; + + + +/** + * 单位进制换算 + * length 换算前大小 + * ary 进制,如KB-MB-GB,进制1024 + * precision 数值精度 + * arr 进制的数组,如["B","KB","MB","GB"] + * calcSize(length,1024,3,["B","KB","MB","GB"]); + */ +function calcSize(length = 0, ary, precision, arr) { + var size = parseFloat(length); + var mySize = 0; + var type = ""; + if (size < ary || arr.length <= 1) { + type = arr[0]; + mySize = parseFloat(size.toFixed(precision)); + } else { + for (var i = 1; i < arr.length; i++) { + var g = arr[i]; + size = size / ary; + if (size < ary) { + type = g; + mySize = parseFloat(size.toFixed(precision)); + break; + } + } + } + return { + size: mySize, + type: type, + title: mySize + " " + type + } +}; + +function watchLocalStorage(obj) { + if (typeof localStorage.watch === "function") { + localStorage.watch(obj); + } +} \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js new file mode 100644 index 0000000..f4cb84b --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.navigate.js @@ -0,0 +1,462 @@ +/** + * 函数 - 页面导航 + */ +// #ifndef VUE3 +var config; +try { + config = require('@/app.config.js'); + if (typeof config.default === "object") { + config = config.default; + } +} catch (e) { + config = {}; +} +// #endif + +// #ifdef VUE3 +import config from '@/app.config.js' +// #endif + + +var util = {}; +var lastNavigate = { + url: "", + time: 0 +}; +/** + * 保留当前页面,跳转到应用内的某个页面,使用vk.navigateBack可以返回到原页面。 + * vk.navigateTo(url); + */ +util.navigateTo = function(obj) { + let vk = uni.vk; + if (typeof obj == "string") { + let url = obj; + obj = { + url: url + }; + } else if (typeof obj == "undefined") { + obj = {}; + } + if (!obj.url) { + vk.toast("url不能为空!"); + return false; + } + let time = Date.now(); + if (lastNavigate.url === obj.url && (time - lastNavigate.time) < 200) { + return false; + } + lastNavigate = { url: obj.url, time }; + util.checkNeedLogin({ + url: obj.url, + success: function(res) { + if (res.needLogin) { + obj.url = vk.pubfn.getPageFullPath(obj.url); + vk.navigate.setOriginalPage(obj); + obj.url = config.login.url; + // login拦截器开始----------------------------------------------------------- + let { interceptor = {} } = config; + if (typeof interceptor.login === "function") { + let key = interceptor.login({ + vk, + params: obj, + res: { + ...res, + code: 30204, + msg: "本地token校验未通过" + } + }); + if (typeof key === "undefined" || key !== true) return false; + } + // login拦截器结束----------------------------------------------------------- + } else { + vk.navigate.setOriginalPage(null); + } + util._navigateTo(obj); + } + }); +}; +util._navigateTo = function(obj) { + let { interceptor = {} } = config; + if (typeof interceptor.navigateTo === "function") { + let vk = uni.vk; + obj.pagePath = vk.pubfn.getPageFullPath(obj.url); + let key = interceptor.navigateTo({ + ...obj, + vk + }); + if (typeof key == "boolean" && key === false) return false; + } + let { + url, + animationType = "pop-in", + animationDuration = 300, + events, + mode = "navigateTo" + } = obj; + // 此处写法仅为支持vue3,vue3不支持uni[apiName]的形式调用 + let navigateFn; + if (mode === "navigateTo") { + navigateFn = uni.navigateTo; + } else if (mode === "redirectTo") { + navigateFn = uni.redirectTo; + } else if (mode === "reLaunch") { + navigateFn = uni.reLaunch; + } else if (mode === "switchTab") { + navigateFn = uni.switchTab; + } else { + navigateFn = uni.navigateTo; + } + // 此处写法仅为支持vue3,vue3不支持uni[apiName]的形式调用 + navigateFn({ + url: url, + animationType: animationType, + animationDuration: animationDuration, + events: events, // 参考 https://uniapp.dcloud.io/api/router?id=navigateto + success: function(res) { + if (typeof obj.success == "function") obj.success(res); + }, + fail: function(err) { + if (err.errMsg.indexOf("not found") > -1) { + let vk = uni.vk; + let errUrl = vk.pubfn.getPageFullPath(url); + vk.toast(`页面 ${errUrl} 不存在`, "none"); + console.error(err); + return false; + } + uni.switchTab({ + url: url, + success: obj.success, + fail: function() { + uni.redirectTo({ + url: url, + success: obj.success, + fail: function(err) { + console.error(err); + if (typeof obj.fail == "function") obj.fail(err); + } + }); + } + }); + }, + complete: function(res) { + if (typeof obj.complete == "function") obj.complete(res); + } + }); +}; + +/** + * 关闭当前页面,跳转到应用内的某个页面。 + * vk.redirectTo(url); + */ +util.redirectTo = function(obj) { + obj = util.paramsInit(obj); + obj.mode = "redirectTo"; + util.navigateTo(obj); +}; + +/** + * 关闭所有页面,打开到应用内的某个页面。 + * vk.reLaunch(url); + */ +util.reLaunch = function(obj) { + obj = util.paramsInit(obj); + obj.mode = "reLaunch"; + util.navigateTo(obj); +}; + +/** + * 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。 + * vk.switchTab(url); + */ +util.switchTab = function(obj) { + obj = util.paramsInit(obj); + obj.mode = "switchTab"; + util.navigateTo(obj); +}; +/** + * 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。 + * vk.navigateBack(); + */ +util.navigateBack = function(obj) { + let vk = uni.vk; + if (typeof obj == "number") { + let delta = obj; + obj = { + delta: delta + }; + } else if (typeof obj == "undefined") { + obj = {}; + } + let { + delta = 1, + animationType = "pop-out", + animationDuration = 300 + } = obj; + uni.navigateBack({ + delta: delta, + animationType: animationType, + animationDuration: animationDuration, + success: function() { + if (typeof obj.success == "function") obj.success(); + }, + fail: function(res) { + console.error(res); + if (typeof obj.fail == "function") obj.fail(); + }, + complete: function() { + if (typeof obj.complete == "function") obj.complete(); + } + }); +}; +/** + * 跳转到登录前的页面 + * vk.navigate.originalTo(); + */ +util.originalTo = function() { + let vk = uni.vk; + let originalPage = vk.navigate.getOriginalPage(); + vk.navigate.setOriginalPage(null); + util.redirectTo(originalPage); +}; + +/** + * 获取登录前的页面 + * vk.navigate.getOriginalPage(); + */ +util.getOriginalPage = function() { + if (typeof uni.vk.getVuex === "function") { + // 有安装vuex则使用vuex + return uni.vk.getVuex('$app.originalPage'); + } else { + // 未安装则使用本地缓存 + return uni.vk.getStorageSync('vk.navigate.originalPage'); + } +}; + +/** + * 设置登录前的页面 + * vk.navigate.setOriginalPage(originalPage); + */ +util.setOriginalPage = function(originalPage) { + uni.vk.navigate.originalPage = originalPage; // 兼容老版本 + if (typeof uni.vk.getVuex === "function") { + // 有安装vuex则使用vuex + return uni.vk.setVuex('$app.originalPage', originalPage); + } else { + // 未安装则使用本地缓存 + return uni.vk.setStorageSync('vk.navigate.originalPage', originalPage); + } +}; + + +/** + * 跳转到首页 + * vk.navigateToHome(); + */ +util.navigateToHome = function(obj = {}) { + let vk = uni.vk; + let { + mode = "reLaunch" + } = obj; + vk[mode](config.index.url); +}; + +/** + * 跳转到登录页 + * vk.navigateToLogin(); + */ +util.navigateToLogin = function(obj = {}) { + let vk = uni.vk; + let { + mode = "reLaunch" + } = obj; + vk[mode](config.login.url); +}; + +/** + * 检测是否满足条件(内部方法) + util.checkWildcardTest({ + url:url, + pagesRule:config.checkTokenPages, + success:function(res){ + if(res.success){ + + } + } + }) + */ +util.checkWildcardTest = function(obj) { + let vk = uni.vk; + let { + url, + pagesRule + } = obj; + // ../ 转成绝对路径 + url = vk.pubfn.getPageFullPath(url); + let key = false; + if (vk.pubfn.isNotNull(pagesRule)) { + let { mode = 0, list = [] } = pagesRule; + if (mode > 0) { + let regExpKey = false; + let path = util.getPagePath(url); + for (let i = 0; i < list.length; i++) { + let pageRegExp = list[i]; + regExpKey = vk.pubfn.wildcardTest(path, pageRegExp); + if (regExpKey) { + break; + } + } + if (mode === 1 && regExpKey) { + key = true; + } else if (mode === 2 && !regExpKey) { + key = true; + } + } + } + return { + url, + key + }; +}; + + +/** + * 检测是否需要登录(内部方法) + util.checkNeedLogin({ + url:url, + success:function(res){ + if(res.needLogin){ + + } + } + }) + */ +util.checkNeedLogin = function(obj) { + let vk = uni.vk; + let { url, success } = obj; + let needLogin = false; // 用户是否需要重新登录 + let pageNeedLogin = false; // 该页面是否需要登录才能访问 + let pagesRule = config.checkTokenPages; + if (pagesRule) { + let res = util.checkWildcardTest({ + url, + pagesRule + }); + pageNeedLogin = res.key; + if (pageNeedLogin) { + // 本地判断token有效期(联网会浪费性能) + if (!vk.checkToken()) { + needLogin = true; + } + } + } + success({ + url, + needLogin, + pageNeedLogin + }); +}; + + +// 获取?前面的地址 +util.getPagePath = function(url) { + let pathIndex = url.indexOf("?"); + let path = url; + if (pathIndex > -1) { + path = path.substring(0, pathIndex); + } + return path; +}; + +util.paramsInit = function(obj) { + let vk = uni.vk; + if (typeof obj == "string") { + let url = obj; + obj = { + url: url + }; + } else if (typeof obj == "undefined") { + obj = {}; + } + if (!obj.url) { + vk.toast("url不能为空!"); + return false; + } + return obj; +} + + + +/** + * 跳转到小程序 + vk.navigateToMiniProgram({ + appId: 'appId', + path: 'pages/index/index', + extraData:{ + //发送数据携带的参数 + }, + success(res) { + // 打开成功 + + } + }) + */ +util.navigateToMiniProgram = function(obj) { + let vk = uni.vk; + // #ifdef H5 + vk.toast("不支持打开小程序", "none"); + // #endif + + // #ifndef H5 + uni.navigateToMiniProgram(obj); + // #endif +}; + + +/** + * 检测是否可以分享(内部方法) + util.checkAllowShare({ + url:url, + }); + */ +util.checkAllowShare = function(obj) { + let vk = uni.vk; + let { url, success } = obj; + let pagesRule = config.checkSharePages || {}; + if (pagesRule && pagesRule.mode > 0) { + let res = util.checkWildcardTest({ + url, + pagesRule + }); + // #ifdef MP + let menus = pagesRule.menus || ['shareAppMessage', 'shareTimeline']; + if (res.key) { + //console.log("允许分享"); + uni.showShareMenu({ + withShareTicket: false, + menus + }); + } else { + //console.log("禁止分享"); + uni.hideShareMenu({ + menus + }) + } + // #endif + } +}; + +util.$emit = function(...obj) { + return uni.$emit(...obj); +}; +util.$on = function(...obj) { + return uni.$on(...obj); +}; +util.$once = function(...obj) { + return uni.$once(...obj); +}; +util.$off = function(...obj) { + return uni.$off(...obj); +}; + +export default util; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js new file mode 100644 index 0000000..ee3e9ca --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.request.js @@ -0,0 +1,434 @@ +var requestUtil = {}; + + +requestUtil.config = { + // 请求配置 + request: { + // 公共请求参数(每次请求都会带上的参数) + dataParam: {} + }, + requestGlobalParamKeyName: "vk_url_request_global_param", + debug: process.env.NODE_ENV !== "production", + // 日志风格 + logger: { + colorArr: [ + "#0095ff", + "#67C23A" + ] + }, +}; +var counterNum = 0; +/** + * request 请求库 + * 注意: 该请求库目前主要是框架自身使用,且近期变动频率较高,目前请勿使用在你自己的业务中。 + * @param {String} url 服务器接口地址 + * @param {Object/String/ArrayBuffer} data 请求的参数 App(自定义组件编译模式)不支持ArrayBuffer类型 + * @param {Object} header 设置请求的 header,header 中不能设置 Referer。 App、H5端会自动带上cookie,且H5端不可手动修改 + * @param {String} method 默认 POST 可选 GET + * @param {Number} timeout 超时时间,单位 ms 默认3000(30秒) + * @param {String} dataType 默认json 如果设为 json,会尝试对返回的数据做一次 JSON.parse + * @param {String} responseType 默认 text 设置响应的数据类型。合法值:text、arraybuffer App和支付宝小程序不支持 + * @param {Boolean} sslVerify 默认 true 是否需要验证ssl证书 仅App安卓端支持(HBuilderX 2.3.3+) 仅App安卓端支持(HBuilderX 2.3.3+) + * @param {Boolean} withCredentials 默认 false 跨域请求时是否携带凭证(cookies) 仅H5支持(HBuilderX 2.6.15+) + * @param {Boolean} firstIpv4 默认 false DNS解析时优先使用ipv4 仅 App-Android 支持 (HBuilderX 2.8.0+) + * @param {String} success 成功回调 + * @param {String} fail 失败回调 + * @param {String} complete 完成回调 + * 以下为特殊参数 + * @param {String} errorCodeName 服务器返回的错误码的字段名,若不为空,则会对返回结果进行判断 + * @param {String} errorMsgName 服务器返回的错误码的字符串含义,若不为空,且errorCodeName对应的值不为0,则会alert弹窗 + * @param {Boolean} needAlert 服务器返回的错误时,是否需要alert弹出提示 + * + * 调用示例 +vk.request({ + url: `https://www.xxx.com/api/xxxx`, + method:"POST", + header:{ + "content-type": "application/json; charset=utf-8", + }, + data:{ + + }, + success: function(data){ + + }, + fail: function(err){ + + } +}); + */ + +requestUtil.request = function(obj = {}) { + let vk = uni.vk; + // 去除值为 undefined 的参数 + if (typeof obj.data === "object") { + obj.data = vk.pubfn.copyObject(obj.data); + } + // 注入自定义全局参数开始----------------------------------------------------------- + let config = requestUtil.config; + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + // 根据正则规格自动匹配全局请求参数 + for (let i in globalParam) { + let customDate = globalParam[i]; + if (customDate.regExp) { + if (typeof customDate.regExp === "object") { + // 数组形式 + for (let i = 0; i < customDate.regExp.length; i++) { + let regExp = new RegExp(customDate.regExp[i]); + if (regExp.test(obj.url)) { + obj.data = Object.assign(customDate.data, obj.data); + break; + } + } + } else { + // 字符串形式 + let regExp = new RegExp(customDate.regExp); + if (regExp.test(obj.url)) { + obj.data = Object.assign(customDate.data, obj.data); + } + } + } + } + // 根据指定globalParamName匹配全局请求参数 + let customDate = requestUtil.getRequestGlobalParam(obj.globalParamName); + if (customDate && JSON.stringify(customDate) !== "{}") { + if (customDate.regExp) { + obj.data = Object.assign(customDate.data, obj.data); // 新版本 + } else { + obj.data = Object.assign(customDate, obj.data); // 兼容旧版本 + } + } + // 注入自定义全局参数结束----------------------------------------------------------- + + if (!obj.method) obj.method = "POST"; // 默认POST请求 + if (typeof obj.dataType === "undefined") obj.dataType = "json"; + if (obj.dataType == "default" || obj.dataType === "") delete obj.dataType; + if (typeof obj.header === "undefined" && typeof obj.headers !== "undefined") { + obj.header = obj.headers; + } + + // 自动注入token到请求头开始----------------------------------------------------------- + // 注意:自2.15.1开始,需要手动指定uniIdToken: true 才会自动添加token到请求头里 + if (typeof vk.getToken === "function" && obj.uniIdToken) { + let uni_id_token; + if (obj.uniIdToken === true) { + uni_id_token = vk.getToken(); + } else if (typeof obj.uniIdToken === "boolean") { + uni_id_token = obj.uniIdToken; + } + if (uni_id_token) { + if (!obj.header) obj.header = {}; + obj.header["uni-id-token"] = uni_id_token; + } + } + // 自动注入token到请求头结束----------------------------------------------------------- + let interceptor = obj.interceptor; + delete obj.interceptor; + if (interceptor && typeof interceptor.invoke === "function") { + let interceptorRes = interceptor.invoke(obj); + if (interceptorRes === false) { + return; + } + } + if (typeof obj.timeout === "undefined") obj.timeout = 30000; // 超时时间,单位 ms(默认30秒) + let Logger = {}; + if (config.debug) { + Logger.params = (typeof obj.data == "object") ? vk.pubfn.copyObject(obj.data) : obj.data; + Logger.startTime = new Date().getTime(); + let url = obj.url; + let path = obj.url.split("?")[0]; + if (path.indexOf("://") > -1) { + path = path.substring(path.indexOf("://") + 3); + Logger.domainName = path.substring(0, path.indexOf("/")); + } else { + Logger.domainName = ""; + } + Logger.action = path.substring(path.indexOf("/") + 1); + Logger.url = url; + } + if (obj.title) vk.showLoading(obj.title); + if (obj.loading) vk.setLoading(true, obj.loading); + let promiseAction = new Promise(function(resolve, reject) { + uni.request({ + ...obj, + success: (res) => { + if (interceptor && typeof interceptor.success === "function") { + let interceptorRes = interceptor.success(res); + if (interceptorRes === false) { + return; + } + } + requestSuccess({ + res, + params: obj, + Logger, + resolve, + reject + }); + }, + fail: (res) => { + if (interceptor && typeof interceptor.fail === "function") { + let interceptorRes = interceptor.fail(res); + if (interceptorRes === false) { + return; + } + } + requestFail({ + res, + params: obj, + Logger, + reject + }); + }, + complete: (res) => { + if (interceptor && typeof interceptor.complete === "function") { + let interceptorRes = interceptor.complete(res); + if (interceptorRes === false) { + return; + } + } + requestComplete({ + res, + params: obj, + Logger + }); + } + }); + }); + promiseAction.catch(error => {}); + return promiseAction; +} +// 请求成功回调 +function requestSuccess(obj = {}) { + let vk = uni.vk; + let config = requestUtil.config; + let { + res = {}, + params, + Logger, + resolve, + reject + } = obj; + let { + title, + needOriginalRes, + dataType, + errorCodeName, + errorMsgName, + success, + loading + } = params; + let data = res.data || {}; + if (vk.pubfn.isNotNullAll(errorCodeName, data[errorCodeName])) { + data.code = data[errorCodeName]; + delete data[errorCodeName]; + } + if (vk.pubfn.isNotNullAll(errorMsgName, data[errorMsgName])) { + data.msg = data[errorMsgName]; + if (typeof data[errorMsgName] === "string") { + delete data[errorMsgName]; + } + } + if (config.debug) Logger.result = (typeof data == "object") ? vk.pubfn.copyObject(data) : data; + if ([1301, 1302, 30201, 30202, 30203, 30204].indexOf(data.code) > -1 && data.msg.indexOf("token") > -1) { + // 执行 login 拦截器函数(跳转到页面页面) + let { interceptor = {} } = vk.callFunctionUtil; + if (typeof interceptor.login === "function") { + interceptor.login({ + res: data, + params, + vk + }); + } + reject(data); + } else if (res.statusCode >= 400 || data.code) { + requestFail({ + res: data, + params, + Logger, + reject + }); + } else { + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + if (needOriginalRes) data.originalRes = vk.pubfn.copyObject(res); + if (data.vk_uni_token) vk.callFunctionUtil.saveToken(data.vk_uni_token); + if (data.userInfo && data.needUpdateUserInfo) vk.callFunctionUtil.updateUserInfo(data); + if (typeof success === "function") success(data); + if (typeof resolve === "function") resolve(data); + } +} + +// 请求失败回调 +function requestFail(obj = {}) { + let vk = uni.vk; + let config = requestUtil.config; + let { + res = {}, + params, + Logger, + reject + } = obj; + let { + title, + needAlert, + fail, + loading + } = params; + if (typeof needAlert === "undefined") { + needAlert = (typeof fail === "function") ? false : true; + } + + let errMsg = ""; + let sysErr = false; + if (typeof res.code !== "undefined") { + errMsg = res.msg; + } else { + sysErr = true; + errMsg = JSON.stringify(res); + } + if (errMsg.indexOf("fail timeout") > -1) { + sysErr = true; + errMsg = "请求超时,请重试!"; + } + if (config.debug) Logger.error = res; + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + let runKey = true; + // 自定义拦截器开始----------------------------------------------------------- + let { interceptor = {} } = vk.callFunctionUtil.getConfig(); + if (interceptor.request && typeof interceptor.request.fail == "function") { + runKey = interceptor.request.fail({ + vk, + res: res, + params: params + }); + if (runKey === undefined) runKey = true; + } + // 自定义拦截器结束----------------------------------------------------------- + if (runKey) { + if (needAlert && vk.pubfn.isNotNull(errMsg)) { + if (sysErr) { + vk.toast("网络开小差了!", "none"); + } else { + vk.alert(errMsg); + } + } + if (typeof fail === "function") fail(res); + if (typeof reject === "function") reject(res); + } + +} + +// 请求完成回调 +function requestComplete(obj = {}) { + let vk = uni.vk; + let config = requestUtil.config; + let { + res = {}, + params, + Logger + } = obj; + let { + title, + needOriginalRes, + complete + } = params; + if (config.debug) { + Logger.endTime = new Date().getTime(); + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + console.log("%c--------【开始】【服务器请求】【" + Logger.action + "】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + console.log("【请求地址】: ", Logger.url); + console.log("【请求参数】: ", Logger.params); + console.log("【返回数据】: ", Logger.result); + console.log("【请求状态】: ", res.statusCode, "【http状态码】"); + console.log("【总体耗时】: ", Logger.runTime, "毫秒【含页面渲染】"); + console.log("【请求时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) { + let errorLog = console.warn || console.error; + if (Logger.error.err && Logger.error.err.stack) { + console.error("【Error】: ", Logger.error); + console.error("【Stack】: ", Logger.error.err.stack); + } else { + errorLog("【Error】: ", Logger.error); + } + } + console.log("%c--------【结束】【服务器请求】【" + Logger.action + "】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + } + let data = res.data; + if (needOriginalRes) data.originalRes = vk.pubfn.copyObject(res); + if (typeof complete === "function") complete(data); +} + +/** + * 修改请求配置中的公共请求参数 + * 若把shop-manage改成*则代表全局 + vk.requestUtil.updateRequestGlobalParam({ + "shop-manage":{ + regExp:"^xxx/kh/", + data:{ + shop_id : shop_id + } + } + }); + 对应的request中增加参数globalParamName:"shop-manage" + vk.request({ + url: 'xxx/xxxxxx', + title: '请求中...', + globalParamName:"shop-manage",// 如果设置了正则规则,则不需要此参数 + data: {}, + success(data) { + } + }); + */ +requestUtil.updateRequestGlobalParam = (data = {}, setKey) => { + let vk = uni.vk; + let config = requestUtil.config; + if (setKey) { + // 覆盖对象 + config.request.dataParam = data; + } else { + // 覆盖参数(有就覆盖,没有则新增) + config.request.dataParam = Object.assign(config.request.dataParam, data); + } + vk.setStorageSync(config.requestGlobalParamKeyName, config.request.dataParam); +} + +/** + * 获取请求配置中的公共请求参数 + vk.requestUtil.getRequestGlobalParam(); + */ +requestUtil.getRequestGlobalParam = (globalParamName = "*") => { + let vk = uni.vk; + let config = requestUtil.config; + let data = config.request.dataParam; + if (!data || JSON.stringify(data) === "{}") { + data = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + config.request.dataParam = data; + } + let param = data[globalParamName] || {}; + return JSON.parse(JSON.stringify(param)); +} + +/** + * 删除请求配置中的公共请求参数 + * globalParamName 不传代表删除所有 + vk.requestUtil.deleteRequestGlobalParam(globalParamName); + */ +requestUtil.deleteRequestGlobalParam = (globalParamName) => { + let vk = uni.vk; + let config = requestUtil.config; + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + if (globalParamName) { + delete globalParam[globalParamName]; + } else { + globalParam = {}; + } + config.request.dataParam = globalParam; + vk.setStorageSync(config.requestGlobalParamKeyName, globalParam); +} + +export default requestUtil; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js new file mode 100644 index 0000000..fd29637 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/vk.sessionStorage.js @@ -0,0 +1,146 @@ +/** + * vk依赖扩展 - sessionStorage 本地会话缓存(仅H5可用) + * sessionStorage 属性允许你访问一个,对应当前源的 session Storage 对象。 + * 它与 localStorage 相似,不同之处在于 localStorage 里面存储的数据没有过期时间设置 + * 而存储在 sessionStorage 里面的数据在页面会话结束时会被清除。 + * pub - 公共的可随时删除的缓存 + * kh - 跟登录账号有关联的缓存 + * sys - 系统级缓存 - 一般不删除 + * + * 储存缓存 + * vk.setSessionStorageSync(key, data); + * 获取缓存 + * vk.getSessionStorageSync(key); + */ +var storage = {}; +/** + * 将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。 + * @param {String} key 本地缓存中的指定的 key + * @param {Any} data 需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象 + * vk.setSessionStorageSync(key, data); + */ +storage.setSessionStorageSync = function(key, data = "") { + // #ifdef H5 + let type = typeof data; + let value = { + type: typeof data, + data: data + }; + sessionStorage.setItem(key, JSON.stringify(value)); + watchSessionStorage({ type: "set", key, data }); + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +/** + * 从本地缓存中异步获取指定 key 对应的内容。 + * @param {String} key 本地缓存中的指定的 key + * vk.getSessionStorageSync(key); + */ +storage.getSessionStorageSync = function(key) { + // #ifdef H5 + let data; + try { + let value = JSON.parse(sessionStorage.getItem(key)); + data = value.data; + } catch (err) { + data = sessionStorage.getItem(key); + } + // get 没有必要监听 + // watchSessionStorage({ type:"get", key, data }); + return data; + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +/** + * 从本地缓存中同步移除指定 key。 + * @param {String} key 本地缓存中的指定的 key + * vk.removeSessionStorageSync(key); + */ +storage.removeSessionStorageSync = function(key) { + // #ifdef H5 + sessionStorage.removeItem(key); + watchSessionStorage({ type: "remove", key }); + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +/** + * 同步清理本地数据缓存。若key有值,则清除键值为指定字符串开头的缓存 + * @param {String} key 本地缓存中的指定的 key + * vk.clearSessionStorageSync(); + */ +storage.clearSessionStorageSync = function(key) { + // #ifdef H5 + if (key) { + let keys = Object.keys(sessionStorage); + if (keys) { + keys.map((keyName) => { + if (keyName.indexOf(key) == 0) { + sessionStorage.removeItem(keyName); + } + }); + } + } else { + sessionStorage.clear(); + watchSessionStorage({ type: "clear" }); + } + // #endif + + // #ifndef H5 + console.warn("非H5环境不支持此API"); + // #endif +}; + +export default storage; + + + +/** + * 单位进制换算 + * length 换算前大小 + * ary 进制,如KB-MB-GB,进制1024 + * precision 数值精度 + * arr 进制的数组,如["B","KB","MB","GB"] + * calcSize(length,1024,3,["B","KB","MB","GB"]); + */ +function calcSize(length = 0, ary, precision, arr) { + var size = parseFloat(length); + var mySize = 0; + var type = ""; + if (size < ary || arr.length <= 1) { + type = arr[0]; + mySize = parseFloat(size.toFixed(precision)); + } else { + for (var i = 1; i < arr.length; i++) { + var g = arr[i]; + size = size / ary; + if (size < ary) { + type = g; + mySize = parseFloat(size.toFixed(precision)); + break; + } + } + } + return { + size: mySize, + type: type, + title: mySize + " " + type + } +}; + +function watchSessionStorage(obj) { + if (typeof storage.watch === "function") { + storage.watch(obj); + } +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js new file mode 100644 index 0000000..b605321 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/function/weixin-js-sdk.js @@ -0,0 +1,890 @@ +function n(o, e) { + if (!o.jWeixin) { + var n, + c = { + config: "preVerifyJSAPI", + onMenuShareTimeline: "menu:share:timeline", + onMenuShareAppMessage: "menu:share:appmessage", + onMenuShareQQ: "menu:share:qq", + onMenuShareWeibo: "menu:share:weiboApp", + onMenuShareQZone: "menu:share:QZone", + previewImage: "imagePreview", + getLocation: "geoLocation", + openProductSpecificView: "openProductViewWithPid", + addCard: "batchAddCard", + openCard: "batchViewCard", + chooseWXPay: "getBrandWCPayRequest", + openEnterpriseRedPacket: "getRecevieBizHongBaoRequest", + startSearchBeacons: "startMonitoringBeacons", + stopSearchBeacons: "stopMonitoringBeacons", + onSearchBeacons: "onBeaconsInRange", + consumeAndShareCard: "consumedShareCard", + openAddress: "editAddress" + }, + a = (function() { + var e = {}; + for (var n in c) e[c[n]] = n; + return e; + })(), + i = o.document, + t = i.title, + r = navigator.userAgent.toLowerCase(), + s = navigator.platform.toLowerCase(), + d = !(!s.match("mac") && !s.match("win")), + u = -1 != r.indexOf("wxdebugger"), + l = -1 != r.indexOf("micromessenger"), + p = -1 != r.indexOf("android"), + f = -1 != r.indexOf("iphone") || -1 != r.indexOf("ipad"), + m = (n = + r.match(/micromessenger\/(\d+\.\d+\.\d+)/) || + r.match(/micromessenger\/(\d+\.\d+)/)) ? + n[1] : + "", + g = { + initStartTime: L(), + initEndTime: 0, + preVerifyStartTime: 0, + preVerifyEndTime: 0 + }, + h = { + version: 1, + appId: "", + initTime: 0, + preVerifyTime: 0, + networkType: "", + isPreVerifyOk: 1, + systemType: f ? 1 : p ? 2 : -1, + clientVersion: m, + url: encodeURIComponent(location.href) + }, + v = {}, + S = { _completes: [] }, + y = { state: 0, data: {} }; + O(function() { + g.initEndTime = L(); + }); + var I = !1, + _ = [], + w = { + config: function(e) { + B("config", (v = e)); + var t = !1 !== v.check; + O(function() { + if (t) + M( + c.config, { + verifyJsApiList: C(v.jsApiList), + verifyOpenTagList: C(v.openTagList) + }, + (function() { + (S._complete = function(e) { + (g.preVerifyEndTime = L()), (y.state = 1), (y.data = e); + }), + (S.success = function(e) { + h.isPreVerifyOk = 0; + }), + (S.fail = function(e) { + S._fail ? S._fail(e) : (y.state = -1); + }); + var t = S._completes; + return ( + t.push(function() { + !(function() { + if ( + !( + d || + u || + v.debug || + m < "6.0.2" || + h.systemType < 0 + ) + ) { + var i = new Image(); + (h.appId = v.appId), + (h.initTime = g.initEndTime - g + .initStartTime), + (h.preVerifyTime = + g.preVerifyEndTime - g + .preVerifyStartTime), + w.getNetworkType({ + isInnerInvoke: !0, + success: function(e) { + h.networkType = + e + .networkType; + var n = + "https://open.weixin.qq.com/sdk/report?v=" + + h.version + + "&o=" + + h + .isPreVerifyOk + + "&s=" + + h + .systemType + + "&c=" + + h + .clientVersion + + "&a=" + + h.appId + + "&n=" + + h + .networkType + + "&i=" + + h.initTime + + "&p=" + + h + .preVerifyTime + + "&u=" + + h.url; + i.src = n; + } + }); + } + })(); + }), + (S.complete = function(e) { + for (var n = 0, i = t.length; n < i; ++n) t[n] + (); + S._completes = []; + }), + S + ); + })() + ), + (g.preVerifyStartTime = L()); + else { + y.state = 1; + for (var e = S._completes, n = 0, i = e.length; n < i; ++n) + e[n](); + S._completes = []; + } + }), + w.invoke || + ((w.invoke = function(e, n, i) { + o.WeixinJSBridge && WeixinJSBridge.invoke(e, x(n), i); + }), + (w.on = function(e, n) { + o.WeixinJSBridge && WeixinJSBridge.on(e, n); + })); + }, + ready: function(e) { + 0 != y.state ? e() : (S._completes.push(e), !l && v.debug && e()); + }, + error: function(e) { + m < "6.0.2" || (-1 == y.state ? e(y.data) : (S._fail = e)); + }, + checkJsApi: function(e) { + M( + "checkJsApi", { jsApiList: C(e.jsApiList) }, + ((e._complete = function(e) { + if (p) { + var n = e.checkResult; + n && (e.checkResult = JSON.parse(n)); + } + e = (function(e) { + var n = e.checkResult; + for (var i in n) { + var t = a[i]; + t && ((n[t] = n[i]), delete n[i]); + } + return e; + })(e); + }), + e) + ); + }, + onMenuShareTimeline: function(e) { + P( + c.onMenuShareTimeline, { + complete: function() { + M( + "shareTimeline", { + title: e.title || t, + desc: e.title || t, + img_url: e.imgUrl || "", + link: e.link || location.href, + type: e.type || "link", + data_url: e.dataUrl || "" + }, + e + ); + } + }, + e + ); + }, + onMenuShareAppMessage: function(n) { + P( + c.onMenuShareAppMessage, { + complete: function(e) { + "favorite" === e.scene ? + M("sendAppMessage", { + title: n.title || t, + desc: n.desc || "", + link: n.link || location.href, + img_url: n.imgUrl || "", + type: n.type || "link", + data_url: n.dataUrl || "" + }) : + M( + "sendAppMessage", { + title: n.title || t, + desc: n.desc || "", + link: n.link || location.href, + img_url: n.imgUrl || "", + type: n.type || "link", + data_url: n.dataUrl || "" + }, + n + ); + } + }, + n + ); + }, + onMenuShareQQ: function(e) { + P( + c.onMenuShareQQ, { + complete: function() { + M( + "shareQQ", { + title: e.title || t, + desc: e.desc || "", + img_url: e.imgUrl || "", + link: e.link || location.href + }, + e + ); + } + }, + e + ); + }, + onMenuShareWeibo: function(e) { + P( + c.onMenuShareWeibo, { + complete: function() { + M( + "shareWeiboApp", { + title: e.title || t, + desc: e.desc || "", + img_url: e.imgUrl || "", + link: e.link || location.href + }, + e + ); + } + }, + e + ); + }, + onMenuShareQZone: function(e) { + P( + c.onMenuShareQZone, { + complete: function() { + M( + "shareQZone", { + title: e.title || t, + desc: e.desc || "", + img_url: e.imgUrl || "", + link: e.link || location.href + }, + e + ); + } + }, + e + ); + }, + updateTimelineShareData: function(e) { + M( + "updateTimelineShareData", { title: e.title, link: e.link, imgUrl: e.imgUrl }, + e + ); + }, + updateAppMessageShareData: function(e) { + M( + "updateAppMessageShareData", { + title: e.title, + desc: e.desc, + link: e.link, + imgUrl: e + .imgUrl + }, + e + ); + }, + startRecord: function(e) { + M("startRecord", {}, e); + }, + stopRecord: function(e) { + M("stopRecord", {}, e); + }, + onVoiceRecordEnd: function(e) { + P("onVoiceRecordEnd", e); + }, + playVoice: function(e) { + M("playVoice", { localId: e.localId }, e); + }, + pauseVoice: function(e) { + M("pauseVoice", { localId: e.localId }, e); + }, + stopVoice: function(e) { + M("stopVoice", { localId: e.localId }, e); + }, + onVoicePlayEnd: function(e) { + P("onVoicePlayEnd", e); + }, + uploadVoice: function(e) { + M( + "uploadVoice", { + localId: e.localId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + downloadVoice: function(e) { + M( + "downloadVoice", { + serverId: e.serverId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + translateVoice: function(e) { + M( + "translateVoice", { + localId: e.localId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + chooseImage: function(e) { + M( + "chooseImage", { + scene: "1|2", + count: e.count || 9, + sizeType: e.sizeType || ["original", "compressed"], + sourceType: e.sourceType || ["album", "camera"] + }, + ((e._complete = function(e) { + if (p) { + var n = e.localIds; + try { + n && (e.localIds = JSON.parse(n)); + } catch (e) {} + } + }), + e) + ); + }, + getLocation: function(e) {}, + previewImage: function(e) { + M(c.previewImage, { current: e.current, urls: e.urls }, e); + }, + uploadImage: function(e) { + M( + "uploadImage", { + localId: e.localId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + downloadImage: function(e) { + M( + "downloadImage", { + serverId: e.serverId, + isShowProgressTips: 0 == e.isShowProgressTips ? 0 : 1 + }, + e + ); + }, + getLocalImgData: function(e) { + !1 === I ? + ((I = !0), + M( + "getLocalImgData", { localId: e.localId }, + ((e._complete = function(e) { + if (((I = !1), 0 < _.length)) { + var n = _.shift(); + wx.getLocalImgData(n); + } + }), + e) + )) : + _.push(e); + }, + getNetworkType: function(e) { + M( + "getNetworkType", {}, + ((e._complete = function(e) { + e = (function(e) { + var n = e.errMsg; + e.errMsg = "getNetworkType:ok"; + var i = e.subtype; + if ((delete e.subtype, i)) e.networkType = i; + else { + var t = n.indexOf(":"), + o = n.substring(t + 1); + switch (o) { + case "wifi": + case "edge": + case "wwan": + e.networkType = o; + break; + default: + e.errMsg = "getNetworkType:fail"; + } + } + return e; + })(e); + }), + e) + ); + }, + openLocation: function(e) { + M( + "openLocation", { + latitude: e.latitude, + longitude: e.longitude, + name: e.name || "", + address: e.address || "", + scale: e.scale || 28, + infoUrl: e.infoUrl || "" + }, + e + ); + }, + getLocation: function(e) { + M( + c.getLocation, { type: (e = e || {}).type || "wgs84" }, + ((e._complete = function(e) { + delete e.type; + }), + e) + ); + }, + hideOptionMenu: function(e) { + M("hideOptionMenu", {}, e); + }, + showOptionMenu: function(e) { + M("showOptionMenu", {}, e); + }, + closeWindow: function(e) { + M("closeWindow", {}, (e = e || {})); + }, + hideMenuItems: function(e) { + M("hideMenuItems", { menuList: e.menuList }, e); + }, + showMenuItems: function(e) { + M("showMenuItems", { menuList: e.menuList }, e); + }, + hideAllNonBaseMenuItem: function(e) { + M("hideAllNonBaseMenuItem", {}, e); + }, + showAllNonBaseMenuItem: function(e) { + M("showAllNonBaseMenuItem", {}, e); + }, + scanQRCode: function(e) { + M( + "scanQRCode", { + needResult: (e = e || {}).needResult || 0, + scanType: e.scanType || ["qrCode", "barCode"] + }, + ((e._complete = function(e) { + if (f) { + var n = e.resultStr; + if (n) { + var i = JSON.parse(n); + e.resultStr = i && i.scan_code && i.scan_code.scan_result; + } + } + }), + e) + ); + }, + openAddress: function(e) { + M( + c.openAddress, {}, + ((e._complete = function(e) { + e = (function(e) { + return ( + (e.postalCode = e.addressPostalCode), + delete e.addressPostalCode, + (e.provinceName = e.proviceFirstStageName), + delete e.proviceFirstStageName, + (e.cityName = e.addressCitySecondStageName), + delete e.addressCitySecondStageName, + (e.countryName = e.addressCountiesThirdStageName), + delete e.addressCountiesThirdStageName, + (e.detailInfo = e.addressDetailInfo), + delete e.addressDetailInfo, + e + ); + })(e); + }), + e) + ); + }, + openProductSpecificView: function(e) { + M( + c.openProductSpecificView, { + pid: e.productId, + view_type: e.viewType || 0, + ext_info: e.extInfo + }, + e + ); + }, + addCard: function(e) { + for (var n = e.cardList, i = [], t = 0, o = n.length; t < o; ++t) { + var r = n[t], + a = { card_id: r.cardId, card_ext: r.cardExt }; + i.push(a); + } + M( + c.addCard, { card_list: i }, + ((e._complete = function(e) { + var n = e.card_list; + if (n) { + for (var i = 0, t = (n = JSON.parse(n)).length; i < t; ++i) { + var o = n[i]; + (o.cardId = o.card_id), + (o.cardExt = o.card_ext), + (o.isSuccess = !!o.is_succ), + delete o.card_id, + delete o.card_ext, + delete o.is_succ; + } + (e.cardList = n), delete e.card_list; + } + }), + e) + ); + }, + chooseCard: function(e) { + M( + "chooseCard", { + app_id: v.appId, + location_id: e.shopId || "", + sign_type: e.signType || "SHA1", + card_id: e.cardId || "", + card_type: e.cardType || "", + card_sign: e.cardSign, + time_stamp: e.timestamp + "", + nonce_str: e.nonceStr + }, + ((e._complete = function(e) { + (e.cardList = e.choose_card_info), delete e.choose_card_info; + }), + e) + ); + }, + openCard: function(e) { + for (var n = e.cardList, i = [], t = 0, o = n.length; t < o; ++t) { + var r = n[t], + a = { card_id: r.cardId, code: r.code }; + i.push(a); + } + M(c.openCard, { card_list: i }, e); + }, + consumeAndShareCard: function(e) { + M( + c.consumeAndShareCard, { consumedCardId: e.cardId, consumedCode: e.code }, + e + ); + }, + chooseWXPay: function(e) { + M(c.chooseWXPay, V(e), e); + }, + openEnterpriseRedPacket: function(e) { + M(c.openEnterpriseRedPacket, V(e), e); + }, + startSearchBeacons: function(e) { + M(c.startSearchBeacons, { ticket: e.ticket }, e); + }, + stopSearchBeacons: function(e) { + M(c.stopSearchBeacons, {}, e); + }, + onSearchBeacons: function(e) { + P(c.onSearchBeacons, e); + }, + openEnterpriseChat: function(e) { + M( + "openEnterpriseChat", { useridlist: e.userIds, chatname: e.groupName }, + e + ); + }, + launchMiniProgram: function(e) { + M( + "launchMiniProgram", { + targetAppId: e.targetAppId, + path: (function(e) { + if ("string" == typeof e && 0 < e.length) { + var n = e.split("?")[0], + i = e.split("?")[1]; + return (n += ".html"), void 0 !== i ? n + "?" + i : n; + } + })(e.path), + envVersion: e.envVersion + }, + e + ); + }, + openBusinessView: function(e) { + M( + "openBusinessView", { + businessType: e.businessType, + queryString: e.queryString || "", + envVersion: e.envVersion + }, + ((e._complete = function(n) { + if (p) { + var e = n.extraData; + if (e) + try { + n.extraData = JSON.parse(e); + } catch (e) { + n.extraData = {}; + } + } + }), + e) + ); + }, + miniProgram: { + navigateBack: function(e) { + (e = e || {}), + O(function() { + M( + "invokeMiniProgramAPI", { + name: "navigateBack", + arg: { + delta: e + .delta || 1 + } + }, + e + ); + }); + }, + navigateTo: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "navigateTo", arg: { url: e.url } }, + e + ); + }); + }, + redirectTo: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "redirectTo", arg: { url: e.url } }, + e + ); + }); + }, + switchTab: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "switchTab", arg: { url: e.url } }, + e + ); + }); + }, + reLaunch: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "reLaunch", arg: { url: e.url } }, + e + ); + }); + }, + postMessage: function(e) { + O(function() { + M( + "invokeMiniProgramAPI", { name: "postMessage", arg: e.data || {} }, + e + ); + }); + }, + getEnv: function(e) { + O(function() { + e({ miniprogram: "miniprogram" === o.__wxjs_environment }); + }); + } + } + }, + T = 1, + k = {}; + return ( + i.addEventListener( + "error", + function(e) { + if (!p) { + var n = e.target, + i = n.tagName, + t = n.src; + if ("IMG" == i || "VIDEO" == i || "AUDIO" == i || "SOURCE" == i) + if (-1 != t.indexOf("wxlocalresource://")) { + e.preventDefault(), e.stopPropagation(); + var o = n["wx-id"]; + if ((o || ((o = T++), (n["wx-id"] = o)), k[o])) return; + (k[o] = !0), + wx.ready(function() { + wx.getLocalImgData({ + localId: t, + success: function(e) { + n.src = e.localData; + } + }); + }); + } + } + }, + !0 + ), + i.addEventListener( + "load", + function(e) { + if (!p) { + var n = e.target, + i = n.tagName; + n.src; + if ("IMG" == i || "VIDEO" == i || "AUDIO" == i || "SOURCE" == i) { + var t = n["wx-id"]; + t && (k[t] = !1); + } + } + }, + !0 + ), + e && (o.wx = o.jWeixin = w), + w + ); + } + + function M(n, e, i) { + o.WeixinJSBridge ? + WeixinJSBridge.invoke(n, x(e), function(e) { + A(n, e, i); + }) : + B(n, i); + } + + function P(n, i, t) { + o.WeixinJSBridge ? + WeixinJSBridge.on(n, function(e) { + t && t.trigger && t.trigger(e), A(n, e, i); + }) : + B(n, t || i); + } + + function x(e) { + return ( + ((e = e || {}).appId = v.appId), + (e.verifyAppId = v.appId), + (e.verifySignType = "sha1"), + (e.verifyTimestamp = v.timestamp + ""), + (e.verifyNonceStr = v.nonceStr), + (e.verifySignature = v.signature), + e + ); + } + + function V(e) { + return { + timeStamp: e.timestamp + "", + nonceStr: e.nonceStr, + package: e.package, + paySign: e.paySign, + signType: e.signType || "SHA1" + }; + } + + function A(e, n, i) { + ("openEnterpriseChat" != e && "openBusinessView" !== e) || + (n.errCode = n.err_code), + delete n.err_code, + delete n.err_desc, + delete n.err_detail; + var t = n.errMsg; + t || + ((t = n.err_msg), + delete n.err_msg, + (t = (function(e, n) { + var i = e, + t = a[i]; + t && (i = t); + var o = "ok"; + if (n) { + var r = n.indexOf(":"); + "confirm" == (o = n.substring(r + 1)) && (o = "ok"), + "failed" == o && (o = "fail"), + -1 != o.indexOf("failed_") && (o = o.substring(7)), + -1 != o.indexOf("fail_") && (o = o.substring(5)), + ("access denied" != + (o = (o = o.replace(/_/g, " ")).toLowerCase()) && + "no permission to execute" != o) || + (o = "permission denied"), + "config" == i && "function not exist" == o && (o = "ok"), + "" == o && (o = "fail"); + } + return (n = i + ":" + o); + })(e, t)), + (n.errMsg = t)), + (i = i || {})._complete && (i._complete(n), delete i._complete), + (t = n.errMsg || ""), + v.debug && !i.isInnerInvoke && alert(JSON.stringify(n)); + var o = t.indexOf(":"); + switch (t.substring(o + 1)) { + case "ok": + i.success && i.success(n); + break; + case "cancel": + i.cancel && i.cancel(n); + break; + default: + i.fail && i.fail(n); + } + i.complete && i.complete(n); + } + + function C(e) { + if (e) { + for (var n = 0, i = e.length; n < i; ++n) { + var t = e[n], + o = c[t]; + o && (e[n] = o); + } + return e; + } + } + + function B(e, n) { + if (!(!v.debug || (n && n.isInnerInvoke))) { + var i = a[e]; + i && (e = i), + n && n._complete && delete n._complete, + console.log('"' + e + '",', n || ""); + } + } + + function L() { + return new Date().getTime(); + } + + function O(e) { + l && + (o.WeixinJSBridge ? + e() : + i.addEventListener && + i.addEventListener("WeixinJSBridgeReady", e, !1)); + } +}; + +export default n(window); \ No newline at end of file diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js new file mode 100644 index 0000000..e4beb6a --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/install/console.log.js @@ -0,0 +1,18 @@ +let debug = process.env.NODE_ENV !== 'production'; +const install = Vue => { + let vk = Vue.prototype ? Vue.prototype.vk : Vue.config.globalProperties.vk; + if (vk) { + vk.log = console.log; + if (typeof vk.getConfig === "function") { + debug = vk.getConfig().debug; + } + if(!debug){ + console.log = function(...obj){}; + } + } +} + +export default { + install +} + diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js new file mode 100644 index 0000000..68910e3 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/mixin/mixin.js @@ -0,0 +1,40 @@ +var isOnLaunch = true; +export default { + data() { + return {} + }, + onLoad() { + // 将vk实例挂载到app.globalData上,方便在非Vue页面自身函数中调用vk实例(因为获取不到this) + let app = getApp({ allowDefault: true }); + if (app && app.globalData && !app.globalData.vk) { + app.globalData.vk = this.vk; + } + if (this.vk) { + const url = this.vk.pubfn.getCurrentPageRoute(); + // 检测是否可以分享(小程序专属) + this.vk.navigate.checkAllowShare({ url }); + // 检测是否需要登录,只有首次启动的页面才需要检测,其他页面通过 vk.navigateTo 跳转前会自动判断。 + if (isOnLaunch && !this.vk.checkToken() && getCurrentPages().length == 1) { + isOnLaunch = false; // 重新标记为非首次页面 + const currentPage = this.vk.pubfn.getCurrentPage() || {}; + let pagePath = currentPage.pagePath || `/${currentPage.route}` || url; + let fullPath = currentPage.fullPath; + let options = currentPage.options; + this.vk.pubfn.checkLogin({ url: pagePath, fullPath, options, isOnLaunch: true }); // 检测是否需要登录 + } + } + }, + created() { + // 将vk实例挂载到app.globalData上,方便在非Vue页面自身函数中调用vk实例(因为获取不到this) + let app = getApp({ allowDefault: true }); + if (app && app.globalData && !app.globalData.vk) { + app.globalData.vk = this.vk; + } + }, + methods: { + $getData(data, key, defaultValue) { + let { vk } = this; + return vk.pubfn.getData(data, key, defaultValue); + } + } +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js new file mode 100644 index 0000000..5fa7d5f --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/baidu/index.js @@ -0,0 +1,170 @@ +/** + * 百度API + */ +var baidu = {}; +var vk = {}; +var baiduOpenApiAccessTokenCacheName = "vk_openapi_baidu_open_token"; +baidu.init = function(util={}) { + vk = util.vk; +}; + +// 百度开放平台api +baidu.open = {}; +// 文字识别 +baidu.open.ocr = {}; + +/** + * 营业执照识别 + * 以下data参数三选一即可 + * @param {File} file 文件对象 + * @param {String} image 图像base64编码后进行urlencode + * @param {String} url 图片完整URL + * +vk.openapi.baidu.open.ocr.business_license({ + title:"识别中...", + data: { + file: res.tempFiles[0] + }, + success: (res) => { + that.data = res.data; + }, +}); + */ +baidu.open.ocr.business_license = function(obj={}){ + obj.action = "ocr/v1/business_license"; + let file = obj.data.file; + if(file){ + vk.pubfn.fileToBase64({ file }).then(base64 => { + obj.data.image = base64; + delete obj.data.file; + baidu.request(obj); + }); + }else{ + baidu.request(obj); + } +} + +/** + * 身份证识别 + * 以下data参数三选一即可 + * @param {File} file 文件对象 + * @param {String} image 图像base64编码后进行urlencode + * @param {String} url 图片完整URL +vk.openapi.baidu.open.ocr.idcard({ + title:"识别中...", + data: { + image:base64, + id_card_side:"front", // front:身份证含照片的一面 back:身份证带国徽的一面 + }, + success: (res) => { + that.data = res.data; + }, +}); + */ +baidu.open.ocr.idcard = function(obj={}){ + obj.action = "ocr/v1/idcard"; + let file = obj.data.file; + if(!obj.data.id_card_side) obj.data.id_card_side = "front"; + if(file){ + vk.pubfn.fileToBase64({ file }).then(base64 => { + obj.data.image = base64; + delete obj.data.file; + baidu.request(obj); + }); + }else{ + baidu.request(obj); + } +} + +/** + * 百度开放平台通用请求接口 + * @param {String} action 接口名称 + * @param {String} actionVersion 接口版本名称 默认2.0 + * @param {String} title loading文字 + * @param {object} data 请求参数 + * @param {String} success 成功回调 + * @param {String} fail 失败回调 + * @param {String} complete 完成回调 + * 使用示例 +vk.openapi.baidu.request({ + action: 'ocr/v1/business_license', + title:"识别中...", + data: { + image:base64 + }, + success: (data) => { + that.data = data; + }, +}); + */ +baidu.request = function(obj={}){ + let { + title + } = obj; + if(title) vk.showLoading(title); + let baiduApiAccessToken = vk.getStorageSync(baiduOpenApiAccessTokenCacheName); + if(baiduApiAccessToken && baiduApiAccessToken.expTime > new Date().getTime()){ + // 获取缓存中的token + obj.accessToken = baiduApiAccessToken.accessToken; + request(obj); + }else{ + // 发起请求获取token + vk.callFunction({ + url: 'plugs/baidu/client/pub/getAccessToken', + success:function(tokenRes) { + vk.setStorageSync(baiduOpenApiAccessTokenCacheName,{ + accessToken : tokenRes.access_token, + expTime : 2590000000 + new Date().getTime(), + }); + obj.accessToken = tokenRes.access_token; + request(obj); + }, + fail:function(res){ + if(title) vk.hideLoading(); + if(typeof obj.fail === "function") obj.fail(res); + if(typeof obj.complete === "function") obj.complete(res); + } + }); + } +} + +function request(obj={}){ + let { + action, + actionVersion = "2.0", + accessToken, + header = { "content-type": "application/x-www-form-urlencoded" }, + data, + title + } = obj; + vk.request({ + url: `https://aip.baidubce.com/rest/${actionVersion}/${action}?access_token=${accessToken}`, + method:"POST", + header:{ + "content-type": "application/x-www-form-urlencoded", + }, + errorCodeName:"error_code", + errorMsgName:"error_msg", + data, + needAlert:true, + success: function(data){ + if(title) vk.hideLoading(); + if(data.code){ + if(typeof obj.fail === "function") obj.fail(data); + }else{ + if(typeof obj.success === "function") obj.success(data); + } + }, + fail: function(data){ + if(title) vk.hideLoading(); + // 如果是因为token失效报的错误,则清空下本地token缓存 + if(data && data.code === 110) vk.removeStorageSync(baiduOpenApiAccessTokenCacheName); + if(typeof obj.fail === "function") obj.fail(data); + }, + complete: function(data){ + if(typeof obj.complete === "function") obj.complete(data); + } + }); +} + +export default baidu; diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js new file mode 100644 index 0000000..531c653 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/openapi/index.js @@ -0,0 +1,14 @@ +/** + * 开放API + */ +import baidu from './baidu' + +var openapi = {}; +openapi.baidu = baidu; +openapi.init = function(util){ + openapi.baidu.init(util); +} +// 微信小程序API +export default openapi; + + diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js new file mode 100644 index 0000000..4cc9271 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/libs/error.js @@ -0,0 +1,25 @@ + +const install = Vue => { + const debug = process.env.NODE_ENV !== 'production'; + let vk = Vue.prototype ? Vue.prototype.vk : Vue.config.globalProperties.vk; + if (debug && vk) { + const oldErrorHandler = Vue.config.errorHandler; + Vue.config.errorHandler = function errorHandler(err, vm, info) { + const route = vm.$page && vm.$page.route; + let date = new Date(); + let log = { + err: err.toString(), + info, + route, + time: date.getTime(), + timeStr: date.toLocaleTimeString() + }; + if(vk.vuex) vk.vuex.dispatch('$error/add', log); + return oldErrorHandler(err, vm, info); + } + } +} + +export default { + install +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js new file mode 100644 index 0000000..72d96ee --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/store/mixin/mixin.js @@ -0,0 +1,67 @@ +export default { + beforeCreate() { + // 将vuex方法挂在到vk实例中 beforeCreate created + let { vk, $store } = this; + if (typeof $store !== "undefined" && typeof vk.getVuexStore === "undefined") { + vk.getVuexStore = function() { + return $store; + }; + vk.vuex = (name, value) => { + $store.commit('updateStore', { name, value }); + }; + /** + * (推荐) 设置vuex + * vk.vuex.set('$user.userInfo.avatar', avatar); + */ + vk.vuex.set = (name, value) => { + $store.commit('updateStore', { name, value }); + }; + /** + * (推荐) 读取vuex(具有解除对象内存印射功能,且任意一层数据为undefined,不会报错) + * vk.vuex.get('$user.userInfo.avatar'); + */ + vk.vuex.get = (name, defaultValue) => { + let value = vk.pubfn.getData($store.state, name); + if (typeof value === "undefined") return (typeof defaultValue !== "undefined") ? defaultValue : ""; + return JSON.parse(JSON.stringify(value)); + }; + vk.vuex.getters = (name) => { + return $store.getters[name]; + }; + /** + * 触发vuex的指定actions(异步) + * $user是模块名,addFootprint是对应模块的action名称 + * vk.vuex.dispatch('$user/addFootprint', data); + */ + vk.vuex.dispatch = $store.dispatch; + /** + * 触发vuex的指定mutations + * $user是模块名,setFootprint是对应模块的action名称 + * vk.vuex.commit('$user/setFootprint', data); + */ + vk.vuex.commit = $store.commit; + + /* 另一种方式 */ + /** + * vk.setVuex('$user.userInfo.avatar', avatar); + */ + vk.setVuex = vk.vuex.set; + /** + * vk.getVuex('$user.userInfo.avatar'); + */ + vk.getVuex = vk.vuex.get; + /* 兼容老版本 */ + vk.state = vk.vuex.get; + try { + if (!vk.checkToken()) { + vk.callFunctionUtil.deleteUserInfo({ + log: false + }); + } + } catch (err) {} + } + }, + computed: { + + } +} diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js new file mode 100644 index 0000000..2ef380d --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js @@ -0,0 +1,1040 @@ +var vk = {}; +var counterNum = 0; +var uniCloudEnvs = {}; // uniCloud 环境列表 +var lastToLoginTime = 0; +class CallFunctionUtil { + constructor() { + this.config = { + // 是否开启测试环境的云函数,true:使用测试环境,false:使用正式环境,默认true + isTest: false, + // 设为false可关闭打印日志 + debug: true, + // 云函数路由(主函数名) + functionName: "router", + // 云函数路由(开发测试函数名) + testFunctionName: "router-test", + // 云函数url化后对应的url地址 + functionNameToUrl: { + "router": "https://xxxxxxx.bspapp.com/http/router", + "router-test": "https://xxxxxxx.bspapp.com/http/router" + }, + // vk.callFunction的isRequest的默认值 + isRequestDefault: false, + // 默认时区(中国为8) + targetTimezone: 8, + // 客户端登录页面地址 + login: { + url: '/pages_template/uni-id/login/index/index' + }, + // 请求配置 + request: { + // 公共请求参数(每次请求都会带上的参数) + dataParam: {} + }, + // 日志风格 + logger: { + colorArr: [ + "#0095ff", + "#67C23A" + ] + }, + // 缓存键名 - token(请勿修改) + uniIdTokenKeyName: "uni_id_token", + // 缓存键名 - token过期时间(请勿修改) + uniIdTokenExpiredKeyName: "uni_id_token_expired", + // 缓存键名 - 当前登录用户信息(请勿修改) + uniIdUserInfoKeyName: "uni_id_user_info", + // 缓存键名 - 公共请求参数(请勿修改) + requestGlobalParamKeyName: "vk_request_global_param", + // 监听token刷新事件的事件名 + onRefreshTokenEventName: "onRefreshToken", + // 自定义组件配置 + components: {} + } + /** + * 获取我的token + * vk.getToken(); + */ + this.getToken = (res = {}) => { + let config = this.config; + return vk.getStorageSync(config.uniIdTokenKeyName); + } + /** + * 保存新的token + * 可通过下方的代码监听token的改变(写在app.vue的onLaunch内) + vk.$on('onRefreshToken',(data) => { + console.log('token改变监听:', data); + }); + */ + this.saveToken = (res = {}) => { + let config = this.config; + vk.setStorageSync(config.uniIdTokenKeyName, res.token); + vk.setStorageSync(config.uniIdTokenExpiredKeyName, res.tokenExpired); + this.emitRefreshToken(res); // 触发token刷新事件 + if (this.config.debug) console.log("--------【token已更新】--------"); + } + // 删除token,并删除userInfo缓存 + this.deleteToken = () => { + let config = this.config; + vk.removeStorageSync(config.uniIdTokenKeyName); + vk.removeStorageSync(config.uniIdTokenExpiredKeyName); + this.deleteUserInfo(); + this.emitRefreshToken(); // 触发token刷新事件 + if (this.config.debug) console.log("--------【token已删除】--------"); + } + // 更新userInfo缓存 + this.updateUserInfo = (res = {}) => { + let config = this.config; + let { + userInfo = {} + } = res; + if (typeof vk.setVuex === "function") { + // 有安装vuex则使用vuex + vk.setVuex('$user.userInfo', userInfo); + } else { + // 否则使用本地缓存 + vk.setStorageSync(config.uniIdUserInfoKeyName, userInfo); + } + //if (this.config.debug) console.log("--------【用户信息已更新】--------"); + } + // 删除userInfo缓存 + this.deleteUserInfo = (res = {}) => { + let { + log = true + } = res; + let config = this.config; + if (typeof vk.setVuex === "function") { + // 有安装vuex则使用vuex + vk.setVuex('$user.userInfo', {}); + vk.setVuex('$user.permission', []); + vk.removeStorageSync(config.uniIdUserInfoKeyName); + } else { + // 否则使用本地缓存 + vk.removeStorageSync(config.uniIdUserInfoKeyName); + } + if (this.config.debug && log) console.log("--------【用户信息已删除】--------"); + } + // 检查token是否有效(本地版) + // let valid = vk.callFunctionUtil.checkToken(); + this.checkToken = (res = {}) => { + let config = this.config; + let token = uni.getStorageSync(config.uniIdTokenKeyName); + let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName); + let valid = false; + if (token && tokenExpired && tokenExpired > Date.now()) { + valid = true; + } + return valid; + } + /** + * 触发监听token更新事件 + */ + this.emitRefreshToken = (data = {}) => { + let config = this.config; + return vk.$emit(config.onRefreshTokenEventName, data); // 触发token刷新事件 + } + /** + * 监听token更新事件 + */ + this.onRefreshToken = (callback) => { + let config = this.config; + return vk.$on(config.onRefreshTokenEventName, callback); + } + /** + * 移除token更新事件 + */ + this.offRefreshToken = (callback) => { + let config = this.config; + return vk.$off(config.onRefreshTokenEventName, callback); + } + /** + * 修改请求配置中的公共请求参数 + * 若把shop-manage改成*则代表全局 + vk.callFunctionUtil.updateRequestGlobalParam({ + "shop-manage":{ + regExp:"^xxx/kh/", + data:{ + shop_id : shop_id + } + } + }); + 对应的callFunction中增加参数globalParamName:"shop-manage" + vk.callFunction({ + url: 'xxx/xxxxxx', + title: '请求中...', + globalParamName:"shop-manage",// 如果设置了正则规则,则不需要此参数 + data: {}, + success(data) { + } + }); + */ + this.updateRequestGlobalParam = (data = {}, setKey) => { + let config = this.config; + if (setKey) { + // 覆盖对象 + config.request.dataParam = data; + } else { + // 覆盖参数(有就覆盖,没有则新增) + let dataParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + config.request.dataParam = Object.assign(dataParam, data); + } + vk.setStorageSync(config.requestGlobalParamKeyName, config.request.dataParam); + } + /** + * 获取请求配置中的公共请求参数 + vk.callFunctionUtil.getRequestGlobalParam(); + */ + this.getRequestGlobalParam = (globalParamName = "*") => { + let config = this.config; + let data = config.request.dataParam; + if (!data || JSON.stringify(data) === "{}") { + data = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + config.request.dataParam = data; + } + let param = data[globalParamName] || {}; + return JSON.parse(JSON.stringify(param)); + } + /** + * 删除请求配置中的公共请求参数 + * globalParamName 不传代表删除所有 + vk.callFunctionUtil.deleteRequestGlobalParam(globalParamName); + */ + this.deleteRequestGlobalParam = (globalParamName) => { + let config = this.config; + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + if (globalParamName) { + delete globalParam[globalParamName]; + } else { + globalParam = {}; + } + config.request.dataParam = globalParam; + vk.setStorageSync(config.requestGlobalParamKeyName, globalParam); + } + // 拦截器 + this.interceptor = { + // 拦截1301、1302错误码(非法token和token失效) + login: (obj = {}) => { + let nowTime = Date.now(); + if (nowTime - lastToLoginTime < 300) { + return false; + } + lastToLoginTime = nowTime; + let { + params, + res + } = obj; + let config = this.config; + let callFunction = this.callFunction; + if (config.debug) console.log("跳登录页面"); + let { tokenExpiredAutoDelete = true } = config; + if (tokenExpiredAutoDelete) this.deleteToken(); + setTimeout(() => { + if (config.login.url) { + let currentPage = getCurrentPages()[getCurrentPages().length - 1]; + if (currentPage && currentPage.route && "/" + currentPage.route === config.login.url) { + return false; + } + // 此处代码是为了防止首页启动时检测和正常检测冲突----------------------------------------------------------- + if (vk.navigate.isOnLaunchToLogin) { + setTimeout(() => { + vk.navigate.isOnLaunchToLogin = false; + }, 500); + return false; + } + // 此处代码是为了防止首页启动时检测和正常检测冲突----------------------------------------------------------- + uni.navigateTo({ + url: config.login.url, + events: { + // 监听登录成功后的事件 + loginSuccess: function(data) { + let num = 2; + let pages = getCurrentPages(); + if (pages.length >= num) { + let that = pages[pages.length - num]; + if (typeof that.onLoad == "function") { + // 重新执行页面onLoad函数 + that.onLoad(that.options); + } else if (typeof that.init == "function") { + // 重新执行页面初始化函数 + that.init(that.options); + } else { + // 重新执行一次云函数调用 + callFunction(params); + } + } else { + // 重新执行一次云函数调用 + callFunction(params); + } + } + } + }); + } else { + if (params.needAlert) { + vk.alert(res.result.msg); + } + } + }, 0); + }, + // 全局请求失败拦截器 + fail: (obj = {}) => { + return true; + } + } + /** + * 云函数请求封装 - 统一入口 + * @description 通过云函数路由,1个云函数实现多个云函数的效果。 + * @param {String} name 大云函数名称(默认router) + * @param {String} url 请求路径 + * @param {Object} data 请求参数,如 { a:1, b:"2" } 云函数内可通过 let { a, b } = data; 获取参数 + * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。 + * @param {Boolean|Object} loading 若设置为false,即使title有值也不显示遮罩层 + * @param {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false + * @param {String} env 云空间环境 文档:https://vkdoc.fsq.pub/client/question/q9.html#%E5%89%8D%E7%AB%AF%E8%AF%B7%E6%B1%82%E5%A4%9A%E6%9C%8D%E5%8A%A1%E7%A9%BA%E9%97%B4 + * @param {Boolean} needAlert 为true代表请求错误时,会有弹窗提示,默认为true + * @param {Number} retryCount 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中) + * @param {Function} success 请求成功时,执行的回调函数 + * @param {Function} fail 请求失败时,执行的回调函数 + * @param {Function} complete 无论请求成功与否,都会执行的回调函数 + */ + this.callFunction = (obj = {}) => { + let that = this; + let { config } = that; + let { + url, + data = {}, + globalParamName + } = obj; + + if (!url) { + vk.toast('vk.callFunction的url参数不能为空'); + return; + } + + if (obj.retryCount) { + // 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中) + return that.callFunctionRetry(obj); + } + // 去除值为 undefined 的参数 + if (typeof data === "object") { + obj.data = vk.pubfn.copyObject(data); + } + // 注入自定义全局参数开始----------------------------------------------------------- + let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {}; + // 根据正则规格自动匹配全局请求参数 + for (let i in globalParam) { + let customDate = globalParam[i]; + if (customDate.regExp) { + if (typeof customDate.regExp === "object") { + // 数组形式 + for (let i = 0; i < customDate.regExp.length; i++) { + let regExp = new RegExp(customDate.regExp[i]); + if (regExp.test(url)) { + obj.data = Object.assign(customDate.data, obj.data); + break; + } + } + } else { + // 字符串形式 + let regExp = new RegExp(customDate.regExp); + if (regExp.test(url)) { + obj.data = Object.assign(customDate.data, obj.data); + } + } + } + } + // 根据指定globalParamName匹配全局请求参数 + let customDate = that.getRequestGlobalParam(globalParamName); + if (customDate && JSON.stringify(customDate) !== "{}") { + if (customDate.regExp) { + obj.data = Object.assign(customDate.data, obj.data); // 新版本 + } else { + obj.data = Object.assign(customDate, obj.data); // 兼容旧版本 + } + } + // 注入自定义全局参数结束----------------------------------------------------------- + // 若执行的函数不是pub类型函数,则先本地判断下token,可以提高效率。 + // if (url.indexOf("/pub/") == -1 && url.indexOf("/pub_") == -1) { + // 若执行的函数是kh或sys类型函数,先本地判断下token,可以提高效率。 + if (url.indexOf("/kh/") > -1 || url.indexOf("/sys/") > -1 || (url.indexOf(".") > -1 && url.indexOf("pub_") == -1 && url.indexOf("/pub/") == -1 && url.indexOf( + "/pub.") == -1 && url.indexOf("pub.") !== 0 && url.indexOf("pub_") !== 0)) { + if (!vk.checkToken()) { + // 若本地token校验未通过,则直接执行 login 拦截器函数 + return new Promise((resolve, reject) => { + // 执行 login 拦截器函数(跳转到页面页面) + let res = { code: 30204, msg: "本地token校验未通过" }; + let params = obj; + if (typeof that.interceptor.login === "function") { + that.interceptor.login({ + res, + params, + vk + }); + } + reject(res); + }); + } + } + if (typeof obj.isRequest === "undefined") { + obj.isRequest = config.isRequestDefault; + } + // 执行请求 + if (obj.isRequest) { + return that.runRequest(obj); + } else { + return that.runCallFunction(obj); + } + } + + // 设置全局默认配置 + this.setConfig = (customConfig = {}) => { + for (let key in customConfig) { + if (key === "vk") { + vk = customConfig[key]; + } else if (key === "interceptor") { + this.interceptor = Object.assign(this.interceptor, customConfig[key]); + this.config.interceptor = customConfig[key]; + } else if (key === "myfn") { + vk.myfn = customConfig[key]; + } else if (key === "loginPagePath") { + // 兼容老版本 + this.config.login.url = customConfig[key]; + } else if (key === "uniCloud") { + let uniCloudConfig = customConfig[key]; + if (uniCloudConfig && uniCloudConfig.envs) { + for (let envKey in uniCloudConfig.envs) { + let envItem = uniCloudConfig.envs[envKey]; + if (envItem && envItem.provider && envItem.spaceId) { + let initConifg = { + provider: envItem.provider, + spaceId: envItem.spaceId + }; + if (envItem.clientSecret) initConifg.clientSecret = envItem.clientSecret; + if (envItem.endpoint) initConifg.endpoint = envItem.endpoint; + uniCloudEnvs[envKey] = uniCloud.init(initConifg); + } + } + } + } else if (typeof customConfig[key] === "object" && typeof this.config[key] === "object") { + this.config[key] = Object.assign(this.config[key], customConfig[key]); + } else if (typeof customConfig[key] !== "undefined") { + this.config[key] = customConfig[key]; + } + } + } + /** + * 获取vk前端配置 + * 示例 + * vk.callFunctionUtil.getConfig(); + * vk.callFunctionUtil.getConfig("login.url"); + */ + this.getConfig = (key) => { + let config = this.config; + if (key) { + return vk.pubfn.getData(config, key); + } else { + return config; + } + } + + // 初始化 + this.init = (obj = {}) => { + vk = obj.vk; + } + /** + * 云函数上传图片 + * @param {String} title 上传时的loading提示语 + * @param {String} file 要上传的文件对象,file与filePath二选一即可 + * @param {String} filePath 要上传的文件路径,file与filePath二选一即可 + * @param {String} suffix 指定上传后的文件后缀,如果传了file 参数,则此参数可不传 + * @param {String} provider 云存储供应商,支持:unicloud、aliyun + * @param {String} cloudPath 指定上传后的云端文件路径(不指定会自动生成)cloudPath优先级大于cloudDirectory + * @param {String} cloudDirectory 指定上传后的云端文件目录(不指定会自动生成) + * @param {String} needSave 是否需要将图片信息保存到admin素材库 + * @param {String} category_id 素材库分类id,当needSave为true时生效 + * @param {String} uniCloud 上传到其他空间时使用,uniCloud和env二选一即可 + * @param {String} env 上传到其他空间时使用,uniCloud和env二选一即可 + * @param {String} cloudPathAsRealPath 阿里云目录支持,需HBX3.8.5以上版本才支持 + * @param {String} cloudPathRemoveChinese 删除文件名中的中文 + * @param {String} fileType 文件类型,可选image、video、audio 不用传,会自动识别 + * @param {Function} onUploadProgress 上传进度回调 + * @param {Function} success 上传成功时,执行的回调函数 + * @param {Function} fail 上传失败时,执行的回调函数 + * @param {Function} complete 无论上传成功与否,都会执行的回调函数 + * vk.callFunctionUtil.uploadFile + */ + this.uploadFile = (obj = {}) => { + let that = this; + let config = that.config; + if (!obj.filePath && obj.file && obj.file.path) obj.filePath = obj.file.path; + let { + filePath, + cloudPath, + title, + errorToast, + needAlert, + success, + fail, + complete, + type, + provider, + file = {}, + needSave = false, + category_id, + uniCloud: myCloud, + env = "default", + cloudPathAsRealPath = true, // 阿里云目录支持,需HBX3.8.5以上版本才支持 + cloudPathRemoveChinese = true, // 删除文件名中的中文 + cloudDirectory, + } = obj; + // 获取文件类型(image:图片 video:视频 other:其他) + let fileType = this.getFileType(obj); + obj.fileType = fileType; + if (type && !provider) provider = type; + if (!provider) { + let aliyunOSS = vk.pubfn.getData(config, "service.aliyunOSS"); + if (aliyunOSS && aliyunOSS.isDefault) { + provider = "aliyun"; + } else { + provider = "unicloud"; + } + } + if (provider === "aliyun") { + return vk.aliyunOSSUtil.uploadFile(obj); + } + if (title) vk.showLoading(title); + if (errorToast) needAlert = false; + // 生成文件名 + if (!cloudPath) cloudPath = this.createFileName(obj); + let Logger = {}; + if (config.debug) Logger.filePath = filePath; + if (config.debug) Logger.startTime = Date.now(); + let runCloud = myCloud || uniCloudEnvs[env] || uniCloud; + return new Promise((resolve, reject) => { + runCloud.uploadFile({ + filePath: filePath, + cloudPath: cloudPath, + fileType: fileType, + cloudPathAsRealPath, + onUploadProgress: function(progressEvent) { + let percentCompleted = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + if (typeof obj.onUploadProgress == "function") { + obj.onUploadProgress({ + progressEvent, + percentCompleted, + progress: percentCompleted + }); + } + }, + success(res) { + if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res; + if (title) vk.hideLoading(); + uniCloud.getTempFileURL({ + fileList: [res.fileID], + success(data) { + let { fileID, tempFileURL } = data.fileList[0]; + res.fileID = tempFileURL; + res.url = tempFileURL; + res.file_id = fileID; + if (config.debug) Logger.result.url = tempFileURL; + if (typeof success == "function") success(res); + resolve(res); + if (needSave) { + // 保存文件记录到数据库 + vk.userCenter.addUploadRecord({ + data: { + url: res.url, + name: file.name, + size: file.size, + file_id: res.file_id, + provider, + category_id, + }, + filePath, + fileType, + success: function() { + if (typeof obj.addSuccess == "function") obj.addSuccess(res); + }, + fail: function(res) { + if (typeof obj.addFail === "function") obj.addFail(res); + } + }); + } + } + }); + }, + fail(err) { + if (title) vk.hideLoading(); + if (config.debug) Logger.error = err; + if (errorToast) vk.toast(JSON.stringify(err), "none"); + if (needAlert) { + if (config.debug) vk.alert(JSON.stringify(err)); + } + if (typeof fail == "function") fail(err); + reject(err); + }, + complete() { + if (config.debug) { + Logger.endTime = Date.now(); + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + console.log("%c--------【开始】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + console.log("【本地文件】: ", Logger.filePath); + console.log("【返回数据】: ", Logger.result); + console.log("【预览地址】: ", Logger.result.fileID); + console.log("【上传耗时】: ", Logger.runTime, "毫秒"); + console.log("【上传时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) console.error("【error】:", Logger.error); + console.log("%c--------【结束】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;'); + } + if (typeof complete == "function") complete(); + } + }); + }); + } + } + // 云函数普通请求 + runCallFunction(obj = {}) { + let that = this; + let config = that.config; + let { + url, + data, + title, + loading, + isRequest, + name, + complete, + uniCloud: myCloud, + env = "default" + } = obj; + if (title) vk.showLoading(title); + if (loading) vk.setLoading(true, loading); + if (!name) name = config.isTest ? config.testFunctionName : config.functionName; + obj.name = name; + let Logger = {}; + if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data; + let promiseAction = new Promise(function(resolve, reject) { + if (config.debug) Logger.startTime = Date.now(); + let runCloud = myCloud || uniCloudEnvs[env] || uniCloud; + runCloud.callFunction({ + name: name, + data: { + $url: url, + data: data + }, + success(res = {}) { + that.callFunctionSuccess({ + res: res.result, + params: obj, + Logger, + resolve, + reject + }); + }, + fail(res) { + that.callFunctionFail({ + res, + params: obj, + Logger, + reject, + sysFail: true + }); + }, + complete(res) { + that.callFunctionComplete({ + res, + params: obj, + Logger + }); + } + }); + }); + promiseAction.catch(error => {}); + return promiseAction; + } + + // 云函数url化请求 + runRequest(obj = {}) { + let that = this; + let config = that.config; + let { + url, + data, + title, + loading, + name, + complete + } = obj; + if (typeof obj.needAlert === "undefined") obj.needAlert = true; + if (!name) name = config.isTest ? config.testFunctionName : config.functionName; + obj.name = name; + let requestUrl = config.functionNameToUrl[name]; + let Logger = {}; + if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data; + let uniIdToken = uni.getStorageSync(config.uniIdTokenKeyName); + let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName); + if (title) vk.showLoading(title); + if (loading) vk.setLoading(true, loading); + let promiseAction = new Promise(function(resolve, reject) { + if (config.debug) Logger.startTime = Date.now(); + uni.request({ + method: "POST", + url: requestUrl, + data: { + $url: url, + data: data, + uniIdToken: uniIdToken + }, + success(res = {}) { + that.callFunctionSuccess({ + res: res.data, + params: obj, + Logger, + resolve, + reject + }); + }, + fail(res) { + that.callFunctionFail({ + res, + params: obj, + Logger, + reject, + sysFail: true + }); + }, + complete(res) { + that.callFunctionComplete({ + res, + params: obj, + Logger + }); + } + }); + }); + promiseAction.catch(error => {}); + return promiseAction; + } + + // 云函数请求成功时执行 + callFunctionSuccess(obj) { + let that = this; + let config = that.config; + let { + res = {}, + params, + Logger, + resolve, + reject + } = obj; + let { + title, + loading, + success + } = params; + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + if (typeof res.code === "undefined" && typeof res.errCode !== "undefined") res.code = res.errCode; + let code = res.code; + if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res; + if (code == 0 || res.key == 1 || (code == undefined && res.uid)) { + if (res.vk_uni_token) that.saveToken(res.vk_uni_token); + if (res.userInfo && res.needUpdateUserInfo) that.updateUserInfo(res); + if (typeof success == "function") success(res); + resolve(res); + } else if ([1301, 1302, 30201, 30202, 30203, 30204].indexOf(code) > -1 && res.msg.indexOf("token") > -1) { + // 执行 login 拦截器函数(跳转到页面页面) + if (typeof that.interceptor.login === "function") { + that.interceptor.login({ + res, + params, + vk + }); + } + reject(res); + } else { + that.callFunctionFail({ + res, + params, + Logger, + reject + }); + } + } + + // 云函数请求失败时执行 + callFunctionFail(obj) { + let that = this; + let config = that.config; + let { globalErrorCode = {} } = config; + let { + res = {}, + params, + Logger, + reject, + sysFail + } = obj; + let { + title, + loading, + errorToast, + noAlert, + needAlert, + fail, + } = params; + // 只有是系统异常时才进行重试 + if (params.needRetry) { + if (sysFail || (res.code && [90001].indexOf(res.code) > -1)) { + if (!obj.hookResult || (typeof obj.hookResult === "function" && !obj.hookResult(err))) { + Logger.sysFail = true; + if (typeof params.retry == "function") params.retry(res, params); + return false; + } + } + } + + if (typeof noAlert !== "undefined") needAlert = !noAlert; + if (typeof needAlert === "undefined") { + needAlert = (typeof fail === "function") ? false : true; + } + if (errorToast) needAlert = false; + if (title) vk.hideLoading(); + if (loading) vk.setLoading(false, loading); + let errMsg = ""; + let sysErr = false; + if (typeof res.code !== "undefined") { + if (res.msg) { + errMsg = res.msg; + } else if (res.errMsg) { + errMsg = res.errMsg; + } else if (res.message) { + errMsg = res.message; + } + } else { + sysErr = true; + errMsg = JSON.stringify(res); + } + if (typeof errMsg !== "string") errMsg = JSON.stringify(errMsg); + if (!errMsg) errMsg = ""; + if (res.code >= 90001 && errMsg.indexOf("数据库") > -1) { + sysErr = true; + } else if ([404, 500].indexOf(res.code) > -1 && errMsg.indexOf("云函数") > -1) { + sysErr = true; + } else if ((res.code === 501 && errMsg.indexOf("timeout for 10000ms") > -1) || (res.code === "SYS_ERR" && errMsg.indexOf(": request:ok") > -1)) { + errMsg = globalErrorCode["cloudfunction-unusual-timeout"] || "请求超时,但请求还在执行,请重新进入页面。"; + } else if (typeof errMsg.toLowerCase === "function" && (errMsg.toLowerCase().indexOf("timeout") > -1 || errMsg.toLowerCase().indexOf("etimedout") > -1)) { + sysErr = true; + errMsg = globalErrorCode["cloudfunction-timeout"] || "请求超时,请重试!"; + } else if (errMsg.indexOf("reaches burst limit") > -1) { + errMsg = globalErrorCode["cloudfunction-reaches-burst-limit"] || "系统繁忙,请稍后再试。"; + } else if (res.code === "InternalServerError") { + sysErr = true; + } + let runKey = true; + if (typeof that.interceptor.fail == "function") { + runKey = that.interceptor.fail({ + vk, + res: res, + params: params + }); + if (runKey === undefined) runKey = true; + } + if (runKey) { + Logger.error = res; + if (errorToast) vk.toast(errMsg, "none"); + if (needAlert && vk.pubfn.isNotNull(errMsg)) { + if (sysErr) { + let toastMsg = globalErrorCode["cloudfunction-system-error"] || "网络开小差了!"; + vk.toast(toastMsg, "none"); + } else { + vk.alert(errMsg); + } + } + if (typeof fail == "function") fail(res); + } + if (typeof reject == "function") reject(res); + } + + // 云函数请求完成后执行 + callFunctionComplete(obj) { + let that = this; + let config = that.config; + let { + res = {}, + params, + Logger + } = obj; + let { + name, + url, + isRequest, + complete, + debug: debugLog + } = params; + if (params.needRetry && Logger.sysFail) { + return false; + } + if (typeof debugLog === "undefined") debugLog = config.debug; + if (debugLog) { + Logger.endTime = Date.now(); + if (isRequest) { + Logger.label = "【url化】"; + } else { + Logger.label = ""; + } + Logger.runTime = (Logger.endTime - Logger.startTime); + let colorArr = config.logger.colorArr; + let colorStr = colorArr[counterNum % colorArr.length]; + counterNum++; + let functionType = url.indexOf(".") > -1 ? "云对象" : "云函数"; + console.log(`%c--------【开始】${Logger.label}【${functionType}请求】【${name}】【${url}】--------`, `color: ${colorStr};font-size: 12px;font-weight: bold;`); + console.log("【请求参数】: ", Logger.params); + console.log("【返回数据】: ", Logger.result); + console.log("【总体耗时】: ", Logger.runTime, "毫秒【含页面渲染】"); + console.log("【请求时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss")); + if (Logger.error) { + let errorLog = console.warn || console.error; + if (Logger.error.err && Logger.error.err.stack) { + console.error("【Error】: ", Logger.error); + console.error("【Stack】: ", Logger.error.err.stack); + } else { + errorLog("【Error】: ", Logger.error); + } + } + console.log(`%c--------【结束】${Logger.label}【${functionType}请求】【${name}】【${url}】--------`, `color: ${colorStr};font-size: 12px;font-weight: bold;`); + } + if (typeof complete == "function") complete(res); + } + // 生成文件名 + createFileName(obj = {}) { + let { + file, + filePath, + index = 0, + cloudPathRemoveChinese = true, + cloudDirectory + } = obj; + let suffix = this.getFileSuffix(obj); + let oldName = index + "." + suffix; + // 注意:小程序无法获取到 file.name + if (file && file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) oldName = file.name; + // 只保留["数字","英文",".","-"] + if (cloudPathRemoveChinese) { + oldName = oldName.replace(/[^a-zA-Z.-d]/g, ''); + } + if (oldName.indexOf(".") == 0) oldName = "0" + oldName; + } + let date = new Date(); + let dateYYYYMMDD = vk.pubfn.timeFormat(date, "yyyy/MM/dd"); + let dateTime = date.getTime().toString(); // 时间戳 + // 时间戳后8位 + let dateTimeEnd8 = dateTime.substring(dateTime.length - 8, dateTime.length); + let randomNumber = vk.pubfn.random(8); // 8位随机数 + // 文件路径 + let newFilePath = ""; + if (cloudDirectory) { + // 如果自定义了上传目录,则使用自定义的上传目录 + if (cloudDirectory.lastIndexOf("/") !== cloudDirectory.length-1) { + cloudDirectory = cloudDirectory + "/"; + } + newFilePath = cloudDirectory; + } else { + // 否则,使用年月日作为上传目录 + newFilePath = dateYYYYMMDD + "/"; + } + // 文件名 = 时间戳后8位 - 随机数8位 + 原本文件名 + let fileNickName = dateTimeEnd8 + "-" + randomNumber + "-" + oldName; + // 文件名全称(包含文件路径) = 文件路径 + 文件名 + let fileFullName = newFilePath + fileNickName; + return fileFullName; + } + + getFileSuffix(obj = {}) { + let { + file, + filePath, + suffix = "png" + } = obj; + if (filePath) { + let suffixName = filePath.substring(filePath.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file) { + if (file.path) { + let suffixName = file.path.substring(file.path.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + if (file.name) { + let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1); + if (suffixName && suffixName.length < 5) suffix = suffixName; + } + } + return suffix; + } + getFileType(obj = {}) { + let { + file, + filePath + } = obj; + let fileType = "other"; + let suffix = this.getFileSuffix(obj); + if (["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"].indexOf(suffix) > -1) { + fileType = "image"; + } else if (["avi", "mp3", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"].indexOf(suffix) > -1) { + fileType = "video"; + } + return fileType; + } + + // 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中) + callFunctionRetry(obj = {}) { + let { retryCount } = obj; + delete obj.retryCount; + return new Promise((resolve, reject) => { + this.callRetryFn(obj, resolve, reject, retryCount); + }); + } + // 重试实现 + callRetryFn(obj, resolve, reject, retryCount) { + let that = this; + let debug = that.config.debug; + that.callFunction({ + ...obj, + needRetry: retryCount ? true : false, // 判断是否需要重试 + retry: function(err) { + obj.runCount = obj.runCount ? obj.runCount + 1 : 1; + obj.needRetry = retryCount > obj.runCount ? true : false; // 判断是否需要重试 + let errorMsg = err.message ? `异常信息:${err.message}` : ""; + if (debug) console.log(`【请求失败】正在第【${obj.runCount}】次重试:${obj.url}`); + if (obj.retryInterval) { + setTimeout(function() { + that._callRetryFn(obj, resolve, reject, retryCount); + }, obj.retryInterval); + } else { + // 如果无延迟,则不写setTimeout,因为setTimeout 即使time为0,也有一定延迟。 + that._callRetryFn(obj, resolve, reject, retryCount); + } + } + }); + } + + _callRetryFn(obj, resolve, reject, retryCount) { + if (obj.runCount < retryCount) { + this.callRetryFn(obj, resolve, reject, retryCount); + } else { + this.callFunction(obj).catch((err) => { + reject(); + }); + } + } + + +} + +export default new CallFunctionUtil diff --git a/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js new file mode 100644 index 0000000..770fc31 --- /dev/null +++ b/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-user-center.js @@ -0,0 +1,1068 @@ +/** + * unicloud-user-center 接口类(uni-id封装) + * author VK + */ +import callFunctionUtil from './vk-unicloud-callFunctionUtil.js' +var { callFunction, config, saveToken, deleteToken } = callFunctionUtil; +import debounce from '../function/debounce.js' + +const debounceTime = 1000; // 防抖时长 + +const localeObj = { + "zh-Hans": { + "loading": "请求中...", + "login": "登录中...", + "register": "注册中...", + "create": "生成中...", + }, + "zh-Hant": { + "loading": "請求中...", + "login": "登入中...", + "register": "注册中...", + "create": "生成中...", + }, + "en": { + "loading": "loading...", + "login": "login...", + "register": "register...", + "create": "create...", + } +}; + +function addLoading(obj, title) { + if (typeof obj.loading === "undefined" && !obj.title && title) { + let locale; + if (typeof uni.vk !== "undefined") { + locale = localeObj[uni.vk.pubfn.getLocale()]; + } else { + locale = localeObj["zh-Hans"]; + } + obj.title = locale[title] || "loading..."; + } + return obj; +} + +export default { + /** + * 用户注册(用户名+密码) + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + * @param {String} uid 用户ID + */ + register(obj = {}) { + return debounce(() => { + addLoading(obj, "register"); + return callFunction({ + ...obj, + url: 'user/pub/register' + }); + }, debounceTime, true, "login"); + }, + /** + * 用户登录(用户名+密码) + * data 请求参数 说明 + * @param {String} username 用户名 + * @param {String} password 密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + * @param {Object} userInfo 用户信息 + * @param {String} uid 用户ID + */ + login(obj = {}) { + addLoading(obj, "login"); + return callFunction({ + ...obj, + url: 'user/pub/login' + }); + }, + /** + * 登出(退出) + * data 请求参数 说明 + * 无 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + logout(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/logout', + success(res) { + deleteToken(); + if (typeof obj.success == "function") obj.success(res); + } + }); + }, + /** + * 修改密码 + * @description 修改成功后,需要重新登录获取新的token + * data 请求参数 说明 + * @param {String} oldPassword 旧密码 + * @param {String} newPassword 新密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + updatePwd(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/updatePwd', + }); + }, + /** + * 重置密码 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + resetPwd(obj) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/resetPwd', + }); + }, + /** + * 设置头像 + * data 请求参数 说明 + * @param {String} avatar 头像地址 + * @param {Boolean} deleteOldFile 是否同时删除云储存内的头像文件 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + setAvatar(obj = {}) { + addLoading(obj, "loading"); + //obj.isRequest = true; + return callFunction({ + ...obj, + url: 'user/kh/setAvatar', + }); + }, + /** + * 设置昵称等用户展示的个人信息 + * data 请求参数 说明 + * @param {String} nickname 昵称 + * @param {String} avatar 头像 + * @param {Number} gender 性别 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + updateUser(obj = {}) { + addLoading(obj, "loading"); + callFunction({ + ...obj, + url: 'user/kh/updateUser' + }); + }, + /** + * 获取用户最新信息 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 错误信息 + * @param {Object} userInfo 用户信息 + */ + getCurrentUserInfo(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/getMyUserInfo', + }); + }, + /** + * token校验 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {Object} userInfo 当前用户信息 + * @param {Array} role 当前用户角色 + * @param {Array} permission 当前用户权限 + */ + checkToken(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/checkToken', + }); + }, + /** + * 绑定手机号 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindMobile', + }); + }, + /** + * 解绑手机号 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindMobile', + }); + }, + /** + * 绑定新的手机号(换绑手机号) + * data 请求参数 说明 + * @param {String} oldMobile 旧手机号码 + * @param {String} oldMobileCode 旧手机收到的验证码 + * @param {String} mobile 新手机号码 + * @param {String} code 新手机收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindNewMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindNewMobile', + }); + }, + /** + * 手机号登录(手机号+手机验证码) + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} code 验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginBySms(obj = {}) { + return debounce(() => { + addLoading(obj, "login"); + return callFunction({ + url: 'user/pub/loginBySms', + ...obj + }); + }, debounceTime, true, "login"); + }, + /** + * 发送手机号验证码 + * data 请求参数 说明 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {Object} requestRes 原始返回数据 + * @param {Object} requestParam 包含服务供应商和发送的手机号 + */ + sendSmsCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/sendSmsCode', + }); + }, + /** + * APP端 手机一键登录 + * data 请求参数 说明 + * @param {String} access_token uni.login登录成功后,返回的access_token参数 + * @param {String} openid uni.login登录成功后,返回的openid参数 + * @param {String} type 指定操作类型,可选值为login、register,不传此参数时表现为手机号已注册则登录,手机号未注册则进行注册 + * @param {String} password 密码,type为register时生效 + * @param {String} inviteCode 邀请人的邀请码,type为register时生效 + * @param {String} myInviteCode 设置当前注册用户自己的邀请码,type为register时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} uid 当前token对应的用户uid + * @param {String} type 操作类型,login为登录、register为注册 + * @param {String} mobile 登录者手机号 + * @param {String} userInfo 用户全部信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByUniverify(obj = {}) { + addLoading(obj, "login"); + if (typeof obj.needAlert === "undefined") obj.needAlert = true; + // #ifdef APP-PLUS + uni.login({ + provider: 'univerify', + univerifyStyle: obj.univerifyStyle, + success(res) { + let dataJson = Object.assign(obj.data, res.authResult); + callFunction({ + url: 'user/pub/loginByUniverify', + ...obj, + data: dataJson, + }); + }, + fail: obj.fail, + complete: (res) => { + uni.vk.hideLoading(); + } + }); + // #endif + // #ifndef APP-PLUS + uni.vk.toast("请在APP中使用本机号码一键登录", "none"); + // #endif + }, + + /** + * 绑定邮箱 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindEmail', + }); + }, + /** + * 解绑邮箱 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + */ + unbindEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindEmail', + }); + }, + /** + * 绑定新的邮箱(换绑邮箱) + * @param {String} oldEmail 旧邮箱码 + * @param {String} oldEmailCode 旧邮箱收到的验证码 + * @param {String} email 新邮箱码 + * @param {String} code 新邮箱收到的验证码 + */ + bindNewEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/bindNewEmail', + }); + }, + /** + * 邮箱登录(邮箱+邮箱验证码) + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} code 邮箱收到的验证码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 注册完成自动登录之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByEmail(obj = {}) { + addLoading(obj, "login"); + return callFunction({ + url: 'user/pub/loginByEmail', + ...obj + }); + }, + /** + * 发送邮件验证码 + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} email 手机号 + * @param {String} verifyCode 验证码 + */ + sendEmailCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/sendEmailCode', + }); + }, + /** + * 根据邮箱+验证码重置密码 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} email 邮箱号码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + resetPasswordByEmail(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/resetPasswordByEmail', + }); + }, + /** + * 设置验证码 + * @description 设置验证码(此接口正式环境不要暴露,故写在了sys目录下) + * data 请求参数 说明 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} type 验证码类型 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} email 邮箱 + * @param {String} mobile 手机号 + * @param {String} verifyCode 验证码(uni 1.1.2开始不再返回verifyCode) + */ + setVerifyCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/sys/setVerifyCode', + }); + }, + /** + * 微信登录获取用户code + */ + getWeixinCode() { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + uni.login({ + provider: 'weixin', + success(res) { + resolve(res.code) + }, + fail(err) { + reject(new Error('微信登录失败')) + } + }) + // #endif + // #ifdef APP-PLUS + plus.oauth.getServices((services) => { + let weixinAuthService = services.find((service) => { + return service.id === 'weixin'; + }); + if (weixinAuthService) { + weixinAuthService.authorize(function(res) { + resolve(res.code); + }, function(err) { + console.log(err); + reject(new Error('微信登录失败')); + }); + } + }); + // #endif + // #ifdef H5 + resolve(); + // #endif + }) + }, + /** + * 用户登录(微信授权) + * @description 用户登录(微信授权) + * data 请求参数 说明 + * @param {String} code 微信登录返回的code + * @param {String} platform 客户端类型:mp-weixin、app-plus,默认uni-id会自动取客户端类型,但是在云函数url化等场景无法取到客户端类型,可以使用此参数指定 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByWeixin(obj = {}) { + let that = this; + debounce(() => { + addLoading(obj, "login"); + let { data = {} } = obj; + that.getWeixinCode().then((code) => { + // #ifdef H5 + // H5平台需要区分环境(如微信公众号?网页H5?) + data.vk_platform = uni.vk.h5.getEnv(); + // #endif + callFunction({ + url: 'user/pub/loginByWeixin', + ...obj, + data: { + code, + ...data + } + }); + }); + }, debounceTime, true, "login"); + }, + /** + * 获取微信openid + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} unionid 用户unionid,可以取到此值时返回 + * @param {String} sessionKey 客户端为微信小程序时返回 + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + */ + code2SessionWeixin(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getWeixinCode().then((code) => { + callFunction({ + ...obj, + url: 'user/pub/code2SessionWeixin', + data: { + code, + ...data, + } + }); + }); + }, + /** + * 绑定微信 + * @description 将当前登录用户绑定微信 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindWeixin(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getWeixinCode().then((code) => { + // #ifdef H5 + // H5平台需要区分环境(如微信公众号?网页H5?) + data.vk_platform = uni.vk.h5.getEnv(); + // #endif + callFunction({ + ...obj, + url: 'user/kh/bindWeixin', + data: { + code, + ...data + } + }); + }); + }, + /** + * 解绑微信 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindWeixin(obj = {}) { + addLoading(obj, "loading"); + let { data = {} } = obj; + // #ifdef H5 + // H5平台需要区分环境(如微信公众号?网页H5?) + data.vk_platform = uni.vk.h5.getEnv(); + obj.data = data; + // #endif + return callFunction({ + ...obj, + url: 'user/kh/unbindWeixin', + }); + }, + /** + * 获取微信绑定的手机号(后面会支持支付宝) + * data 请求参数 + * @param {String} encryptedData + * @param {String} iv + * @param {String} sessionKey + */ + getPhoneNumber(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/getPhoneNumber' + }); + }, + /** + * 通过微信小程序绑定的手机号登录 + * data 请求参数 说明 + * @param {String} encryptedData + * @param {String} iv + * @param {String} sessionKey + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByWeixinPhoneNumber(obj = {}) { + return debounce(() => { + addLoading(obj, "login"); + return callFunction({ + url: 'user/pub/loginByWeixinPhoneNumber', + ...obj + }); + }, debounceTime, true, "login"); + }, + /** + * 生成微信小程序码 + * @param {String} scene 自定义参数最大32个可见字符 只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {number} width 二维码的宽度,单位 px,最小 280px,最大 1280px + * @param {boolean} auto_color 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false + * @param {Object} line_color auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示 + * @param {boolean} is_hyaline 是否需要透明底色,为 true 时,生成透明底色的小程序 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getWeixinMPqrcode(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getWeixinMPqrcode', + }); + }, + /** + * 生成微信小程序scheme码 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getWeixinMPscheme(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getWeixinMPscheme', + }); + }, + /** + * 生成微信小程序url链接 + * data 请求参数 说明 + * @param {String} path 小程序页面路径 + * @param {String} query 小程序页面参数 + * @param {String} env_version 默认值"release"。要打开的小程序版本。正式版为 "release",体验版为"trial",开发版为"develop",仅在微信外打开时生效 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getWeixinMPurl(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getWeixinMPurl', + }); + }, + /** + * 获取支付宝code + */ + getAlipayCode() { + // #ifdef APP-PLUS || MP-ALIPAY + return new Promise((resolve, reject) => { + uni.login({ + provider: 'alipay', + success(res) { + resolve(res.code); + }, + fail(err) { + reject(new Error('支付宝登录失败')); + } + }); + }); + // #endif + }, + /** + * 支付宝登录 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByAlipay(obj = {}) { + let that = this; + debounce(() => { + addLoading(obj, "login"); + let { data = {} } = obj; + that.getAlipayCode().then((code) => { + callFunction({ + url: 'user/pub/loginByAlipay', + ...obj, + data: { + ...data, + code: code + } + }); + }); + }, debounceTime, true, "login"); + }, + /** + * 获取支付宝openid + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} openid 用户openid + * @param {String} accessToken 客户端为APP时返回 + * @param {String} expiresIn 客户端为APP时返回,accessToken 接口调用凭证超时时间,单位(秒) + * @param {String} refreshToken 客户端为APP时返回,用于刷新accessToken + * @param {String} reExpiresIn refreshToken超时时间,单位(秒) + */ + code2SessionAlipay(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getAlipayCode().then((code) => { + callFunction({ + ...obj, + url: 'user/pub/code2SessionAlipay', + data: { + ...data, + code: code + } + }); + }); + }, + /** + * 绑定支付宝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindAlipay(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getAlipayCode().then((code) => { + callFunction({ + ...obj, + url: 'user/kh/bindAlipay', + data: { + ...data, + code: code + } + }); + }); + }, + /** + * 解绑支付宝 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindAlipay(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindAlipay', + }); + }, + /** + * 生成支付宝小程序码 + * @param {String} page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * @param {String} scene 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getAlipayMiniCode(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getAlipayMiniCode', + }); + }, + /** + * 密码加密测试(暂不用) + */ + encryptPwd(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/sys/encryptPwd', + }); + }, + // 1.1.2新增 + /** + * 设置用户邀请码(自动生成) + * @description 针对未生成邀请码的用户使用此方法生成邀请码(自动生成) + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} myInviteCode 最终设置的邀请码 + */ + setUserInviteCode(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/setUserInviteCode', + }); + }, + /** + * 用户接受邀请 + * @description 此接口用于在注册之后再填写邀请码的场景,多数情况下不会用到此接口而是在注册时填写邀请码 + * data 请求参数 说明 + * @param {String} inviteCode 邀请人的邀请码 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + acceptInvite(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/acceptInvite', + }); + }, + /** + * 获取接受邀请的用户清单 + * data 请求参数 说明 + * @param {Number} pageIndex 当前页码 + * @param {Number} pageSize 每页显示数量 + * @param {Array} sortRule 排序规则 + * @param {object} formData 查询条件数据源 + * @param {Array} columns 查询条件规则 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getInvitedUser(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/getInvitedUser', + }); + }, + /** + * 根据手机验证码重置账号密码 + * data 请求参数 说明 + * @param {String} password 重置后的密码 + * @param {String} code 验证码 + * @param {String} mobile 手机号 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + resetPasswordByMobile(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/pub/resetPasswordByMobile', + }); + }, + /** + * 获取我拥有的菜单列表 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} menus 树形结构的菜单 + * @param {String} menuList 数组结构的菜单 + * @param {String} userInfo 用户信息 + */ + getMenu(obj = {}) { + return callFunction({ + ...obj, + url: 'user/kh/getMenu' + }); + }, + /** + * 添加文件上传记录 + * data 请求参数 说明 + * @param {String} url 文件外网访问url + * @param {String} name 文件名 + * @param {Number} size 文件大小 + * @param {String} file_id 文件id + * @param {String} provider 供应商 + * @param {String} category_id 分类ID + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + addUploadRecord(obj = {}) { + let { fileType, filePath } = obj; + if (fileType === "image") { + uni.getImageInfo({ + src: filePath, + success: function(res) { + return callFunction({ + ...obj, + url: 'user/kh/addUploadRecord', + data: { + ...obj.data, + orientation: res.orientation, + width: res.width, + height: res.height + } + }); + }, + fail: function(err) { + console.error(err) + } + }); + } else if (fileType === "video") { + uni.getVideoInfo({ + src: filePath, + success: function(res) { + return callFunction({ + ...obj, + url: 'user/kh/addUploadRecord', + data: { + ...obj.data, + duration: parseFloat(res.duration.toFixed(3)), + width: res.width, + height: res.height + } + }); + }, + fail: function(err) { + console.error(err) + } + }); + } else { + return callFunction({ + ...obj, + url: 'user/kh/addUploadRecord' + }); + } + }, + /** + * 获取QQ code + */ + getQQCode() { + // #ifdef APP-PLUS || MP-QQ + return new Promise((resolve, reject) => { + uni.login({ + provider: 'qq', + success(res) { + // #ifdef APP-PLUS + resolve({ + accessToken: res.authResult.access_token, + }) + // #endif + // #ifdef MP-QQ + resolve({ + code: res.code, + }) + // #endif + }, + fail(err) { + reject(new Error('QQ登录失败')); + } + }); + }); + // #endif + }, + /** + * QQ登录 + * data 请求参数 说明 + * @param {String} type 可传login或register,若为login:则不存在不会自动注册,若为register,则用户存在会报错,不传,则存在自动登录,不存在,则注册。 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + * @param {String} token 登录成功之后返回的token信息 + * @param {String} tokenExpired token过期时间 + */ + loginByQQ(obj = {}) { + let that = this; + debounce(() => { + addLoading(obj, "login"); + let { data = {} } = obj; + that.getQQCode().then(({ code, accessToken } = {}) => { + callFunction({ + url: 'user/pub/loginByQQ', + ...obj, + data: { + ...data, + code, + accessToken + } + }); + }); + }, debounceTime, true, "login"); + }, + /** + * 绑定QQ + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + bindQQ(obj = {}) { + let that = this; + addLoading(obj, "loading"); + let { data = {} } = obj; + that.getQQCode().then(({ code, accessToken } = {}) => { + callFunction({ + ...obj, + url: 'user/kh/bindQQ', + data: { + ...data, + code, + accessToken + } + }); + }); + }, + /** + * 解绑QQ + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + unbindQQ(obj = {}) { + addLoading(obj, "loading"); + return callFunction({ + ...obj, + url: 'user/kh/unbindQQ', + }); + }, + /** + * 生成qq小程序码 + * @param {String} path 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + getQQMiniCode(obj = {}) { + addLoading(obj, "create"); + return callFunction({ + ...obj, + url: 'user/kh/getQQMiniCode', + }); + }, + /** + * App升级中心 - 检测是当前版本是否需要升级 + * res 返回参数说明 + * @param {Number} code 错误码,0表示成功 + * @param {String} msg 详细信息 + */ + checkVersion(obj = {}) { + return callFunction({ + ...obj, + url: 'user/pub/checkVersion', + }); + }, +}; diff --git a/windows/components/breadcrumb.vue b/windows/components/breadcrumb.vue new file mode 100644 index 0000000..43ff4d9 --- /dev/null +++ b/windows/components/breadcrumb.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/windows/components/errorLog.vue b/windows/components/errorLog.vue new file mode 100644 index 0000000..c46fba8 --- /dev/null +++ b/windows/components/errorLog.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/windows/components/updatePassword.vue b/windows/components/updatePassword.vue new file mode 100644 index 0000000..f260678 --- /dev/null +++ b/windows/components/updatePassword.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/windows/leftWindow.vue b/windows/leftWindow.vue new file mode 100644 index 0000000..e659940 --- /dev/null +++ b/windows/leftWindow.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/windows/topWindow.vue b/windows/topWindow.vue new file mode 100644 index 0000000..2cf3481 --- /dev/null +++ b/windows/topWindow.vue @@ -0,0 +1,518 @@ + + + + + diff --git a/使用帮助/0、此处的文档已不更新,请直接看官网文档.md b/使用帮助/0、此处的文档已不更新,请直接看官网文档.md new file mode 100644 index 0000000..1dbdc9c --- /dev/null +++ b/使用帮助/0、此处的文档已不更新,请直接看官网文档.md @@ -0,0 +1,2 @@ +# 此处的文档已不更新,请直接看官网文档 +[官网地址](https://vkdoc.fsq.pub/admin/) \ No newline at end of file diff --git a/使用帮助/1、快速上手 - 安装步骤.md b/使用帮助/1、快速上手 - 安装步骤.md new file mode 100644 index 0000000..56833ea --- /dev/null +++ b/使用帮助/1、快速上手 - 安装步骤.md @@ -0,0 +1,3 @@ +# 快速上手 - 安装步骤 +## 此处的文档已不更新,请直接看官网文档 +[文档地址](https://vkdoc.fsq.pub/admin/1/quickstart.html) \ No newline at end of file diff --git a/使用帮助/代码快捷提示/javascript代码块提示.json b/使用帮助/代码快捷提示/javascript代码块提示.json new file mode 100644 index 0000000..2fec9c4 --- /dev/null +++ b/使用帮助/代码快捷提示/javascript代码块提示.json @@ -0,0 +1,1243 @@ +// 将下方代码复制到 hbx 工具 - 代码块设置 - javascript代码块 +{ + "发起云函数请求(常用形式)": { + "prefix": "vk.callFunction", + "body": [ + "vk.callFunction({", + "\turl: '云函数路径',", + "\ttitle: '请求中...',", + "\tdata: {", + "\t\t", + "\t},", + "\tsuccess: (data) => {", + "\t\t$0", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "发起一个云函数请求" + }, + "发起云函数请求(promise形式)": { + "prefix": "vk.callFunction", + "body": [ + "vk.callFunction({", + "\turl: '云函数路径',", + "\ttitle: '请求中...',", + "\tdata: {", + "\t\t", + "\t},", + "}).then((data) => {", + "\t\t$0", + "});" + ], + "triggerAssist": false, + "description": "发起一个云函数请求" + }, + "发起云函数请求(async/await形式)": { + "prefix": "vk.callFunction", + "body": [ + "let data = await vk.callFunction({", + "\turl: '云函数路径',", + "\ttitle: '请求中...',", + "\tdata: {", + "\t\t", + "\t},", + "});" + ], + "triggerAssist": false, + "description": "发起一个云函数请求" + }, + "vk.alert": { + "prefix": "vk.alert", + "body": [ + "vk.alert('$0');" + ], + "triggerAssist": false, + "description": "弹出提示框" + }, + "vk.confirm": { + "prefix": "vk.confirm", + "body": [ + "vk.confirm('内容', '提示', '确定', '取消', res => {", + "\tif (res.confirm) {", + "\t\t$0", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "弹出二次确认框" + }, + "vk.prompt": { + "prefix": "vk.prompt", + "body": [ + "vk.prompt('请输入', '提示', '确定', '取消', res => {", + "\tif (res.confirm) {", + "\t\t$0console.log(res.content)", + "\t}", + "},'输入框内初始内容');" + ], + "triggerAssist": false, + "description": "弹出输入框" + }, + "vk.toast": { + "prefix": "vk.toast", + "body": [ + "vk.toast('$0','none');" + ], + "triggerAssist": false, + "description": "弹出toast提示" + }, + "vk.showActionSheet": { + "prefix": "vk.showActionSheet", + "body": [ + "let sheetList = ['$0位置', '@好友'];", + "vk.showActionSheet({", + "\ttitle: '',", + "\tlist: sheetList,", + "\tcolor: '#000000',", + "\tsuccess: res => {", + "\t\tif (sheetList[res.index] == '位置') {", + "\t\t\t", + "\t\t} else if (sheetList[res.index] == '@好友') {", + "\t\t\t", + "\t\t}", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "弹出操作面板" + }, + "vk.showLoading": { + "prefix": "vk.showLoading", + "body": [ + "vk.showLoading('$0加载中...');" + ], + "triggerAssist": false, + "description": "显示加载提示" + }, + "vk.hideLoading": { + "prefix": "vk.hideLoading", + "body": [ + "vk.hideLoading();" + ], + "triggerAssist": false, + "description": "关闭加载提示" + }, + "弹窗-alert": { + "prefix": "tc", + "body": [ + "vk.alert('$0');" + ], + "triggerAssist": false, + "description": "弹出提示框" + }, + "弹窗-confirm": { + "prefix": "tc", + "body": [ + "vk.confirm('内容', '提示', '确定', '取消', res => {", + "\tif (res.confirm) {", + "\t\t$0", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "弹出二次确认框" + }, + "弹窗-prompt": { + "prefix": "tc", + "body": [ + "vk.prompt('请输入', '提示', '确定', '取消', res => {", + "\tif (res.confirm) {", + "\t\t$0console.log(res.content)", + "\t}", + "},'输入框内初始内容');" + ], + "triggerAssist": false, + "description": "弹出输入框" + }, + "弹窗-toast": { + "prefix": "tc", + "body": [ + "vk.toast('$0','none');" + ], + "triggerAssist": false, + "description": "弹出toast提示" + }, + "弹窗-showActionSheet": { + "prefix": "tc", + "body": [ + "let sheetList = ['$0位置', '@好友'];", + "vk.showActionSheet({", + "\ttitle: '',", + "\tlist: sheetList,", + "\tcolor: '#000000',", + "\tsuccess: res => {", + "\t\tif (sheetList[res.index] == '位置') {", + "\t\t\t", + "\t\t} else if (sheetList[res.index] == '@好友') {", + "\t\t\t", + "\t\t}", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "弹出操作面板" + }, + "弹窗-showLoading": { + "prefix": "tc", + "body": [ + "vk.showLoading('$0加载中...');" + ], + "triggerAssist": false, + "description": "显示加载提示" + }, + "弹窗-hideLoading": { + "prefix": "tc", + "body": [ + "vk.hideLoading();" + ], + "triggerAssist": false, + "description": "关闭加载提示" + }, + "vk.navigateTo": { + "prefix": "vk.navigateTo", + "body": [ + "vk.navigateTo('$0');" + ], + "triggerAssist": false, + "description": "页面跳转" + }, + "vk.navigateBack": { + "prefix": "vk.navigateBack", + "body": [ + "vk.navigateBack();" + ], + "triggerAssist": false, + "description": "页面返回" + }, + "vk.redirectTo": { + "prefix": "vk.redirectTo", + "body": [ + "vk.redirectTo('$0');" + ], + "triggerAssist": false, + "description": "关闭当前页面,跳转到应用内的某个页面。" + }, + "vk.switchTab": { + "prefix": "vk.switchTab", + "body": [ + "vk.switchTab('$0');" + ], + "triggerAssist": false, + "description": "跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。" + }, + "vk.reLaunch": { + "prefix": "vk.reLaunch", + "body": [ + "vk.reLaunch('$0');" + ], + "triggerAssist": false, + "description": "关闭所有页面,打开到应用内的某个页面。" + }, + "vk.navigateToHome": { + "prefix": "vk.navigateToHome", + "body": [ + "vk.navigateToHome('$0');" + ], + "triggerAssist": false, + "description": "关闭所有页面,并跳转到首页 (app.config.js 的 index.url)" + }, + "vk.navigateToLogin": { + "prefix": "vk.navigateToLogin", + "body": [ + "vk.navigateToLogin('$0');" + ], + "triggerAssist": false, + "description": "关闭所有页面,并跳转到登录页 (app.config.js 的 login.url)" + }, + "vk.getStorageSync": { + "prefix": "vk.getStorageSync", + "body": [ + "vk.getStorageSync(key$0);" + ], + "triggerAssist": false, + "description": "获取前端本地缓存" + }, + "vk.setStorageSync": { + "prefix": "vk.setStorageSync", + "body": [ + "vk.setStorageSync(key,data);" + ], + "triggerAssist": false, + "description": "保存前端本地缓存" + }, + "vk.removeStorageSync": { + "prefix": "vk.removeStorageSync", + "body": [ + "vk.removeStorageSync($0);" + ], + "triggerAssist": false, + "description": "删除前端本地缓存" + }, + "vk.clearStorageSync": { + "prefix": "vk.clearStorageSync", + "body": [ + "vk.clearStorageSync();" + ], + "triggerAssist": false, + "description": "清空前端本地缓存" + }, + "vk.getStorageInfoSync": { + "prefix": "vk.getStorageInfoSync", + "body": [ + "vk.getStorageInfoSync();" + ], + "triggerAssist": false, + "description": "获取前端本地缓存信息" + }, + "vk.globalDataCache.get": { + "prefix": "vk.globalDataCache.get", + "body": [ + "await vk.globalDataCache.get($0);" + ], + "triggerAssist": false, + "description": "获取云函数全局缓存" + }, + "vk.globalDataCache.set": { + "prefix": "vk.globalDataCache.set", + "body": [ + "await vk.globalDataCache.set(key$0, value, second);" + ], + "triggerAssist": false, + "description": "设置云函数全局缓存" + }, + "vk.globalDataCache.del": { + "prefix": "vk.globalDataCache.del", + "body": [ + "await vk.globalDataCache.del($0);" + ], + "triggerAssist": false, + "description": "删除云函数全局缓存" + }, + "vk.globalDataCache.clear": { + "prefix": "k.globalDataCache.clear", + "body": [ + "await vk.globalDataCache.clear($0);" + ], + "triggerAssist": false, + "description": "清空云函数全局缓存" + }, + "vk.globalDataCache.count": { + "prefix": "vk.globalDataCache.count", + "body": [ + "await vk.globalDataCache.count({$0});" + ], + "triggerAssist": false, + "description": "获取云函数全局缓存总数" + }, + "vk.pubfn.objectAssign": { + "prefix": "vk.pubfn.objectAssign", + "body": [ + "vk.pubfn.objectAssign(obj1, obj2);" + ], + "triggerAssist": false, + "description": "将obj2的属性赋值给obj1" + }, + "vk.pubfn.copyObject": { + "prefix": "vk.pubfn.copyObject", + "body": [ + "vk.pubfn.copyObject($0);" + ], + "triggerAssist": false, + "description": "复制一份对象-解除对象映射关系(不支持克隆函数)" + }, + "vk.pubfn.deepClone": { + "prefix": "vk.pubfn.deepClone", + "body": [ + "vk.pubfn.deepClone($0);" + ], + "triggerAssist": false, + "description": "复制一份对象-解除对象映射关系(支持克隆函数)" + }, + "vk.pubfn.arrayObjectGetArray": { + "prefix": "vk.pubfn.arrayObjectGetArray", + "body": [ + "vk.pubfn.arrayObjectGetArray($0);" + ], + "triggerAssist": false, + "description": "从数组中提取指定字段形式成为新的数组" + }, + "vk.pubfn.getCommonTime": { + "prefix": "vk.pubfn.getCommonTime", + "body": [ + "$0vk.pubfn.getCommonTime();" + ], + "triggerAssist": false, + "description": "获取时间范围" + }, + "vk.pubfn.getData": { + "prefix": "vk.pubfn.getData", + "body": [ + "vk.pubfn.getData(dataObj, name);$0" + ], + "triggerAssist": false, + "description": "自动根据字符串路径获取对象中的值支持.和[] , 且任意一个值为undefined时,不会报错,会直接返回undefined" + }, + "vk.pubfn.isNull": { + "prefix": "vk.pubfn.isNull", + "body": [ + "vk.pubfn.isNull($0)" + ], + "triggerAssist": false, + "description": "检测参数是否为空" + }, + "vk.pubfn.isNotNull": { + "prefix": "vk.pubfn.isNotNull", + "body": [ + "vk.pubfn.isNotNull($0)" + ], + "triggerAssist": false, + "description": "检测参数是否不为空" + }, + "vk.pubfn.isNullOne": { + "prefix": "vk.pubfn.isNullOne", + "body": [ + "vk.pubfn.isNullOne($0)" + ], + "triggerAssist": false, + "description": "检测所有参数 - 是否至少有一个为空" + }, + "vk.pubfn.isNullOneByObject": { + "prefix": "vk.pubfn.isNullOneByObject", + "body": [ + "vk.pubfn.isNullOneByObject($0);" + ], + "triggerAssist": false, + "description": "检测整个对象是否没有一个属性是空值,如果有空值,则返回首个是空值的属性名" + }, + "参数一个都不能为空检测": { + "prefix": "qq.", + "body": [ + "// 参数非空检测", + "let nullKey = vk.pubfn.isNullOneByObject({ params1$0, params2 });", + "if(nullKey) return { code:-1, msg:'参数 '+nullKey+' 不能为空' };" + ], + "triggerAssist": false, + "description": "检测整个对象是否没有一个属性是空值,如果有空值,则返回首个是空值的属性名" + }, + "vk.pubfn.isNullAll": { + "prefix": "vk.pubfn.isNullAll", + "body": [ + "vk.pubfn.isNullAll($0)" + ], + "triggerAssist": false, + "description": "检测所有参数 - 是否全部为空" + }, + "vk.pubfn.isNotNullAll": { + "prefix": "vk.pubfn.isNotNullAll", + "body": [ + "vk.pubfn.isNotNullAll($0)" + ], + "triggerAssist": false, + "description": "检测所有参数 - 是否全部都不为空" + }, + "vk.pubfn.isArray": { + "prefix": "vk.pubfn.isArray", + "body": [ + "vk.pubfn.isArray($0)" + ], + "triggerAssist": false, + "description": "检测变量是否是数组类型" + }, + "vk.pubfn.isObject": { + "prefix": "vk.pubfn.isObject", + "body": [ + "vk.pubfn.isObject($0)" + ], + "triggerAssist": false, + "description": "检测变量是否是对象类型" + }, + "vk.pubfn.getListItem": { + "prefix": "vk.pubfn.getListItem", + "body": [ + "vk.pubfn.getListItem(list, key, value);" + ], + "triggerAssist": false, + "description": "获取对象数组中的某一个item,根据指定的键名和键值" + }, + "vk.pubfn.getListIndex": { + "prefix": "vk.pubfn.getListIndex", + "body": [ + "vk.pubfn.getListIndex(list, key, value);" + ], + "triggerAssist": false, + "description": "获取对象数组中某个元素的index,根据指定的键名和键值" + }, + "vk.pubfn.getListItemIndex": { + "prefix": "vk.pubfn.getListItemIndex", + "body": [ + "vk.pubfn.getListItemIndex(list, key, value);" + ], + "triggerAssist": false, + "description": "获取对象数组中某个元素的item和index,根据指定的键名和键值" + }, + "vk.pubfn.arrayToJson": { + "prefix": "vk.pubfn.arrayToJson", + "body": [ + "vk.pubfn.arrayToJson(list, key);" + ], + "triggerAssist": false, + "description": "数组转对象 - 将对象数组转成json" + }, + "vk.pubfn.random": { + "prefix": "vk.pubfn.random", + "body": [ + "vk.pubfn.random($0);" + ], + "triggerAssist": false, + "description": "产生指定位数的随机数(支持任意字符,默认纯数字)" + }, + "vk.pubfn.hidden": { + "prefix": "vk.pubfn.hidden", + "body": [ + "vk.pubfn.hidden(str, first, last);" + ], + "triggerAssist": false, + "description": "将手机号,账号等隐藏中间字段" + }, + "vk.pubfn.checkArrayIntersection": { + "prefix": "vk.pubfn.checkArrayIntersection", + "body": [ + "vk.pubfn.checkArrayIntersection(arr1, arr2);" + ], + "triggerAssist": false, + "description": "判断常量数组A是否至少有一个元素在常量数组B中存在(两数组有交集)" + }, + "vk.pubfn.arrayToTree": { + "prefix": "vk.pubfn.arrayToTree", + "body": [ + "vk.pubfn.arrayToTree(treeData, treeProps);" + ], + "triggerAssist": false, + "description": "数组结构转树形结构" + }, + "vk.pubfn.treeToArray": { + "prefix": "vk.pubfn.treeToArray", + "body": [ + "vk.pubfn.treeToArray(treeData, treeProps);" + ], + "triggerAssist": false, + "description": "树形结构转数组结构" + }, + "vk.pubfn.createOrderNo": { + "prefix": "vk.pubfn.createOrderNo", + "body": [ + "vk.pubfn.createOrderNo();" + ], + "triggerAssist": false, + "description": "产生订单号,不依赖数据库,高并发时性能高(理论上会重复,但概率非常非常低)" + }, + "vk.pubfn.getCurrentPage": { + "prefix": "vk.pubfn.getCurrentPage", + "body": [ + "vk.pubfn.getCurrentPage();" + ], + "triggerAssist": false, + "description": "获取当前页面实例" + }, + "vk.pubfn.openForm": { + "prefix": "vk.pubfn.openForm", + "body": [ + "vk.pubfn.openForm('弹窗名',{ item })" + ], + "triggerAssist": false, + "description": "打开弹窗" + }, + "vk.pubfn.sleep": { + "prefix": "vk.pubfn.sleep", + "body": [ + "await vk.pubfn.sleep(1000);" + ], + "triggerAssist": false, + "description": "进程强制等待,休眠" + }, + "vk.pubfn.getDayOffsetStartAndEnd": { + "prefix": "vk.pubfn.getDayOffsetStartAndEnd", + "body": [ + "let dayTime = vk.pubfn.getDayOffsetStartAndEnd(0);" + ], + "triggerAssist": false, + "description": "获得相对当前时间的偏移 count 天的起止日期" + }, + "vk.pubfn.getMonthOffsetStartAndEnd": { + "prefix": "vk.pubfn.getMonthOffsetStartAndEnd", + "body": [ + "let monthTime = vk.pubfn.getMonthOffsetStartAndEnd(0);" + ], + "triggerAssist": false, + "description": "获得相对当前时间的偏移 count 月的起止日期" + }, + "vk.pubfn.getYearOffsetStartAndEnd": { + "prefix": "vk.pubfn.getYearOffsetStartAndEnd", + "body": [ + "let yearTime = vk.pubfn.getYearOffsetStartAndEnd(0);" + ], + "triggerAssist": false, + "description": "获得相对当前时间的偏移 count 年的起止日期" + }, + "vk.pubfn.priceFilter": { + "prefix": "vk.pubfn.priceFilter", + "body": [ + "vk.pubfn.priceFilter(${0})" + ], + "triggerAssist": false, + "description": "金额过滤器" + }, + "vk.pubfn.timeFormat": { + "prefix": "vk.pubfn.timeFormat", + "body": [ + "vk.pubfn.timeFormat(${0})" + ], + "triggerAssist": false, + "description": "时间过滤器,第二个参数支持yyyy-MM-dd HH:mm:ss" + }, + "vk.pubfn.string2Number": { + "prefix": "vk.pubfn.string2Number", + "body": [ + "vk.pubfn.string2Number(${0})" + ], + "triggerAssist": false, + "description": "将对象字段中能转成字符串的值转Number类型" + }, + "vk.pubfn.toDecimal": { + "prefix": "vk.pubfn.toDecimal", + "body": [ + "vk.pubfn.toDecimal(${0}, 2)" + ], + "triggerAssist": false, + "description": "保留小数" + }, + "vk.pubfn.dateDiff": { + "prefix": "vk.pubfn.dateDiff", + "body": [ + "vk.pubfn.dateDiff(${0})" + ], + "triggerAssist": false, + "description": "将时间显示成1秒前、1天前" + }, + "vk.pubfn.dateDiff2": { + "prefix": "vk.pubfn.dateDiff2", + "body": [ + "vk.pubfn.dateDiff2(${0})" + ], + "triggerAssist": false, + "description": "将时间显示成当前时间距离time剩余时间为:3天" + }, + "vk.pubfn.numStr": { + "prefix": "vk.pubfn.numStr", + "body": [ + "vk.pubfn.numStr(${0})" + ], + "triggerAssist": false, + "description": "将大数字转中文,如15234120转成1千万" + }, + "vk.pubfn.percentageFilter": { + "prefix": "vk.pubfn.percentageFilter", + "body": [ + "vk.pubfn.percentageFilter(${0})" + ], + "triggerAssist": false, + "description": "百分比过滤器" + }, + "vk.pubfn.calcSize": { + "prefix": "vk.pubfn.calcSize", + "body": [ + "vk.pubfn.calcSize(${0}value,['B','KB','MB','GB'],1024,3).title" + ], + "triggerAssist": false, + "description": "计量单位过滤器" + }, + "vk.pubfn.priceLeftFilter": { + "prefix": "vk.pubfn.priceLeftFilter", + "body": [ + "vk.pubfn.priceLeftFilter(${0})" + ], + "triggerAssist": false, + "description": "金额过滤器 - 只显示小数点左边" + }, + "vk.pubfn.priceRightFilter": { + "prefix": "vk.pubfn.priceRightFilter", + "body": [ + "vk.pubfn.priceRightFilter(${0})" + ], + "triggerAssist": false, + "description": "金额过滤器 - 只显示小数点右边" + }, + "金额过滤器": { + "prefix": "qw", + "body": [ + "vk.pubfn.priceFilter(${0})" + ], + "triggerAssist": false, + "description": "金额过滤器" + }, + "时间过滤器": { + "prefix": "qw", + "body": [ + "vk.pubfn.timeFormat(${0})" + ], + "triggerAssist": false, + "description": "时间过滤器,第二个参数支持yyyy-MM-dd HH:mm:ss" + }, + "将时间显示成1秒前、1天前": { + "prefix": "qw", + "body": [ + "vk.pubfn.dateDiff(${0})" + ], + "triggerAssist": false, + "description": "将时间显示成1秒前、1天前" + }, + "将时间显示成当前时间距离time剩余时间为:3天": { + "prefix": "qw", + "body": [ + "vk.pubfn.dateDiff2(${0})" + ], + "triggerAssist": false, + "description": "将时间显示成当前时间距离time剩余时间为:3天" + }, + "将大数字转中文": { + "prefix": "qw", + "body": [ + "vk.pubfn.numStr(${0})" + ], + "triggerAssist": false, + "description": "将大数字转中文,如15234120转成1千万" + }, + "百分比过滤器": { + "prefix": "qw", + "body": [ + "vk.pubfn.percentageFilter(${0})" + ], + "triggerAssist": false, + "description": "百分比过滤器" + }, + "折扣过滤器": { + "prefix": "qw", + "body": [ + "vk.pubfn.discountFilter(${0})" + ], + "triggerAssist": false, + "description": "折扣过滤器" + }, + "计量单位过滤器": { + "prefix": "qw", + "body": [ + "vk.pubfn.calcSize(${0}value,['B','KB','MB','GB'],1024,3).title" + ], + "triggerAssist": false, + "description": "计量单位过滤器" + }, + "金额过滤器 - 只显示小数点左边": { + "prefix": "qw", + "body": [ + "vk.pubfn.priceLeftFilter(${0})" + ], + "triggerAssist": false, + "description": "金额过滤器 - 只显示小数点左边" + }, + "金额过滤器 - 只显示小数点右边": { + "prefix": "qw", + "body": [ + "vk.pubfn.priceRightFilter(${0})" + ], + "triggerAssist": false, + "description": "金额过滤器 - 只显示小数点右边" + }, + "userDao.findById": { + "prefix": "dao.", + "body": [ + "await vk.daoCenter.userDao.findById(user_id$0);" + ], + "triggerAssist": false, + "description": "获取用户信息" + }, + + "setTimeout": { + "prefix": "qq.", + "body": [ + "setTimeout(() => {", + "\t$0", + "}, 1000);" + ], + "triggerAssist": false, + "description": "延迟执行" + }, + "for循环": { + "prefix": "qq.", + "body": [ + "for(let i=0; i {", + "\t$0", + "});" + ], + "triggerAssist": false, + "description": "数组遍历" + }, + "Array.splice": { + "prefix": "qq.", + "body": [ + "list.splice(index,1);" + ], + "triggerAssist": false, + "description": "数组删除" + }, + "Array.filter": { + "prefix": "qq.", + "body": [ + "let newList = list.filter((item,index,arr) => {", + "\treturn index % 2 == 1;$0", + "});" + ], + "triggerAssist": false, + "description": "数组过滤" + }, + + "保留两位小数": { + "prefix": "qq.", + "body": [ + "parseFloat(${0}).toFixed(2);" + ], + "triggerAssist": false, + "description": "保留两位小数,并舍去最后的0" + }, + "try{...} catch(err){...}": { + "prefix": "try", + "body": [ + "try {", + "\t$0", + "}catch(err){", + "\t", + "}" + ], + "triggerAssist": false, + "description": "try-catch" + }, + "throw new Error": { + "prefix": "try-throw", + "body": [ + "throw new Error(\"msg:${0}\");" + ], + "triggerAssist": false, + "description": "主动抛出异常" + }, + "获取当前时间戳": { + "prefix": "time", + "body": [ + "let time = new Date().getTime();" + ], + "triggerAssist": false, + "description": "获取当前时间戳" + }, + "获取今日0点-24点时间戳": { + "prefix": "time", + "body": [ + "let { todayStart, todayEnd } = vk.pubfn.getCommonTime();" + ], + "triggerAssist": false, + "description": "获取今日0点-24点时间戳" + }, + "获取指定时间偏移": { + "prefix": "time", + "body": [ + "vk.pubfn.getOffsetTime(new Date(), {", + "\tyear:0,", + "\tmonth:0,", + "\tday:0,", + "\thours:0,", + "\tminutes:0,", + "\tseconds:0,", + "\tmode:\"after\" // after 之后 before 之前", + "});" + ], + "triggerAssist": false, + "description": "获取指定时间偏移" + }, + "vk.baseDao.findById": { + "prefix": "baseDao.findById", + "body": [ + "let info = await vk.baseDao.findById({", + "\tdbName:\"$0\",", + "\tid:id,", + "\tfieldJson:{}", + "});" + ], + "triggerAssist": false, + "description": "根据ID获取一条数据库数据" + }, + "vk.baseDao.findByWhereJson": { + "prefix": "baseDao.findByWhereJson", + "body": [ + "let info = await vk.baseDao.findByWhereJson({", + "\tdbName:\"$0\",", + "\twhereJson:{", + "\t\t", + "\t},", + "\tfieldJson:{}", + "});" + ], + "triggerAssist": false, + "description": "根据whereJson获取一条数据库数据" + }, + "vk.baseDao.count": { + "prefix": "baseDao.count", + "body": [ + "res.num = await vk.baseDao.count({", + "\tdbName:\"$0\",", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "count满足条件的数据库条数" + }, + "vk.baseDao.update": { + "prefix": "baseDao.update", + "body": [ + "res.num = await vk.baseDao.update({", + "\tdbName:\"$0\",", + "\twhereJson:{", + "\t\t", + "\t},", + "\tdataJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "修改满足条件的数据库数据" + }, + "vk.baseDao.updateById": { + "prefix": "baseDao.updateById", + "body": [ + "let num = await vk.baseDao.updateById({", + "\tdbName:\"$0\",", + "\tid:_id,", + "\tdataJson:{", + "\t\t", + "\t},", + "\tgetUpdateData:false", + "});" + ], + "triggerAssist": false, + "description": "根据id修改数据库数据" + }, + "vk.baseDao.updateAndReturn": { + "prefix": "baseDao.updateAndReturn", + "body": [ + "let newInfo = await vk.baseDao.updateAndReturn({", + "\tdbName:\"$0\",", + "\twhereJson:{", + "\t\t_id: _id", + "\t},", + "\tdataJson:{", + "\t\t", + "\t},", + "});" + ], + "triggerAssist": false, + "description": "修改符合条件的首条数据,并返回修改后的结果。" + }, + "vk.baseDao.updateAndReturnById": { + "prefix": "baseDao.updateAndReturnById", + "body": [ + "let newInfo = await vk.baseDao.updateAndReturn({", + "\tdbName:\"$0\",", + "\tid:_id,", + "\tdataJson:{", + "\t\t", + "\t},", + "});" + ], + "triggerAssist": false, + "description": "根据id修改数据库数据,并返回修改后的结果。" + }, + "vk.baseDao.select": { + "prefix": "baseDao.select", + "body": [ + "res = await vk.baseDao.select({", + "\tdbName:\"$0\",", + "\tgetCount: false,", + "\tpageIndex:1,", + "\tpageSize:20,", + "\twhereJson:{", + "\t\t", + "\t},", + "\tfieldJson:{},", + "\tsortArr:[{ \"name\":\"_id\", \"type\":\"desc\" }],", + "});" + ], + "triggerAssist": false, + "description": "根据条件获取数据库数据" + }, + "vk.baseDao.selects(连表查询)": { + "prefix": "baseDao.selects", + "body": [ + "res = await vk.baseDao.selects({", + "\tdbName:\"$0\",", + "\tgetCount:false,", + "\tpageIndex:1,", + "\tpageSize:20,", + "\t// 主表where条件", + "\twhereJson:{", + "\t\t", + "\t},", + "\t// 主表字段显示规则", + "\tfieldJson:{},", + "\t// 主表排序规则", + "\tsortArr:[{ \"name\":\"_id\", \"type\":\"desc\" }],", + "\t// 副表列表", + "\tforeignDB:[", + "\t\t{", + "\t\t\tdbName:\"副表表名\",", + "\t\t\tlocalKey:\"主表外键名\",", + "\t\t\tforeignKey:\"副表外键名\",", + "\t\t\tas:\"副表as字段\",", + "\t\t\tlimit:1", + "\t\t}", + "\t]", + "});" + ], + "triggerAssist": false, + "description": "根据条件获取数据库数据(连表查询)" + }, + "vk.baseDao.getTableData": { + "prefix": "baseDao.getTableData", + "body": [ + "res = await vk.baseDao.getTableData({", + "\tdbName:\"$0\",", + "\tdata,", + "\t// 强制where条件", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "获取表格数据(连表查询)" + }, + "vk.baseDao.getTableData(连表查询)": { + "prefix": "baseDao.getTableData", + "body": [ + "res = await vk.baseDao.getTableData({", + "\tdbName:\"$0\",", + "\tdata,", + "\t// 主表强制where条件", + "\twhereJson:{", + "\t\t", + "\t},", + "\t// 副表列表", + "\tforeignDB:[", + "\t\t{", + "\t\t\tdbName:\"副表表名\",", + "\t\t\tlocalKey:\"主表外键名\",", + "\t\t\tforeignKey:\"副表外键名\",", + "\t\t\tas:\"副表as字段\",", + "\t\t\tlimit:1", + "\t\t}", + "\t]", + "});" + ], + "triggerAssist": false, + "description": "获取表格数据(连表查询)" + }, + "vk.baseDao.del": { + "prefix": "baseDao.del", + "body": [ + "let num = await vk.baseDao.del({", + "\tdbName:\"$0\",", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "删除满足条件的数据库数据" + }, + "vk.baseDao.deleteById": { + "prefix": "baseDao.deleteById", + "body": [ + "let num = await vk.baseDao.deleteById({", + "\tdbName:\"$0\",", + "\tid:_id", + "});" + ], + "triggerAssist": false, + "description": "根据ID删除数据库数据" + }, + "vk.baseDao.add": { + "prefix": "baseDao.add", + "body": [ + "let num = await vk.baseDao.add({", + "\tdbName:\"$0\",", + "\tdataJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "添加数据库数据" + }, + "vk.baseDao.adds": { + "prefix": "baseDao.adds", + "body": [ + "let num = await vk.baseDao.adds({", + "\tdbName:\"$0\",", + "\tdataJson:[", + "\t\t", + "\t]", + "});" + ], + "triggerAssist": false, + "description": "批量添加数据库数据" + }, + "vk.baseDao.sample": { + "prefix": "baseDao.sample", + "body": [ + "let num = await vk.baseDao.sample({", + "\tdbName:\"$0\",", + "\tsize:1,", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "随机获取数据库数据" + }, + "vk.baseDao.selects(树状结构)": { + "prefix": "baseDao.selects(tree)", + "body": [ + "res = await vk.baseDao.selects({", + "\tdbName: \"opendb-admin-menus$0\",", + "\tpageIndex: 1,", + "\tpageSize: 500,", + "\twhereJson:{", + "\t\tenable: true,", + "\t\tparent_id: null", + "\t},", + "\tsortArr: [{ name: \"sort\", type: \"asc\" }],", + "\t// 树状结构参数", + "\ttreeProps: {", + "\t\tid: \"menu_id\",", // 唯一标识字段,默认为 _id + "\t\tparent_id: \"parent_id\",", // 父级标识字段,默认为 parent_id + "\t\tchildren: \"children\",", // 自定义返回的下级字段名,默认为 children + "\t\tlevel: 3,", // 查询返回的树的最大层级。超过设定层级的节点不会返回。默认10级,最大15,最小1 + "\t\tlimit: 500,", // 每一级最大返回的数据。 + "\t\twhereJson: {", + "\t\t\tenable: true", + "\t\t}", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "获取数据并返回树状结构" + }, + "vk.baseDao.selects(分组统计查询)": { + "prefix": "baseDao.selects", + "body": [ + "res = await vk.baseDao.selects({", + "\tdbName: \"表名${0}\",", + "\tpageIndex: 1,", + "\tpageSize: 10,", + "\t// 主表where条件", + "\twhereJson: {", + "\t\t", + "\t},", + "\tgroupJson: {", + "\t\t_id: \"$\", // _id是分组id, $ 后面接字段名,如user_id字段进行分组", + "\t\tuser_id: _.$.first(\"$\"), // $ 后面接字段名,如把user_id原样输出", + "\t\tmoney: _.$.sum(\"$\"), // $ 后面接字段名,sum求和该字段", + "\t},", + "\tsortArr: [{ name: \"money\",type: \"desc\" }], // 对分组后的结果进行排序", + "\t// 副表列表", + "\tforeignDB: [{", + "\t\tdbName: \"uni-id-users\",", + "\t\tlocalKey: \"user_id\",", + "\t\tforeignKey: \"_id\",", + "\t\tas: \"userInfo\",", + "\t\tlimit: 1,", + "\t\tfieldJson:{ token:false, password:false },", + "\t}]", + "});" + ], + "triggerAssist": false, + "description": "分组统计查询" + }, + "vk.baseDao.sum": { + "prefix": "baseDao.sum", + "body": [ + "res = await vk.baseDao.sum({", + "\tdbName:\"$0\",", + "\tfieldName:\"\",", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "根据条件求和" + }, + "vk.baseDao.max": { + "prefix": "baseDao.max", + "body": [ + "res = await vk.baseDao.max({", + "\tdbName:\"$0\",", + "\tfieldName:\"\",", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "根据条件求最大值" + }, + "vk.baseDao.min": { + "prefix": "baseDao.min", + "body": [ + "res = await vk.baseDao.min({", + "\tdbName:\"$0\",", + "\tfieldName:\"\",", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "根据条件求最小值" + }, + "vk.baseDao.avg": { + "prefix": "baseDao.avg", + "body": [ + "res = await vk.baseDao.avg({", + "\tdbName:\"$0\",", + "\tfieldName:\"\",", + "\twhereJson:{", + "\t\t", + "\t}", + "});" + ], + "triggerAssist": false, + "description": "根据条件求最平均值" + } +} diff --git a/使用帮助/代码快捷提示/vue代码块提示.json b/使用帮助/代码快捷提示/vue代码块提示.json new file mode 100644 index 0000000..734c1ea --- /dev/null +++ b/使用帮助/代码快捷提示/vue代码块提示.json @@ -0,0 +1,195 @@ +// 将下方代码复制到 hbx 工具 - 代码块设置 - vue代码块 +{ + "$getData(data,key,defaultValue)": { + "prefix": "$getData", + "body": [ + "$getData(data, 'aa.aa', defaultValue)" + ], + "triggerAssist": false, + "description": "智能获取对象属性数据" + }, + "vk-data-table(万能表格)": { + "body": [ + "", + "", + "" + ], + "prefix": "vk-data-table", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-dialog(弹窗表单)": { + "body": [ + "", + "", + "\t", + "", + "" + ], + "prefix": "vk-data-dialog", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-dialog(普通弹窗)": { + "body": [ + "", + "", + "\t这里是自定义内容${0}", + "\t", + "", + "" + ], + "prefix": "vk-data-dialog", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-icon(图标)": { + "body": [ + "" + ], + "prefix": "vk-data-icon", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(数字输入框)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(金额输入框)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(百分比输入框)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(折扣输入框)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(步进器)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(多行文本)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input(单行文本)": { + "body": [ + "" + ], + "prefix": "vk-data-input", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input-address(地址)": { + "body": [ + "" + ], + "prefix": "vk-data-input-address", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input-select(下拉选择)": { + "body": [ + "" + ], + "prefix": "vk-data-input-select", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-input-remote-select(远程选择)": { + "body": [ + "" + ], + "prefix": "vk-data-input-remote-select", + "project": "uni-app", + "scope": "source.vue.html" + }, + "vk-data-upload(图片上传)": { + "body": [ + "" + ], + "prefix": "vk-data-upload", + "project": "uni-app", + "scope": "source.vue.html" + } + +}