1117 changed files with 29420 additions and 102329 deletions
File diff suppressed because it is too large
@ -1,21 +0,0 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) 2018 DCloud |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
@ -0,0 +1,36 @@ |
|||
# uniproject |
|||
|
|||
#### Description |
|||
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} |
|||
|
|||
#### Software Architecture |
|||
Software architecture description |
|||
|
|||
#### Installation |
|||
|
|||
1. xxxx |
|||
2. xxxx |
|||
3. xxxx |
|||
|
|||
#### Instructions |
|||
|
|||
1. xxxx |
|||
2. xxxx |
|||
3. xxxx |
|||
|
|||
#### Contribution |
|||
|
|||
1. Fork the repository |
|||
2. Create Feat_xxx branch |
|||
3. Commit your code |
|||
4. Create Pull Request |
|||
|
|||
|
|||
#### Gitee Feature |
|||
|
|||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md |
|||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com) |
|||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) |
|||
4. The most valuable open source project [GVP](https://gitee.com/gvp) |
|||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) |
|||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) |
@ -1,129 +1,39 @@ |
|||
# hello-uniapp |
|||
# uniproject |
|||
|
|||
`uni-app`框架示例,一套代码,同时发行到iOS、Android、H5、小程序等多个平台,请使用手机在下方扫码快速体验`uni-app`的强大功能。[官方文档](https://uniapp.dcloud.net.cn/) |
|||
#### 介绍 |
|||
{**以下是 Gitee 平台说明,您可以替换此简介** |
|||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 |
|||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} |
|||
|
|||
## 快速上手 |
|||
hello-uniapp 示例工程可以通过两种方式创建, 一种是 HBuilderX, 配套 IDE,集成开发;另一种是 CLI 创建;推荐前者。 |
|||
### 通过 HBuilderX 可视化界面创建(推荐) |
|||
#### 软件架构 |
|||
软件架构说明 |
|||
|
|||
可视化的方式比较简单,HBuilderX内置相关环境,开箱即用,无需配置nodejs。 |
|||
|
|||
开始之前,开发者需先下载安装如下工具: |
|||
#### 安装教程 |
|||
|
|||
- HBuilderX:[官方IDE下载地址](https://www.dcloud.io/hbuilderx.html) |
|||
1. xxxx |
|||
2. xxxx |
|||
3. xxxx |
|||
|
|||
HBuilderX是通用的前端开发工具,但为`uni-app`做了特别强化,请下载App开发版。 |
|||
#### 使用说明 |
|||
|
|||
由于截图在 github 不便浏览,参见官方文档 [HBuilderX 可视化界面创建](https://uniapp.dcloud.net.cn/quickstart?id=_1-%e9%80%9a%e8%bf%87-hbuilderx-%e5%8f%af%e8%a7%86%e5%8c%96%e7%95%8c%e9%9d%a2) |
|||
1. xxxx |
|||
2. xxxx |
|||
3. xxxx |
|||
|
|||
### 通过 vue-cli 创建 |
|||
#### 参与贡献 |
|||
|
|||
``` |
|||
npm install -g @vue/cli |
|||
``` |
|||
1. Fork 本仓库 |
|||
2. 新建 Feat_xxx 分支 |
|||
3. 提交代码 |
|||
4. 新建 Pull Request |
|||
|
|||
#### 创建uni-app |
|||
|
|||
**使用正式版**(对应HBuilderX最新正式版) |
|||
|
|||
``` |
|||
vue create -p dcloudio/uni-preset-vue my-project |
|||
``` |
|||
|
|||
**使用alpha版**(对应HBuilderX最新alpha版) |
|||
|
|||
``` |
|||
vue create -p dcloudio/uni-preset-vue#alpha my-alpha-project |
|||
``` |
|||
|
|||
此时,会提示选择项目模板,选择 `hello uni-app` 项目模板,如下所示: |
|||
|
|||
<div> |
|||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/h5-cli-01.png" width="300"> |
|||
</div> |
|||
|
|||
创建好后,进入项目目录 |
|||
``` |
|||
cd my-project |
|||
``` |
|||
|
|||
执行该命令运行到 h5 端 |
|||
``` |
|||
npm run dev:h5 |
|||
``` |
|||
|
|||
欢迎提 issues,推荐到[官方社区](https://ask.dcloud.net.cn/explore/)提问。 |
|||
|
|||
## 扫码体验 |
|||
|
|||
<div class="quick"> |
|||
<p>一套代码编到10个平台,这不是梦想。眼见为实,扫描10个二维码,亲自体验最全面的跨平台效果!</p> |
|||
<div style="display: flex;"> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/ba7d0750-517d-11eb-bdc1-8bd33eb6adaa.png" width="160" /> |
|||
</div> |
|||
<b>Android版</b> |
|||
</a> |
|||
<a href="https://itunes.apple.com/cn/app/hello-uni-app/id1417078253?mt=8" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/bb3ef7c0-517d-11eb-bdc1-8bd33eb6adaa.png" width="160" /> |
|||
</div> |
|||
<b>iOS版</b> |
|||
</a> |
|||
<a href="https://hellouniapp.dcloud.net.cn/" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/bb3ef7c0-517d-11eb-bdc1-8bd33eb6adaa.png" width="160" /> |
|||
</div> |
|||
<b>H5版</b> |
|||
</a> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"><img src="//img.cdn.aliyun.dcloud.net.cn/guide/uniapp/gh_33446d7f7a26_430.jpg" width="160" /></div> |
|||
<b>微信小程序版</b> |
|||
</a> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"><img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/b131e0d0-517d-11eb-a16f-5b3e54966275.png" width="160" /></div> |
|||
<b>支付宝小程序版</b> |
|||
</a> |
|||
</div> |
|||
<div class="flex-img-group-view" style="margin-top: 20px;"> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"><img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/b204e840-517d-11eb-8ff1-d5dcf8779628.png" width="160" /></div> |
|||
<b>百度小程序版</b> |
|||
</a> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/mp-toutiao.png" width="160" /> |
|||
</div> |
|||
<b>字节跳动小程序版</b> |
|||
</a> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-qq.png" width="160" /> |
|||
</div> |
|||
<b>QQ小程序版</b> |
|||
</a> |
|||
<a href="//m3w.cn/uniapp" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-qa-union.png" width="160" /> |
|||
</div> |
|||
<b>快应用</b> |
|||
</a> |
|||
<a href="https://so.mp.360.cn/mp.html?appid=qh4j181qqtru354st6" target="_blank" class="clear-style barcode-view"> |
|||
<div class="barcode-img-box"> |
|||
<img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/hello-uni-mp-360-qr.png" width="160" /> |
|||
</div> |
|||
<b>360小程序</b> |
|||
</a> |
|||
</div> |
|||
<p> |
|||
<em>注:某些平台不能提交简单demo,故补充了一些其他功能;hello uni-app示例代码可从[github](https://github.com/dcloudio/hello-uniapp)获取</em></br> |
|||
<em>快应用仅支持 vivo 、oppo、华为</em></br> |
|||
<em>360小程序仅 windows平台支持,需要在360浏览器中打开</em></br> |
|||
</p> |
|||
</div> |
|||
|
|||
`uni-app`官网文档详见[https://uniapp.dcloud.io](https://uniapp.dcloud.io) |
|||
|
|||
更多uni-app的模板、示例详见[插件市场](https://ext.dcloud.net.cn/) |
|||
#### 特技 |
|||
|
|||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md |
|||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) |
|||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 |
|||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 |
|||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) |
|||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) |
|||
|
@ -1,22 +0,0 @@ |
|||
// import request from '@/common/request.js'
|
|||
// import promise from '@/common/promise.js'
|
|||
import request from '@/common/request_test.js' |
|||
// let devUrl = this.$dev_url;
|
|||
|
|||
let devUrl = "http://dev.ccwin-in.com:59096" |
|||
export function getlogin(params) { |
|||
return request({ |
|||
url: devUrl + "/api/pda/account/login", |
|||
method: "post", |
|||
data: params, |
|||
}); |
|||
} |
|||
|
|||
//修改用户密码
|
|||
export function changePassword(params) { //
|
|||
return request({ |
|||
url:devUrl + "/api/pda/account/change-password",//
|
|||
data: params, |
|||
method: "post" |
|||
}) |
|||
} |
@ -1,22 +0,0 @@ |
|||
// // import request from '@/common/request.js'
|
|||
// // import promise from '@/common/promise.js'
|
|||
// import request from '@/common/request_test.js'
|
|||
// // let devUrl = this.$dev_url;
|
|||
|
|||
// let devUrl = "http://dev.ccwin-in.com:59096"
|
|||
// export function getlogin(params) {
|
|||
// return request({
|
|||
// url: devUrl + "/api/pda/account/login",
|
|||
// method: "post",
|
|||
// data: params,
|
|||
// });
|
|||
// }
|
|||
|
|||
// //修改用户密码
|
|||
// export function changePassword(params) { //
|
|||
// return request({
|
|||
// url:devUrl + "/api/pda/account/change-password",//
|
|||
// data: params,
|
|||
// method: "post"
|
|||
// })
|
|||
// }
|
@ -1,171 +0,0 @@ |
|||
## 3.4.4(2022-07-25) |
|||
- 新增 同步 uni-ui@1.4.20 |
|||
- uni-forms 【重要】组件逻辑重构,部分用法旧版本不兼容,请注意兼容问题 |
|||
- uni-section 新增组件 |
|||
## 3.4.3(2022-07-14) |
|||
- 修复 HBuilderX 拉取 hello uni-app 项目直接运行提示无服务空间关联的bug |
|||
## 3.4.2(2022-07-06) |
|||
- 新增 同步 uni-ui@1.4.18 |
|||
- uni-forms 【重要】组件逻辑重构,部分用法旧版本不兼容,请注意兼容问题 |
|||
- uni-forms 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力 |
|||
- uni-forms 新增 更多表单示例 |
|||
- uni-forms 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃 |
|||
- uni-forms 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效 |
|||
- uni-forms 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法 |
|||
- uni-forms 新增 子表单的 setRules 方法,配合自定义校验函数使用 |
|||
- uni-forms 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则 |
|||
- uni-forms 修复 由 1.4.0 引发的 label 插槽不生效的bug |
|||
- uni-forms 修复 子组件找不到 setValue 报错的bug |
|||
- uni-forms 修复 uni-data-picker 在 uni-forms-item 中报错的bug |
|||
- uni-forms 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug |
|||
- uni-forms 修复 表单校验顺序无序问题 |
|||
- uni-forms 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式 |
|||
- uni-forms 优化 动态表单校验方式,废弃拼接name的方式 |
|||
- uni-breadcrumb 修复 微信小程序 separator 不显示问题 |
|||
- uni-data-checkbox 优化 在 uni-forms 中的依赖注入方式 |
|||
- uni-data-picker 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug |
|||
- uni-data-picker 优化 显示样式 |
|||
- uni-data-select 优化 显示样式 |
|||
- uni-datetime-picker 修复 日历顶部年月及底部确认未国际化 bug |
|||
- uni-datetime-picker 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致 |
|||
- uni-easyinput 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容 |
|||
- uni-easyinput 新增 clear 事件,点击右侧叉号图标触发 |
|||
- uni-easyinput 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发 |
|||
- uni-easyinput 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等 |
|||
- uni-easyinput 优化 clearable 显示策略 |
|||
- uni-file-picker 修复 在uni-forms下样式不生效的bug |
|||
- uni-nav-bar 修复 组件示例中插槽用法无法显示内容的bug |
|||
- uni-swipe-action 修复 vue3 下使用组件不能正常运行的Bug |
|||
- uni-swipe-action 修复 h5端点击click触发两次的Bug |
|||
- uni-table 修复 微信小程序存在无使用组件的问题 |
|||
## 3.4.1(2022-06-30) |
|||
- 新增 支持 ios 安全区 |
|||
## 3.3.8(2022-05-08) |
|||
- 新增 同步 uni-ui@1.4.15 |
|||
- uni-data-picker 修复 字节小程序 本地数据无法选择下一级的Bug |
|||
- uni-data-select 新增 记住上次的选项(仅 collection 存在时有效) |
|||
- uni-search-bar 修复 vue3 input 事件不生效的bug |
|||
- uni-search-bar 修复 多余代码导致的bug |
|||
- uni-tooltip 更新 text 属性变更为 content |
|||
- uni-tooltip 更新 移除 width 属性 |
|||
- uni-tooltip 修复 组件根 text 嵌套组件 warning |
|||
## 3.3.7(2022-04-06) |
|||
- 新增 更新扩展组件 uni-nav-bar、uni-list 的展示页面 |
|||
## 3.3.6(2022-03-31) |
|||
- 更新 uni-ui 组件及示例 |
|||
## 3.3.5(2022-03-30) |
|||
- 修复 插槽兼容 vue3, slot -> v-slot |
|||
- 新增 更新 uni-ui |
|||
## 3.3.4(2022-02-25) |
|||
- 修复 编译到 App 平台的控制台报错 |
|||
## 3.3.3(2022-02-23) |
|||
- 修复 模板城市选择 vue3 报错的bug |
|||
- 修复 删除 map.nvue 中多余的 enableOverlooking 变量 |
|||
- 修复 swipe-dot.nvue 中条件编译媒体查询 |
|||
## 3.3.2(2022-01-26) |
|||
- 修复 默认运行到 vue2 |
|||
## 3.3.1(2022-01-26) |
|||
- 新增 同步 uni-ui@1.4.11 |
|||
- uni-collapse 修复 微信小程序resize后组件收起的bug |
|||
- uni-countdown 修复 在微信小程序中样式不生效的bug |
|||
- uni-countdown 新增 update 方法 ,在动态更新时间后,刷新组件 |
|||
- uni-load-more 新增 showText属性 ,是否显示文本 |
|||
- uni-load-more 修复 nvue 平台下不显示文本的bug |
|||
- uni-load-more 修复 微信小程序平台样式选择器报警告的问题 |
|||
- uni-nav-bar 修复 在vue下,标题不垂直居中的bug |
|||
- uni-nav-bar 修复 height 属性类型错误 |
|||
- uni-nav-bar 新增 height 属性,可修改组件高度 |
|||
- uni-nav-bar 新增 dark 属性可可开启暗黑模式 |
|||
- uni-nav-bar 优化 标题字数过多显示省略号 |
|||
- uni-nav-bar 优化 插槽,插入内容可完全覆盖 |
|||
- uni-popup 修复 isMaskClick 失效的bug |
|||
- uni-popup 新增 cancelText \ confirmText 属性 ,可自定义文本 |
|||
- uni-popup 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 |
|||
- uni-popup 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 |
|||
## 3.3.0(2022-01-04) |
|||
- 修复 开发时在 vue3 下由 pc 端切换到手机端,不能返回上一级页面的 bug |
|||
- 优化 去掉 pc 端 topwindow 右上角用于演示的 url 导航 |
|||
## 3.2.12(2021-12-20) |
|||
- 新增 适配京东小程序 |
|||
## 3.2.11(2021-12-07) |
|||
- 修复 uni-ui 在 hello-uniapp 中丢失图标、ui 受到公共样式影响等问题 |
|||
- 修复 微信登录取值报错的问题 |
|||
## 3.2.10(2021-11-30) |
|||
- 修复 map 组件示例不显示的 bug |
|||
## 3.2.9(2021-11-19) |
|||
- 新增 uni-ui 以 uni_modules 方式引入,方便开发者从 hello-uniapp 中 copy 组件及示例 |
|||
- 优化 uni-ui 示例页面,完善组件示例 |
|||
## 3.2.8(2021-11-10) |
|||
- 新增 适配飞书平台(lark) |
|||
## 3.2.7(2021-10-26) |
|||
- 修复 uni-popup 示例的 button 文字在 iPhone 5 上换行的 bug |
|||
- 修复 uni-table 示例,页面顶部距离不对的 bug |
|||
- 修复 GlobalData示例,在vue3是无效的 bug |
|||
- 优化 删除无用的 project.swan.json 文件 |
|||
## 3.2.6(2021-10-08) |
|||
- 由于体验问题,暂时撤销 uni-ui 以 uni_modules 方式引入的修改 |
|||
|
|||
## 3.2.4(2021-09-07) |
|||
- 修复 vue3 在 H5 编译报错的 bug |
|||
- 新增 同步 uni-ui |
|||
- 新增 uni-ui 组件支持国际化 i18n |
|||
- uni-data-checkbox 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题 |
|||
- uni-datetime-picker 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次 |
|||
- uni-datetime-picker 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法 |
|||
- uni-datetime-picker 优化 调整字号大小,美化日历界面 |
|||
- uni-datetime-picker 修复 因国际化导致的 placeholder 失效的 bug |
|||
- uni-file-picker 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug |
|||
- uni-file-picker 新增 参数中返回 fileID 字段 |
|||
- uni-file-picker 修复 腾讯云传入fileID 不能回显的bug |
|||
- uni-file-picker 修复 选择图片后,不能放大的问题 |
|||
- uni-link 修复 在 nvue 下不显示的 bug |
|||
- uni-list 修复 在vue3中to属性在发行应用的时候报错的bug |
|||
- uni-search-bar 修复 value 属性与 modelValue 属性不兼容的Bug |
|||
- uni-swipe-action 优化 close-all 方法 |
|||
- uni-collapse 优化 show-arrow 属性默认为true |
|||
- uni-collapse 新增 show-arrow 属性,控制是否显示右侧箭头 |
|||
- uni-data-checkbox 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 |
|||
- uni-easyinput 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug |
|||
- uni-file-picker 修复 由于 0.2.11 版本引起的不能回显图片的Bug |
|||
- uni-file-picker 新增 clearFiles(index) 方法,可以手动删除指定文件 |
|||
- uni-file-picker 修复 v-model 值设为 null 报错的Bug |
|||
- uni-swipe-action 新增 close-all 方法,关闭所有已打开的组件 |
|||
- uni-swipe-action 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件 |
|||
- uni-swipe-action 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 |
|||
- uni-swipe-action 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题 |
|||
|
|||
|
|||
## 3.2.3(2021-08-27) |
|||
- 优化 tabbar 页面移除 vuex 相关代码 |
|||
- 新增 适配 vue3 (app) |
|||
## 3.2.2(2021-08-10) |
|||
- 新增 适配快手小程序 |
|||
- 新增 同步 uni-ui |
|||
- uni-datetime-picker 新增 return-type 属性支持返回 date 日期对象 |
|||
- uni-file-picker 修复 fileExtname属性不指定值报错的Bug |
|||
- uni-file-picker 修复 在某种场景下图片不回显的Bug |
|||
- uni-link 支持自定义插槽 |
|||
- uni-calendar 修复 弹出层被 tabbar 遮盖 bug |
|||
- uni-dateformat 调整 默认时间不再是当前时间,而是显示'-'字符 |
|||
- uni-datetime-picker 新增 适配 vue3 |
|||
- uni-datetime-picker 新增 支持作为 uni-forms 子组件相关功能 |
|||
- uni-datetime-picker 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的 bug |
|||
- uni-datetime-picker 修复 type 属性动态赋值无效的 bug |
|||
- uni-datetime-picker 修复 ‘确认’按钮被 tabbar 遮盖 bug |
|||
- uni-datetime-picker 修复 组件未赋值时范围选左、右日历相同的 bug |
|||
- uni-datetime-picker 修复 范围选未正确显示当前值的 bug |
|||
- uni-datetime-picker 修复 h5 平台(移动端)报错 'cale' of undefined 的 bug |
|||
- uni-file-picker 修复 auto-upload 属性失效的Bug |
|||
## 3.2.1(2021-07-31) |
|||
- 新增 同步 uni-ui@1.3.8 |
|||
## 3.2.0(2021-07-30) |
|||
- 新增 同时兼容 vue2 & vue3 |
|||
## 3.1.20(2021-07-30) |
|||
- 新增 同时兼容 vue2 & vue3 |
|||
## 3.1.17(2021-05-26) |
|||
- 修复 3.1.16 依赖 sass 的问题 |
|||
- 条件编译 nuve 不支持 css 属性 |
|||
## 3.1.16(2021-05-26) |
|||
- 修复 uni-data-checkbox 不关联服务空间的情况下组件报错的 Bug |
|||
## 3.1.12(2021-05-07) |
|||
- hello-uniapp 发布插件市场 |
@ -1,262 +0,0 @@ |
|||
export default { |
|||
"list": [{ |
|||
"letter": "A", |
|||
"data": [ |
|||
"阿克苏机场", |
|||
"阿拉山口机场", |
|||
"阿勒泰机场", |
|||
"阿里昆莎机场", |
|||
"安庆天柱山机场", |
|||
"澳门国际机场" |
|||
] |
|||
}, { |
|||
"letter": "B", |
|||
"data": [ |
|||
"保山机场", |
|||
"包头机场", |
|||
"北海福成机场", |
|||
"北京南苑机场", |
|||
"北京首都国际机场" |
|||
] |
|||
}, { |
|||
"letter": "C", |
|||
"data": [ |
|||
"长白山机场", |
|||
"长春龙嘉国际机场", |
|||
"常德桃花源机场", |
|||
"昌都邦达机场", |
|||
"长沙黄花国际机场", |
|||
"长治王村机场", |
|||
"常州奔牛机场", |
|||
"成都双流国际机场", |
|||
"赤峰机场" |
|||
] |
|||
}, { |
|||
"letter": "D", |
|||
"data": [ |
|||
"大理机场", |
|||
"大连周水子国际机场", |
|||
"大庆萨尔图机场", |
|||
"大同东王庄机场", |
|||
"达州河市机场", |
|||
"丹东浪头机场", |
|||
"德宏芒市机场", |
|||
"迪庆香格里拉机场", |
|||
"东营机场", |
|||
"敦煌机场" |
|||
] |
|||
}, { |
|||
"letter": "E", |
|||
"data": [ |
|||
"鄂尔多斯机场", |
|||
"恩施许家坪机场", |
|||
"二连浩特赛乌苏国际机场" |
|||
] |
|||
}, { |
|||
"letter": "F", |
|||
"data": [ |
|||
"阜阳西关机场", |
|||
"福州长乐国际机场" |
|||
] |
|||
}, { |
|||
"letter": "G", |
|||
"data": [ |
|||
"赣州黄金机场", |
|||
"格尔木机场", |
|||
"固原六盘山机场", |
|||
"广元盘龙机场", |
|||
"广州白云国际机场", |
|||
"桂林两江国际机场", |
|||
"贵阳龙洞堡国际机场" |
|||
] |
|||
}, { |
|||
"letter": "H", |
|||
"data": [ |
|||
"哈尔滨太平国际机场", |
|||
"哈密机场", |
|||
"海口美兰国际机场", |
|||
"海拉尔东山国际机场", |
|||
"邯郸机场", |
|||
"汉中机场", |
|||
"杭州萧山国际机场", |
|||
"合肥骆岗国际机场", |
|||
"和田机场", |
|||
"黑河机场", |
|||
"呼和浩特白塔国际机场", |
|||
"淮安涟水机场", |
|||
"黄山屯溪国际机场" |
|||
] |
|||
}, { |
|||
"letter": "I", |
|||
"data": [] |
|||
}, { |
|||
"letter": "J", |
|||
"data": [ |
|||
"济南遥墙国际机场", |
|||
"济宁曲阜机场", |
|||
"鸡西兴凯湖机场", |
|||
"佳木斯东郊机场", |
|||
"嘉峪关机场", |
|||
"锦州小岭子机场", |
|||
"景德镇机场", |
|||
"井冈山机场", |
|||
"九江庐山机场", |
|||
"九寨黄龙机场" |
|||
] |
|||
}, { |
|||
"letter": "K", |
|||
"data": [ |
|||
"喀什机场", |
|||
"克拉玛依机场", |
|||
"库车龟兹机场", |
|||
"库尔勒机场", |
|||
"昆明巫家坝国际机场" |
|||
] |
|||
}, { |
|||
"letter": "L", |
|||
"data": [ |
|||
"拉萨贡嘎机场", |
|||
"兰州中川机场", |
|||
"丽江三义机场", |
|||
"黎平机场", |
|||
"连云港白塔埠机场", |
|||
"临沧机场", |
|||
"临沂机场", |
|||
"林芝米林机场", |
|||
"柳州白莲机场", |
|||
"龙岩冠豸山机场", |
|||
"泸州蓝田机场", |
|||
"洛阳北郊机场" |
|||
] |
|||
}, { |
|||
"letter": "M", |
|||
"data": [ |
|||
"满洲里西郊机场", |
|||
"绵阳南郊机场", |
|||
"漠河古莲机场", |
|||
"牡丹江海浪机场" |
|||
] |
|||
}, { |
|||
"letter": "N", |
|||
"data": [ |
|||
"南昌昌北国际机场", |
|||
"南充高坪机场", |
|||
"南京禄口国际机场", |
|||
"南宁吴圩机场", |
|||
"南通兴东机场", |
|||
"南阳姜营机场", |
|||
"宁波栎社国际机场" |
|||
] |
|||
}, { |
|||
"letter": "O", |
|||
"data": [] |
|||
}, { |
|||
"letter": "P", |
|||
"data": [ |
|||
"普洱思茅机场" |
|||
] |
|||
}, { |
|||
"letter": "Q", |
|||
"data": [ |
|||
"齐齐哈尔三家子机场", |
|||
"秦皇岛山海关机场", |
|||
"青岛流亭国际机场", |
|||
"衢州机场", |
|||
"泉州晋江机场" |
|||
] |
|||
}, { |
|||
"letter": "R", |
|||
"data": [ |
|||
"日喀则和平机场" |
|||
] |
|||
}, { |
|||
"letter": "S", |
|||
"data": [ |
|||
"三亚凤凰国际机场", |
|||
"汕头外砂机场", |
|||
"上海虹桥国际机场", |
|||
"上海浦东国际机场", |
|||
"深圳宝安国际机场", |
|||
"沈阳桃仙国际机场", |
|||
"石家庄正定国际机场", |
|||
"苏南硕放国际机场" |
|||
] |
|||
}, { |
|||
"letter": "T", |
|||
"data": [ |
|||
"塔城机场", |
|||
"太原武宿国际机场", |
|||
"台州路桥机场 (黄岩机场)", |
|||
"唐山三女河机场", |
|||
"腾冲驼峰机场", |
|||
"天津滨海国际机场", |
|||
"通辽机场", |
|||
"铜仁凤凰机场" |
|||
] |
|||
}, { |
|||
"letter": "U", |
|||
"data": [] |
|||
}, { |
|||
"letter": "V", |
|||
"data": [] |
|||
}, { |
|||
"letter": "W", |
|||
"data": [ |
|||
"万州五桥机场", |
|||
"潍坊机场", |
|||
"威海大水泊机场", |
|||
"文山普者黑机场", |
|||
"温州永强国际机场", |
|||
"乌海机场", |
|||
"武汉天河国际机场", |
|||
"乌兰浩特机场", |
|||
"乌鲁木齐地窝堡国际机场", |
|||
"武夷山机场", |
|||
"梧州长洲岛机场" |
|||
] |
|||
}, { |
|||
"letter": "X", |
|||
"data": [ |
|||
"西安咸阳国际机场", |
|||
"西昌青山机场", |
|||
"锡林浩特机场", |
|||
"西宁曹家堡机场", |
|||
"西双版纳嘎洒机场", |
|||
"厦门高崎国际机场", |
|||
"香港国际机场", |
|||
"襄阳刘集机场", |
|||
"兴义机场", |
|||
"徐州观音机场" |
|||
] |
|||
}, { |
|||
"letter": "Y", |
|||
"data": [ |
|||
"延安二十里堡机场", |
|||
"盐城机场", |
|||
"延吉朝阳川机场", |
|||
"烟台莱山国际机场", |
|||
"宜宾菜坝机场", |
|||
"宜昌三峡机场", |
|||
"伊春林都机场", |
|||
"伊宁机场", |
|||
"义乌机场", |
|||
"银川河东机场", |
|||
"永州零陵机场", |
|||
"榆林榆阳机场", |
|||
"玉树巴塘机场", |
|||
"运城张孝机场" |
|||
] |
|||
}, { |
|||
"letter": "Z", |
|||
"data": [ |
|||
"湛江机场", |
|||
"昭通机场", |
|||
"郑州新郑国际机场", |
|||
"芷江机场", |
|||
"重庆江北国际机场", |
|||
"中卫香山机场", |
|||
"舟山朱家尖机场", |
|||
"珠海三灶机场" |
|||
] |
|||
}] |
|||
} |
@ -1,97 +0,0 @@ |
|||
/** |
|||
数据验证(表单验证) |
|||
来自 grace.hcoder.net |
|||
作者 hcoder 深海 |
|||
*/ |
|||
export default { |
|||
error:'', |
|||
check : function (data, rule){ |
|||
for(var i = 0; i < rule.length; i++){ |
|||
if (!rule[i].checkType){return true;} |
|||
if (!rule[i].name) {return true;} |
|||
if (!rule[i].errorMsg) {return true;} |
|||
if (!data[rule[i].name]) {this.error = rule[i].errorMsg; return false;} |
|||
switch (rule[i].checkType){ |
|||
case 'string': |
|||
var reg = new RegExp('^.{' + rule[i].checkRule + '}$'); |
|||
if(!reg.test(data[rule[i].name])) {this.error = rule[i].errorMsg; return false;} |
|||
break; |
|||
case 'int': |
|||
var reg = new RegExp('^(-[1-9]|[1-9])[0-9]{' + rule[i].checkRule + '}$'); |
|||
if(!reg.test(data[rule[i].name])) {this.error = rule[i].errorMsg; return false;} |
|||
break; |
|||
break; |
|||
case 'between': |
|||
if (!this.isNumber(data[rule[i].name])){ |
|||
this.error = rule[i].errorMsg; |
|||
return false; |
|||
} |
|||
var minMax = rule[i].checkRule.split(','); |
|||
minMax[0] = Number(minMax[0]); |
|||
minMax[1] = Number(minMax[1]); |
|||
if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { |
|||
this.error = rule[i].errorMsg; |
|||
return false; |
|||
} |
|||
break; |
|||
case 'betweenD': |
|||
var reg = /^-?[1-9][0-9]?$/; |
|||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
|||
var minMax = rule[i].checkRule.split(','); |
|||
minMax[0] = Number(minMax[0]); |
|||
minMax[1] = Number(minMax[1]); |
|||
if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { |
|||
this.error = rule[i].errorMsg; |
|||
return false; |
|||
} |
|||
break; |
|||
case 'betweenF': |
|||
var reg = /^-?[0-9][0-9]?.+[0-9]+$/; |
|||
if (!reg.test(data[rule[i].name])){this.error = rule[i].errorMsg; return false;} |
|||
var minMax = rule[i].checkRule.split(','); |
|||
minMax[0] = Number(minMax[0]); |
|||
minMax[1] = Number(minMax[1]); |
|||
if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) { |
|||
this.error = rule[i].errorMsg; |
|||
return false; |
|||
} |
|||
break; |
|||
case 'same': |
|||
if (data[rule[i].name] != rule[i].checkRule) { this.error = rule[i].errorMsg; return false;} |
|||
break; |
|||
case 'notsame': |
|||
if (data[rule[i].name] == rule[i].checkRule) { this.error = rule[i].errorMsg; return false; } |
|||
break; |
|||
case 'email': |
|||
var reg = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/; |
|||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
|||
break; |
|||
case 'phoneno': |
|||
var reg = /^1[0-9]{10,10}$/; |
|||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
|||
break; |
|||
case 'zipcode': |
|||
var reg = /^[0-9]{6}$/; |
|||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
|||
break; |
|||
case 'reg': |
|||
var reg = new RegExp(rule[i].checkRule); |
|||
if (!reg.test(data[rule[i].name])) { this.error = rule[i].errorMsg; return false; } |
|||
break; |
|||
case 'in': |
|||
if(rule[i].checkRule.indexOf(data[rule[i].name]) == -1){ |
|||
this.error = rule[i].errorMsg; return false; |
|||
} |
|||
break; |
|||
case 'notnull': |
|||
if(data[rule[i].name] == null || data[rule[i].name].length < 1){this.error = rule[i].errorMsg; return false;} |
|||
break; |
|||
} |
|||
} |
|||
return true; |
|||
}, |
|||
isNumber : function (checkVal){ |
|||
var reg = /^-?[1-9][0-9]?.?[0-9]*$/; |
|||
return reg.test(checkVal); |
|||
} |
|||
} |
@ -1,352 +0,0 @@ |
|||
/* |
|||
* HTML5 Parser By Sam Blowes |
|||
* |
|||
* Designed for HTML5 documents |
|||
* |
|||
* Original code by John Resig (ejohn.org) |
|||
* http://ejohn.org/blog/pure-javascript-html-parser/
|
|||
* Original code by Erik Arvidsson, Mozilla Public License |
|||
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
|||
* |
|||
* ---------------------------------------------------------------------------- |
|||
* License |
|||
* ---------------------------------------------------------------------------- |
|||
* |
|||
* This code is triple licensed using Apache Software License 2.0, |
|||
* Mozilla Public License or GNU Public License |
|||
* |
|||
* ////////////////////////////////////////////////////////////////////////////
|
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not |
|||
* use this file except in compliance with the License. You may obtain a copy |
|||
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* ////////////////////////////////////////////////////////////////////////////
|
|||
* |
|||
* The contents of this file are subject to the Mozilla Public License |
|||
* Version 1.1 (the "License"); you may not use this file except in |
|||
* compliance with the License. You may obtain a copy of the License at |
|||
* http://www.mozilla.org/MPL/
|
|||
* |
|||
* Software distributed under the License is distributed on an "AS IS" |
|||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|||
* License for the specific language governing rights and limitations |
|||
* under the License. |
|||
* |
|||
* The Original Code is Simple HTML Parser. |
|||
* |
|||
* The Initial Developer of the Original Code is Erik Arvidsson. |
|||
* Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights |
|||
* Reserved. |
|||
* |
|||
* ////////////////////////////////////////////////////////////////////////////
|
|||
* |
|||
* This program is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU General Public License |
|||
* as published by the Free Software Foundation; either version 2 |
|||
* of the License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|||
* |
|||
* ---------------------------------------------------------------------------- |
|||
* Usage |
|||
* ---------------------------------------------------------------------------- |
|||
* |
|||
* // Use like so:
|
|||
* HTMLParser(htmlString, { |
|||
* start: function(tag, attrs, unary) {}, |
|||
* end: function(tag) {}, |
|||
* chars: function(text) {}, |
|||
* comment: function(text) {} |
|||
* }); |
|||
* |
|||
* // or to get an XML string:
|
|||
* HTMLtoXML(htmlString); |
|||
* |
|||
* // or to get an XML DOM Document
|
|||
* HTMLtoDOM(htmlString); |
|||
* |
|||
* // or to inject into an existing document/DOM node
|
|||
* HTMLtoDOM(htmlString, document); |
|||
* HTMLtoDOM(htmlString, document.body); |
|||
* |
|||
*/ |
|||
// Regular Expressions for parsing tags and attributes
|
|||
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; |
|||
var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/; |
|||
var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
|
|||
|
|||
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5
|
|||
// fixed by xxx 将 ins 标签从块级名单中移除
|
|||
|
|||
var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5
|
|||
|
|||
var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open
|
|||
// (and which close themselves)
|
|||
|
|||
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled"
|
|||
|
|||
var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything)
|
|||
|
|||
var special = makeMap('script,style'); |
|||
function HTMLParser(html, handler) { |
|||
var index; |
|||
var chars; |
|||
var match; |
|||
var stack = []; |
|||
var last = html; |
|||
|
|||
stack.last = function () { |
|||
return this[this.length - 1]; |
|||
}; |
|||
|
|||
while (html) { |
|||
chars = true; // Make sure we're not in a script or style element
|
|||
|
|||
if (!stack.last() || !special[stack.last()]) { |
|||
// Comment
|
|||
if (html.indexOf('<!--') == 0) { |
|||
index = html.indexOf('-->'); |
|||
|
|||
if (index >= 0) { |
|||
if (handler.comment) { |
|||
handler.comment(html.substring(4, index)); |
|||
} |
|||
|
|||
html = html.substring(index + 3); |
|||
chars = false; |
|||
} // end tag
|
|||
|
|||
} else if (html.indexOf('</') == 0) { |
|||
match = html.match(endTag); |
|||
|
|||
if (match) { |
|||
html = html.substring(match[0].length); |
|||
match[0].replace(endTag, parseEndTag); |
|||
chars = false; |
|||
} // start tag
|
|||
|
|||
} else if (html.indexOf('<') == 0) { |
|||
match = html.match(startTag); |
|||
|
|||
if (match) { |
|||
html = html.substring(match[0].length); |
|||
match[0].replace(startTag, parseStartTag); |
|||
chars = false; |
|||
} |
|||
} |
|||
|
|||
if (chars) { |
|||
index = html.indexOf('<'); |
|||
var text = index < 0 ? html : html.substring(0, index); |
|||
html = index < 0 ? '' : html.substring(index); |
|||
|
|||
if (handler.chars) { |
|||
handler.chars(text); |
|||
} |
|||
} |
|||
} else { |
|||
html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) { |
|||
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2'); |
|||
|
|||
if (handler.chars) { |
|||
handler.chars(text); |
|||
} |
|||
|
|||
return ''; |
|||
}); |
|||
parseEndTag('', stack.last()); |
|||
} |
|||
|
|||
if (html == last) { |
|||
throw 'Parse Error: ' + html; |
|||
} |
|||
|
|||
last = html; |
|||
} // Clean up any remaining tags
|
|||
|
|||
|
|||
parseEndTag(); |
|||
|
|||
function parseStartTag(tag, tagName, rest, unary) { |
|||
tagName = tagName.toLowerCase(); |
|||
|
|||
if (block[tagName]) { |
|||
while (stack.last() && inline[stack.last()]) { |
|||
parseEndTag('', stack.last()); |
|||
} |
|||
} |
|||
|
|||
if (closeSelf[tagName] && stack.last() == tagName) { |
|||
parseEndTag('', tagName); |
|||
} |
|||
|
|||
unary = empty[tagName] || !!unary; |
|||
|
|||
if (!unary) { |
|||
stack.push(tagName); |
|||
} |
|||
|
|||
if (handler.start) { |
|||
var attrs = []; |
|||
rest.replace(attr, function (match, name) { |
|||
var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : ''; |
|||
attrs.push({ |
|||
name: name, |
|||
value: value, |
|||
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
|
|||
|
|||
}); |
|||
}); |
|||
|
|||
if (handler.start) { |
|||
handler.start(tagName, attrs, unary); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function parseEndTag(tag, tagName) { |
|||
// If no tag name is provided, clean shop
|
|||
if (!tagName) { |
|||
var pos = 0; |
|||
} // Find the closest opened tag of the same type
|
|||
else { |
|||
for (var pos = stack.length - 1; pos >= 0; pos--) { |
|||
if (stack[pos] == tagName) { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (pos >= 0) { |
|||
// Close all the open elements, up the stack
|
|||
for (var i = stack.length - 1; i >= pos; i--) { |
|||
if (handler.end) { |
|||
handler.end(stack[i]); |
|||
} |
|||
} // Remove the open elements from the stack
|
|||
|
|||
|
|||
stack.length = pos; |
|||
} |
|||
} |
|||
} |
|||
|
|||
function makeMap(str) { |
|||
var obj = {}; |
|||
var items = str.split(','); |
|||
|
|||
for (var i = 0; i < items.length; i++) { |
|||
obj[items[i]] = true; |
|||
} |
|||
|
|||
return obj; |
|||
} |
|||
|
|||
function removeDOCTYPE(html) { |
|||
return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, ''); |
|||
} |
|||
|
|||
function parseAttrs(attrs) { |
|||
return attrs.reduce(function (pre, attr) { |
|||
var value = attr.value; |
|||
var name = attr.name; |
|||
|
|||
if (pre[name]) { |
|||
pre[name] = pre[name] + " " + value; |
|||
} else { |
|||
pre[name] = value; |
|||
} |
|||
|
|||
return pre; |
|||
}, {}); |
|||
} |
|||
|
|||
function parseHtml(html) { |
|||
html = removeDOCTYPE(html); |
|||
var stacks = []; |
|||
var results = { |
|||
node: 'root', |
|||
children: [] |
|||
}; |
|||
HTMLParser(html, { |
|||
start: function start(tag, attrs, unary) { |
|||
var node = { |
|||
name: tag |
|||
}; |
|||
|
|||
if (attrs.length !== 0) { |
|||
node.attrs = parseAttrs(attrs); |
|||
} |
|||
|
|||
if (unary) { |
|||
var parent = stacks[0] || results; |
|||
|
|||
if (!parent.children) { |
|||
parent.children = []; |
|||
} |
|||
|
|||
parent.children.push(node); |
|||
} else { |
|||
stacks.unshift(node); |
|||
} |
|||
}, |
|||
end: function end(tag) { |
|||
var node = stacks.shift(); |
|||
if (node.name !== tag) console.error('invalid state: mismatch end tag'); |
|||
|
|||
if (stacks.length === 0) { |
|||
results.children.push(node); |
|||
} else { |
|||
var parent = stacks[0]; |
|||
|
|||
if (!parent.children) { |
|||
parent.children = []; |
|||
} |
|||
|
|||
parent.children.push(node); |
|||
} |
|||
}, |
|||
chars: function chars(text) { |
|||
var node = { |
|||
type: 'text', |
|||
text: text |
|||
}; |
|||
|
|||
if (stacks.length === 0) { |
|||
results.children.push(node); |
|||
} else { |
|||
var parent = stacks[0]; |
|||
|
|||
if (!parent.children) { |
|||
parent.children = []; |
|||
} |
|||
|
|||
parent.children.push(node); |
|||
} |
|||
}, |
|||
comment: function comment(text) { |
|||
var node = { |
|||
node: 'comment', |
|||
text: text |
|||
}; |
|||
var parent = stacks[0]; |
|||
|
|||
if (!parent.children) { |
|||
parent.children = []; |
|||
} |
|||
|
|||
parent.children.push(node); |
|||
} |
|||
}); |
|||
return results.children; |
|||
} |
|||
|
|||
export default parseHtml; |
@ -1,103 +0,0 @@ |
|||
import urlConfig from './config.js' |
|||
// import store from '@/store/index'
|
|||
|
|||
function service(options = {}) { |
|||
let contentType = localStorage.token_type ? "application/json" : "application/x-www-form-urlencoded"; |
|||
options.header = { |
|||
"content-type": contentType, |
|||
"Authorization": localStorage.token_type, |
|||
'withCredentials': true, |
|||
// 'Blade-Auth':'bearer '+store.state.token,
|
|||
'token_type': localStorage.token_type |
|||
}; |
|||
return new Promise((resolve, reject) => { |
|||
options.success = (res) => { |
|||
console.log("请求成功", res); |
|||
// 如果请求回来的状态码不是200则执行以下操作
|
|||
if (res != null ) { |
|||
if (res.statusCode != null) { |
|||
let statusCode = res.statusCode.toString(); |
|||
// 状态码类型 2开头的全是成功
|
|||
let code = statusCode.substring(0, 1); |
|||
if (statusCode == '200') { |
|||
resolve(res.data); |
|||
} else if (statusCode == '204') { |
|||
if (options.method == 'get') { |
|||
return null; |
|||
} else { |
|||
reject(res.data) |
|||
} |
|||
} else if (statusCode == '400') { |
|||
if (res.data.error) { |
|||
if (res.data.error.message) { |
|||
reject(res.data.error.message); |
|||
} |
|||
} else if (res.data.errors) { |
|||
let errors = res.data.errors; |
|||
let errorMsg = '请求参数错误:\n'; |
|||
let keys = Object.keys(errors); |
|||
for (var i = 0; i < keys.length; i++) { |
|||
let key = keys[i]; |
|||
let value = errors[key]; |
|||
errorMsg += i + 1 + ':' + value + '\n'; |
|||
} |
|||
reject(errorMsg); |
|||
} |
|||
} else if (statusCode == '404') { |
|||
if (res.data === '') { |
|||
reject('未找到接口'); |
|||
} else { |
|||
reject(res.data); |
|||
} |
|||
} |
|||
else if (statusCode == '403') { |
|||
let message = res.data.error.message; |
|||
if (message) { |
|||
let temp; |
|||
try { |
|||
temp = JSON.parse(message) |
|||
} catch (err) { |
|||
reject(message) ; |
|||
} |
|||
if (temp) { |
|||
var hintError = temp.error; |
|||
var hintErrorDes = temp.error_description; |
|||
if (hintError == 'invalid_grant') { |
|||
if (hintErrorDes.includes('Invalid username or password!')) { |
|||
reject('用户名或密码错误'); |
|||
} else if (hintErrorDes.includes( |
|||
'The user account has been locked out due to invalid login attempts' |
|||
)) { |
|||
reject("账号已被锁定,请稍后再试"); |
|||
} |
|||
} else { |
|||
reject(message) |
|||
} |
|||
} |
|||
} else { |
|||
reject(res.statusCode + "错误") |
|||
} |
|||
} |
|||
else { |
|||
let message = res.data.error.message; |
|||
if (message != undefined) { |
|||
reject(res.data.error.message) |
|||
} else { |
|||
reject(res.statusCode + "错误") |
|||
} |
|||
} |
|||
} else { |
|||
reject('options.url' + "返回的状态码类型为空") |
|||
} |
|||
} else { |
|||
reject('options.url' + "返回的res为空") |
|||
} |
|||
}; |
|||
options.fail = (err) => { |
|||
reject(err); |
|||
}; |
|||
uni.request(options); |
|||
}); |
|||
} |
|||
|
|||
export default service; |
@ -1,136 +0,0 @@ |
|||
/* #ifndef APP-PLUS-NVUE */ |
|||
page { |
|||
min-height: 100%; |
|||
height: auto; |
|||
} |
|||
/* #endif */ |
|||
|
|||
/* 解决头条小程序字体图标不显示问题,因为头条运行时自动插入了span标签,且有全局字体 */ |
|||
/* #ifdef MP-TOUTIAO */ |
|||
/* text :not(view) { |
|||
font-family: uniicons; |
|||
} */ |
|||
/* #endif */ |
|||
|
|||
.uni-icon { |
|||
font-family: uniicons; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
.uni-container { |
|||
padding: 15px; |
|||
background-color: #f8f8f8; |
|||
} |
|||
|
|||
.uni-header-logo { |
|||
/* #ifdef H5 */ |
|||
display: flex; |
|||
/* #endif */ |
|||
padding: 15px 15px; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
margin-top: 10rpx; |
|||
} |
|||
|
|||
.uni-header-image { |
|||
width: 80px; |
|||
height: 80px; |
|||
} |
|||
|
|||
.uni-hello-text { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.hello-text { |
|||
color: #7A7E83; |
|||
font-size: 14px; |
|||
line-height: 20px; |
|||
} |
|||
|
|||
.hello-link { |
|||
color: #7A7E83; |
|||
font-size: 14px; |
|||
line-height: 20px; |
|||
} |
|||
|
|||
.uni-panel { |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.uni-panel-h { |
|||
/* #ifdef H5 */ |
|||
display: flex; |
|||
/* #endif */ |
|||
background-color: #ffffff; |
|||
flex-direction: row !important; |
|||
/* justify-content: space-between !important; */ |
|||
align-items: center !important; |
|||
padding: 12px; |
|||
/* #ifdef H5 */ |
|||
cursor: pointer; |
|||
/* #endif */ |
|||
} |
|||
/* |
|||
.uni-panel-h:active { |
|||
background-color: #f8f8f8; |
|||
} |
|||
*/ |
|||
.uni-panel-h-on { |
|||
background-color: #f0f0f0; |
|||
} |
|||
|
|||
.uni-panel-text { |
|||
flex: 1; |
|||
color: #000000; |
|||
font-size: 14px; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
.uni-panel-icon { |
|||
margin-left: 15px; |
|||
color: #999999; |
|||
font-size: 14px; |
|||
font-weight: normal; |
|||
transform: rotate(0deg); |
|||
transition-duration: 0s; |
|||
transition-property: transform; |
|||
} |
|||
|
|||
.uni-panel-icon-on { |
|||
transform: rotate(180deg); |
|||
} |
|||
|
|||
.uni-navigate-item { |
|||
/* #ifdef H5 */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
background-color: #FFFFFF; |
|||
border-top-style: solid; |
|||
border-top-color: #f0f0f0; |
|||
border-top-width: 1px; |
|||
padding: 12px; |
|||
/* #ifdef H5 */ |
|||
cursor: pointer; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-navigate-item:active { |
|||
background-color: #f8f8f8; |
|||
} |
|||
|
|||
.uni-navigate-text { |
|||
flex: 1; |
|||
color: #000000; |
|||
font-size: 14px; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
.uni-navigate-icon { |
|||
margin-left: 15px; |
|||
color: #999999; |
|||
font-size: 14px; |
|||
font-weight: normal; |
|||
} |
@ -1 +1 @@ |
|||
export default './lib/marked' |
|||
module.exports = require('./lib/marked'); |
|||
|
@ -0,0 +1,77 @@ |
|||
<template> |
|||
<div class="qrcode"> |
|||
<div class="code"> |
|||
<!-- decode是扫描结果的函数,torch用于是否需要打开手电筒,init用于检查该设备是否能够调用摄像头的权限,camera可用于打开前面或者后面摄像头 --> |
|||
<qrcode-drop-zone @decode="onDecode"> |
|||
<qrcode-stream @decode="onDecode" :torch="torchActive" @init="onInit" :camera="camera" /> |
|||
</qrcode-drop-zone> |
|||
<div class="code-button"> |
|||
<button @click="switchCamera">相机反转</button> |
|||
<button @click="ClickFlash">打开手电筒</button> |
|||
<button @click="turnCameraOff">关闭相机</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
// 引用vue-qrcode-reader插件 |
|||
import { QrcodeStream, QrcodeDropZone, QrcodeCapture } from 'vue-qrcode-reader' |
|||
|
|||
export default { |
|||
name: 'Approve', |
|||
props: { |
|||
camera: { |
|||
type: String, |
|||
default: 'rear', |
|||
}, |
|||
torchActive: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
qrcode: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
noStreamApiSupport: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
}, |
|||
data() { |
|||
return {} |
|||
}, |
|||
created() {}, |
|||
|
|||
components: { |
|||
// 注册组件 |
|||
QrcodeStream, |
|||
QrcodeDropZone, |
|||
QrcodeCapture, |
|||
}, |
|||
methods: { |
|||
// 扫码结果回调 |
|||
onDecode(result) { |
|||
this.$emit('onDecode', result) |
|||
}, |
|||
// 相机反转 |
|||
switchCamera() { |
|||
this.$emit('switchCamera') |
|||
}, |
|||
// 关闭相机?????? |
|||
turnCameraOff() { |
|||
this.$emit('turnCameraOff') |
|||
}, |
|||
// 打开手电筒 |
|||
ClickFlash() { |
|||
this.$emit('ClickFlash') |
|||
}, |
|||
// 检查是否调用摄像头 |
|||
onInit(promise) { |
|||
this.$emit('onInit', promise) |
|||
}, |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
|
@ -0,0 +1,420 @@ |
|||
<template> |
|||
<view class="uni-card uni-border" :class="{ 'uni-card--full': isFull === true || isFull === 'true', 'uni-card--shadow': isShadow === true || isShadow === 'true'}"> |
|||
<!-- 基础 --> |
|||
<view v-if="mode === 'basic' && title" @click.stop="onClick" class="uni-card__head-padding"> |
|||
<view class="uni-card__header uni-border-bottom"> |
|||
<slot name="header"> |
|||
<view v-if="thumbnail" class="uni-card__header-extra-img-view"> |
|||
<image :src="thumbnail" class="uni-card__header-extra-img" /> |
|||
</view> |
|||
<text class="uni-card__header-title-text">{{ title }}</text> |
|||
<text v-if="extra" class="uni-card__header-extra-text">{{ extra }}</text> |
|||
</slot> |
|||
</view> |
|||
</view> |
|||
<!-- 标题 --> |
|||
<view v-if="mode === 'title'" @click.stop="onClick" class="uni-card__head-padding"> |
|||
<view class="uni-card__title uni-border-bottom"> |
|||
<slot name="header"> |
|||
<view class="uni-card__title-box"> |
|||
<view v-if="thumbnail" class="uni-card__title-header"> |
|||
<image class="uni-card__title-header-image" :src="thumbnail" mode="scaleToFill" /> |
|||
</view> |
|||
<view class="uni-card__title-content"> |
|||
<text class="uni-card__title-content-title uni-ellipsis">{{ title }}</text> |
|||
<text class="uni-card__title-content-extra uni-ellipsis">{{ subTitle }}</text> |
|||
</view> |
|||
</view> |
|||
<view v-if="extra"> |
|||
<text class="uni-card__header-extra-text">{{ extra }}</text> |
|||
</view> |
|||
</slot> |
|||
</view> |
|||
</view> |
|||
<!-- 图文 --> |
|||
<view v-if="mode === 'style'" class="uni-card__thumbnailimage" @click.stop="onClick"> |
|||
<view class="uni-card__thumbnailimage-box"> |
|||
<image v-if="thumbnail" class="uni-card__thumbnailimage-image" :src="thumbnail" mode="aspectFill" /> |
|||
<uni-icons v-if="!thumbnail" type="image" size="30" color="#999" /> |
|||
</view> |
|||
<view v-if="title" class="uni-card__thumbnailimage-title"> |
|||
<text class="uni-card__thumbnailimage-title-text">{{ title }}</text> |
|||
</view> |
|||
</view> |
|||
<!-- 内容 --> |
|||
<view class="uni-card__content uni-card__content--pd" @click.stop="onClick"> |
|||
<view v-if="mode === 'style' && extra" class=""><text class="uni-card__content-extra">{{ extra }}</text> |
|||
</view> |
|||
<slot /> |
|||
</view> |
|||
<!-- 底部 --> |
|||
<view v-if="note" class="uni-card__footer uni-border-top"> |
|||
<slot name="footer"> |
|||
<text class="uni-card__footer-text">{{ note }}</text> |
|||
</slot> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
/** |
|||
* Card 卡片 |
|||
* @description 卡片视图组件 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=22 |
|||
* @property {String} title 标题文字 |
|||
* @property {String} subTitle 副标题(仅仅mode=title下生效) |
|||
* @property {String} extra 标题额外信息 |
|||
* @property {String} note 底部信息 |
|||
* @property {String} thumbnail 标题左侧缩略图 |
|||
* @property {String} mode = [basic|style|title] 卡片模式 |
|||
* @value basic 基础卡片 |
|||
* @value style 图文卡片 |
|||
* @value title 标题卡片 |
|||
* @property {Boolean} isFull = [true | false] 卡片内容是否通栏,为 true 时将去除padding值 |
|||
* @property {Boolean} isShadow = [true | false] 卡片内容是否开启阴影 |
|||
* @event {Function} click 点击 Card 触发事件 |
|||
* @example <uni-card title="标题文字" thumbnail="xxx.jpg" extra="额外信息" note="Tips">内容主体,可自定义内容及样式</uni-card> |
|||
*/ |
|||
export default { |
|||
name: 'UniCard', |
|||
emits: ['click'], |
|||
props: { |
|||
title: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
subTitle: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
extra: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
note: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
thumbnail: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
mode: { |
|||
type: String, |
|||
default: 'basic' |
|||
}, |
|||
isFull: { |
|||
// 内容区域是否通栏 |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
isShadow: { |
|||
// 是否开启阴影 |
|||
type: [Boolean, String], |
|||
default: false |
|||
} |
|||
}, |
|||
methods: { |
|||
onClick() { |
|||
this.$emit('click') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-card { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
flex: 1; |
|||
box-shadow: 0 0 0 rgba(0, 0, 0, 0); |
|||
/* #endif */ |
|||
margin: 12px 15px; |
|||
background-color: #ffffff; |
|||
position: relative; |
|||
flex-direction: column; |
|||
border-radius: 5px; |
|||
overflow: hidden; |
|||
/* #ifdef H5 */ |
|||
cursor: pointer; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-border { |
|||
position: relative; |
|||
/* #ifdef APP-NVUE */ |
|||
border-color: #e5e5e5; |
|||
border-style: solid; |
|||
border-width: 0.5px; |
|||
/* #endif */ |
|||
z-index: 1; |
|||
} |
|||
|
|||
/* #ifndef APP-NVUE */ |
|||
.uni-border:after { |
|||
content: ""; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
border: 1px solid #e5e5e5; |
|||
border-radius: 10px; |
|||
box-sizing: border-box; |
|||
width: 200%; |
|||
height: 200%; |
|||
transform: scale(0.5); |
|||
transform-origin: left top; |
|||
z-index: -1; |
|||
} |
|||
|
|||
/* #endif */ |
|||
.uni-border-bottom { |
|||
position: relative; |
|||
/* #ifdef APP-NVUE */ |
|||
border-bottom-color: #e5e5e5; |
|||
border-bottom-style: solid; |
|||
border-bottom-width: 0.5px; |
|||
/* #endif */ |
|||
z-index: 1; |
|||
} |
|||
|
|||
/* #ifndef APP-NVUE */ |
|||
.uni-border-bottom:after { |
|||
content: ""; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
border-bottom: 1px solid #e5e5e5; |
|||
box-sizing: border-box; |
|||
width: 200%; |
|||
height: 200%; |
|||
transform: scale(0.5); |
|||
transform-origin: left top; |
|||
z-index: -1; |
|||
} |
|||
|
|||
/* #endif */ |
|||
.uni-border-top { |
|||
position: relative; |
|||
/* #ifdef APP-NVUE */ |
|||
border-top-color: #e5e5e5; |
|||
border-top-style: solid; |
|||
border-top-width: 0.5px; |
|||
/* #endif */ |
|||
z-index: 1; |
|||
} |
|||
|
|||
/* #ifndef APP-NVUE */ |
|||
.uni-border-top:after { |
|||
content: ""; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
border-top: 1px solid #e5e5e5; |
|||
box-sizing: border-box; |
|||
width: 200%; |
|||
height: 200%; |
|||
transform: scale(0.5); |
|||
transform-origin: left top; |
|||
z-index: -1; |
|||
} |
|||
|
|||
/* #endif */ |
|||
.uni-card__thumbnailimage { |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
height: 150px; |
|||
background-color: #F1F1F1; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.uni-card__thumbnailimage-box { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex: 1; |
|||
height: 150px; |
|||
flex-direction: row; |
|||
justify-content: center; |
|||
align-items: center; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.uni-card__thumbnailimage-image { |
|||
flex: 1; |
|||
} |
|||
|
|||
.uni-card__thumbnailimage-title { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
flex-direction: row; |
|||
padding: 8px 12px; |
|||
background-color: rgba(0, 0, 0, 0.4); |
|||
} |
|||
|
|||
.uni-card__thumbnailimage-title-text { |
|||
flex: 1; |
|||
font-size: 14px; |
|||
color: #fff; |
|||
} |
|||
|
|||
.uni-card__title { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
padding: 10px; |
|||
} |
|||
|
|||
.uni-card__title-box { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex: 1; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.uni-card__title-header { |
|||
width: 40px; |
|||
height: 40px; |
|||
overflow: hidden; |
|||
border-radius: 5px; |
|||
padding-right: 10px; |
|||
} |
|||
|
|||
.uni-card__title-header-image { |
|||
width: 40px; |
|||
height: 40px; |
|||
} |
|||
|
|||
.uni-card__title-content { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
flex: 1; |
|||
height: 40px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.uni-card__title-content-title { |
|||
font-size: 14px; |
|||
line-height: 22px; |
|||
} |
|||
|
|||
.uni-card__title-content-extra { |
|||
font-size: 12px; |
|||
line-height: 27px; |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-card__header { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
position: relative; |
|||
flex-direction: row; |
|||
padding: 12px; |
|||
align-items: center; |
|||
} |
|||
|
|||
.uni-card__header-title { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
margin-right: 8px; |
|||
justify-content: flex-start; |
|||
align-items: center; |
|||
} |
|||
|
|||
.uni-card__header-title-text { |
|||
font-size: 16px; |
|||
flex: 1; |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-card__header-extra-img { |
|||
height: 20px; |
|||
width: 20px; |
|||
margin-right: 8px; |
|||
} |
|||
|
|||
.uni-card__header-extra-text { |
|||
flex: 1; |
|||
margin-left: 8px; |
|||
font-size: 12px; |
|||
text-align: right; |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-card__content { |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-card__content--pd { |
|||
padding: 12px; |
|||
} |
|||
|
|||
.uni-card__content-extra { |
|||
font-size: 14px; |
|||
padding-bottom: 10px; |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-card__footer { |
|||
justify-content: space-between; |
|||
padding: 12px; |
|||
} |
|||
|
|||
.uni-card__footer-text { |
|||
color: #999; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.uni-card--shadow { |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.1); |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-card--full { |
|||
margin: 0; |
|||
border-radius: 0; |
|||
} |
|||
|
|||
/* #ifndef APP-NVUE */ |
|||
.uni-card--full:after { |
|||
border-radius: 0; |
|||
} |
|||
|
|||
/* #endif */ |
|||
.uni-ellipsis { |
|||
/* #ifndef APP-NVUE */ |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
/* #endif */ |
|||
/* #ifdef APP-NVUE */ |
|||
lines: 1; |
|||
/* #endif */ |
|||
} |
|||
</style> |
File diff suppressed because it is too large
@ -0,0 +1,792 @@ |
|||
<template> |
|||
<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}"> |
|||
<template v-if="!isLocal"> |
|||
<view class="uni-data-loading"> |
|||
<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more> |
|||
<text v-else>{{mixinDatacomErrorMessage}}</text> |
|||
</view> |
|||
</template> |
|||
<template v-else> |
|||
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne"> |
|||
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']" :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index"> |
|||
<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" /> |
|||
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner" :style="item.styleIcon"> |
|||
<view class="checkbox__inner-icon"></view> |
|||
</view> |
|||
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}"> |
|||
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text> |
|||
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view> |
|||
</view> |
|||
</label> |
|||
</checkbox-group> |
|||
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne"> |
|||
<!-- --> |
|||
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']" :style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index"> |
|||
<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" /> |
|||
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner" :style="item.styleBackgroud"> |
|||
<view class="radio__inner-icon" :style="item.styleIcon"></view> |
|||
</view> |
|||
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}"> |
|||
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text> |
|||
<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view> |
|||
</view> |
|||
</label> |
|||
</radio-group> |
|||
</template> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
/** |
|||
* DataChecklist 数据选择器 |
|||
* @description 通过数据渲染 checkbox 和 radio |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx |
|||
* @property {String} mode = [default| list | button | tag] 显示模式 |
|||
* @value default 默认横排模式 |
|||
* @value list 列表模式 |
|||
* @value button 按钮模式 |
|||
* @value tag 标签模式 |
|||
* @property {Boolean} multiple = [true|false] 是否多选 |
|||
* @property {Array|String|Number} value 默认值 |
|||
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}] |
|||
* @property {Number|String} min 最小选择个数 ,multiple为true时生效 |
|||
* @property {Number|String} max 最大选择个数 ,multiple为true时生效 |
|||
* @property {Boolean} wrap 是否换行显示 |
|||
* @property {String} icon = [left|right] list 列表模式下icon显示位置 |
|||
* @property {Boolean} selectedColor 选中颜色 |
|||
* @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效 |
|||
* @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示 |
|||
* @property {Object} map 字段映射, 默认 map={text:'text',value:'value'} |
|||
* @value left 左侧显示 |
|||
* @value right 右侧显示 |
|||
* @event {Function} change 选中发生变化触发 |
|||
*/ |
|||
|
|||
// import clientdb from './clientdb.js' |
|||
export default { |
|||
name: 'uniDataChecklist', |
|||
// mixins: [clientdb], |
|||
mixins: [uniCloud.mixinDatacom || {}], |
|||
// model: { |
|||
// prop: 'modelValue', |
|||
// event: 'update:modelValue' |
|||
// }, |
|||
emits: ['input', 'update:modelValue', 'change'], |
|||
props: { |
|||
mode: { |
|||
type: String, |
|||
default: 'default' |
|||
}, |
|||
|
|||
multiple: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
value: { |
|||
type: [Array, String, Number], |
|||
default () { |
|||
return '' |
|||
} |
|||
}, |
|||
// TODO vue3 |
|||
modelValue: { |
|||
type: [Array, String, Number], |
|||
default () { |
|||
return ''; |
|||
} |
|||
}, |
|||
localdata: { |
|||
type: Array, |
|||
default () { |
|||
return [] |
|||
} |
|||
}, |
|||
min: { |
|||
type: [Number, String], |
|||
default: '' |
|||
}, |
|||
max: { |
|||
type: [Number, String], |
|||
default: '' |
|||
}, |
|||
wrap: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
icon: { |
|||
type: String, |
|||
default: 'left' |
|||
}, |
|||
selectedColor: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
selectedTextColor: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
emptyText: { |
|||
type: String, |
|||
default: '暂无数据' |
|||
}, |
|||
disabled: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
map: { |
|||
type: Object, |
|||
default () { |
|||
return { |
|||
text: 'text', |
|||
value: 'value' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
localdata: { |
|||
handler(newVal) { |
|||
this.range = newVal |
|||
this.dataList = this.getDataList(this.getSelectedValue(newVal)) |
|||
}, |
|||
deep: true |
|||
}, |
|||
mixinDatacomResData(newVal) { |
|||
this.range = newVal |
|||
this.dataList = this.getDataList(this.getSelectedValue(newVal)) |
|||
}, |
|||
value(newVal) { |
|||
this.dataList = this.getDataList(newVal) |
|||
this.formItem && this.formItem.setValue(newVal) |
|||
}, |
|||
modelValue(newVal) { |
|||
this.dataList = this.getDataList(newVal); |
|||
this.formItem && this.formItem.setValue(newVal); |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
dataList: [], |
|||
range: [], |
|||
contentText: { |
|||
contentdown: '查看更多', |
|||
contentrefresh: '加载中', |
|||
contentnomore: '没有更多' |
|||
}, |
|||
isLocal: true, |
|||
styles: { |
|||
selectedColor: '#007aff', |
|||
selectedTextColor: '#333', |
|||
}, |
|||
isTop: 0 |
|||
}; |
|||
}, |
|||
computed: { |
|||
dataValue() { |
|||
if (this.value === '') return this.modelValue |
|||
if (this.modelValue === '') return this.value |
|||
return this.value |
|||
} |
|||
}, |
|||
created() { |
|||
this.form = this.getForm('uniForms') |
|||
this.formItem = this.getForm('uniFormsItem') |
|||
// this.formItem && this.formItem.setValue(this.value) |
|||
|
|||
if (this.formItem) { |
|||
this.isTop = 6 |
|||
if (this.formItem.name) { |
|||
this.rename = this.formItem.name |
|||
this.form.inputChildrens.push(this) |
|||
} |
|||
} |
|||
|
|||
if (this.localdata && this.localdata.length !== 0) { |
|||
this.isLocal = true |
|||
this.range = this.localdata |
|||
this.dataList = this.getDataList(this.getSelectedValue(this.range)) |
|||
} else { |
|||
if (this.collection) { |
|||
this.isLocal = false |
|||
this.loadData() |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
loadData() { |
|||
this.mixinDatacomGet().then(res => { |
|||
this.mixinDatacomResData = res.result.data |
|||
if (this.mixinDatacomResData.length === 0) { |
|||
this.isLocal = false |
|||
this.mixinDatacomErrorMessage = this.emptyText |
|||
} else { |
|||
this.isLocal = true |
|||
} |
|||
}).catch(err => { |
|||
this.mixinDatacomErrorMessage = err.message |
|||
}) |
|||
}, |
|||
/** |
|||
* 获取父元素实例 |
|||
*/ |
|||
getForm(name = 'uniForms') { |
|||
let parent = this.$parent; |
|||
let parentName = parent.$options.name; |
|||
while (parentName !== name) { |
|||
parent = parent.$parent; |
|||
if (!parent) return false |
|||
parentName = parent.$options.name; |
|||
} |
|||
return parent; |
|||
}, |
|||
chagne(e) { |
|||
const values = e.detail.value |
|||
|
|||
let detail = { |
|||
value: [], |
|||
data: [] |
|||
} |
|||
|
|||
if (this.multiple) { |
|||
this.range.forEach(item => { |
|||
|
|||
if (values.includes(item[this.map.value] + '')) { |
|||
detail.value.push(item[this.map.value]) |
|||
detail.data.push(item) |
|||
} |
|||
}) |
|||
} else { |
|||
const range = this.range.find(item => (item[this.map.value] + '') === values) |
|||
if (range) { |
|||
detail = { |
|||
value: range[this.map.value], |
|||
data: range |
|||
} |
|||
} |
|||
} |
|||
this.formItem && this.formItem.setValue(detail.value) |
|||
// TODO 兼容 vue2 |
|||
this.$emit('input', detail.value); |
|||
// // TOTO 兼容 vue3 |
|||
this.$emit('update:modelValue', detail.value); |
|||
this.$emit('change', { |
|||
detail |
|||
}) |
|||
if (this.multiple) { |
|||
// 如果 v-model 没有绑定 ,则走内部逻辑 |
|||
// if (this.value.length === 0) { |
|||
this.dataList = this.getDataList(detail.value, true) |
|||
// } |
|||
} else { |
|||
this.dataList = this.getDataList(detail.value) |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 获取渲染的新数组 |
|||
* @param {Object} value 选中内容 |
|||
*/ |
|||
getDataList(value) { |
|||
// 解除引用关系,破坏原引用关系,避免污染源数据 |
|||
let dataList = JSON.parse(JSON.stringify(this.range)) |
|||
let list = [] |
|||
if (this.multiple) { |
|||
if (!Array.isArray(value)) { |
|||
value = [] |
|||
} |
|||
} |
|||
dataList.forEach((item, index) => { |
|||
item.disabled = item.disable || item.disabled || false |
|||
if (this.multiple) { |
|||
if (value.length > 0) { |
|||
let have = value.find(val => val === item[this.map.value]) |
|||
item.selected = have !== undefined |
|||
} else { |
|||
item.selected = false |
|||
} |
|||
} else { |
|||
item.selected = value === item[this.map.value] |
|||
} |
|||
|
|||
list.push(item) |
|||
}) |
|||
return this.setRange(list) |
|||
}, |
|||
/** |
|||
* 处理最大最小值 |
|||
* @param {Object} list |
|||
*/ |
|||
setRange(list) { |
|||
let selectList = list.filter(item => item.selected) |
|||
let min = Number(this.min) || 0 |
|||
let max = Number(this.max) || '' |
|||
list.forEach((item, index) => { |
|||
if (this.multiple) { |
|||
if (selectList.length <= min) { |
|||
let have = selectList.find(val => val[this.map.value] === item[this.map.value]) |
|||
if (have !== undefined) { |
|||
item.disabled = true |
|||
} |
|||
} |
|||
|
|||
if (selectList.length >= max && max !== '') { |
|||
let have = selectList.find(val => val[this.map.value] === item[this.map.value]) |
|||
if (have === undefined) { |
|||
item.disabled = true |
|||
} |
|||
} |
|||
} |
|||
this.setStyles(item, index) |
|||
list[index] = item |
|||
}) |
|||
return list |
|||
}, |
|||
/** |
|||
* 设置 class |
|||
* @param {Object} item |
|||
* @param {Object} index |
|||
*/ |
|||
setStyles(item, index) { |
|||
// 设置自定义样式 |
|||
item.styleBackgroud = this.setStyleBackgroud(item) |
|||
item.styleIcon = this.setStyleIcon(item) |
|||
item.styleIconText = this.setStyleIconText(item) |
|||
item.styleRightIcon = this.setStyleRightIcon(item) |
|||
}, |
|||
|
|||
/** |
|||
* 获取选中值 |
|||
* @param {Object} range |
|||
*/ |
|||
getSelectedValue(range) { |
|||
if (!this.multiple) return this.dataValue |
|||
let selectedArr = [] |
|||
range.forEach((item) => { |
|||
if (item.selected) { |
|||
selectedArr.push(item[this.map.value]) |
|||
} |
|||
}) |
|||
return this.dataValue.length > 0 ? this.dataValue : selectedArr |
|||
}, |
|||
|
|||
/** |
|||
* 设置背景样式 |
|||
*/ |
|||
setStyleBackgroud(item) { |
|||
let styles = {} |
|||
let selectedColor = this.selectedColor ? this.selectedColor : '#007aff' |
|||
if (this.mode !== 'list') { |
|||
styles['border-color'] = item.selected ? selectedColor : '#DCDFE6' |
|||
} |
|||
if (this.mode === 'tag') { |
|||
styles['background-color'] = item.selected ? selectedColor : '#f5f5f5' |
|||
} |
|||
let classles = '' |
|||
for (let i in styles) { |
|||
classles += `${i}:${styles[i]};` |
|||
} |
|||
return classles |
|||
}, |
|||
setStyleIcon(item) { |
|||
let styles = {} |
|||
let classles = '' |
|||
let selectedColor = this.selectedColor ? this.selectedColor : '#007aff' |
|||
styles['background-color'] = item.selected ? selectedColor : '#fff' |
|||
styles['border-color'] = item.selected ? selectedColor : '#DCDFE6' |
|||
|
|||
if (!item.selected && item.disabled) { |
|||
styles['background-color'] = '#F2F6FC' |
|||
styles['border-color'] = item.selected ? selectedColor : '#DCDFE6' |
|||
} |
|||
|
|||
for (let i in styles) { |
|||
classles += `${i}:${styles[i]};` |
|||
} |
|||
return classles |
|||
}, |
|||
setStyleIconText(item) { |
|||
let styles = {} |
|||
let classles = '' |
|||
let selectedColor = this.selectedColor ? this.selectedColor : '#007aff' |
|||
if (this.mode === 'tag') { |
|||
styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : '#fff') : '#333' |
|||
} else { |
|||
styles.color = item.selected ? (this.selectedTextColor ? this.selectedTextColor : selectedColor) : '#333' |
|||
} |
|||
if (!item.selected && item.disabled) { |
|||
styles.color = '#999' |
|||
} |
|||
|
|||
for (let i in styles) { |
|||
classles += `${i}:${styles[i]};` |
|||
} |
|||
return classles |
|||
}, |
|||
setStyleRightIcon(item) { |
|||
let styles = {} |
|||
let classles = '' |
|||
if (this.mode === 'list') { |
|||
styles['border-color'] = item.selected ? this.styles.selectedColor : '#DCDFE6' |
|||
} |
|||
for (let i in styles) { |
|||
classles += `${i}:${styles[i]};` |
|||
} |
|||
|
|||
return classles |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-data-loading { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 36px; |
|||
padding-left: 10px; |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-data-checklist { |
|||
position: relative; |
|||
z-index: 0; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group.is-list { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
position: relative; |
|||
margin: 5px 0; |
|||
margin-right: 25px; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .hidden { |
|||
position: absolute; |
|||
opacity: 0; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .checklist-content { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex: 1; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .checklist-content .checklist-text { |
|||
font-size: 14px; |
|||
color: #333; |
|||
margin-left: 5px; |
|||
line-height: 14px; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .checklist-content .checkobx__list { |
|||
border-right-width: 1px; |
|||
border-right-color: #007aff; |
|||
border-right-style: solid; |
|||
border-bottom-width: 1px; |
|||
border-bottom-color: #007aff; |
|||
border-bottom-style: solid; |
|||
height: 12px; |
|||
width: 6px; |
|||
left: -5px; |
|||
transform-origin: center; |
|||
transform: rotate(45deg); |
|||
opacity: 0; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .checkbox__inner { |
|||
/* #ifndef APP-NVUE */ |
|||
flex-shrink: 0; |
|||
box-sizing: border-box; |
|||
/* #endif */ |
|||
position: relative; |
|||
width: 16px; |
|||
height: 16px; |
|||
border: 1px solid #DCDFE6; |
|||
border-radius: 2px; |
|||
background-color: #fff; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .checkbox__inner .checkbox__inner-icon { |
|||
position: absolute; |
|||
/* #ifdef APP-NVUE */ |
|||
top: 2px; |
|||
/* #endif */ |
|||
/* #ifndef APP-NVUE */ |
|||
top: 1px; |
|||
/* #endif */ |
|||
left: 5px; |
|||
height: 8px; |
|||
width: 4px; |
|||
border-right-width: 1px; |
|||
border-right-color: #fff; |
|||
border-right-style: solid; |
|||
border-bottom-width: 1px; |
|||
border-bottom-color: #fff; |
|||
border-bottom-style: solid; |
|||
opacity: 0; |
|||
transform-origin: center; |
|||
transform: rotate(40deg); |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .radio__inner { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
/* #ifndef APP-NVUE */ |
|||
flex-shrink: 0; |
|||
box-sizing: border-box; |
|||
/* #endif */ |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: relative; |
|||
width: 16px; |
|||
height: 16px; |
|||
border: 1px solid #DCDFE6; |
|||
border-radius: 16px; |
|||
background-color: #fff; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box .radio__inner .radio__inner-icon { |
|||
width: 8px; |
|||
height: 8px; |
|||
border-radius: 10px; |
|||
opacity: 0; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-disable { |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-disable .checkbox__inner { |
|||
background-color: #F2F6FC; |
|||
border-color: #DCDFE6; |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-disable .radio__inner { |
|||
background-color: #F2F6FC; |
|||
border-color: #DCDFE6; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-disable .checklist-text { |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checkbox__inner { |
|||
border-color: #007aff; |
|||
background-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checkbox__inner .checkbox__inner-icon { |
|||
opacity: 1; |
|||
transform: rotate(45deg); |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .radio__inner { |
|||
border-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .radio__inner .radio__inner-icon { |
|||
opacity: 1; |
|||
background-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checklist-text { |
|||
color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked.is-disable .checkbox__inner { |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked.is-disable .checklist-text { |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--default.is-checked.is-disable .radio__inner { |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button { |
|||
margin-right: 10px; |
|||
padding: 5px 15px; |
|||
border: 1px #DCDFE6 solid; |
|||
border-radius: 3px; |
|||
transition: border-color 0.2s; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-disable { |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
border: 1px #eee solid; |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-disable .checkbox__inner { |
|||
background-color: #F2F6FC; |
|||
border-color: #DCDFE6; |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-disable .radio__inner { |
|||
background-color: #F2F6FC; |
|||
border-color: #DCDFE6; |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-disable .checklist-text { |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked { |
|||
border-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked .checkbox__inner { |
|||
border-color: #007aff; |
|||
background-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked .checkbox__inner .checkbox__inner-icon { |
|||
opacity: 1; |
|||
transform: rotate(45deg); |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked .radio__inner { |
|||
border-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked .radio__inner .radio__inner-icon { |
|||
opacity: 1; |
|||
background-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked .checklist-text { |
|||
color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--button.is-checked.is-disable { |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--tag { |
|||
margin-right: 10px; |
|||
padding: 5px 10px; |
|||
border: 1px #DCDFE6 solid; |
|||
border-radius: 3px; |
|||
background-color: #f5f5f5; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--tag .checklist-text { |
|||
margin: 0; |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--tag.is-disable { |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--tag.is-checked { |
|||
background-color: #007aff; |
|||
border-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--tag.is-checked .checklist-text { |
|||
color: #fff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
padding: 10px 15px; |
|||
padding-left: 0; |
|||
margin: 0; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-list-border { |
|||
border-top: 1px #eee solid; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-disable { |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-disable .checkbox__inner { |
|||
background-color: #F2F6FC; |
|||
border-color: #DCDFE6; |
|||
/* #ifdef H5 */ |
|||
cursor: not-allowed; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-disable .checklist-text { |
|||
color: #999; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-checked .checkbox__inner { |
|||
border-color: #007aff; |
|||
background-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-checked .checkbox__inner .checkbox__inner-icon { |
|||
opacity: 1; |
|||
transform: rotate(45deg); |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-checked .checklist-text { |
|||
color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-checked .checklist-content .checkobx__list { |
|||
opacity: 1; |
|||
border-color: #007aff; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-checked.is-disable .checkbox__inner { |
|||
opacity: 0.4; |
|||
} |
|||
|
|||
.uni-data-checklist .checklist-group .checklist-box.is--list.is-checked.is-disable .checklist-text { |
|||
opacity: 0.4; |
|||
} |
|||
</style> |
@ -0,0 +1,362 @@ |
|||
|
|||
const events = { |
|||
load: 'load', |
|||
error: 'error' |
|||
} |
|||
const pageMode = { |
|||
add: 'add', |
|||
replace: 'replace' |
|||
} |
|||
|
|||
const attrs = [ |
|||
'pageCurrent', |
|||
'pageSize', |
|||
'collection', |
|||
'action', |
|||
'field', |
|||
'getcount', |
|||
'orderby', |
|||
'where' |
|||
] |
|||
|
|||
export default { |
|||
props: { |
|||
collection: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
action: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
field: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
pageData: { |
|||
type: String, |
|||
default: 'add' |
|||
}, |
|||
pageCurrent: { |
|||
type: Number, |
|||
default: 1 |
|||
}, |
|||
pageSize: { |
|||
type: Number, |
|||
default: 20 |
|||
}, |
|||
getcount: { |
|||
type: [Boolean, String], |
|||
default: false |
|||
}, |
|||
orderby: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
where: { |
|||
type: [String, Object], |
|||
default: '' |
|||
}, |
|||
getone: { |
|||
type: [Boolean, String], |
|||
default: false |
|||
}, |
|||
manual: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
loading: false, |
|||
listData: this.getone ? {} : [], |
|||
paginationInternal: { |
|||
current: this.pageCurrent, |
|||
size: this.pageSize, |
|||
count: 0 |
|||
}, |
|||
errorMessage: '' |
|||
} |
|||
}, |
|||
created() { |
|||
let db = null; |
|||
let dbCmd = null; |
|||
|
|||
if(this.collection){ |
|||
this.db = uniCloud.database(); |
|||
this.dbCmd = this.db.command; |
|||
} |
|||
|
|||
this._isEnded = false |
|||
|
|||
this.$watch(() => { |
|||
var al = [] |
|||
attrs.forEach(key => { |
|||
al.push(this[key]) |
|||
}) |
|||
return al |
|||
}, (newValue, oldValue) => { |
|||
this.paginationInternal.pageSize = this.pageSize |
|||
|
|||
let needReset = false |
|||
for (let i = 2; i < newValue.length; i++) { |
|||
if (newValue[i] != oldValue[i]) { |
|||
needReset = true |
|||
break |
|||
} |
|||
} |
|||
if (needReset) { |
|||
this.clear() |
|||
this.reset() |
|||
} |
|||
if (newValue[0] != oldValue[0]) { |
|||
this.paginationInternal.current = this.pageCurrent |
|||
} |
|||
|
|||
this._execLoadData() |
|||
}) |
|||
|
|||
// #ifdef H5
|
|||
if (process.env.NODE_ENV === 'development') { |
|||
this._debugDataList = [] |
|||
if (!window.unidev) { |
|||
window.unidev = { |
|||
clientDB: { |
|||
data: [] |
|||
} |
|||
} |
|||
} |
|||
unidev.clientDB.data.push(this._debugDataList) |
|||
} |
|||
// #endif
|
|||
|
|||
// #ifdef MP-TOUTIAO
|
|||
let changeName |
|||
let events = this.$scope.dataset.eventOpts |
|||
for (var i = 0; i < events.length; i++) { |
|||
let event = events[i] |
|||
if (event[0].includes('^load')) { |
|||
changeName = event[1][0][0] |
|||
} |
|||
} |
|||
if (changeName) { |
|||
let parent = this.$parent |
|||
let maxDepth = 16 |
|||
this._changeDataFunction = null |
|||
while (parent && maxDepth > 0) { |
|||
let fun = parent[changeName] |
|||
if (fun && typeof fun === 'function') { |
|||
this._changeDataFunction = fun |
|||
maxDepth = 0 |
|||
break |
|||
} |
|||
parent = parent.$parent |
|||
maxDepth--; |
|||
} |
|||
} |
|||
// #endif
|
|||
|
|||
// if (!this.manual) {
|
|||
// this.loadData()
|
|||
// }
|
|||
}, |
|||
// #ifdef H5
|
|||
beforeDestroy() { |
|||
if (process.env.NODE_ENV === 'development' && window.unidev) { |
|||
var cd = this._debugDataList |
|||
var dl = unidev.clientDB.data |
|||
for (var i = dl.length - 1; i >= 0; i--) { |
|||
if (dl[i] === cd) { |
|||
dl.splice(i, 1) |
|||
break |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
// #endif
|
|||
methods: { |
|||
loadData(args1, args2) { |
|||
let callback = null |
|||
if (typeof args1 === 'object') { |
|||
if (args1.clear) { |
|||
this.clear() |
|||
this.reset() |
|||
} |
|||
if (args1.current !== undefined) { |
|||
this.paginationInternal.current = args1.current |
|||
} |
|||
if (typeof args2 === 'function') { |
|||
callback = args2 |
|||
} |
|||
} else if (typeof args1 === 'function') { |
|||
callback = args1 |
|||
} |
|||
|
|||
this._execLoadData(callback) |
|||
}, |
|||
loadMore() { |
|||
if (this._isEnded) { |
|||
return |
|||
} |
|||
this._execLoadData() |
|||
}, |
|||
refresh() { |
|||
this.clear() |
|||
this._execLoadData() |
|||
}, |
|||
clear() { |
|||
this._isEnded = false |
|||
this.listData = [] |
|||
}, |
|||
reset() { |
|||
this.paginationInternal.current = 1 |
|||
}, |
|||
remove(id, { |
|||
action, |
|||
callback, |
|||
confirmTitle, |
|||
confirmContent |
|||
} = {}) { |
|||
if (!id || !id.length) { |
|||
return |
|||
} |
|||
uni.showModal({ |
|||
title: confirmTitle || '提示', |
|||
content: confirmContent || '是否删除该数据', |
|||
showCancel: true, |
|||
success: (res) => { |
|||
if (!res.confirm) { |
|||
return |
|||
} |
|||
this._execRemove(id, action, callback) |
|||
} |
|||
}) |
|||
}, |
|||
_execLoadData(callback) { |
|||
if (this.loading) { |
|||
return |
|||
} |
|||
this.loading = true |
|||
this.errorMessage = '' |
|||
|
|||
this._getExec().then((res) => { |
|||
this.loading = false |
|||
const { |
|||
data, |
|||
count |
|||
} = res.result |
|||
this._isEnded = data.length < this.pageSize |
|||
|
|||
callback && callback(data, this._isEnded) |
|||
this._dispatchEvent(events.load, data) |
|||
|
|||
if (this.getone) { |
|||
this.listData = data.length ? data[0] : undefined |
|||
} else if (this.pageData === pageMode.add) { |
|||
this.listData.push(...data) |
|||
if (this.listData.length) { |
|||
this.paginationInternal.current++ |
|||
} |
|||
} else if (this.pageData === pageMode.replace) { |
|||
this.listData = data |
|||
this.paginationInternal.count = count |
|||
} |
|||
|
|||
// #ifdef H5
|
|||
if (process.env.NODE_ENV === 'development') { |
|||
this._debugDataList.length = 0 |
|||
this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData))) |
|||
} |
|||
// #endif
|
|||
}).catch((err) => { |
|||
this.loading = false |
|||
this.errorMessage = err |
|||
callback && callback() |
|||
this.$emit(events.error, err) |
|||
}) |
|||
}, |
|||
_getExec() { |
|||
let exec = this.db |
|||
if (this.action) { |
|||
exec = exec.action(this.action) |
|||
} |
|||
|
|||
exec = exec.collection(this.collection) |
|||
|
|||
if (!(!this.where || !Object.keys(this.where).length)) { |
|||
exec = exec.where(this.where) |
|||
} |
|||
if (this.field) { |
|||
exec = exec.field(this.field) |
|||
} |
|||
if (this.orderby) { |
|||
exec = exec.orderBy(this.orderby) |
|||
} |
|||
|
|||
const { |
|||
current, |
|||
size |
|||
} = this.paginationInternal |
|||
exec = exec.skip(size * (current - 1)).limit(size).get({ |
|||
getCount: this.getcount |
|||
}) |
|||
|
|||
return exec |
|||
}, |
|||
_execRemove(id, action, callback) { |
|||
if (!this.collection || !id) { |
|||
return |
|||
} |
|||
|
|||
const ids = Array.isArray(id) ? id : [id] |
|||
if (!ids.length) { |
|||
return |
|||
} |
|||
|
|||
uni.showLoading({ |
|||
mask: true |
|||
}) |
|||
|
|||
let exec = this.db |
|||
if (action) { |
|||
exec = exec.action(action) |
|||
} |
|||
|
|||
exec.collection(this.collection).where({ |
|||
_id: dbCmd.in(ids) |
|||
}).remove().then((res) => { |
|||
callback && callback(res.result) |
|||
if (this.pageData === pageMode.replace) { |
|||
this.refresh() |
|||
} else { |
|||
this.removeData(ids) |
|||
} |
|||
}).catch((err) => { |
|||
uni.showModal({ |
|||
content: err.message, |
|||
showCancel: false |
|||
}) |
|||
}).finally(() => { |
|||
uni.hideLoading() |
|||
}) |
|||
}, |
|||
removeData(ids) { |
|||
let il = ids.slice(0) |
|||
let dl = this.listData |
|||
for (let i = dl.length - 1; i >= 0; i--) { |
|||
let index = il.indexOf(dl[i]._id) |
|||
if (index >= 0) { |
|||
dl.splice(i, 1) |
|||
il.splice(index, 1) |
|||
} |
|||
} |
|||
}, |
|||
_dispatchEvent(type, data) { |
|||
if (this._changeDataFunction) { |
|||
this._changeDataFunction(data, this._isEnded) |
|||
} else { |
|||
this.$emit(type, data, this._isEnded) |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,142 @@ |
|||
<template> |
|||
<view> |
|||
<view v-if="loaded || list.itemIndex < 15" class="uni-indexed-list__title-wrapper"> |
|||
<text v-if="list.items && list.items.length > 0" class="uni-indexed-list__title">{{ list.title }}</text> |
|||
</view> |
|||
<view v-if="(loaded || list.itemIndex < 15) && list.items && list.items.length > 0" class="uni-indexed-list__list"> |
|||
<view v-for="(item, index) in list.items" :key="index" class="uni-indexed-list__item" hover-class="uni-indexed-list__item--hover"> |
|||
<view class="uni-indexed-list__item-container" @click="onClick(idx, index)"> |
|||
<view class="uni-indexed-list__item-border" :class="{'uni-indexed-list__item-border--last':index===list.items.length-1}"> |
|||
<view v-if="showSelect" style="margin-right: 20rpx;"> |
|||
<uni-icons :type="item.checked ? 'checkbox-filled' : 'circle'" :color="item.checked ? '#007aff' : '#aaa'" size="24" /> |
|||
</view> |
|||
<text class="uni-indexed-list__item-content">{{ item.text }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import uniIcons from '../uni-icons/uni-icons.vue' |
|||
export default { |
|||
name: 'UniIndexedList', |
|||
components: { |
|||
uniIcons |
|||
}, |
|||
props: { |
|||
loaded: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
idx: { |
|||
type: Number, |
|||
default: 0 |
|||
}, |
|||
list: { |
|||
type: Object, |
|||
default () { |
|||
return {} |
|||
} |
|||
}, |
|||
showSelect: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
methods: { |
|||
onClick(idx, index) { |
|||
this.$emit("itemClick", { |
|||
idx, |
|||
index |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-indexed-list__list { |
|||
background-color: #ffffff; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
border-top-style: solid; |
|||
border-top-width: 1px; |
|||
border-top-color: #e5e5e5; |
|||
} |
|||
|
|||
.uni-indexed-list__item { |
|||
font-size: 16px; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex: 1; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.uni-indexed-list__item-container { |
|||
padding-left: 15px; |
|||
flex: 1; |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
box-sizing: border-box; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.uni-indexed-list__item-border { |
|||
flex: 1; |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
box-sizing: border-box; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
height: 50px; |
|||
padding: 15px; |
|||
padding-left: 0; |
|||
border-bottom-style: solid; |
|||
border-bottom-width: 1px; |
|||
border-bottom-color: #e5e5e5; |
|||
} |
|||
|
|||
.uni-indexed-list__item-border--last { |
|||
border-bottom-width: 0px; |
|||
} |
|||
|
|||
.uni-indexed-list__item-content { |
|||
flex: 1; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.uni-indexed-list { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.uni-indexed-list__title-wrapper { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
width: 100%; |
|||
/* #endif */ |
|||
background-color: #f7f7f7; |
|||
} |
|||
|
|||
.uni-indexed-list__title { |
|||
padding: 6px 12px; |
|||
line-height: 24px; |
|||
font-size: 12px; |
|||
} |
|||
</style> |
@ -0,0 +1,364 @@ |
|||
<template> |
|||
<view class="uni-indexed-list" ref="list" id="list"> |
|||
<!-- #ifdef APP-NVUE --> |
|||
<list class="uni-indexed-list__scroll" scrollable="true" show-scrollbar="false"> |
|||
<cell v-for="(list, idx) in lists" :key="idx" :ref="'uni-indexed-list-' + idx"> |
|||
<!-- #endif --> |
|||
<!-- #ifndef APP-NVUE --> |
|||
<scroll-view :scroll-into-view="scrollViewId" class="uni-indexed-list__scroll" scroll-y> |
|||
<view v-for="(list, idx) in lists" :key="idx" :id="'uni-indexed-list-' + idx"> |
|||
<!-- #endif --> |
|||
<uni-indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect" @itemClick="onClick"></uni-indexed-list-item> |
|||
<!-- #ifndef APP-NVUE --> |
|||
</view> |
|||
</scroll-view> |
|||
<!-- #endif --> |
|||
<!-- #ifdef APP-NVUE --> |
|||
</cell> |
|||
</list> |
|||
<!-- #endif --> |
|||
<view :class="touchmove ? 'uni-indexed-list__menu--active' : ''" @touchstart="touchStart" @touchmove.stop.prevent="touchMove" @touchend="touchEnd" class="uni-indexed-list__menu"> |
|||
<view v-for="(list, key) in lists" :key="key" class="uni-indexed-list__menu-item"> |
|||
<text class="uni-indexed-list__menu-text" :class="touchmoveIndex == key ? 'uni-indexed-list__menu-text--active' : ''">{{ list.value }}</text> |
|||
</view> |
|||
</view> |
|||
<view v-if="touchmove" class="uni-indexed-list__alert-wrapper"> |
|||
<text class="uni-indexed-list__alert">{{ lists[touchmoveIndex] }}</text> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
<script> |
|||
import uniIcons from '../uni-icons/uni-icons.vue' |
|||
import uniIndexedListItem from './uni-data-indexed-list-item.vue' |
|||
import clientdb from './clientdb.js' |
|||
// #ifdef APP-NVUE |
|||
const dom = weex.requireModule('dom'); |
|||
// #endif |
|||
// #ifdef APP-PLUS |
|||
function throttle(func, delay) { |
|||
var prev = Date.now(); |
|||
return function() { |
|||
var context = this; |
|||
var args = arguments; |
|||
var now = Date.now(); |
|||
if (now - prev >= delay) { |
|||
func.apply(context, args); |
|||
prev = Date.now(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function touchMove(e) { |
|||
let pageY = e.touches[0].pageY |
|||
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) |
|||
if (this.touchmoveIndex === index) { |
|||
return false |
|||
} |
|||
let item = this.lists[index] |
|||
if (item) { |
|||
// #ifndef APP-NVUE |
|||
this.scrollViewId = 'uni-indexed-list-' + index |
|||
this.touchmoveIndex = index |
|||
// #endif |
|||
// #ifdef APP-NVUE |
|||
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], { |
|||
animated: false |
|||
}) |
|||
this.touchmoveIndex = index |
|||
// #endif |
|||
} |
|||
} |
|||
const throttleTouchMove = throttle(touchMove, 40) |
|||
// #endif |
|||
|
|||
/** |
|||
* IndexedList 索引列表 |
|||
* @description 用于展示索引列表 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=375 |
|||
* @property {Boolean} showSelect = [true|false] 展示模式 |
|||
* @value true 展示模式 |
|||
* @value false 选择模式 |
|||
* @property {Object} options 索引列表需要的数据对象 |
|||
* @property {String|DBCollectionString} collection 表名 |
|||
* @property {String|ClientDBActionString} action 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理 |
|||
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割 |
|||
* @property {String} orderby 排序字段及正序倒叙设置 |
|||
* @property {String|JQLString} where 查询条件 |
|||
* @event {Function} click 点击列表事件 ,返回当前选择项的事件对象 |
|||
* @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list> |
|||
*/ |
|||
export default { |
|||
name: 'UniDataIndexedList', |
|||
mixins: [clientdb], |
|||
components: { |
|||
uniIcons, |
|||
uniIndexedListItem |
|||
}, |
|||
props: { |
|||
options: { |
|||
type: Array, |
|||
default () { |
|||
return [] |
|||
} |
|||
}, |
|||
localdata: { |
|||
type: Array, |
|||
default () { |
|||
return [] |
|||
} |
|||
}, |
|||
showSelect: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
lists: [], |
|||
winHeight: 0, |
|||
itemHeight: 0, |
|||
winOffsetY: 0, |
|||
touchmove: false, |
|||
touchmoveIndex: -1, |
|||
scrollViewId: '', |
|||
touchmoveTimeout: '', |
|||
loaded: false |
|||
} |
|||
}, |
|||
watch: { |
|||
options: { |
|||
handler: function() { |
|||
this.setList() |
|||
}, |
|||
deep: true |
|||
} |
|||
}, |
|||
mounted() { |
|||
if (this.localdata.length || this.options.length) { |
|||
setTimeout(() => { |
|||
this.setList() |
|||
}, 50) |
|||
setTimeout(() => { |
|||
this.loaded = true |
|||
}, 300); |
|||
} else if (this.collection) { |
|||
if (!this.manual) { |
|||
this._execLoadData((data) => { |
|||
this.lists = this.groupData(data); |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
groupData(data) { |
|||
let groups = {}; |
|||
for (let i = 0; i < data.length; i++) { |
|||
let item = data[i]; |
|||
let group = item.group; |
|||
if (!groups[group]) { |
|||
groups[group] = { |
|||
"title": group, |
|||
"value": group, |
|||
"itemIndex": i, |
|||
"items": [] |
|||
} |
|||
} |
|||
groups[group].items.push(item); |
|||
} |
|||
let result = [] |
|||
for (let g in groups) { |
|||
let group = groups[g]; |
|||
let items = group.items; |
|||
for (let j = 0; j < items.length; j++) { |
|||
items[j].itemIndex = j; |
|||
} |
|||
result.push(group); |
|||
} |
|||
return result; |
|||
}, |
|||
setList(data) { |
|||
let index = 0; |
|||
this.lists = [] |
|||
this.options.forEach((value, index) => { |
|||
if (value.data.length === 0) { |
|||
return |
|||
} |
|||
let indexBefore = index |
|||
let items = value.data.map(item => { |
|||
let obj = {} |
|||
obj['value'] = value.letter |
|||
obj['text'] = item |
|||
obj['itemIndex'] = index |
|||
index++ |
|||
obj.checked = item.checked ? item.checked : false |
|||
return obj |
|||
}) |
|||
this.lists.push({ |
|||
title: value.letter, |
|||
value: value.letter, |
|||
items: items, |
|||
itemIndex: indexBefore |
|||
}) |
|||
}) |
|||
// #ifndef APP-NVUE |
|||
uni.createSelectorQuery() |
|||
.in(this) |
|||
.select('#list') |
|||
.boundingClientRect() |
|||
.exec(ret => { |
|||
this.winOffsetY = ret[0].top |
|||
this.winHeight = ret[0].height |
|||
this.itemHeight = this.winHeight / this.lists.length |
|||
}) |
|||
// #endif |
|||
// #ifdef APP-NVUE |
|||
dom.getComponentRect(this.$refs['list'], (res) => { |
|||
this.winOffsetY = res.size.top |
|||
this.winHeight = res.size.height |
|||
this.itemHeight = this.winHeight / this.lists.length |
|||
}) |
|||
// #endif |
|||
}, |
|||
touchStart(e) { |
|||
this.touchmove = true |
|||
let pageY = e.touches[0].pageY |
|||
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) |
|||
let item = this.lists[index] |
|||
if (item) { |
|||
this.scrollViewId = 'uni-indexed-list-' + index |
|||
this.touchmoveIndex = index |
|||
// #ifdef APP-NVUE |
|||
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], { |
|||
animated: false |
|||
}) |
|||
// #endif |
|||
} |
|||
}, |
|||
touchMove(e) { |
|||
// #ifndef APP-PLUS |
|||
let pageY = e.touches[0].pageY |
|||
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight) |
|||
if (this.touchmoveIndex === index) { |
|||
return false |
|||
} |
|||
let item = this.lists[index] |
|||
if (item) { |
|||
this.scrollViewId = 'uni-indexed-list-' + index |
|||
this.touchmoveIndex = index |
|||
} |
|||
// #endif |
|||
// #ifdef APP-PLUS |
|||
throttleTouchMove.call(this, e) |
|||
// #endif |
|||
}, |
|||
touchEnd() { |
|||
this.touchmove = false |
|||
this.touchmoveIndex = -1 |
|||
}, |
|||
onClick(e) { |
|||
let { |
|||
idx, |
|||
index |
|||
} = e |
|||
let obj = {} |
|||
for (let key in this.lists[idx].items[index]) { |
|||
obj[key] = this.lists[idx].items[index][key] |
|||
} |
|||
let select = [] |
|||
if (this.showSelect) { |
|||
this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked |
|||
this.lists.forEach((value, idx) => { |
|||
value.items.forEach((item, index) => { |
|||
if (item.checked) { |
|||
let obj = {} |
|||
for (let key in this.lists[idx].items[index]) { |
|||
obj[key] = this.lists[idx].items[index][key] |
|||
} |
|||
select.push(obj) |
|||
} |
|||
}) |
|||
}) |
|||
} |
|||
this.$emit('click', { |
|||
item: obj, |
|||
select: select |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
<style scoped> |
|||
.uni-indexed-list { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.uni-indexed-list__scroll { |
|||
flex: 1; |
|||
} |
|||
|
|||
.uni-indexed-list__menu { |
|||
width: 24px; |
|||
background-color: lightgrey; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.uni-indexed-list__menu-item { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex: 1; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.uni-indexed-list__menu-text { |
|||
line-height: 20px; |
|||
font-size: 12px; |
|||
text-align: center; |
|||
color: #aaa; |
|||
} |
|||
|
|||
.uni-indexed-list__menu--active { |
|||
background-color: #c8c8c8; |
|||
} |
|||
|
|||
.uni-indexed-list__menu-text--active { |
|||
color: #007aff; |
|||
} |
|||
|
|||
.uni-indexed-list__alert-wrapper { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.uni-indexed-list__alert { |
|||
width: 80px; |
|||
height: 80px; |
|||
border-radius: 80px; |
|||
text-align: center; |
|||
line-height: 80px; |
|||
font-size: 35px; |
|||
color: #fff; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
} |
|||
</style> |
After Width: | Height: | Size: 673 B |
@ -0,0 +1,171 @@ |
|||
<template> |
|||
<view class="uni-calendar-item__weeks-box" :class="{ |
|||
'uni-calendar-item--disable':weeks.disable, |
|||
'uni-calendar-item--before-checked-x':weeks.beforeMultiple, |
|||
'uni-calendar-item--multiple': weeks.multiple, |
|||
'uni-calendar-item--after-checked-x':weeks.afterMultiple, |
|||
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)"> |
|||
<view class="uni-calendar-item__weeks-box-item" :class="{ |
|||
'uni-calendar-item--isDay-text': weeks.isDay, |
|||
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, |
|||
'uni-calendar-item--checked-range-text': checkHover, |
|||
'uni-calendar-item--before-checked':weeks.beforeMultiple, |
|||
'uni-calendar-item--multiple': weeks.multiple, |
|||
'uni-calendar-item--after-checked':weeks.afterMultiple, |
|||
'uni-calendar-item--disable':weeks.disable, |
|||
}"> |
|||
<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text> |
|||
<text class="uni-calendar-item__weeks-box-text">{{weeks.date}}</text> |
|||
<!-- <text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text">今天</text> |
|||
<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" >{{weeks.isDay?'今天': (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text> --> |
|||
<!-- <text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text">{{weeks.extraInfo.info}}</text> --> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
weeks: { |
|||
type: Object, |
|||
default () { |
|||
return {} |
|||
} |
|||
}, |
|||
calendar: { |
|||
type: Object, |
|||
default: () => { |
|||
return {} |
|||
} |
|||
}, |
|||
selected: { |
|||
type: Array, |
|||
default: () => { |
|||
return [] |
|||
} |
|||
}, |
|||
lunar: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
checkHover: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
methods: { |
|||
choiceDate(weeks) { |
|||
this.$emit('change', weeks) |
|||
}, |
|||
handleMousemove(weeks) { |
|||
this.$emit('handleMouse', weeks) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-calendar-item__weeks-box { |
|||
flex: 1; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
margin: 3px 0; |
|||
} |
|||
|
|||
.uni-calendar-item__weeks-box-text { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.uni-calendar-item__weeks-lunar-text { |
|||
font-size: 24rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-calendar-item__weeks-box-item { |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
width: 100rpx; |
|||
height: 100rpx; |
|||
/* #ifdef H5 */ |
|||
cursor: pointer; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-calendar-item__weeks-box-circle { |
|||
position: absolute; |
|||
top: 5px; |
|||
right: 5px; |
|||
width: 8px; |
|||
height: 8px; |
|||
border-radius: 8px; |
|||
background-color: #dd524d; |
|||
} |
|||
|
|||
.uni-calendar-item__weeks-box .uni-calendar-item--disable { |
|||
color: #c0c0c0; |
|||
cursor: default; |
|||
} |
|||
|
|||
.uni-calendar-item--isDay-text { |
|||
color: #007aff !important; |
|||
} |
|||
|
|||
.uni-calendar-item--isDay { |
|||
background-color: #007aff; |
|||
opacity: 0.8; |
|||
color: #fff; |
|||
} |
|||
|
|||
.uni-calendar-item--extra { |
|||
color: #dd524d; |
|||
opacity: 0.8; |
|||
} |
|||
|
|||
.uni-calendar-item--checked { |
|||
background-color: #007aff; |
|||
box-sizing: border-box; |
|||
border: 6px solid #f2f6fc; |
|||
color: #fff; |
|||
opacity: 0.8; |
|||
} |
|||
|
|||
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text { |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-calendar-item--multiple { |
|||
background-color: #f2f6fc; |
|||
opacity: 0.8; |
|||
} |
|||
|
|||
.uni-calendar-item--multiple .uni-calendar-item--before-checked { |
|||
background-color: #409eff; |
|||
color: #fff; |
|||
box-sizing: border-box; |
|||
border: 6px solid #f2f6fc; |
|||
} |
|||
|
|||
.uni-calendar-item--multiple .uni-calendar-item--after-checked { |
|||
background-color: #409eff; |
|||
color: #fff; |
|||
box-sizing: border-box; |
|||
border: 6px solid #f2f6fc; |
|||
} |
|||
|
|||
.uni-calendar-item--before-checked-x { |
|||
background-color: #f2f6fc; |
|||
} |
|||
|
|||
.uni-calendar-item--after-checked-x { |
|||
background-color: #f2f6fc; |
|||
} |
|||
</style> |
@ -0,0 +1,739 @@ |
|||
<template> |
|||
<view class="uni-calendar" @mouseleave="leaveCale"> |
|||
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view> |
|||
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}"> |
|||
|
|||
<view class="uni-calendar__header"> |
|||
<view v-if="left" class="uni-calendar__header-btn-box" @click.stop="pre"> |
|||
<view class="uni-calendar__header-btn uni-calendar--left"></view> |
|||
</view> |
|||
<picker mode="date" :value="date" fields="month" @change="bindDateChange"> |
|||
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +'年'+( nowDate.month||'') +'月'}}</text> |
|||
</picker> |
|||
<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next"> |
|||
<view class="uni-calendar__header-btn uni-calendar--right"></view> |
|||
</view> |
|||
<!-- <text class="uni-calendar__backtoday" @click="backtoday">回到今天</text> --> |
|||
|
|||
</view> |
|||
<view class="uni-calendar__box"> |
|||
<view v-if="showMonth" class="uni-calendar__box-bg"> |
|||
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks"> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">日</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">一</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">二</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">三</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">四</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">五</text> |
|||
</view> |
|||
<view class="uni-calendar__weeks-day"> |
|||
<text class="uni-calendar__weeks-day-text">六</text> |
|||
</view> |
|||
</view> |
|||
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex"> |
|||
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex"> |
|||
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" :checkHover="range" @change="choiceDate" @handleMouse="handleMouse"> |
|||
</calendar-item> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top" style="padding: 0 40px;"> |
|||
<text class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : '选择日期'}}</text> |
|||
<time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time" :disabled="!tempSingleDate" :border="false" class="time-picker-style"> |
|||
</time-picker> |
|||
</view> |
|||
|
|||
<view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"> |
|||
<view class="uni-date-changed--time-start"> |
|||
<text class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : '开始日期'}}</text> |
|||
<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false" :disabled="!tempRange.before" class="time-picker-style"> |
|||
</time-picker> |
|||
</view> |
|||
<uni-icons type="arrowthinright" color="#999" style="line-height: 50px;"></uni-icons> |
|||
<view class="uni-date-changed--time-end"> |
|||
<text class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : '结束日期'}}</text> |
|||
<time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false" :disabled="!tempRange.after" class="time-picker-style"> |
|||
</time-picker> |
|||
</view> |
|||
</view> |
|||
|
|||
<view v-if="!insert" class="uni-date-changed uni-calendar__header" @click="confirm"> |
|||
<!-- <view class="uni-calendar__header-btn-box" @click="close"> |
|||
<text class="uni-calendar__header-text uni-calendar--fixed-width">取消</text> |
|||
</view> --> |
|||
<view class="uni-calendar__header-btn-box"> |
|||
<text class="uni-calendar__button-text uni-calendar--fixed-width">确定</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import Calendar from './util.js'; |
|||
import calendarItem from './uni-calendar-item.vue' |
|||
import timePicker from './time-picker.vue' |
|||
/** |
|||
* Calendar 日历 |
|||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=56 |
|||
* @property {String} date 自定义当前时间,默认为今天 |
|||
* @property {Boolean} lunar 显示农历 |
|||
* @property {String} startDate 日期选择范围-开始日期 |
|||
* @property {String} endDate 日期选择范围-结束日期 |
|||
* @property {Boolean} range 范围选择 |
|||
* @property {Boolean} insert = [true|false] 插入模式,默认为false |
|||
* @value true 弹窗模式 |
|||
* @value false 插入模式 |
|||
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容 |
|||
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] |
|||
* @property {Boolean} showMonth 是否选择月份为背景 |
|||
* @event {Function} change 日期改变,`insert :ture` 时生效 |
|||
* @event {Function} confirm 确认选择`insert :false` 时生效 |
|||
* @event {Function} monthSwitch 切换月份时触发 |
|||
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" /> |
|||
*/ |
|||
export default { |
|||
components: { |
|||
calendarItem, |
|||
timePicker |
|||
}, |
|||
props: { |
|||
date: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
defTime: { |
|||
type: [String, Object], |
|||
default: '' |
|||
}, |
|||
selectableTimes: { |
|||
type: [Object], |
|||
default () { |
|||
return {} |
|||
} |
|||
}, |
|||
selected: { |
|||
type: Array, |
|||
default () { |
|||
return [] |
|||
} |
|||
}, |
|||
lunar: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
startDate: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
endDate: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
range: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
typeHasTime: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
insert: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
showMonth: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
clearDate: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
left: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
right: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
checkHover: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
pleStatus: { |
|||
type: Object, |
|||
default () { |
|||
return { |
|||
before: '', |
|||
after: '', |
|||
data: [], |
|||
fulldate: '' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
show: false, |
|||
weeks: [], |
|||
calendar: {}, |
|||
nowDate: '', |
|||
aniMaskShow: false, |
|||
firstEnter: true, |
|||
time: this.defTime ? this.defTime : '', |
|||
timeRange: { |
|||
startTime: this.defTime.start ? this.defTime.start : '', |
|||
endTime: this.defTime.end ? this.defTime.end : '' |
|||
}, |
|||
tempSingleDate: this.date, |
|||
tempRange: { |
|||
before: '', |
|||
after: '' |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
date(newVal, oldVal) { |
|||
// this.cale.setDate(newVal) |
|||
this.init(newVal) |
|||
}, |
|||
startDate(val) { |
|||
this.cale.resetSatrtDate(val) |
|||
}, |
|||
endDate(val) { |
|||
this.cale.resetEndDate(val) |
|||
}, |
|||
selected(newVal) { |
|||
this.cale.setSelectInfo(this.nowDate.fullDate, newVal) |
|||
this.weeks = this.cale.weeks |
|||
}, |
|||
// tempRange: { |
|||
// immediate: true, |
|||
// handler(newVal, oldVal) {debugger |
|||
// if (!oldVal) return |
|||
// if (!newVal.before) this.timeRange.startTime = '' |
|||
// if (!newVal.after) this.timeRange.endTime = '' |
|||
// } |
|||
// }, |
|||
pleStatus: { |
|||
immediate: true, |
|||
handler(newVal, oldVal) { |
|||
const { |
|||
before, |
|||
after, |
|||
fulldate, |
|||
which |
|||
} = newVal |
|||
this.tempRange.before = before |
|||
this.tempRange.after = after |
|||
setTimeout(() => { |
|||
if (fulldate) { |
|||
this.cale.setHoverMultiple(fulldate) |
|||
if (before && after) { |
|||
this.cale.lastHover = true |
|||
if (this.rangeWithinMonth(after, before)) return |
|||
this.setDate(before) |
|||
} |
|||
if (!before && !after) { |
|||
this.cale.setMultiple(fulldate) |
|||
this.setDate(this.nowDate.fullDate) |
|||
this.calendar.fullDate = '' |
|||
this.cale.lastHover = false |
|||
} |
|||
} else { |
|||
this.cale.setDefaultMultiple(before, after) |
|||
if (which === 'left') { |
|||
this.setDate(before) |
|||
} else { |
|||
this.setDate(after) |
|||
} |
|||
this.cale.lastHover = true |
|||
} |
|||
}, 16) |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
reactStartTime() { |
|||
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate |
|||
const res = activeDate === this.startDate ? this.selectableTimes.start : '' |
|||
return res |
|||
}, |
|||
reactEndTime() { |
|||
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate |
|||
const res = activeDate === this.endDate ? this.selectableTimes.end : '' |
|||
return res |
|||
} |
|||
}, |
|||
created() { |
|||
// 获取日历方法实例 |
|||
this.cale = new Calendar({ |
|||
// date: new Date(), |
|||
selected: this.selected, |
|||
startDate: this.startDate, |
|||
endDate: this.endDate, |
|||
range: this.range, |
|||
// multipleStatus: this.pleStatus |
|||
}) |
|||
// 选中某一天 |
|||
// this.cale.setDate(this.date) |
|||
|
|||
this.init(this.date) |
|||
// this.setDay |
|||
}, |
|||
methods: { |
|||
leaveCale() { |
|||
this.firstEnter = true |
|||
}, |
|||
handleMouse(weeks) { |
|||
if (weeks.disable) return |
|||
if (this.cale.lastHover) return |
|||
let { |
|||
before, |
|||
after |
|||
} = this.cale.multipleStatus |
|||
if (!before) return |
|||
this.calendar = weeks |
|||
// 设置范围选 |
|||
this.cale.setHoverMultiple(this.calendar.fullDate) |
|||
this.weeks = this.cale.weeks |
|||
// hover时,进入一个日历,更新另一个 |
|||
if (this.firstEnter) { |
|||
this.$emit('firstEnterCale', this.cale.multipleStatus) |
|||
this.firstEnter = false |
|||
} |
|||
}, |
|||
rangeWithinMonth(A, B) { |
|||
const [yearA, monthA] = A.split('-') |
|||
const [yearB, monthB] = B.split('-') |
|||
return yearA === yearB && monthA === monthB |
|||
}, |
|||
|
|||
// 取消穿透 |
|||
clean() { |
|||
this.close() |
|||
}, |
|||
|
|||
bindDateChange(e) { |
|||
const value = e.detail.value + '-1' |
|||
console.log(this.cale.getDate(value)); |
|||
this.init(value) |
|||
}, |
|||
/** |
|||
* 初始化日期显示 |
|||
* @param {Object} date |
|||
*/ |
|||
init(date) { |
|||
|
|||
this.cale.setDate(date) |
|||
this.weeks = this.cale.weeks |
|||
this.nowDate = this.calendar = this.cale.getInfo(date) |
|||
}, |
|||
/** |
|||
* 打开日历弹窗 |
|||
*/ |
|||
open() { |
|||
// 弹窗模式并且清理数据 |
|||
if (this.clearDate && !this.insert) { |
|||
this.cale.cleanMultipleStatus() |
|||
// this.cale.setDate(this.date) |
|||
this.init(this.date) |
|||
} |
|||
this.show = true |
|||
this.$nextTick(() => { |
|||
setTimeout(() => { |
|||
this.aniMaskShow = true |
|||
}, 50) |
|||
}) |
|||
}, |
|||
/** |
|||
* 关闭日历弹窗 |
|||
*/ |
|||
close() { |
|||
this.aniMaskShow = false |
|||
this.$nextTick(() => { |
|||
setTimeout(() => { |
|||
this.show = false |
|||
this.$emit('close') |
|||
}, 300) |
|||
}) |
|||
}, |
|||
/** |
|||
* 确认按钮 |
|||
*/ |
|||
confirm() { |
|||
this.setEmit('confirm') |
|||
this.close() |
|||
}, |
|||
/** |
|||
* 变化触发 |
|||
*/ |
|||
change() { |
|||
if (!this.insert) return |
|||
this.setEmit('change') |
|||
}, |
|||
/** |
|||
* 选择月份触发 |
|||
*/ |
|||
monthSwitch() { |
|||
let { |
|||
year, |
|||
month |
|||
} = this.nowDate |
|||
this.$emit('monthSwitch', { |
|||
year, |
|||
month: Number(month) |
|||
}) |
|||
}, |
|||
/** |
|||
* 派发事件 |
|||
* @param {Object} name |
|||
*/ |
|||
setEmit(name) { |
|||
let { |
|||
year, |
|||
month, |
|||
date, |
|||
fullDate, |
|||
lunar, |
|||
extraInfo |
|||
} = this.calendar |
|||
this.$emit(name, { |
|||
range: this.cale.multipleStatus, |
|||
year, |
|||
month, |
|||
date, |
|||
time: this.time, |
|||
timeRange: this.timeRange, |
|||
fulldate: fullDate, |
|||
lunar, |
|||
extraInfo: extraInfo || {} |
|||
}) |
|||
}, |
|||
/** |
|||
* 选择天触发 |
|||
* @param {Object} weeks |
|||
*/ |
|||
choiceDate(weeks) { |
|||
if (weeks.disable) return |
|||
this.calendar = weeks |
|||
// 设置多选 |
|||
this.cale.setMultiple(this.calendar.fullDate, true) |
|||
this.weeks = this.cale.weeks |
|||
this.tempSingleDate = this.calendar.fullDate |
|||
this.tempRange.before = this.cale.multipleStatus.before |
|||
this.tempRange.after = this.cale.multipleStatus.after |
|||
this.change() |
|||
}, |
|||
/** |
|||
* 回到今天 |
|||
*/ |
|||
backtoday() { |
|||
console.log(this.cale.getDate(new Date()).fullDate); |
|||
let date = this.cale.getDate(new Date()).fullDate |
|||
// this.cale.setDate(date) |
|||
this.init(date) |
|||
this.change() |
|||
}, |
|||
/** |
|||
* 比较时间大小 |
|||
*/ |
|||
dateCompare(startDate, endDate) { |
|||
// 计算截止时间 |
|||
startDate = new Date(startDate.replace('-', '/').replace('-', '/')) |
|||
// 计算详细项的截止时间 |
|||
endDate = new Date(endDate.replace('-', '/').replace('-', '/')) |
|||
if (startDate <= endDate) { |
|||
return true |
|||
} else { |
|||
return false |
|||
} |
|||
}, |
|||
/** |
|||
* 上个月 |
|||
*/ |
|||
pre() { |
|||
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate |
|||
this.setDate(preDate) |
|||
this.monthSwitch() |
|||
|
|||
}, |
|||
/** |
|||
* 下个月 |
|||
*/ |
|||
next() { |
|||
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate |
|||
this.setDate(nextDate) |
|||
this.monthSwitch() |
|||
}, |
|||
/** |
|||
* 设置日期 |
|||
* @param {Object} date |
|||
*/ |
|||
setDate(date) { |
|||
this.cale.setDate(date) |
|||
this.weeks = this.cale.weeks |
|||
this.nowDate = this.cale.getInfo(date) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-calendar { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.uni-calendar__mask { |
|||
position: fixed; |
|||
bottom: 0; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
background-color: rgba(0, 0, 0, 0.4); |
|||
transition-property: opacity; |
|||
transition-duration: 0.3s; |
|||
opacity: 0; |
|||
/* #ifndef APP-NVUE */ |
|||
z-index: 99; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-calendar--mask-show { |
|||
opacity: 1; |
|||
} |
|||
|
|||
.uni-calendar--fixed { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
transition-property: transform; |
|||
transition-duration: 0.3s; |
|||
transform: translateY(460px); |
|||
/* #ifndef APP-NVUE */ |
|||
z-index: 99; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-calendar--ani-show { |
|||
transform: translateY(0); |
|||
} |
|||
|
|||
.uni-calendar__content { |
|||
background-color: #fff; |
|||
} |
|||
|
|||
.uni-calendar__header { |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 50px; |
|||
} |
|||
|
|||
.uni-calendar--fixed-top { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
border-top-color: #c8c7cc; |
|||
border-top-style: solid; |
|||
border-top-width: 1px; |
|||
} |
|||
|
|||
.uni-calendar--fixed-width { |
|||
width: 50px; |
|||
} |
|||
|
|||
.uni-calendar__backtoday { |
|||
position: absolute; |
|||
right: 0; |
|||
top: 25rpx; |
|||
padding: 0 5px; |
|||
padding-left: 10px; |
|||
height: 25px; |
|||
line-height: 25px; |
|||
font-size: 12px; |
|||
border-top-left-radius: 25px; |
|||
border-bottom-left-radius: 25px; |
|||
color: #333; |
|||
background-color: #f1f1f1; |
|||
} |
|||
|
|||
.uni-calendar__header-text { |
|||
text-align: center; |
|||
width: 100px; |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-calendar__button-text { |
|||
text-align: center; |
|||
width: 100px; |
|||
font-size: 28rpx; |
|||
color: #007aff; |
|||
letter-spacing: 3px; |
|||
} |
|||
|
|||
.uni-calendar__header-btn-box { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 50px; |
|||
height: 50px; |
|||
} |
|||
|
|||
.uni-calendar__header-btn { |
|||
width: 10px; |
|||
height: 10px; |
|||
border-left-color: #808080; |
|||
border-left-style: solid; |
|||
border-left-width: 2px; |
|||
border-top-color: #555555; |
|||
border-top-style: solid; |
|||
border-top-width: 2px; |
|||
} |
|||
|
|||
.uni-calendar--left { |
|||
transform: rotate(-45deg); |
|||
} |
|||
|
|||
.uni-calendar--right { |
|||
transform: rotate(135deg); |
|||
} |
|||
|
|||
.uni-calendar__weeks { |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.uni-calendar__weeks-item { |
|||
flex: 1; |
|||
} |
|||
|
|||
.uni-calendar__weeks-day { |
|||
flex: 1; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 45px; |
|||
border-bottom-color: #F5F5F5; |
|||
border-bottom-style: solid; |
|||
border-bottom-width: 1px; |
|||
} |
|||
|
|||
.uni-calendar__weeks-day-text { |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.uni-calendar__box { |
|||
position: relative; |
|||
} |
|||
|
|||
.uni-calendar__box-bg { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
justify-content: center; |
|||
align-items: center; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
} |
|||
|
|||
.uni-calendar__box-bg-text { |
|||
font-size: 200px; |
|||
font-weight: bold; |
|||
color: #999; |
|||
opacity: 0.1; |
|||
text-align: center; |
|||
/* #ifndef APP-NVUE */ |
|||
line-height: 1; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-date-changed { |
|||
padding: 0 10px; |
|||
text-align: center; |
|||
color: #333; |
|||
border-top-color: #c8c7cc; |
|||
border-top-style: solid; |
|||
border-top-width: 1px; |
|||
} |
|||
|
|||
.uni-date-changed--time text { |
|||
line-height: 50px; |
|||
} |
|||
|
|||
.uni-date-changed { |
|||
flex: 1; |
|||
} |
|||
|
|||
.uni-date-changed--time { |
|||
display: flex; |
|||
flex: 1; |
|||
} |
|||
|
|||
.uni-date-changed--time-start { |
|||
display: flex; |
|||
justify-content: right; |
|||
align-items: center; |
|||
} |
|||
|
|||
.uni-date-changed--time-end { |
|||
display: flex; |
|||
justify-content: left; |
|||
align-items: center; |
|||
} |
|||
|
|||
.uni-date-changed--time-date { |
|||
color: #999; |
|||
line-height: 50px; |
|||
} |
|||
|
|||
.time-picker-style { |
|||
width: 62px; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.mr-10 { |
|||
margin-right: 10px; |
|||
} |
|||
</style> |
@ -0,0 +1,500 @@ |
|||
<template> |
|||
<view class="uni-forms-item" :class="{ 'uni-forms-item--border': border, 'is-first-border': border && isFirstBorder, 'uni-forms-item-error': msg }"> |
|||
<view class="uni-forms-item__box"> |
|||
<view class="uni-forms-item__inner" :class="['is-direction-' + labelPos]"> |
|||
<view class="uni-forms-item__label" :style="{ width: labelWid , justifyContent: justifyContent }"> |
|||
<slot name="left"> |
|||
<uni-icons v-if="leftIcon" class="label-icon" size="16" :type="leftIcon" :color="iconColor" /> |
|||
<text class="label-text">{{ label }}</text> |
|||
<text v-if="required" class="is-required">*</text> |
|||
<view v-if="label" class="label-seat"></view> |
|||
</slot> |
|||
</view> |
|||
<view class="uni-forms-item__content" :class="{ 'is-input-error-border': msg }"> |
|||
<slot></slot> |
|||
</view> |
|||
</view> |
|||
<view v-if="msg" class="uni-error-message" :class="{ 'uni-error-msg--boeder': border }" :style="{ |
|||
paddingLeft: labelLeft |
|||
}"> |
|||
<text class="uni-error-message-text">{{ showMsg === 'undertext' ? msg : '' }}</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
/** |
|||
* Field 输入框 |
|||
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=21001 |
|||
* @property {Boolean} required 是否必填,左边显示红色"*"号(默认false) |
|||
* @property {String} validateTrigger = [bind|submit] 校验触发器方式 默认 submit 可选 |
|||
* @value bind 发生变化时触发 |
|||
* @value submit 提交时触发 |
|||
* @property {String } leftIcon label左边的图标,限 uni-ui 的图标名称 |
|||
* @property {String } iconColor 左边通过icon配置的图标的颜色(默认#606266) |
|||
* @property {String } label 输入框左边的文字提示 |
|||
* @property {Number } labelWidth label的宽度,单位px(默认65) |
|||
* @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left) |
|||
* @value left label 左侧显示 |
|||
* @value center label 居中 |
|||
* @value right label 右侧对齐 |
|||
* @property {String } labelPosition = [top|left] label的文字的位置(默认left) |
|||
* @value top 顶部显示 label |
|||
* @value left 左侧显示 label |
|||
* @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息 |
|||
* @property {String } name 表单域的属性名,在使用校验规则时必填 |
|||
*/ |
|||
|
|||
export default { |
|||
name: 'uniFormsItem', |
|||
props: { |
|||
// 自定义内容 |
|||
custom: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
// 是否显示报错信息 |
|||
showMessage: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
name: String, |
|||
required: Boolean, |
|||
validateTrigger: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
leftIcon: String, |
|||
iconColor: { |
|||
type: String, |
|||
default: '#606266' |
|||
}, |
|||
label: String, |
|||
// 左边标题的宽度单位px |
|||
labelWidth: { |
|||
type: [Number, String], |
|||
default: '' |
|||
}, |
|||
// 对齐方式,left|center|right |
|||
labelAlign: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
// lable的位置,可选为 left-左边,top-上边 |
|||
labelPosition: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
errorMessage: { |
|||
type: [String, Boolean], |
|||
default: '' |
|||
}, |
|||
// 表单校验规则 |
|||
rules: { |
|||
type: Array, |
|||
default () { |
|||
return []; |
|||
} |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
errorTop: false, |
|||
errorBottom: false, |
|||
labelMarginBottom: '', |
|||
errorWidth: '', |
|||
errMsg: '', |
|||
val: '', |
|||
labelPos: '', |
|||
labelWid: '', |
|||
labelAli: '', |
|||
showMsg: 'undertext', |
|||
border: false, |
|||
isFirstBorder: false, |
|||
isArray: false, |
|||
arrayField: '' |
|||
}; |
|||
}, |
|||
computed: { |
|||
msg() { |
|||
return this.errorMessage || this.errMsg; |
|||
}, |
|||
fieldStyle() { |
|||
let style = {}; |
|||
if (this.labelPos == 'top') { |
|||
style.padding = '0 0'; |
|||
this.labelMarginBottom = '6px'; |
|||
} |
|||
if (this.labelPos == 'left' && this.msg !== false && this.msg != '') { |
|||
style.paddingBottom = '0px'; |
|||
this.errorBottom = true; |
|||
this.errorTop = false; |
|||
} else if (this.labelPos == 'top' && this.msg !== false && this.msg != '') { |
|||
this.errorBottom = false; |
|||
this.errorTop = true; |
|||
} else { |
|||
// style.paddingBottom = '' |
|||
this.errorTop = false; |
|||
this.errorBottom = false; |
|||
} |
|||
return style; |
|||
}, |
|||
|
|||
// uni不支持在computed中写style.justifyContent = 'center'的形式,故用此方法 |
|||
justifyContent() { |
|||
if (this.labelAli === 'left') return 'flex-start'; |
|||
if (this.labelAli === 'center') return 'center'; |
|||
if (this.labelAli === 'right') return 'flex-end'; |
|||
}, |
|||
labelLeft() { |
|||
return (this.labelPos === 'left' ? parseInt(this.labelWid) : 0) + 'px' |
|||
} |
|||
}, |
|||
watch: { |
|||
validateTrigger(trigger) { |
|||
this.formTrigger = trigger; |
|||
} |
|||
}, |
|||
created() { |
|||
this.form = this.getForm(); |
|||
this.group = this.getForm('uniGroup'); |
|||
this.formRules = []; |
|||
this.formTrigger = this.validateTrigger; |
|||
// 处理 name,是否数组 |
|||
if (this.name && this.name.indexOf('[') !== -1 && this.name.indexOf(']') !== -1) { |
|||
this.isArray = true; |
|||
this.arrayField = this.name |
|||
// fix by mehaotian 修改不修改的情况,动态值不检验的问题 |
|||
this.form.formData[this.name] = this.form._getValue(this.name, '') |
|||
} |
|||
}, |
|||
mounted() { |
|||
if (this.form) { |
|||
this.form.childrens.push(this); |
|||
} |
|||
this.init(); |
|||
}, |
|||
// #ifndef VUE3 |
|||
destroyed() { |
|||
if (this.__isUnmounted) return |
|||
this.unInit() |
|||
}, |
|||
// #endif |
|||
// #ifdef VUE3 |
|||
unmounted() { |
|||
this.__isUnmounted = true |
|||
this.unInit() |
|||
}, |
|||
// #endif |
|||
methods: { |
|||
init() { |
|||
if (this.form) { |
|||
let { |
|||
formRules, |
|||
validator, |
|||
formData, |
|||
value, |
|||
labelPosition, |
|||
labelWidth, |
|||
labelAlign, |
|||
errShowType |
|||
} = this.form; |
|||
this.labelPos = this.labelPosition ? this.labelPosition : labelPosition; |
|||
|
|||
if (this.label) { |
|||
this.labelWid = (this.labelWidth ? this.labelWidth : (labelWidth || 70)) |
|||
} else { |
|||
this.labelWid = (this.labelWidth ? this.labelWidth : (labelWidth || 'auto')) |
|||
} |
|||
if (this.labelWid && this.labelWid !== 'auto') { |
|||
this.labelWid += 'px' |
|||
} |
|||
this.labelAli = this.labelAlign ? this.labelAlign : labelAlign; |
|||
|
|||
// 判断第一个 item |
|||
if (!this.form.isFirstBorder) { |
|||
this.form.isFirstBorder = true; |
|||
this.isFirstBorder = true; |
|||
} |
|||
|
|||
// 判断 group 里的第一个 item |
|||
if (this.group) { |
|||
if (!this.group.isFirstBorder) { |
|||
this.group.isFirstBorder = true; |
|||
this.isFirstBorder = true; |
|||
} |
|||
} |
|||
|
|||
this.border = this.form.border; |
|||
this.showMsg = errShowType; |
|||
let name = this.isArray ? this.arrayField : this.name; |
|||
if (formRules) { |
|||
if (!formRules[name]) { |
|||
formRules[name] = { |
|||
rules: this.rules |
|||
} |
|||
} |
|||
this.formRules = formRules[name]; |
|||
} |
|||
if (this.rules.length > 0) { |
|||
validator.updateSchema(formRules); |
|||
} |
|||
|
|||
this.validator = validator; |
|||
} else { |
|||
this.labelPos = this.labelPosition || 'left'; |
|||
this.labelWid = this.labelWidth || 65; |
|||
this.labelAli = this.labelAlign || 'left'; |
|||
} |
|||
}, |
|||
unInit() { |
|||
if (this.form) { |
|||
this.form.childrens.forEach((item, index) => { |
|||
if (item === this) { |
|||
this.form.childrens.splice(index, 1) |
|||
delete this.form.formData[item.name] |
|||
} |
|||
}) |
|||
} |
|||
}, |
|||
/** |
|||
* 获取父元素实例 |
|||
*/ |
|||
getForm(name = 'uniForms') { |
|||
let parent = this.$parent; |
|||
let parentName = parent.$options.name; |
|||
while (parentName !== name) { |
|||
parent = parent.$parent; |
|||
if (!parent) return false; |
|||
parentName = parent.$options.name; |
|||
} |
|||
return parent; |
|||
}, |
|||
|
|||
/** |
|||
* 移除该表单项的校验结果 |
|||
*/ |
|||
clearValidate() { |
|||
this.errMsg = ''; |
|||
}, |
|||
/** |
|||
* 子组件调用,如 easyinput |
|||
* @param {Object} value |
|||
*/ |
|||
setValue(value) { |
|||
let name = this.isArray ? this.arrayField : this.name; |
|||
if (name) { |
|||
if (this.errMsg) this.errMsg = ''; |
|||
// 给组件赋值 |
|||
this.form.formData[name] = this.form._getValue(name, value); |
|||
if (!this.formRules || (typeof this.formRules && JSON.stringify(this.formRules) === '{}')) return; |
|||
this.triggerCheck(this.form._getValue(this.name, value)); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 校验规则 |
|||
* @param {Object} value |
|||
*/ |
|||
async triggerCheck(value, formTrigger) { |
|||
let promise = null; |
|||
this.errMsg = ''; |
|||
if (!this.validator) return; |
|||
const isNoField = this.isRequired(this.formRules.rules || []); |
|||
let isTrigger = this.isTrigger(this.formRules.validateTrigger, this.validateTrigger, this.form.validateTrigger); |
|||
let result = null; |
|||
if (!!isTrigger || formTrigger) { |
|||
let name = this.isArray ? this.arrayField : this.name; |
|||
result = await this.validator.validateUpdate({ |
|||
[name]: value |
|||
}, |
|||
this.form.formData |
|||
); |
|||
} |
|||
// 判断是否必填,非必填,不填不校验,填写才校验 |
|||
if (!isNoField && (value === undefined || value === '')) { |
|||
result = null; |
|||
} |
|||
const inputComp = this.form.inputChildrens.find(child => child.rename === this.name); |
|||
if ((isTrigger || formTrigger) && result && result.errorMessage) { |
|||
if (inputComp) { |
|||
inputComp.errMsg = result.errorMessage; |
|||
} |
|||
if (this.form.errShowType === 'toast') { |
|||
uni.showToast({ |
|||
title: result.errorMessage || '校验错误', |
|||
icon: 'none' |
|||
}); |
|||
} |
|||
if (this.form.errShowType === 'modal') { |
|||
uni.showModal({ |
|||
title: '提示', |
|||
content: result.errorMessage || '校验错误' |
|||
}); |
|||
} |
|||
} else { |
|||
if (inputComp) { |
|||
inputComp.errMsg = ''; |
|||
} |
|||
} |
|||
|
|||
this.errMsg = !result ? '' : result.errorMessage; |
|||
// 触发validate事件 |
|||
this.form.validateCheck(result ? result : null); |
|||
// typeof callback === 'function' && callback(result ? result : null); |
|||
// if (promise) return promise |
|||
return result ? result : null; |
|||
}, |
|||
/** |
|||
* 触发时机 |
|||
* @param {Object} event |
|||
*/ |
|||
isTrigger(rule, itemRlue, parentRule) { |
|||
let rl = true; |
|||
// bind submit |
|||
if (rule === 'submit' || !rule) { |
|||
if (rule === undefined) { |
|||
if (itemRlue !== 'bind') { |
|||
if (!itemRlue) { |
|||
return parentRule === 'bind' ? true : false; |
|||
} |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
// 是否有必填字段 |
|||
isRequired(rules) { |
|||
let isNoField = false; |
|||
for (let i = 0; i < rules.length; i++) { |
|||
const ruleData = rules[i]; |
|||
if (ruleData.required) { |
|||
isNoField = true; |
|||
break; |
|||
} |
|||
} |
|||
return isNoField; |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-forms-item { |
|||
position: relative; |
|||
padding: 0px; |
|||
text-align: left; |
|||
color: #333; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.uni-forms-item__box { |
|||
position: relative; |
|||
} |
|||
|
|||
.uni-forms-item__inner { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
padding-bottom: 22px; |
|||
} |
|||
|
|||
.is-direction-left { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.is-direction-top { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.uni-forms-item__label { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
flex-shrink: 0; |
|||
box-sizing: border-box; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
width: 65px; |
|||
padding: 5px 0; |
|||
height: 36px; |
|||
} |
|||
|
|||
.uni-forms-item__label .label-text { |
|||
font-size: 14px; |
|||
color: #333; |
|||
} |
|||
|
|||
.uni-forms-item__label .label-seat { |
|||
margin-right: 5px; |
|||
} |
|||
|
|||
.uni-forms-item__content { |
|||
/* #ifndef APP-NVUE */ |
|||
width: 100%; |
|||
box-sizing: border-box; |
|||
min-height: 36px; |
|||
/* #endif */ |
|||
flex: 1; |
|||
} |
|||
|
|||
.label-icon { |
|||
margin-right: 5px; |
|||
margin-top: -1px; |
|||
} |
|||
|
|||
.is-required { |
|||
color: #dd524d; |
|||
} |
|||
|
|||
.uni-error-message { |
|||
position: absolute; |
|||
bottom: 0px; |
|||
left: 0; |
|||
text-align: left; |
|||
} |
|||
|
|||
.uni-error-message-text { |
|||
line-height: 22px; |
|||
color: #dd524d; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.uni-error-msg--boeder { |
|||
position: relative; |
|||
bottom: 0; |
|||
line-height: 22px; |
|||
} |
|||
|
|||
.is-input-error-border { |
|||
border-color: #dd524d; |
|||
} |
|||
|
|||
.uni-forms-item--border { |
|||
margin-bottom: 0; |
|||
padding: 10px 0; |
|||
border-top: 1px #eee solid; |
|||
} |
|||
|
|||
.uni-forms-item--border .uni-forms-item__inner { |
|||
padding: 0; |
|||
} |
|||
|
|||
.is-first-border { |
|||
/* #ifndef APP-NVUE */ |
|||
border: none; |
|||
/* #endif */ |
|||
/* #ifdef APP-NVUE */ |
|||
border-width: 0; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.uni-forms--no-padding { |
|||
padding: 0; |
|||
} |
|||
</style> |
@ -0,0 +1,467 @@ |
|||
<template> |
|||
<view class="uni-forms" :class="{ 'uni-forms--top': !border }"> |
|||
<form @submit.stop="submitForm" @reset="resetForm"> |
|||
<slot></slot> |
|||
</form> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// #ifndef VUE3 |
|||
import Vue from 'vue'; |
|||
Vue.prototype.binddata = function(name, value, formName) { |
|||
if (formName) { |
|||
this.$refs[formName].setValue(name, value); |
|||
} else { |
|||
let formVm; |
|||
for (let i in this.$refs) { |
|||
const vm = this.$refs[i]; |
|||
if (vm && vm.$options && vm.$options.name === 'uniForms') { |
|||
formVm = vm; |
|||
break; |
|||
} |
|||
} |
|||
if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性'); |
|||
formVm.setValue(name, value); |
|||
} |
|||
}; |
|||
// #endif |
|||
|
|||
|
|||
|
|||
import Validator from './validate.js'; |
|||
/** |
|||
* Forms 表单 |
|||
* @description 由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=2773 |
|||
* @property {Object} rules 表单校验规则 |
|||
* @property {String} validateTrigger = [bind|submit] 校验触发器方式 默认 submit |
|||
* @value bind 发生变化时触发 |
|||
* @value submit 提交时触发 |
|||
* @property {String} labelPosition = [top|left] label 位置 默认 left |
|||
* @value top 顶部显示 label |
|||
* @value left 左侧显示 label |
|||
* @property {String} labelWidth label 宽度,默认 65px |
|||
* @property {String} labelAlign = [left|center|right] label 居中方式 默认 left |
|||
* @value left label 左侧显示 |
|||
* @value center label 居中 |
|||
* @value right label 右侧对齐 |
|||
* @property {String} errShowType = [undertext|toast|modal] 校验错误信息提示方式 |
|||
* @value undertext 错误信息在底部显示 |
|||
* @value toast 错误信息toast显示 |
|||
* @value modal 错误信息modal显示 |
|||
* @event {Function} submit 提交时触发 |
|||
*/ |
|||
|
|||
export default { |
|||
name: 'uniForms', |
|||
components: {}, |
|||
model: { |
|||
prop: 'modelValue', |
|||
event: 'update:modelValue' |
|||
}, |
|||
emits: ['update:modelValue', 'input', 'reset', 'validate', 'submit'], |
|||
props: { |
|||
// 即将弃用 |
|||
value: { |
|||
type: Object, |
|||
default () { |
|||
return {}; |
|||
} |
|||
}, |
|||
// 替换 value 属性 |
|||
modelValue: { |
|||
type: Object, |
|||
default () { |
|||
return {}; |
|||
} |
|||
}, |
|||
// 表单校验规则 |
|||
rules: { |
|||
type: Object, |
|||
default () { |
|||
return {}; |
|||
} |
|||
}, |
|||
// 校验触发器方式,默认 关闭 |
|||
validateTrigger: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
// label 位置,可选值 top/left |
|||
labelPosition: { |
|||
type: String, |
|||
default: 'left' |
|||
}, |
|||
// label 宽度,单位 px |
|||
labelWidth: { |
|||
type: [String, Number], |
|||
default: '' |
|||
}, |
|||
// label 居中方式,可选值 left/center/right |
|||
labelAlign: { |
|||
type: String, |
|||
default: 'left' |
|||
}, |
|||
errShowType: { |
|||
type: String, |
|||
default: 'undertext' |
|||
}, |
|||
border: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
formData: {} |
|||
}; |
|||
}, |
|||
computed: { |
|||
dataValue() { |
|||
if (JSON.stringify(this.modelValue) === '{}') { |
|||
return this.value |
|||
} else { |
|||
return this.modelValue |
|||
} |
|||
} |
|||
}, |
|||
watch: { |
|||
rules(newVal) { |
|||
// 如果规则发生变化,要初始化组件 |
|||
this.init(newVal); |
|||
}, |
|||
labelPosition() { |
|||
this.childrens.forEach(vm => { |
|||
vm.init() |
|||
}) |
|||
} |
|||
}, |
|||
created() { |
|||
// #ifdef VUE3 |
|||
let getbinddata = getApp().$vm.$.appContext.config.globalProperties.binddata |
|||
if (!getbinddata) { |
|||
getApp().$vm.$.appContext.config.globalProperties.binddata = function(name, value, formName) { |
|||
if (formName) { |
|||
this.$refs[formName].setValue(name, value); |
|||
} else { |
|||
let formVm; |
|||
for (let i in this.$refs) { |
|||
const vm = this.$refs[i]; |
|||
if (vm && vm.$options && vm.$options.name === 'uniForms') { |
|||
formVm = vm; |
|||
break; |
|||
} |
|||
} |
|||
if (!formVm) return console.error('当前 uni-froms 组件缺少 ref 属性'); |
|||
formVm.setValue(name, value); |
|||
} |
|||
} |
|||
} |
|||
// #endif |
|||
|
|||
// 存放watch 监听数组 |
|||
this.unwatchs = []; |
|||
// 存放子组件数组 |
|||
this.childrens = []; |
|||
// 存放 easyInput 组件 |
|||
this.inputChildrens = []; |
|||
// 存放 dataCheckbox 组件 |
|||
this.checkboxChildrens = []; |
|||
// 存放规则 |
|||
this.formRules = []; |
|||
this.init(this.rules); |
|||
}, |
|||
// mounted() { |
|||
// this.init(this.rules) |
|||
// }, |
|||
methods: { |
|||
init(formRules) { |
|||
// 判断是否有规则 |
|||
if (Object.keys(formRules).length === 0) { |
|||
this.formData = this.dataValue |
|||
return |
|||
}; |
|||
this.formRules = formRules; |
|||
this.validator = new Validator(formRules); |
|||
this.registerWatch(); |
|||
}, |
|||
// 监听 watch |
|||
registerWatch() { |
|||
// 取消监听,避免多次调用 init 重复执行 $watch |
|||
this.unwatchs.forEach(v => v()); |
|||
this.childrens.forEach((v) => { |
|||
v.init() |
|||
}) |
|||
// watch 每个属性 ,需要知道具体那个属性发变化 |
|||
Object.keys(this.dataValue).forEach(key => { |
|||
let watch = this.$watch( |
|||
'dataValue.' + key, |
|||
value => { |
|||
if (!value) return |
|||
// 如果是对象 ,则平铺内容 |
|||
if (value.toString() === '[object Object]') { |
|||
for (let i in value) { |
|||
let name = `${key}[${i}]`; |
|||
this.formData[name] = this._getValue(name, value[i]); |
|||
} |
|||
} else { |
|||
this.formData[key] = this._getValue(key, value); |
|||
} |
|||
}, { |
|||
deep: true, |
|||
immediate: true |
|||
} |
|||
); |
|||
this.unwatchs.push(watch); |
|||
}); |
|||
}, |
|||
/** |
|||
* 公开给用户使用 |
|||
* 设置校验规则 |
|||
* @param {Object} formRules |
|||
*/ |
|||
setRules(formRules) { |
|||
this.init(formRules); |
|||
}, |
|||
/** |
|||
* 公开给用户使用 |
|||
* 设置自定义表单组件 value 值 |
|||
* @param {String} name 字段名称 |
|||
* @param {String} value 字段值 |
|||
*/ |
|||
setValue(name, value, callback) { |
|||
let example = this.childrens.find(child => child.name === name); |
|||
if (!example) return null; |
|||
value = this._getValue(example.name, value); |
|||
this.formData[name] = value; |
|||
example.val = value; |
|||
this.$emit('input', Object.assign({}, this.value, this.formData)); |
|||
this.$emit('update:modelValue', Object.assign({}, this.value, this.formData)); |
|||
return example.triggerCheck(value, callback); |
|||
}, |
|||
|
|||
/** |
|||
* 表单重置 |
|||
* @param {Object} event |
|||
*/ |
|||
resetForm(event) { |
|||
this.childrens.forEach(item => { |
|||
item.errMsg = ''; |
|||
const inputComp = this.inputChildrens.find(child => child.rename === item.name); |
|||
if (inputComp) { |
|||
inputComp.errMsg = ''; |
|||
inputComp.$emit('input', inputComp.multiple ? [] : ''); |
|||
inputComp.$emit('update:modelValue', inputComp.multiple ? [] : ''); |
|||
} |
|||
}); |
|||
|
|||
this.childrens.forEach(item => { |
|||
if (item.name) { |
|||
this.formData[item.name] = this._getValue(item.name, ''); |
|||
} |
|||
}); |
|||
|
|||
this.$emit('input', this.formData); |
|||
this.$emit('update:modelValue', this.formData); |
|||
this.$emit('reset', event); |
|||
}, |
|||
|
|||
/** |
|||
* 触发表单校验,通过 @validate 获取 |
|||
* @param {Object} validate |
|||
*/ |
|||
validateCheck(validate) { |
|||
if (validate === null) validate = null; |
|||
this.$emit('validate', validate); |
|||
}, |
|||
/** |
|||
* 校验所有或者部分表单 |
|||
*/ |
|||
async validateAll(invalidFields, type, keepitem, callback) { |
|||
let childrens = [] |
|||
for (let i in invalidFields) { |
|||
const item = this.childrens.find(v => v.name === i) |
|||
if (item) { |
|||
childrens.push(item) |
|||
} |
|||
} |
|||
|
|||
if (!callback && typeof keepitem === 'function') { |
|||
callback = keepitem; |
|||
} |
|||
|
|||
let promise; |
|||
if (!callback && typeof callback !== 'function' && Promise) { |
|||
promise = new Promise((resolve, reject) => { |
|||
callback = function(valid, invalidFields) { |
|||
!valid ? resolve(invalidFields) : reject(valid); |
|||
}; |
|||
}); |
|||
} |
|||
|
|||
let results = []; |
|||
let newFormData = {}; |
|||
if (this.validator) { |
|||
for (let key in childrens) { |
|||
const child = childrens[key]; |
|||
let name = child.isArray ? child.arrayField : child.name; |
|||
if (child.isArray) { |
|||
if (child.name.indexOf('[') !== -1 && child.name.indexOf(']') !== -1) { |
|||
const fieldData = child.name.split('['); |
|||
const fieldName = fieldData[0]; |
|||
const fieldValue = fieldData[1].replace(']', ''); |
|||
if (!newFormData[fieldName]) { |
|||
newFormData[fieldName] = {}; |
|||
} |
|||
newFormData[fieldName][fieldValue] = this._getValue(name, invalidFields[name]); |
|||
} |
|||
} else { |
|||
newFormData[name] = this._getValue(name, invalidFields[name]); |
|||
} |
|||
const result = await child.triggerCheck(invalidFields[name], true); |
|||
if (result) { |
|||
results.push(result); |
|||
if (this.errShowType === 'toast' || this.errShowType === 'modal') break; |
|||
} |
|||
} |
|||
} else { |
|||
newFormData = invalidFields |
|||
} |
|||
if (Array.isArray(results)) { |
|||
if (results.length === 0) results = null; |
|||
} |
|||
|
|||
if (Array.isArray(keepitem)) { |
|||
keepitem.forEach(v => { |
|||
newFormData[v] = this.dataValue[v]; |
|||
}); |
|||
} |
|||
|
|||
if (type === 'submit') { |
|||
this.$emit('submit', { |
|||
detail: { |
|||
value: newFormData, |
|||
errors: results |
|||
} |
|||
}); |
|||
} else { |
|||
this.$emit('validate', results); |
|||
} |
|||
|
|||
callback && typeof callback === 'function' && callback(results, newFormData); |
|||
|
|||
if (promise && callback) { |
|||
return promise; |
|||
} else { |
|||
return null; |
|||
} |
|||
}, |
|||
submitForm() {}, |
|||
/** |
|||
* 外部调用方法 |
|||
* 手动提交校验表单 |
|||
* 对整个表单进行校验的方法,参数为一个回调函数。 |
|||
*/ |
|||
submit(keepitem, callback, type) { |
|||
for (let i in this.dataValue) { |
|||
const itemData = this.childrens.find(v => v.name === i); |
|||
if (itemData) { |
|||
if (this.formData[i] === undefined) { |
|||
this.formData[i] = this._getValue(i, this.dataValue[i]); |
|||
} |
|||
} |
|||
} |
|||
if (!type) { |
|||
console.warn('submit 方法即将废弃,请使用validate方法代替!'); |
|||
} |
|||
return this.validateAll(this.formData, 'submit', keepitem, callback); |
|||
}, |
|||
|
|||
/** |
|||
* 外部调用方法 |
|||
* 校验表单 |
|||
* 对整个表单进行校验的方法,参数为一个回调函数。 |
|||
*/ |
|||
validate(keepitem, callback) { |
|||
return this.submit(keepitem, callback, true); |
|||
}, |
|||
|
|||
/** |
|||
* 部分表单校验 |
|||
* @param {Object} props |
|||
* @param {Object} cb |
|||
*/ |
|||
validateField(props, callback) { |
|||
props = [].concat(props); |
|||
let invalidFields = {}; |
|||
this.childrens.forEach(item => { |
|||
if (props.indexOf(item.name) !== -1) { |
|||
invalidFields = Object.assign({}, invalidFields, { |
|||
[item.name]: this.formData[item.name] |
|||
}); |
|||
} |
|||
}); |
|||
return this.validateAll(invalidFields, 'submit', [], callback); |
|||
}, |
|||
|
|||
/** |
|||
* 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 |
|||
*/ |
|||
resetFields() { |
|||
this.resetForm(); |
|||
}, |
|||
|
|||
/** |
|||
* 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果 |
|||
*/ |
|||
clearValidate(props) { |
|||
props = [].concat(props); |
|||
this.childrens.forEach(item => { |
|||
const inputComp = this.inputChildrens.find(child => child.rename === item.name); |
|||
if (props.length === 0) { |
|||
item.errMsg = ''; |
|||
if (inputComp) { |
|||
inputComp.errMsg = ''; |
|||
} |
|||
} else { |
|||
if (props.indexOf(item.name) !== -1) { |
|||
item.errMsg = ''; |
|||
if (inputComp) { |
|||
inputComp.errMsg = ''; |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
}, |
|||
/** |
|||
* 把 value 转换成指定的类型 |
|||
* @param {Object} key |
|||
* @param {Object} value |
|||
*/ |
|||
_getValue(key, value) { |
|||
const rules = (this.formRules[key] && this.formRules[key].rules) || []; |
|||
const isRuleNum = rules.find(val => val.format && this.type_filter(val.format)); |
|||
const isRuleBool = rules.find(val => (val.format && val.format === 'boolean') || val.format === 'bool'); |
|||
// 输入值为 number |
|||
if (isRuleNum) { |
|||
value = isNaN(value) ? value : value === '' || value === null ? null : Number(value); |
|||
} |
|||
// 简单判断真假值 |
|||
if (isRuleBool) { |
|||
value = !value ? false : true; |
|||
} |
|||
return value; |
|||
}, |
|||
/** |
|||
* 过滤数字类型 |
|||
* @param {Object} format |
|||
*/ |
|||
type_filter(format) { |
|||
return format === 'int' || format === 'double' || format === 'number' || format === 'timestamp'; |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,89 @@ |
|||
<template> |
|||
<!-- #ifdef APP-NVUE --> |
|||
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" @click="_onClick">{{unicode}}</text> |
|||
<!-- #endif --> |
|||
<!-- #ifndef APP-NVUE --> |
|||
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text> |
|||
<!-- #endif --> |
|||
</template> |
|||
|
|||
<script> |
|||
import icons from './icons.js'; |
|||
// #ifdef APP-NVUE |
|||
var domModule = weex.requireModule('dom'); |
|||
import iconUrl from './uniicons.ttf' |
|||
domModule.addRule('fontFace', { |
|||
'fontFamily': "uniicons", |
|||
'src': "url('"+iconUrl+"')" |
|||
}); |
|||
// #endif |
|||
|
|||
/** |
|||
* Icons 图标 |
|||
* @description 用于展示 icons 图标 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=28 |
|||
* @property {Number} size 图标大小 |
|||
* @property {String} type 图标图案,参考示例 |
|||
* @property {String} color 图标颜色 |
|||
* @property {String} customPrefix 自定义图标 |
|||
* @event {Function} click 点击 Icon 触发事件 |
|||
*/ |
|||
export default { |
|||
name: 'UniIcons', |
|||
emits:['click'], |
|||
props: { |
|||
type: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
color: { |
|||
type: String, |
|||
default: '#333333' |
|||
}, |
|||
size: { |
|||
type: [Number, String], |
|||
default: 16 |
|||
}, |
|||
customPrefix:{ |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
icons: icons.glyphs |
|||
} |
|||
}, |
|||
computed:{ |
|||
unicode(){ |
|||
let code = this.icons.find(v=>v.font_class === this.type) |
|||
if(code){ |
|||
return unescape(`%u${code.unicode}`) |
|||
} |
|||
return '' |
|||
} |
|||
}, |
|||
methods: { |
|||
_onClick() { |
|||
this.$emit('click') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
/* #ifndef APP-NVUE */ |
|||
@import './uniicons.css'; |
|||
@font-face { |
|||
font-family: uniicons; |
|||
src: url('./uniicons.ttf') format('truetype'); |
|||
} |
|||
|
|||
/* #endif */ |
|||
.uni-icons { |
|||
font-family: uniicons; |
|||
text-decoration: none; |
|||
text-align: center; |
|||
} |
|||
|
|||
</style> |
@ -0,0 +1,663 @@ |
|||
.uniui-color:before { |
|||
content: "\e6cf"; |
|||
} |
|||
|
|||
.uniui-wallet:before { |
|||
content: "\e6b1"; |
|||
} |
|||
|
|||
.uniui-settings-filled:before { |
|||
content: "\e6ce"; |
|||
} |
|||
|
|||
.uniui-auth-filled:before { |
|||
content: "\e6cc"; |
|||
} |
|||
|
|||
.uniui-shop-filled:before { |
|||
content: "\e6cd"; |
|||
} |
|||
|
|||
.uniui-staff-filled:before { |
|||
content: "\e6cb"; |
|||
} |
|||
|
|||
.uniui-vip-filled:before { |
|||
content: "\e6c6"; |
|||
} |
|||
|
|||
.uniui-plus-filled:before { |
|||
content: "\e6c7"; |
|||
} |
|||
|
|||
.uniui-folder-add-filled:before { |
|||
content: "\e6c8"; |
|||
} |
|||
|
|||
.uniui-color-filled:before { |
|||
content: "\e6c9"; |
|||
} |
|||
|
|||
.uniui-tune-filled:before { |
|||
content: "\e6ca"; |
|||
} |
|||
|
|||
.uniui-calendar-filled:before { |
|||
content: "\e6c0"; |
|||
} |
|||
|
|||
.uniui-notification-filled:before { |
|||
content: "\e6c1"; |
|||
} |
|||
|
|||
.uniui-wallet-filled:before { |
|||
content: "\e6c2"; |
|||
} |
|||
|
|||
.uniui-medal-filled:before { |
|||
content: "\e6c3"; |
|||
} |
|||
|
|||
.uniui-gift-filled:before { |
|||
content: "\e6c4"; |
|||
} |
|||
|
|||
.uniui-fire-filled:before { |
|||
content: "\e6c5"; |
|||
} |
|||
|
|||
.uniui-refreshempty:before { |
|||
content: "\e6bf"; |
|||
} |
|||
|
|||
.uniui-location-filled:before { |
|||
content: "\e6af"; |
|||
} |
|||
|
|||
.uniui-person-filled:before { |
|||
content: "\e69d"; |
|||
} |
|||
|
|||
.uniui-personadd-filled:before { |
|||
content: "\e698"; |
|||
} |
|||
|
|||
.uniui-back:before { |
|||
content: "\e6b9"; |
|||
} |
|||
|
|||
.uniui-forward:before { |
|||
content: "\e6ba"; |
|||
} |
|||
|
|||
.uniui-arrow-right:before { |
|||
content: "\e6bb"; |
|||
} |
|||
|
|||
.uniui-arrowthinright:before { |
|||
content: "\e6bb"; |
|||
} |
|||
|
|||
.uniui-arrow-left:before { |
|||
content: "\e6bc"; |
|||
} |
|||
|
|||
.uniui-arrowthinleft:before { |
|||
content: "\e6bc"; |
|||
} |
|||
|
|||
.uniui-arrow-up:before { |
|||
content: "\e6bd"; |
|||
} |
|||
|
|||
.uniui-arrowthinup:before { |
|||
content: "\e6bd"; |
|||
} |
|||
|
|||
.uniui-arrow-down:before { |
|||
content: "\e6be"; |
|||
} |
|||
|
|||
.uniui-arrowthindown:before { |
|||
content: "\e6be"; |
|||
} |
|||
|
|||
.uniui-bottom:before { |
|||
content: "\e6b8"; |
|||
} |
|||
|
|||
.uniui-arrowdown:before { |
|||
content: "\e6b8"; |
|||
} |
|||
|
|||
.uniui-right:before { |
|||
content: "\e6b5"; |
|||
} |
|||
|
|||
.uniui-arrowright:before { |
|||
content: "\e6b5"; |
|||
} |
|||
|
|||
.uniui-top:before { |
|||
content: "\e6b6"; |
|||
} |
|||
|
|||
.uniui-arrowup:before { |
|||
content: "\e6b6"; |
|||
} |
|||
|
|||
.uniui-left:before { |
|||
content: "\e6b7"; |
|||
} |
|||
|
|||
.uniui-arrowleft:before { |
|||
content: "\e6b7"; |
|||
} |
|||
|
|||
.uniui-eye:before { |
|||
content: "\e651"; |
|||
} |
|||
|
|||
.uniui-eye-filled:before { |
|||
content: "\e66a"; |
|||
} |
|||
|
|||
.uniui-eye-slash:before { |
|||
content: "\e6b3"; |
|||
} |
|||
|
|||
.uniui-eye-slash-filled:before { |
|||
content: "\e6b4"; |
|||
} |
|||
|
|||
.uniui-info-filled:before { |
|||
content: "\e649"; |
|||
} |
|||
|
|||
.uniui-reload:before { |
|||
content: "\e6b2"; |
|||
} |
|||
|
|||
.uniui-micoff-filled:before { |
|||
content: "\e6b0"; |
|||
} |
|||
|
|||
.uniui-map-pin-ellipse:before { |
|||
content: "\e6ac"; |
|||
} |
|||
|
|||
.uniui-map-pin:before { |
|||
content: "\e6ad"; |
|||
} |
|||
|
|||
.uniui-location:before { |
|||
content: "\e6ae"; |
|||
} |
|||
|
|||
.uniui-starhalf:before { |
|||
content: "\e683"; |
|||
} |
|||
|
|||
.uniui-star:before { |
|||
content: "\e688"; |
|||
} |
|||
|
|||
.uniui-star-filled:before { |
|||
content: "\e68f"; |
|||
} |
|||
|
|||
.uniui-calendar:before { |
|||
content: "\e6a0"; |
|||
} |
|||
|
|||
.uniui-fire:before { |
|||
content: "\e6a1"; |
|||
} |
|||
|
|||
.uniui-medal:before { |
|||
content: "\e6a2"; |
|||
} |
|||
|
|||
.uniui-font:before { |
|||
content: "\e6a3"; |
|||
} |
|||
|
|||
.uniui-gift:before { |
|||
content: "\e6a4"; |
|||
} |
|||
|
|||
.uniui-link:before { |
|||
content: "\e6a5"; |
|||
} |
|||
|
|||
.uniui-notification:before { |
|||
content: "\e6a6"; |
|||
} |
|||
|
|||
.uniui-staff:before { |
|||
content: "\e6a7"; |
|||
} |
|||
|
|||
.uniui-vip:before { |
|||
content: "\e6a8"; |
|||
} |
|||
|
|||
.uniui-folder-add:before { |
|||
content: "\e6a9"; |
|||
} |
|||
|
|||
.uniui-tune:before { |
|||
content: "\e6aa"; |
|||
} |
|||
|
|||
.uniui-auth:before { |
|||
content: "\e6ab"; |
|||
} |
|||
|
|||
.uniui-person:before { |
|||
content: "\e699"; |
|||
} |
|||
|
|||
.uniui-email-filled:before { |
|||
content: "\e69a"; |
|||
} |
|||
|
|||
.uniui-phone-filled:before { |
|||
content: "\e69b"; |
|||
} |
|||
|
|||
.uniui-phone:before { |
|||
content: "\e69c"; |
|||
} |
|||
|
|||
.uniui-email:before { |
|||
content: "\e69e"; |
|||
} |
|||
|
|||
.uniui-personadd:before { |
|||
content: "\e69f"; |
|||
} |
|||
|
|||
.uniui-chatboxes-filled:before { |
|||
content: "\e692"; |
|||
} |
|||
|
|||
.uniui-contact:before { |
|||
content: "\e693"; |
|||
} |
|||
|
|||
.uniui-chatbubble-filled:before { |
|||
content: "\e694"; |
|||
} |
|||
|
|||
.uniui-contact-filled:before { |
|||
content: "\e695"; |
|||
} |
|||
|
|||
.uniui-chatboxes:before { |
|||
content: "\e696"; |
|||
} |
|||
|
|||
.uniui-chatbubble:before { |
|||
content: "\e697"; |
|||
} |
|||
|
|||
.uniui-upload-filled:before { |
|||
content: "\e68e"; |
|||
} |
|||
|
|||
.uniui-upload:before { |
|||
content: "\e690"; |
|||
} |
|||
|
|||
.uniui-weixin:before { |
|||
content: "\e691"; |
|||
} |
|||
|
|||
.uniui-compose:before { |
|||
content: "\e67f"; |
|||
} |
|||
|
|||
.uniui-qq:before { |
|||
content: "\e680"; |
|||
} |
|||
|
|||
.uniui-download-filled:before { |
|||
content: "\e681"; |
|||
} |
|||
|
|||
.uniui-pyq:before { |
|||
content: "\e682"; |
|||
} |
|||
|
|||
.uniui-sound:before { |
|||
content: "\e684"; |
|||
} |
|||
|
|||
.uniui-trash-filled:before { |
|||
content: "\e685"; |
|||
} |
|||
|
|||
.uniui-sound-filled:before { |
|||
content: "\e686"; |
|||
} |
|||
|
|||
.uniui-trash:before { |
|||
content: "\e687"; |
|||
} |
|||
|
|||
.uniui-videocam-filled:before { |
|||
content: "\e689"; |
|||
} |
|||
|
|||
.uniui-spinner-cycle:before { |
|||
content: "\e68a"; |
|||
} |
|||
|
|||
.uniui-weibo:before { |
|||
content: "\e68b"; |
|||
} |
|||
|
|||
.uniui-videocam:before { |
|||
content: "\e68c"; |
|||
} |
|||
|
|||
.uniui-download:before { |
|||
content: "\e68d"; |
|||
} |
|||
|
|||
.uniui-help:before { |
|||
content: "\e679"; |
|||
} |
|||
|
|||
.uniui-navigate-filled:before { |
|||
content: "\e67a"; |
|||
} |
|||
|
|||
.uniui-plusempty:before { |
|||
content: "\e67b"; |
|||
} |
|||
|
|||
.uniui-smallcircle:before { |
|||
content: "\e67c"; |
|||
} |
|||
|
|||
.uniui-minus-filled:before { |
|||
content: "\e67d"; |
|||
} |
|||
|
|||
.uniui-micoff:before { |
|||
content: "\e67e"; |
|||
} |
|||
|
|||
.uniui-closeempty:before { |
|||
content: "\e66c"; |
|||
} |
|||
|
|||
.uniui-clear:before { |
|||
content: "\e66d"; |
|||
} |
|||
|
|||
.uniui-navigate:before { |
|||
content: "\e66e"; |
|||
} |
|||
|
|||
.uniui-minus:before { |
|||
content: "\e66f"; |
|||
} |
|||
|
|||
.uniui-image:before { |
|||
content: "\e670"; |
|||
} |
|||
|
|||
.uniui-mic:before { |
|||
content: "\e671"; |
|||
} |
|||
|
|||
.uniui-paperplane:before { |
|||
content: "\e672"; |
|||
} |
|||
|
|||
.uniui-close:before { |
|||
content: "\e673"; |
|||
} |
|||
|
|||
.uniui-help-filled:before { |
|||
content: "\e674"; |
|||
} |
|||
|
|||
.uniui-paperplane-filled:before { |
|||
content: "\e675"; |
|||
} |
|||
|
|||
.uniui-plus:before { |
|||
content: "\e676"; |
|||
} |
|||
|
|||
.uniui-mic-filled:before { |
|||
content: "\e677"; |
|||
} |
|||
|
|||
.uniui-image-filled:before { |
|||
content: "\e678"; |
|||
} |
|||
|
|||
.uniui-locked-filled:before { |
|||
content: "\e668"; |
|||
} |
|||
|
|||
.uniui-info:before { |
|||
content: "\e669"; |
|||
} |
|||
|
|||
.uniui-locked:before { |
|||
content: "\e66b"; |
|||
} |
|||
|
|||
.uniui-camera-filled:before { |
|||
content: "\e658"; |
|||
} |
|||
|
|||
.uniui-chat-filled:before { |
|||
content: "\e659"; |
|||
} |
|||
|
|||
.uniui-camera:before { |
|||
content: "\e65a"; |
|||
} |
|||
|
|||
.uniui-circle:before { |
|||
content: "\e65b"; |
|||
} |
|||
|
|||
.uniui-checkmarkempty:before { |
|||
content: "\e65c"; |
|||
} |
|||
|
|||
.uniui-chat:before { |
|||
content: "\e65d"; |
|||
} |
|||
|
|||
.uniui-circle-filled:before { |
|||
content: "\e65e"; |
|||
} |
|||
|
|||
.uniui-flag:before { |
|||
content: "\e65f"; |
|||
} |
|||
|
|||
.uniui-flag-filled:before { |
|||
content: "\e660"; |
|||
} |
|||
|
|||
.uniui-gear-filled:before { |
|||
content: "\e661"; |
|||
} |
|||
|
|||
.uniui-home:before { |
|||
content: "\e662"; |
|||
} |
|||
|
|||
.uniui-home-filled:before { |
|||
content: "\e663"; |
|||
} |
|||
|
|||
.uniui-gear:before { |
|||
content: "\e664"; |
|||
} |
|||
|
|||
.uniui-smallcircle-filled:before { |
|||
content: "\e665"; |
|||
} |
|||
|
|||
.uniui-map-filled:before { |
|||
content: "\e666"; |
|||
} |
|||
|
|||
.uniui-map:before { |
|||
content: "\e667"; |
|||
} |
|||
|
|||
.uniui-refresh-filled:before { |
|||
content: "\e656"; |
|||
} |
|||
|
|||
.uniui-refresh:before { |
|||
content: "\e657"; |
|||
} |
|||
|
|||
.uniui-cloud-upload:before { |
|||
content: "\e645"; |
|||
} |
|||
|
|||
.uniui-cloud-download-filled:before { |
|||
content: "\e646"; |
|||
} |
|||
|
|||
.uniui-cloud-download:before { |
|||
content: "\e647"; |
|||
} |
|||
|
|||
.uniui-cloud-upload-filled:before { |
|||
content: "\e648"; |
|||
} |
|||
|
|||
.uniui-redo:before { |
|||
content: "\e64a"; |
|||
} |
|||
|
|||
.uniui-images-filled:before { |
|||
content: "\e64b"; |
|||
} |
|||
|
|||
.uniui-undo-filled:before { |
|||
content: "\e64c"; |
|||
} |
|||
|
|||
.uniui-more:before { |
|||
content: "\e64d"; |
|||
} |
|||
|
|||
.uniui-more-filled:before { |
|||
content: "\e64e"; |
|||
} |
|||
|
|||
.uniui-undo:before { |
|||
content: "\e64f"; |
|||
} |
|||
|
|||
.uniui-images:before { |
|||
content: "\e650"; |
|||
} |
|||
|
|||
.uniui-paperclip:before { |
|||
content: "\e652"; |
|||
} |
|||
|
|||
.uniui-settings:before { |
|||
content: "\e653"; |
|||
} |
|||
|
|||
.uniui-search:before { |
|||
content: "\e654"; |
|||
} |
|||
|
|||
.uniui-redo-filled:before { |
|||
content: "\e655"; |
|||
} |
|||
|
|||
.uniui-list:before { |
|||
content: "\e644"; |
|||
} |
|||
|
|||
.uniui-mail-open-filled:before { |
|||
content: "\e63a"; |
|||
} |
|||
|
|||
.uniui-hand-down-filled:before { |
|||
content: "\e63c"; |
|||
} |
|||
|
|||
.uniui-hand-down:before { |
|||
content: "\e63d"; |
|||
} |
|||
|
|||
.uniui-hand-up-filled:before { |
|||
content: "\e63e"; |
|||
} |
|||
|
|||
.uniui-hand-up:before { |
|||
content: "\e63f"; |
|||
} |
|||
|
|||
.uniui-heart-filled:before { |
|||
content: "\e641"; |
|||
} |
|||
|
|||
.uniui-mail-open:before { |
|||
content: "\e643"; |
|||
} |
|||
|
|||
.uniui-heart:before { |
|||
content: "\e639"; |
|||
} |
|||
|
|||
.uniui-loop:before { |
|||
content: "\e633"; |
|||
} |
|||
|
|||
.uniui-pulldown:before { |
|||
content: "\e632"; |
|||
} |
|||
|
|||
.uniui-scan:before { |
|||
content: "\e62a"; |
|||
} |
|||
|
|||
.uniui-bars:before { |
|||
content: "\e627"; |
|||
} |
|||
|
|||
.uniui-cart-filled:before { |
|||
content: "\e629"; |
|||
} |
|||
|
|||
.uniui-checkbox:before { |
|||
content: "\e62b"; |
|||
} |
|||
|
|||
.uniui-checkbox-filled:before { |
|||
content: "\e62c"; |
|||
} |
|||
|
|||
.uniui-shop:before { |
|||
content: "\e62f"; |
|||
} |
|||
|
|||
.uniui-headphones:before { |
|||
content: "\e630"; |
|||
} |
|||
|
|||
.uniui-cart:before { |
|||
content: "\e631"; |
|||
} |
@ -0,0 +1,107 @@ |
|||
<template> |
|||
<!-- #ifndef APP-NVUE --> |
|||
<view class="uni-list uni-border-top-bottom"> |
|||
<view v-if="border" class="uni-list--border-top"></view> |
|||
<slot /> |
|||
<view v-if="border" class="uni-list--border-bottom"></view> |
|||
</view> |
|||
<!-- #endif --> |
|||
<!-- #ifdef APP-NVUE --> |
|||
<list class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop" loadmoreoffset="15"> |
|||
<slot /> |
|||
</list> |
|||
<!-- #endif --> |
|||
</template> |
|||
|
|||
<script> |
|||
/** |
|||
* List 列表 |
|||
* @description 列表组件 |
|||
* @tutorial https://ext.dcloud.net.cn/plugin?id=24 |
|||
* @property {String} border = [true|false] 标题 |
|||
*/ |
|||
export default { |
|||
name: 'uniList', |
|||
'mp-weixin': { |
|||
options: { |
|||
multipleSlots: false |
|||
} |
|||
}, |
|||
props: { |
|||
enableBackToTop: { |
|||
type: [Boolean, String], |
|||
default: false |
|||
}, |
|||
scrollY: { |
|||
type: [Boolean, String], |
|||
default: false |
|||
}, |
|||
border: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}, |
|||
// provide() { |
|||
// return { |
|||
// list: this |
|||
// }; |
|||
// }, |
|||
created() { |
|||
this.firstChildAppend = false; |
|||
}, |
|||
methods: { |
|||
loadMore(e) { |
|||
this.$emit('scrolltolower'); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
<style scoped> |
|||
.uni-list { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
background-color: #ffffff; |
|||
position: relative; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.uni-list--border { |
|||
position: relative; |
|||
/* #ifdef APP-NVUE */ |
|||
border-top-color: #e5e5e5; |
|||
border-top-style: solid; |
|||
border-top-width: 0.5px; |
|||
border-bottom-color: #e5e5e5; |
|||
border-bottom-style: solid; |
|||
border-bottom-width: 0.5px; |
|||
/* #endif */ |
|||
z-index: -1; |
|||
} |
|||
|
|||
/* #ifndef APP-NVUE */ |
|||
.uni-list--border-top { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
left: 0; |
|||
height: 1px; |
|||
-webkit-transform: scaleY(0.5); |
|||
transform: scaleY(0.5); |
|||
background-color: #e5e5e5; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.uni-list--border-bottom { |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 0; |
|||
left: 0; |
|||
height: 1px; |
|||
-webkit-transform: scaleY(0.5); |
|||
transform: scaleY(0.5); |
|||
background-color: #e5e5e5; |
|||
} |
|||
|
|||
/* #endif */ |
|||
</style> |
@ -0,0 +1,65 @@ |
|||
<template> |
|||
<!-- #ifdef APP-NVUE --> |
|||
<refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown"> |
|||
<slot /> |
|||
</refresh> |
|||
<!-- #endif --> |
|||
<!-- #ifndef APP-NVUE --> |
|||
<view ref="uni-refresh" class="uni-refresh" v-show="isShow"> |
|||
<slot /> |
|||
</view> |
|||
<!-- #endif --> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'UniRefresh', |
|||
props: { |
|||
display: { |
|||
type: [String], |
|||
default: "hide" |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
pulling: false |
|||
} |
|||
}, |
|||
computed: { |
|||
isShow() { |
|||
if (this.display === "show" || this.pulling === true) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
}, |
|||
created() {}, |
|||
methods: { |
|||
onchange(value) { |
|||
this.pulling = value; |
|||
}, |
|||
onrefresh(e) { |
|||
this.$emit("refresh", e); |
|||
}, |
|||
onpullingdown(e) { |
|||
// #ifdef APP-NVUE |
|||
this.$emit("pullingdown", e); |
|||
// #endif |
|||
// #ifndef APP-NVUE |
|||
var detail = { |
|||
viewHeight: 90, |
|||
pullingDistance: e.height |
|||
} |
|||
this.$emit("pullingdown", detail); |
|||
// #endif |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.uni-refresh { |
|||
height: 0; |
|||
overflow: hidden; |
|||
} |
|||
</style> |
File diff suppressed because one or more lines are too long
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue