移动app
This commit is contained in:
11
uni-im示例/.hbuilderx/launch.json
Normal file
11
uni-im示例/.hbuilderx/launch.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||
"version": "0.0",
|
||||
"configurations": [{
|
||||
"type": "uniCloud",
|
||||
"default": {
|
||||
"launchtype": "local"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
42
uni-im示例/App.vue
Normal file
42
uni-im示例/App.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script>
|
||||
//1. 导入uni身份信息管理模块
|
||||
import uniIdPagesInit from '@/uni_modules/uni-id-pages/init.js';
|
||||
//2. 导入uniIm的Utils工具类
|
||||
import uniImUtils from '@/uni_modules/uni-im/common/utils.js';
|
||||
export default {
|
||||
onLaunch: async function() {
|
||||
// console.log('App Launch');
|
||||
//3. 初始化uni身份信息管理模块
|
||||
uniIdPagesInit();
|
||||
//4. 初始化uniIm
|
||||
uniImUtils.init();
|
||||
},
|
||||
onShow: function() {
|
||||
// console.log('App Show');
|
||||
},
|
||||
onHide: function() {
|
||||
// console.log('App Hide');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/*每个页面公共css */
|
||||
|
||||
/* #ifdef H5 */
|
||||
@media screen and (min-width:960px){
|
||||
/* pc宽屏 隐藏会话页面头部 && 全局底部导航 以下兼容了Vue2和3两种模式的样式*/
|
||||
uni-page[data-page="uni_modules/uni-im/pages/index/index"] uni-page-head,
|
||||
.uni_modules-uni-im-pages-index-index uni-page-head,
|
||||
uni-tabbar,
|
||||
.uni-app--showtabbar uni-page-wrapper::after
|
||||
{
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
@import "@/uni_modules/uni-im/static/iconfont.css";
|
||||
/* #endif */
|
||||
</style>
|
||||
707
uni-im示例/README.md
Normal file
707
uni-im示例/README.md
Normal file
@@ -0,0 +1,707 @@
|
||||
> 本文为uni-im v2.x 的文档,如果旧项目需要继续使用老版本的uni-im v1.x,另见:[https://gitcode.net/dcloud/hello-uni-im/-/blob/main/README.md](https://gitcode.net/dcloud/hello-uni-im/-/blob/main/README.md)
|
||||
|
||||
# 简介
|
||||
uni-im是云端一体的、全平台的、免费的、开源即时通讯系统。
|
||||
- 基于uni-app,App、小程序、web全端兼容
|
||||
- 基于uniCloud,前后端都使用js开发
|
||||
- 基于[uni-push2](https://uniapp.dcloud.net.cn/unipush-v2.html),专业稳定的全端推送系统
|
||||
- 基于[uni-id](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html),完善的账户体系
|
||||
- 支持服务端为非uniCloud(比如:应用服务端的开发语言是php、java、go、.net、python、c#等)或 不基于uni-id-pages 开发的项目接入
|
||||
|
||||
案例:
|
||||
|
||||
<img width="600px" src="https://dcloud-chjh-web.oss-cn-hangzhou.aliyuncs.com/ext/uni-im/20230228110007.jpg"></img>
|
||||
|
||||
如图:在插件市场任意插件详情页面,点击咨询作者按钮,即可看到基于uni-im搭建的客服系统。
|
||||
|
||||
下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im)
|
||||
|
||||
## 特点优势
|
||||
- 性价比高;前后端代码均免费开源,相比竞品使用uni-im仅需花费极少的托管在uniCloud(serverless服务器)产生的费用[详情查看](#cost)
|
||||
- 全端可用
|
||||
- App端支持nvue,更好的长列表性能。list组件性能优势[详情参考](https://uniapp.dcloud.net.cn/component/list.html)
|
||||
- 智能本地缓存(app端sqlite,web端indexDB,小程序端storage),更快的历史消息加载速度,更小的网络请求压力
|
||||
- 中心化响应式数据管理,切换会话无需重新加载数据,更流畅的体验
|
||||
- App端聚合多个手机厂商推送通道,app不在线也可以收到消息
|
||||
|
||||
## 版本计划
|
||||
### 已上线
|
||||
- 应用内嵌入uni-im,使用户方便、实时的与App运营者互动,咨询问题、反馈意见、进行投诉。
|
||||
- 可发送文字、图片、音频、视频、代码、任意文件
|
||||
- im交友场景:群聊、好友关系
|
||||
- 会话细节:消息删除、撤回、消息回复
|
||||
|
||||
### 后续计划
|
||||
1. 通信方式扩展:音频通话、视频通话
|
||||
2. 细节完善:聊天记录识别电话邮件、消息转发和批转、勿扰设置、会话置顶、留言转文字、图片提取文字
|
||||
3. 客服场景:管理端支持座席(暂时可先用通过:给每个用户创建一个群,隐藏群信息查看入口,成员进出群实现转坐席)
|
||||
|
||||
优先开发哪些,取决于开发者的反馈。同时也欢迎开发者共建这个开源项目。
|
||||
|
||||
> uni-im相关功能建议或问题,可以加入由uni-im(本插件)搭建的交流群,[点此加入](https://im.dcloud.net.cn/#/?joinUniImGroup=1),备用QQ群(当系统处于维护中使用)群号:[854520009](https://qm.qq.com/cgi-bin/qm/qr?k=DJNSajXAYHnYcr9pouOfxF9Rwwl1AJHc&jump_from=webapi&authKey=HZ1fG58Eudp3o0GCoyx1/UPMY9Fv1sGT5jdqYqPJlTGT0XVUip3Bk8E+UyToQOMo)
|
||||
|
||||
## 使用uniCloud产生的费用说明@cost
|
||||
|
||||
uni-im本身并不收费,实际使用中需要依赖uniCloud云服务,会产生费用;而uniCloud的价格很实惠:
|
||||
- 调用10000次云函数仅需0.0133元
|
||||
- 调用10000次数据库查询仅需0.015元
|
||||
> 更多计费参考:[阿里云版uniCloud按量计费文档](https://uniapp.dcloud.net.cn/uniCloud/price.html#aliyun-postpay)
|
||||
|
||||
### 举例说明:
|
||||
|
||||
- 单聊场景,向用户发送一条消息的过程:
|
||||
1. 调用uni-im-co云对象的sendMsg方法(产生1次云函数请求)
|
||||
2. 查询当前对话的会话记录(产生1次云数据库读操作)
|
||||
3. 根据步骤2的查询结果,如果已经有会话记录,就更新会话,否则就创建一条会话记录(产生1次云数据库写操作)
|
||||
4. 查询发送消息的用户信息,用于接收消息时在通知栏显示发送者昵称和头像(产生1次云数据库读操作)
|
||||
5. 记录发送的消息内容到数据库,用于保存消息历史记录(产生1次云数据库写操作)
|
||||
6. 以`user_id`为标识通过`uni-push2`向用户发送消息会产生0.00000283元uniCloud使用费用[详情查看](https://uniapp.dcloud.net.cn/unipush-v2.html#cost)
|
||||
|
||||
合计:1次云函数请求、2次数据库读操作、2次数据库写操作、1次uni-push2推送操作,即 (1 * 0.0133 + 2 * 0.015 + 2 * 0.05 + 1 * 0.0283)/10000 ≈ 0.000017元
|
||||
|
||||
- 群聊场景,向用户发送一条消息的过程:
|
||||
1. 调用uni-im-co云对象的sendMsg方法(产生1次云函数请求)
|
||||
2. 查询当前用户是否为群成员,防止非群成员发送消息(产生1次云数据库读操作)
|
||||
3. 查询当前对话的会话记录(产生1次云数据库读操作)
|
||||
4. 根据步骤3的查询结果,如果已经有会话记录,就更新会话,否则就创建一条会话记录(产生1次云数据库写操作)
|
||||
5. 查询发送消息的用户信息,用于接收消息时在通知栏显示发送者昵称和头像(产生1次云数据库读操作)
|
||||
6. 记录发送的消息内容到数据库,用于保存消息历史记录(产生1次云数据库写操作)
|
||||
7. 以群id为参数,调用uni-im-co云对象的sendMsgToGroup方法,这是一个递归方法每次向500名群成员推送消息(如果群成员数量为0-500只需执行1次,500-1000需执行2次,以此类推),(会产生最少1次数据库读操作,和1次以`user_id`为标识通过`uni-push2`向用户发送消息会产生0.00000283元uniCloud使用费用[详情查看](https://uniapp.dcloud.net.cn/unipush-v2.html#cost))
|
||||
|
||||
合计:向500人群发送消息,会产生:1次云函数请求、4次数据库读操作、2次数据库写操作、1次uni-push2推送操作,即 (1 * 0.0133 + 4 * 0.015 + 2 * 0.05 + 1 * 0.0283)/10000 ≈ 0.000020元
|
||||
|
||||
相比市面上同类型产品,使用uni-im仅需花费如此便宜的uniCloud(serverless服务器)费用;在价格这块uni-im性价比极高。
|
||||
|
||||
# 快速部署体验
|
||||
## 前提条件
|
||||
1. 开通uniCloud并创建服务空间 [控制面板](https://unicloud.dcloud.net.cn/)
|
||||
传统的IM产品服务端代码托管在服务商名下的服务器内,你只拥有代码和产生的数据的使用权,并非所有权;而uni-im的前后端代码都是开源的,是将代码托管在你名下的unicloud([serverless](https://uniapp.dcloud.net.cn/uniCloud/#%E4%BB%80%E4%B9%88%E6%98%AFserverless)服务器)内。
|
||||
2. 开通`uni-push2.0`(注意:**无论是APP、小程序、web端都需要开通,否则消息将无法实时更新**)[点此前往开通](https://uniapp.dcloud.net.cn/unipush-v2.html#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E5%BC%80%E9%80%9A)
|
||||
|
||||
## 体验步骤
|
||||
|
||||
1. 打开`uni-im`插件下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im)
|
||||
2. 点击`使用HBuilderX导入示例项目`
|
||||
3. 对项目根目录uniCloud点右键选择“云服务空间初始化向导”界面按提示部署项目(注意:选择绑定的服务空间,须在uni-push2.0的[web控制台](https://dev.dcloud.net.cn/pages/app/push2/info)关联)
|
||||
4. 在HBuilderX控制台,更改`连接本地云函数`为`连接云端云函数`
|
||||
<img width="600px" src="https://dcloud-chjh-web.oss-cn-hangzhou.aliyuncs.com/ext/uni-im/20230317211717.jpg"></img>
|
||||
5. `运行项目`到2个不同的浏览器,因为在同一个浏览器打开相同网络地址(ip或者域名)的uni-im项目,socket会相互占线。
|
||||
所以需要使用两个浏览器(或者使用浏览器`打开新的无痕式窗口`功能充当第二个浏览器)分别`注册账号并登录`,
|
||||
到此部署已经结束
|
||||
6. 向对应的用户发起会话,通过访问路径:`/uni_modules/uni-im/pages/chat/chat?user_id=` + `对应的用户id` 即可
|
||||
|
||||
## 部署到自己的项目
|
||||
1. 打开`uni-im`插件下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im)
|
||||
2. 点击`使用HBuilderX导入插件`,选择你的项目,点击确定(同时会自动导入依赖的uni_modules`uni-id-pages`)按提示操作自动配置`pages.json`
|
||||
3. 打开项目根目录的App.vue文件,初始化uni-id-pages和uniIm模块
|
||||
示例如下:
|
||||
|
||||
```html
|
||||
<script>
|
||||
//1. 导入统一身份信息管理模块
|
||||
import uniIdPagesInit from '@/uni_modules/uni-id-pages/init.js';
|
||||
//2. 导入uniIm的Utils工具类
|
||||
import uniImUtils from '@/uni_modules/uni-im/common/utils.js';
|
||||
export default {
|
||||
onLaunch: async function() {
|
||||
console.log('App Launch');
|
||||
//3. 初始化uni身份信息管理模块
|
||||
uniIdPagesInit();
|
||||
//4. 初始化uniIm
|
||||
uniImUtils.init();
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show');
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
4. 部署到uniCloud
|
||||
对项目根目录uniCloud点右键,选择“云服务空间初始化向导” 按提示部署项目(注意:选择绑定的服务空间,须在uni-push2.0的[web控制台](https://dev.dcloud.net.cn/pages/app/push2/info)关联)
|
||||
|
||||
5. 登录uni-im
|
||||
|
||||
uni-im的服务端代码托管在uniCloud下,账户体系是[uni-id 4.0+](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html)的;
|
||||
uni-app生态下绝大部分项目的架构与uni-im相同,所以不需要考虑账号打通问题,用户登录项目后,不需要额外登录uni-im。
|
||||
|
||||
而有些传统项目,服务端的开发语言是php、java、go、.net、python、c#等,是自己设计的账号体系;用户登录所获得的token,与uni-im所需的token不是同一个账号体系;需要在传统服务器端,通过[uni-id的外部系统联登](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#external)同步你项目的账号数据到uni-im用户体系并获得uni-id的token,客户端再调用uniImUtils的login方法登录uni-im;示例代码如下:
|
||||
|
||||
```js
|
||||
import uniImUtils from '@/uni_modules/uni-im/common/utils.js';
|
||||
|
||||
uni.request({
|
||||
url: 'https://www.example.com/login', //仅为示例,并非真实接口地址。
|
||||
data: {
|
||||
username: 'test',
|
||||
password: '123456'
|
||||
},
|
||||
success:async (res) => {
|
||||
console.log(res.data);
|
||||
// 得到你自己项目的token和uni-id的token
|
||||
let {token,uniIdToken} = res.data
|
||||
uni.setStorageSync('token',token)
|
||||
// 【请注意】这里的`uniIdToken` 是一个`对象`:包含:`token`和`tokenExpired`
|
||||
await uniImUtils.login(uniIdToken)
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
其他情况:
|
||||
|
||||
- 客户端如果不是uni-app的,如果是网页,可iframe内嵌。如果是原生app,可嵌入[uni小程序sdk](https://nativesupport.dcloud.net.cn/README)
|
||||
|
||||
- 不基于`uni-id-pages`的客户端代码,仅基于`uni-id-co`的项目,需要在登录成功和用户信息更新时,同步更新uniId store内的当前用户信息(uni-im显示当前用户头像、昵称时会用到)示例代码:
|
||||
|
||||
```js
|
||||
//导入uniCloud客户端账户体系,用户信息状态管理模块
|
||||
import {mutations as uniIdMutations} from '@/uni_modules/uni-id-pages/common/store.js';
|
||||
await uniIdMutations.updateUserInfo()
|
||||
```
|
||||
- 基于老版uni-id(版本号:3.x) 开发的项目,需要如下改造:
|
||||
1. 在登录成功和token续期后,绑定当前账号与设备推送标识的关联关系。示例代码:
|
||||
|
||||
```js
|
||||
const uniIdCo = uniCloud.importObject("uni-id-co", {customUI: true})
|
||||
uni.getPushClientId({
|
||||
success: async function(e) {
|
||||
console.log(e)
|
||||
let pushClientId = e.cid
|
||||
let res = await uniIdCo.setPushCid({
|
||||
pushClientId
|
||||
})
|
||||
console.log('getPushClientId', res);
|
||||
},
|
||||
fail(e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
```
|
||||
2. 在登录成功和用户信息更新时,同步更新uniId store内的当前用户信息(uni-im显示当前用户头像、昵称时会用到)示例代码:
|
||||
```js
|
||||
//导入uniCloud客户端账户体系,用户信息状态管理模块
|
||||
import {mutations as uniIdMutations} from '@/uni_modules/uni-id-pages/common/store.js';
|
||||
await uniIdMutations.updateUserInfo()
|
||||
```
|
||||
|
||||
6. 确保账户对接成功后,打开“用户列表页”,路径:`/uni_modules/uni-im/pages/userList/userList`可以看到所有的注册用户
|
||||
7. 点击某个用户,会自动创建与该用户的会话,并打开“聊天对话页”(路径:`/uni_modules/uni-im/pages/chat/chat`),然后就可以开始聊天了。
|
||||
8. 还可以导入uni-im的示例项目作为管理员端与用户聊天。
|
||||
9. 如果你是2个不同appId的应用相互通讯(比如:淘宝的买家端和卖家端通讯)的场景,请打开聊天对话文件(路径:`/uni_modules/uni-im/pages/chat/chat`)搜索`data.appId = this.systemInfo.appId`修改`this.systemInfo.appId`为相对的appId
|
||||
|
||||
不基于uni-id-pages开发的项目还要注意以下两个问题:
|
||||
1. 退出登录;需要在执行退出登录/切换账号时,调用uni-id的退出登录接口。否则会出现退出登录后的设备仍然能收到im消息,或导致此设备再登录其他账号不能正常收到消息的问题;示例代码如下:
|
||||
```js
|
||||
import {mutations as uniIdMutations} from '@/uni_modules/uni-id-pages/common/store.js'
|
||||
uniIdMutations.logout()
|
||||
```
|
||||
2. token有效期问题,保证你的项目token有效期和uni-id的token有效期保持一致。这涉及两个操作:
|
||||
- 配置uni-id的token过期时间与你的项目token有效期一致。配置路径:`/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json`,关于配置说明[详情查看](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#config)
|
||||
- 如果你的项目有token续期逻辑,需要在续期后调用uni-id的token续期接口,示例代码:
|
||||
```js
|
||||
const uniIdCo = uniCloud.importObject("uni-id-co", {customUI: true})
|
||||
await uniIdCo.refreshToken()
|
||||
```
|
||||
|
||||
常见问题:
|
||||
1. 为什么不能实时接收到推送的消息,需要刷新或者关闭重新打开才能收到?
|
||||
答: uni-im通过`uni-push2`实现消息实时送达,请检查是否已正确配合并开通,且在配置正常后重新登录
|
||||
|
||||
2. 怎么样快速上手
|
||||
答:先下载示例项目,部署并正确配置push后,体验没问题了再部署到自己的项目。
|
||||
|
||||
|
||||
## 限制普通用户向其他用户发起会话
|
||||
客服场景下,我们希望管理员客服可以向任意用户发起会话。而普通用户的会话对象只能是客服。
|
||||
- 客户端限制
|
||||
删除或隐藏“用户列表页”和“会话列表页”,仅保留“聊天对话页”。并绘制按钮,如:“联系客服”,点击后打开“聊天对话页”
|
||||
逻辑代码如下:
|
||||
```js
|
||||
uni.navigateTo({
|
||||
url:'/uni_modules/uni-im/pages/chat/chat?user_id=' + 对应的用户id
|
||||
})
|
||||
```
|
||||
|
||||
- 服务端限制
|
||||
|
||||
1. 添加`uni-im`配置文件,打开:`/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/`;新建`uni-im`文件夹和`config.json`文件,示例如下:
|
||||
```json
|
||||
{
|
||||
"customer_service_uids":["user-id-01","user-id-02"]
|
||||
}
|
||||
```
|
||||
|
||||
2. 配置`customer_service_uids`的值为管理员客服的user_id(支持多个以数组的形式指定),如果会话双方均不属于此域则无法通讯。不配置或为false则表示不限制。
|
||||
|
||||
# 开发文档
|
||||
## 目录结构
|
||||
<pre v-pre="" data-lang="">
|
||||
<code class="lang-" style="padding:0">
|
||||
├─uni_modules
|
||||
│ ├─其他module
|
||||
│ └─uni-im
|
||||
│ ├─uniCloud
|
||||
│ │ ├─cloudfunctions 云函数目录
|
||||
│ │ │ └─uni-im-co 集成调用uni-im方法的云对象
|
||||
│ │ └─database
|
||||
│ │ ├─uni-id-users.schema.ext.js 用户表触发器
|
||||
│ │ ├─uni-im-conversation.schema.ext.js 聊天会话表触发器
|
||||
│ │ ├─uni-im-conversation.schema.json 聊天会话表的表结构
|
||||
│ │ ├─uni-im-friend-invite.schema.ext.js 邀请加为好友表触发器
|
||||
│ │ ├─uni-im-friend-invite.schema.json 邀请加为好友表表结构
|
||||
│ │ ├─uni-im-friend.schema.ext.js 好友关系表触发器
|
||||
│ │ ├─uni-im-friend.schema.json 好友关系表表结构
|
||||
│ │ ├─uni-im-group-join.schema.ext.js 申请加入群聊表触发器
|
||||
│ │ ├─uni-im-group-join.schema.json 申请加入群聊表表结构
|
||||
│ │ ├─uni-im-group-member.schema.ext.js 群成员表触发器
|
||||
│ │ ├─uni-im-group-member.schema.json 群成员表表结构
|
||||
│ │ ├─uni-im-group.schema.ext.js 群信息表触发器
|
||||
│ │ ├─uni-im-group.schema.json 群信息表表结构
|
||||
│ │ ├─uni-im-msg.schema.ext.js 聊天消息表触发器
|
||||
│ │ ├─uni-im-msg.schema.json 聊天消息表表结构
|
||||
│ │ └─uni-im-notification.schema.json 推送消息记录表(仅记录系统消息)
|
||||
│ ├─common
|
||||
│ │ ├─appEvent.js 生命周期事件api库
|
||||
│ │ ├─emojiCodes.js emoji表情列表
|
||||
│ │ ├─initIndexDB.js indexDB本地数据库初始化文件(仅Web端使用)
|
||||
│ │ ├─md5.js md5哈希加密算法(用于本地直接生成会话id)
|
||||
│ │ ├─toFriendlyTime.js 时间戳转友好时间提示字符库文件(如:x年x月x日,昨天,下午,周二,1小时前等)
|
||||
│ │ ├─sqlite.js sqlite本地数据库初始化文件(仅App端使用)
|
||||
│ │ └─utils.js 工具类库
|
||||
│ ├─components
|
||||
│ │ └─uni-im-msg 显示聊天消息气泡组件
|
||||
│ ├─ lib
|
||||
│ │ ├─createObservable.js 创建响应式对象文件
|
||||
│ │ ├─main.js 核心库入口文件
|
||||
│ │ └─msgManager.js 消息管理类库
|
||||
│ ├─pages
|
||||
│ │ ├─chat
|
||||
│ │ │ ├─info.nvue 对话详情(显示好友信息,可在此页面操作删除好友。后续支持:备注好友、打标签、拉黑、屏蔽等功能)
|
||||
│ │ │ └─chat.nvue 聊天对话页
|
||||
│ │ ├─common 公共页面
|
||||
│ │ │ ├─uni-im-code-pages 代码类型消息浏览专用页面
|
||||
│ │ │ └─video 视频播放专用页面
|
||||
│ │ ├─contacts
|
||||
│ │ │ ├─addPeopleGroups 查找并添加用户或群
|
||||
│ │ │ ├─createGroup 创建群聊
|
||||
│ │ │ ├─groupList 我的群列表
|
||||
│ │ │ ├─notification im系统通知页面
|
||||
│ │ │ └─contacts.nvue 联系人页面
|
||||
│ │ ├─group
|
||||
│ │ │ ├─groupQRCode 群二维码页面(未完成)
|
||||
│ │ │ └─info 群信息页面(管理群)
|
||||
│ │ ├─index 首页(展示会话列表)
|
||||
│ │ └─userList 所有用户列表页
|
||||
│ ├─static 静态资源目录
|
||||
│ ├─changelog.md 更新日志
|
||||
│ ├─package.json 包管理文件
|
||||
│ └─readme.md 插件自述文件
|
||||
</code>
|
||||
</pre>
|
||||
名词解释
|
||||
- 聊天会话ID
|
||||
根据通讯双方用户id,或群聊id,生成的唯一索引值;用于更加方便查找聊天记录等。
|
||||
- 聊天会话
|
||||
以会话ID为索引的一组数据,记录:未读消息数量、会话更新时间、会话类型、会话所属用户的id、对话的用户id、对话的群id、群信息、最后一条消息概述(文本消息的前15个字,消息为多媒体时只描述类型)
|
||||
|
||||
## uni-im-co 云函数(云对象)
|
||||
API列表
|
||||
|
||||
|API |描述 |
|
||||
|-- |-- |
|
||||
|getConversationList |获取会话列表[见下方](#coGetConversationList) |
|
||||
|sendMsg |发送聊天消息[见下方](#coSendMsg) |
|
||||
|sendPushMsg |触发器专用消息推送方法 |
|
||||
|sendMsgToGroup |向群用户递归推送消息[见下方](#coSendMsgToGroup) |
|
||||
|addFriendInvite |向用户发起加好友邀请[见下方](#coAddFriendInvite) |
|
||||
|chooseUserIntoGroup |选择用户加入群聊(不传群id时为创建群)[见下方](#coSendMsgToGroup) |
|
||||
|revokeMsg |撤回已经发送的消息[见下方](#coRevokeMsg) |
|
||||
|
||||
|
||||
|
||||
### 获取会话列表 getConversationList@coGetConversationList
|
||||
**参数说明**
|
||||
|
||||
|参数名 |类型 |必填 |说明 |
|
||||
|-- |-- |-- |-- |
|
||||
|limit |number |否 |数量,默认值:500 |
|
||||
|maxUpdateTime |number |否 |最大更新时间(实现高性能分页) |
|
||||
|page |number |是 |页码 |
|
||||
|
||||
**返回值**
|
||||
|
||||
|参数名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|errCode|string|number |错误码,0表示成功 |
|
||||
|errMsg |string |错误信息 |
|
||||
|data |array |会话数据 |
|
||||
|
||||
### 发送聊天消息 sendMsg@coSendMsg
|
||||
|
||||
|参数名 |类型 |必填 |说明 |
|
||||
|-- |-- |-- |-- |
|
||||
|appId |string |是 |接收消息的appId;如果你是2个不同appId的应用相互发,请修改此值为相对的appId |
|
||||
|to_uid |string |否 |接收消息的用户id |
|
||||
|group_id |string |否 |接收消息的群id|
|
||||
|body |string |是 |消息内容,`type = text`时为文本内容.`type = image`时为图片网络地址|
|
||||
|type |string |是 |消息类型,暂时仅支持:text(表示文本类型)、image(表示图片类型)|
|
||||
|isRetries |Boolean|否 |是否为重发|
|
||||
|
||||
**返回值**
|
||||
|
||||
|参数名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|errCode |string|number |错误码,0表示成功 |
|
||||
|errMsg |string |错误信息 |
|
||||
|data |object | |
|
||||
| |- create_time |无 |创建时间 |
|
||||
|
||||
**接口形式**
|
||||
|
||||
```js
|
||||
const uniImCo = uniCloud.importObject('uni-im-co', {
|
||||
customUI: true
|
||||
});
|
||||
await uniImCo.sendMsg({
|
||||
to_uid:"630cacf46293d20001f3c368",
|
||||
type:"text",
|
||||
body:"您好!"
|
||||
})
|
||||
```
|
||||
|
||||
### 向群用户递归推送消息 sendMsgToGroup@coSendMsgToGroup
|
||||
注意:这是一个递归云对象,500个设备为一组批量向用户推送消息(该方法仅支持云对象的方法,或者触发器调用)
|
||||
|
||||
|参数名 |类型 |必填 |说明 |
|
||||
|-- |-- |-- |-- |
|
||||
|appId |string |是 |接收消息的应用appId|
|
||||
|pushParam |object |是 |参数同uni-push2.0的sendMessage方法,详情参考[https://uniapp.dcloud.net.cn/uniCloud/uni-cloud-push/api.html#sendmessage](https://uniapp.dcloud.net.cn/uniCloud/uni-cloud-push/api.html#sendmessage)|
|
||||
|before_id |string |否 |从哪个用户id开始(用于实现高性能分页)|
|
||||
|push_clientids |array |否 |个推设备id列表|
|
||||
|
||||
**返回值**
|
||||
|
||||
|参数名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|errCode |string|number |错误码,0表示成功 |
|
||||
|errMsg |string |错误信息 |
|
||||
|
||||
### 撤回已发送的消息 revokeMsg@coRevokeMsg
|
||||
|参数名 |类型 |必填 |说明 |
|
||||
|-- |-- |-- |-- |
|
||||
|msgId |string |是 |消息id |
|
||||
**返回值**
|
||||
|
||||
|参数名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|errCode |string|number |错误码,0表示成功 |
|
||||
|errMsg |string |错误信息 |
|
||||
|
||||
|
||||
### 向用户发起加好友邀请 addFriendInvite@coAddFriendInvite
|
||||
|
||||
|参数名 |类型 |必填 |说明 |
|
||||
|-- |-- |-- |-- |
|
||||
|to_uid |string |是 |被邀请的用户id|
|
||||
|message |string |否 |请求信息|
|
||||
|
||||
**返回值**
|
||||
|
||||
|参数名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|errCode |string|number |错误码,0表示成功 |
|
||||
|errMsg |string |错误信息 |
|
||||
|
||||
### 选择用户加入群聊 chooseUserIntoGroup@coSendMsgToGroup
|
||||
|
||||
|参数名 |类型 |必填 |说明 |
|
||||
|-- |-- |-- |-- |
|
||||
|group_id |string |否 |群id(为空则创建群) |
|
||||
|user_ids |string |是 |用户id数组 |
|
||||
|
||||
**返回值**
|
||||
|
||||
|参数名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|errCode |string|number |错误码,0表示成功 |
|
||||
|errMsg |string |错误信息 |
|
||||
|data |object |返回信息 |
|
||||
| |- group_id |string |群id |
|
||||
|
||||
|
||||
## 服务端配置@uni-im-cloud-config
|
||||
路径:`/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/uni-im/config.json`
|
||||
|
||||
|字段名 |数据类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|customer_service_uids |string/boolean |客服用户id,不限制则填`false`即可;仅conversation_grade的值为100时有效 |
|
||||
|conversation_grade |int |控制发起会话的条件,详情[会话控制](#conversation_grade) |
|
||||
|
||||
### 会话控制@conversation_grade
|
||||
|
||||
|值 |说明 |
|
||||
|-- |-- |
|
||||
|0 |不限制 |
|
||||
|100|仅限当前用户向:客服、好友、群成员发起会话 |
|
||||
|200|仅限当前用户向:好友或群成员发起会话 |
|
||||
|
||||
|
||||
## 客户端sdk@clientSkd
|
||||
|
||||
入口文件路径:`@/uni_modules/uni-im/lib/main.js`
|
||||
|
||||
uni-im2.0 废弃了1.0通过Vuex的状态管理方式,不再需要关心vuex的用法,直接当做一个全局的响应式js变量即可。
|
||||
|
||||
### state
|
||||
|
||||
|名称 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|conversation |object |会话对象 |
|
||||
| |- dataList|array |会话数据列表 |
|
||||
| |- hasMore |boolean |是否还有更多会话数据 |
|
||||
|currentConversationId |string |正在对话的会话id |
|
||||
|heartbeat |timestamp |心跳(精确到秒)详情:[心跳概念说明](#heartbeatExplain) |
|
||||
|friend |object |好友对象 |
|
||||
| |- dataList|array |好友数据列表 |
|
||||
| |- hasMore |boolean |是否还有更多好友数据 |
|
||||
|group |object |聊天群对象 |
|
||||
| |- dataList|array |聊天群数据列表 |
|
||||
| |- hasMore |boolean |是否还有更多群聊数据 |
|
||||
|notification |object |系统通知对象 |
|
||||
| |- dataList|array |系统通知数据列表 |
|
||||
| |- hasMore |boolean |是否还有更多系统通知数据 |
|
||||
|usersInfo |object |存储所有出现过的用户信息,包括群好友信息 |
|
||||
|isWidescreen |boolean |是否为pc宽屏 |
|
||||
|systemInfo |object |系统信息详情参考:[https://uniapp.dcloud.net.cn/api/system/info.html#系统信息的概念](https://uniapp.dcloud.net.cn/api/system/info.html#%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E7%9A%84%E6%A6%82%E5%BF%B5) |
|
||||
|indexDB |object/boolean |indexDB对象(仅web端有效) |
|
||||
|audioContext |object/boolean |audio对象 |
|
||||
|dataBaseIsOpen |boolean |判断本地sqlite数据库是否已经打开(仅app端有用) |
|
||||
|socketOpenIndex |number |记录socket打开次数(用于处理:从云端同步,socket意外断开期间丢失的数据使用) |
|
||||
|
||||
心跳概念说明 heartbeat @heartbeatExplain
|
||||
uni-im的会话列表和消息列表,需要显示实时的发生时间。而一个应用开启太多的定时器,会消耗大量的系统性能。
|
||||
所以uni-im提供了一个每秒钟更新一次的响应式数据`heartbeat`,由uniImInit方法:启用一个定时器刷新,挂载在全局,所有应用场景引用这一个变量即可
|
||||
|
||||
#### methods
|
||||
|
||||
|名称 |说明 |
|
||||
|-- |-- |
|
||||
|conversation |会话对象 |
|
||||
| |- get |获取会话数据 |
|
||||
| |- loadMore |加载更多会话数据 |
|
||||
| |- unreadCount |统计所有消息的未读数 |
|
||||
| |- remove |删除会话 |
|
||||
|notification |系统消息 |
|
||||
| |- get |获取系统消息 |
|
||||
| |- loadMore |加载更多系统消息 |
|
||||
| |- unreadCount |统计未读数 |
|
||||
|friend |好友列表 |
|
||||
| |- get |获取好友数据 |
|
||||
| |- loadMore |加载更多系统消息 |
|
||||
|group |群列表 |
|
||||
| |- get |获取群聊数据 |
|
||||
| |- loadMore |加载更多群聊数据 |
|
||||
|mergeUsersInfo |添加用户信息到本地用户信息库 |
|
||||
|clearUnreadCount |设置某个会话的未读消息数为已读 |
|
||||
|
||||
|
||||
使用示例:
|
||||
```js
|
||||
//引入uniImMethods
|
||||
import uniIm from '@/uni_modules/uni-im/lib/main.js';
|
||||
```
|
||||
|
||||
- 获取会话数据
|
||||
|
||||
1. 获取全部会话数据
|
||||
```js
|
||||
let param = null
|
||||
let conversationList = await uniIm.conversation.get(param)
|
||||
```
|
||||
2. 获取指定会话的id会话数据
|
||||
```js
|
||||
//xxx表示会话id
|
||||
let param = "xxx"
|
||||
let conversationList = await uniIm.conversation.get(param)
|
||||
```
|
||||
3. 获取指定好友id的会话数据(如果本地不存在则从云端拉取,仍然不存在则本地自动创建)
|
||||
```js
|
||||
//xxx表示好友id
|
||||
let param = {"friend_uid":"xxx"},
|
||||
let conversationList = await uniIm.conversation.get(param)
|
||||
```
|
||||
4. 获取指定群聊id的会话数据(如果本地不存在则从云端拉取,仍然不存在则本地自动创建)
|
||||
```js
|
||||
//xxx表示群聊id
|
||||
let param = {"group_id":"xxx"}
|
||||
let conversationList = await uniIm.conversation.get(param)
|
||||
```
|
||||
|
||||
- 加载会话数据
|
||||
|
||||
1. 加载更多会话数据(分页加载,新数据的会话更新时间,小于列表中最小的会话更新时间)
|
||||
```js
|
||||
let param = null
|
||||
let conversationList = await uniIm.conversation.loadMore(param)
|
||||
```
|
||||
|
||||
2. 加载指定会话id的会话数据
|
||||
```js
|
||||
// xxx表示会话id
|
||||
let param = 'xxx'
|
||||
let conversationData = await uniIm.conversation.loadMore(param)
|
||||
```
|
||||
|
||||
**返回值**
|
||||
|
||||
|属性名 |类型 |说明 |
|
||||
|-- |-- |-- |
|
||||
|id |string |当前会话id |
|
||||
|title |string |普通会话为对方的用户名或昵称、群会话为群昵称 |
|
||||
|avatar_file |uniCloud file |普通会话为对方的用户头像、群会话为群头像 |
|
||||
|unread_count |number |未读消息数 |
|
||||
|user_id |string |对话的用户id(群聊会话时为空) |
|
||||
|group_id |string |对话的群聊id(普通会话时为空) |
|
||||
|update_time |timestamp |更新时间(每次会话会更新) |
|
||||
|msgList |array |当前会话聊天数据列表 |
|
||||
|chatText |string |当前会话的文本框文字内容 |
|
||||
|
||||
|
||||
- 统计所有消息的未读数
|
||||
```js
|
||||
let unreadCount = await uniIm.conversation.unreadCount()
|
||||
```
|
||||
|
||||
- 删除指定id的会话数据
|
||||
```js
|
||||
// xxx表示会话id
|
||||
let param = 'xxxx'
|
||||
await uniIm.conversation.remove(param)
|
||||
```
|
||||
|
||||
- 获取系统消息数据
|
||||
|
||||
1. 不限类型
|
||||
```js
|
||||
let param = null
|
||||
await uniIm.notification.get(param)
|
||||
```
|
||||
|
||||
2. 指定类型(单个)
|
||||
```js
|
||||
// uni-im-group-join-request 表示加群通知
|
||||
let param = {type:"uni-im-friend-invite"}
|
||||
await uniIm.notification.get(param)
|
||||
```
|
||||
|
||||
3. 指定类型(多个)
|
||||
```js
|
||||
// uni-im-group-join-request uni-im-friend-invite 表示加群通知、好友加请求通知
|
||||
let param = {type:["uni-im-friend-invite","uni-im-friend-invite"]}
|
||||
await uniIm.notification.get(param)
|
||||
```
|
||||
|
||||
4. 排除类型(单个)
|
||||
```js
|
||||
// uni-im-group-join-request 表示加群通知
|
||||
let param = {excludeType:"uni-im-friend-invite"}
|
||||
await uniIm.notification.get(param)
|
||||
```
|
||||
|
||||
5. 排除类型(多个)
|
||||
```js
|
||||
// uni-im-group-join-request uni-im-friend-invite 表示加群通知、好友加请求通知
|
||||
let param = {excludeType:["uni-im-friend-invite","uni-im-friend-invite"]}
|
||||
await uniIm.notification.get(param)
|
||||
```
|
||||
|
||||
- 加载系统消息数据
|
||||
参数与`获取系统消息数据`一致
|
||||
|
||||
- 获取好友数据
|
||||
```js
|
||||
await uniIm.friend.get()
|
||||
```
|
||||
|
||||
- 加载更多好友数据
|
||||
1. 分页加载
|
||||
```js
|
||||
await uniIm.friend.loadMore()
|
||||
```
|
||||
2. 加载指定好友数据
|
||||
```js
|
||||
let param = {"friend_uid":"xxx"}
|
||||
await uniIm.friend.loadMore(param)
|
||||
```
|
||||
- 删除好友数据
|
||||
```js
|
||||
let param = {"friend_uid":"xxx"}
|
||||
await uniIm.friend.remove(param)
|
||||
```
|
||||
|
||||
- 获取群聊数据
|
||||
```js
|
||||
await uniIm.group.get()
|
||||
```
|
||||
|
||||
- 加载更多群聊数据
|
||||
1. 分页加载
|
||||
```js
|
||||
await uniIm.group.loadMore()
|
||||
```
|
||||
2. 加载指定群聊数据
|
||||
```js
|
||||
let param = {"group_id":"xxx"}
|
||||
await uniIm.group.loadMore(param)
|
||||
```
|
||||
- 删除群聊数据
|
||||
```js
|
||||
let param = {"group_id":"xxx"}
|
||||
await uniIm.group.remove(param)
|
||||
```
|
||||
|
||||
- 添加用户信息到本地用户信息库
|
||||
```js
|
||||
// xxx表示用户数据
|
||||
let usersInfo = {xxx}
|
||||
await uniIm.mergeUsersInfo(usersInfo)
|
||||
```
|
||||
|
||||
- 设置某个会话的未读消息数为已读
|
||||
```js
|
||||
// xxx表示会话id
|
||||
let conversation_id = "xxx"
|
||||
await uniIm.clearUnreadCount(conversation_id)
|
||||
```
|
||||
|
||||
#### 工具类库@utils
|
||||
utils封装了uni-im常用方法的模块,路径:`/uni_modules/uni-im/common/utils.js`
|
||||
|
||||
|名称 |类型 |说明 |入参 |返回值 |
|
||||
|-- |-- |-- |-- |-- |
|
||||
|init |function |初始化uni-im(监听聊天消息,定时每秒更新心跳值为当前时间戳) |无 |无 |
|
||||
|getConversationId |function |获取会话id |对话的用户id或群id 详见[详见](#getConversationId) |无 |
|
||||
|toFriendlyTime |function |用于将时间戳转友好时间提示(距离当前2小时内的时间戳,每隔一秒钟会刷新一次) |时间戳:timestamp |格式化后的时间字符串。如:x年x月x日,昨天,下午,1小时前等 |
|
||||
|clearPushNotify |function |清空push消息栏通知 |无 |无 |
|
||||
|login |function |非uni-id体系系统登录到uni-im方法 |时间戳:timestamp |参数为对象,含token和token过期时间,例如:`{"token":"xxx","tokenExpired":1679403132582}` |
|
||||
|
||||
- 获取会话id @getConversationId
|
||||
1. 获取单聊会话id
|
||||
```js
|
||||
let friend_uid = "xxx"
|
||||
uniIm.getConversationId(friend_uid,'single')
|
||||
```
|
||||
2. 获取群聊会话id
|
||||
```js
|
||||
let group_id = "xxx"
|
||||
uniIm.getConversationId(group_id,'group')
|
||||
```
|
||||
|
||||
## 项目升级
|
||||
uni-im遵循uni-app的插件模块化规范,即:[uni_modules](https://uniapp.dcloud.io/uni_modules)。
|
||||
|
||||
在项目根目录下的`uni_modules`目录下,以插件ID即`uni-im`为插件文件夹命名,在该目录右键也会看到“从插件市场更新”选项,点击即可更新该插件。也可以用插件市场web界面下载覆盖。
|
||||
20
uni-im示例/index.html
Normal file
20
uni-im示例/index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
36
uni-im示例/license.md
Normal file
36
uni-im示例/license.md
Normal file
@@ -0,0 +1,36 @@
|
||||
uni-im源码使用许可协议
|
||||
|
||||
2022年10月
|
||||
|
||||
本许可协议,是数字天堂(北京)网络技术有限公司(以下简称DCloud)对其所拥有著作权的“DCloud uni-im”(以下简称软件),提供的使用许可协议。
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受本许可协议的条款的约束,如您不接受本协议,则不能使用、复制、修改本软件。
|
||||
|
||||
授权许可范围
|
||||
|
||||
a) 授予您永久性的、全球性的、免费的、非独占的、不可撤销的本软件的源码使用许可,您可以使用这些源码制作自己的应用。
|
||||
|
||||
b) 您只能在DCloud产品体系内使用本软件及其源码。您不能将源码修改后运行在DCloud产品体系之外的环境,比如客户端脱离uni-app,或服务端脱离uniCloud。
|
||||
|
||||
c) DCloud未向您授权商标使用许可。您在根据本软件源码制作自己的应用时,需以自己的名义发布软件,而不是以DCloud名义发布。
|
||||
|
||||
d) 本协议不构成代理关系。
|
||||
|
||||
DCloud的责任限制
|
||||
“软件”在提供时不带任何明示或默示的担保。在任何情况下,DCloud不对任何人因使用“软件”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
您的责任限制
|
||||
|
||||
a) 您需要在授权许可范围内使用软件。
|
||||
|
||||
b) 您在分发自己的应用时,不得侵犯DCloud商标和名誉权利。
|
||||
|
||||
c) 您不得进行破解、反编译、套壳等侵害DCloud知识产权的行为。您不得利用DCloud系统漏洞谋利或侵害DCloud利益,如您发现DCloud系统漏洞应第一时间通知DCloud。您不得进行攻击DCloud的服务器、网络等妨碍DCloud运营的行为。您不得利用DCloud的产品进行与DCloud争夺开发者的行为。
|
||||
|
||||
d) 如您违反本许可协议,需承担因此给DCloud造成的损失。
|
||||
|
||||
本协议签订地点为中华人民共和国北京市海淀区。
|
||||
|
||||
根据发展,DCloud可能会对本协议进行修改。修改时,DCloud会在产品或者网页中显著的位置发布相关信息以便及时通知到用户。如果您选择继续使用本框架,即表示您同意接受这些修改。
|
||||
|
||||
条款结束
|
||||
22
uni-im示例/main.js
Normal file
22
uni-im示例/main.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import App from './App'
|
||||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
Vue.config.productionTip = false
|
||||
App.mpType = 'app'
|
||||
const app = new Vue({
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef VUE3
|
||||
import {createSSRApp} from 'vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app,
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
171
uni-im示例/manifest.json
Normal file
171
uni-im示例/manifest.json
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"name" : "hs-im",
|
||||
"appid" : "__UNI__8513892",
|
||||
"description" : "hs音视频IM",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
"app-plus" : {
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"usingComponents" : true,
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
"modules" : {
|
||||
"OAuth" : {},
|
||||
"Record" : {},
|
||||
"Camera" : {},
|
||||
"Push" : {},
|
||||
"SQLite" : {},
|
||||
"VideoPlayer" : {}
|
||||
},
|
||||
"distribute" : {
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECEIVE_USER_PRESENT\"/>"
|
||||
]
|
||||
},
|
||||
"ios" : {
|
||||
"dSYMs" : false,
|
||||
"capabilities" : {
|
||||
"entitlements" : {
|
||||
"com.apple.developer.associated-domains" : [ "applinks:static-9f641af8-e860-44e5-b18f-f68dd8fe3fe4.bspapp.com" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sdkConfigs" : {
|
||||
"push" : {
|
||||
"unipush" : {
|
||||
"version" : "2",
|
||||
"offline" : false,
|
||||
"hms" : {},
|
||||
"mi" : {}
|
||||
}
|
||||
},
|
||||
"oauth" : {
|
||||
"weixin" : {
|
||||
"appid" : "xxx",
|
||||
"UniversalLinks" : "https://static-9f641af8-e860-44e5-b18f-f68dd8fe3fe4.bspapp.com/uni-universallinks/__UNI__ECAF623/"
|
||||
}
|
||||
},
|
||||
"ad" : {},
|
||||
"maps" : {},
|
||||
"speech" : {},
|
||||
"statics" : {}
|
||||
},
|
||||
"icons" : {}
|
||||
},
|
||||
"nvueCompiler" : "uni-app",
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"quickapp" : {},
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true,
|
||||
"unipush" : {
|
||||
"enable" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true,
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true,
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true,
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false,
|
||||
"version" : "2"
|
||||
},
|
||||
"vueVersion" : "2",
|
||||
"h5" : {
|
||||
"unipush" : {
|
||||
"enable" : true
|
||||
},
|
||||
"devServer" : {
|
||||
"port" : 8080,
|
||||
"disableHostCheck" : true,
|
||||
"https" : false
|
||||
},
|
||||
"optimization" : {
|
||||
"treeShaking" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"_spaceID" : "9f641af8-e860-44e5-b18f-f68dd8fe3fe4",
|
||||
"fallbackLocale" : "zh-Hans",
|
||||
"mp-jd" : {
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"mp-kuaishou" : {
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"mp-lark" : {
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"mp-qq" : {
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"quickapp-webview-huawei" : {
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"quickapp-webview-union" : {
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
}
|
||||
}
|
||||
}
|
||||
306
uni-im示例/pages.json
Normal file
306
uni-im示例/pages.json
Normal file
@@ -0,0 +1,306 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}
|
||||
// #ifndef MP-WEIXIN
|
||||
,{
|
||||
"path": "uni_modules/uni-im/pages/chat/chat",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"titleNView": {
|
||||
"buttons": [{
|
||||
"color": "#333",
|
||||
"colorPressed": "#111111",
|
||||
"float": "right",
|
||||
"text": "...",
|
||||
"fontSize": 26,
|
||||
"onclick": "more"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
,{
|
||||
"path": "uni_modules/uni-id-pages/pages/userinfo/realname-verify/realname-verify",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTitleText": "实名认证"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "uni_modules/uni-im/pages",
|
||||
"pages": [{
|
||||
"path": "index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "会话列表",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"titleNView": {
|
||||
"buttons": [{
|
||||
"color": "#999999",
|
||||
"colorPressed": "#111111",
|
||||
"float": "right",
|
||||
"text": "我的",
|
||||
"fontSize": 14,
|
||||
"onclick": "toLogin"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "common/uni-im-code-pages/uni-im-code-pages",
|
||||
"style": {
|
||||
"navigationBarTitleText": "代码浏览",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "userList/userList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户列表",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
// #ifdef MP-WEIXIN
|
||||
{
|
||||
"path": "chat/chat",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"titleNView": {
|
||||
"buttons": [{
|
||||
"color": "#333",
|
||||
"colorPressed": "#111111",
|
||||
"float": "right",
|
||||
"text": "...",
|
||||
"fontSize": 26,
|
||||
"onclick": "more"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
{
|
||||
"path": "common/video/video",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"path": "group/info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "群信息",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"titleNView": {
|
||||
"buttons": [{
|
||||
"color": "#333",
|
||||
"colorPressed": "#111111",
|
||||
"float": "right",
|
||||
"text": "管理",
|
||||
"fontSize": 16,
|
||||
"onclick": "more"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "contacts/notification/notification",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "contacts/contacts",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通讯录",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "contacts/addPeopleGroups/addPeopleGroups",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "contacts/createGroup/createGroup",
|
||||
"style": {
|
||||
"navigationBarTitleText": "创建群聊",
|
||||
"enablePullDownRefresh": false,
|
||||
"maxWidth": 950
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "group/groupQRCode",
|
||||
"style": {
|
||||
"navigationBarTitleText": "群聊二维码",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "contacts/groupList/groupList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的群聊",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
|
||||
}, {
|
||||
"path": "chat/info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "聊天设置",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "uni_modules/uni-id-pages/pages",
|
||||
"pages": [{
|
||||
"path": "userinfo/userinfo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人资料"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "login/login-withoutpwd"
|
||||
},
|
||||
{
|
||||
"path": "login/login-withpwd"
|
||||
},
|
||||
{
|
||||
"path": "userinfo/deactivate/deactivate",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注销账号"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "userinfo/bind-mobile/bind-mobile",
|
||||
"style": {
|
||||
"navigationBarTitleText": "绑定手机号码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "login/login-smscode",
|
||||
"style": {
|
||||
"navigationBarTitleText": "手机验证码登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "register/register",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "retrieve/retrieve",
|
||||
"style": {
|
||||
"navigationBarTitleText": "重置密码"
|
||||
}
|
||||
}, {
|
||||
"path": "common/webview/webview",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
}, {
|
||||
"path": "userinfo/change_pwd/change_pwd",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTitleText": "修改密码"
|
||||
}
|
||||
}, {
|
||||
"path": "register/register-by-email",
|
||||
"style": {
|
||||
"navigationBarTitleText": "邮箱验证码注册"
|
||||
}
|
||||
}, {
|
||||
"path": "retrieve/retrieve-by-email",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通过邮箱重置密码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "userinfo/set-pwd/set-pwd",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTitleText": "设置密码"
|
||||
}
|
||||
}
|
||||
// #ifdef H5
|
||||
,
|
||||
{
|
||||
"path": "userinfo/cropImage/cropImage"
|
||||
},
|
||||
{
|
||||
"path": "register/register-admin",
|
||||
"style": {
|
||||
"enablePullDownRefresh": false,
|
||||
"navigationBarTitleText": "注册管理员账号"
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
]
|
||||
}
|
||||
],
|
||||
// #ifndef MP-WEIXIN
|
||||
"tabBar": {
|
||||
"color": "#999999",
|
||||
"selectedColor": "#38BC48",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"list": [{
|
||||
"pagePath": "uni_modules/uni-im/pages/index/index",
|
||||
"text": "会话",
|
||||
"iconPath": "uni_modules/uni-im/static/tabbarIcon/chat.png",
|
||||
"selectedIconPath": "uni_modules/uni-im/static/tabbarIcon/chatex.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "uni_modules/uni-im/pages/userList/userList",
|
||||
"text": "用户列表",
|
||||
"iconPath": "uni_modules/uni-im/static/tabbarIcon/contacts.png",
|
||||
"selectedIconPath": "uni_modules/uni-im/static/tabbarIcon/contactsex.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "uni_modules/uni-im/pages/contacts/contacts",
|
||||
"text": "通讯录",
|
||||
"iconPath": "uni_modules/uni-im/static/tabbarIcon/contacts.png",
|
||||
"selectedIconPath": "uni_modules/uni-im/static/tabbarIcon/contactsex.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
// #endif
|
||||
"uniIdRouter": {
|
||||
"loginPage": "uni_modules/uni-id-pages/pages/login/login-withpwd",
|
||||
"needLogin": [
|
||||
"uni_modules/uni-im/pages/userList/userList",
|
||||
"uni_modules/uni-im/pages/contacts/contacts",
|
||||
"pages/index/index"
|
||||
]
|
||||
},
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
}
|
||||
}
|
||||
77
uni-im示例/pages/index/index.vue
Normal file
77
uni-im示例/pages/index/index.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-list>
|
||||
<uni-list-item
|
||||
title="uni-im 会话列表" @click="toPath('/uni_modules/uni-im/pages/index/index')" :link="true"
|
||||
:show-badge="unreadMsgCount>0" :badge-text="unreadMsgCount+''" :badge-style="{'background':'#f41500'}"
|
||||
></uni-list-item>
|
||||
<uni-list-item
|
||||
title="用户列表" @click="toPath('/uni_modules/uni-im/pages/userList/userList')" :link="true"
|
||||
></uni-list-item>
|
||||
<uni-list-item
|
||||
title="通讯录" @click="toPath('/uni_modules/uni-im/pages/contacts/contacts')" :link="true"
|
||||
:show-badge="notificationUnreadCount>0" :badge-text="notificationUnreadCount+''" :badge-style="{'background':'#f41500'}"
|
||||
></uni-list-item>
|
||||
<uni-list-item
|
||||
title="个人中心" @click="toPath('/uni_modules/uni-id-pages/pages/userinfo/userinfo?showLoginManage=true')" :link="true"
|
||||
></uni-list-item>
|
||||
<uni-list-item title="clear sqlite storage" @click="clear" :link="true" ></uni-list-item>
|
||||
</uni-list>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniIm from '@/uni_modules/uni-im/lib/main.js';
|
||||
import sqlite from '@/uni_modules/uni-im/common/sqlite.js';
|
||||
export default {
|
||||
computed: {
|
||||
unreadMsgCount(){
|
||||
return uniIm.conversation.unreadCount()
|
||||
},
|
||||
notificationUnreadCount(){
|
||||
return uniIm.notification.unreadCount()
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
async onReady() {
|
||||
if(!uniIm.isWidescreen){
|
||||
uni.showLoading({
|
||||
mask: true
|
||||
});
|
||||
try{
|
||||
await uniIm.conversation.loadMore()
|
||||
}catch(e){
|
||||
console.log(e)
|
||||
}
|
||||
uni.hideLoading()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//未读系统通知数量
|
||||
toPath(path){
|
||||
uni.navigateTo({
|
||||
url: path,
|
||||
fail: () => {
|
||||
uni.switchTab({
|
||||
url:path,
|
||||
fail: (e) => {
|
||||
console.error(e);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
async clear(){
|
||||
// #ifdef APP
|
||||
sqlite.init()
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
1
uni-im示例/static/app-plus/mp-html/js/uni.webview.min.js
vendored
Normal file
1
uni-im示例/static/app-plus/mp-html/js/uni.webview.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
uni-im示例/static/app-plus/mp-html/lib/github-dark.min.css
vendored
Normal file
10
uni-im示例/static/app-plus/mp-html/lib/github-dark.min.css
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
|
||||
Theme: GitHub Dark
|
||||
Description: Dark theme as seen on github.com
|
||||
Author: github.com
|
||||
Maintainer: @Hirse
|
||||
Updated: 2021-05-15
|
||||
|
||||
Outdated base version: https://github.com/primer/github-syntax-dark
|
||||
Current colors taken from GitHub's CSS
|
||||
*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}
|
||||
42
uni-im示例/static/app-plus/mp-html/uni-im-code-view-local.html
Normal file
42
uni-im示例/static/app-plus/mp-html/uni-im-code-view-local.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<link rel="stylesheet" href="./lib/github-dark.min.css">
|
||||
<style type="text/css">
|
||||
body,
|
||||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">web-view content</div>
|
||||
<script type="text/javascript" src="./js/uni.webview.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
// 等待初始化完毕
|
||||
document.addEventListener('UniAppJSBridgeReady', () => {
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'onJSBridgeReady'
|
||||
}
|
||||
})
|
||||
})
|
||||
window.setHtml = function(htmlString) {
|
||||
document.body.outerHTML = htmlString
|
||||
let height = document.body.scrollHeight
|
||||
uni.postMessage({
|
||||
data: {
|
||||
action: 'onHeightChange',
|
||||
height
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
BIN
uni-im示例/static/logo.png
Normal file
BIN
uni-im示例/static/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
76
uni-im示例/uni.scss
Normal file
76
uni-im示例/uni.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color:#333;//基本色
|
||||
$uni-text-color-inverse:#fff;//反色
|
||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable:#c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color:#ffffff;
|
||||
$uni-bg-color-grey:#f8f8f8;
|
||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color:#c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm:12px;
|
||||
$uni-font-size-base:14px;
|
||||
$uni-font-size-lg:16;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm:20px;
|
||||
$uni-img-size-base:26px;
|
||||
$uni-img-size-lg:40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2C405A; // 文章标题颜色
|
||||
$uni-font-size-title:20px;
|
||||
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||
$uni-font-size-subtitle:26px;
|
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||
$uni-font-size-paragraph:15px;
|
||||
14
uni-im示例/uniCloud-aliyun/database/JQL查询.jql
Normal file
14
uni-im示例/uniCloud-aliyun/database/JQL查询.jql
Normal file
@@ -0,0 +1,14 @@
|
||||
// 本文件用于,使用JQL语法操作项目关联的uniCloud空间的数据库,方便开发调试和远程数据库管理
|
||||
// 编写clientDB的js API(也支持常规js语法,比如var),可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法
|
||||
// 可以全部运行,也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码
|
||||
// 如果文档中存在多条JQL语句,只有最后一条语句生效
|
||||
// 如果混写了普通js,最后一条语句需是数据库操作语句
|
||||
// 此处代码运行不受DB Schema的权限控制,移植代码到实际业务中注意在schema中配好permission
|
||||
// 不支持clientDB的action
|
||||
// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database.html#limit
|
||||
// 详细JQL语法,请参考:https://uniapp.dcloud.net.cn/uniCloud/jql.html
|
||||
|
||||
// 下面示例查询uni-id-users表的所有数据
|
||||
db.collection('uni-im-msg').update({
|
||||
is_read:true
|
||||
});
|
||||
9
uni-im示例/uniCloud-aliyun/database/db_init.json
Normal file
9
uni-im示例/uniCloud-aliyun/database/db_init.json
Normal file
@@ -0,0 +1,9 @@
|
||||
// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/hellodb?id=db-init
|
||||
// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据
|
||||
{
|
||||
"opendb-tempdata": {},
|
||||
"opendb-department": {},
|
||||
"uni-id-users": {
|
||||
"data": []
|
||||
}
|
||||
}
|
||||
12
uni-im示例/uniCloud-aliyun/database/default.jql
Normal file
12
uni-im示例/uniCloud-aliyun/database/default.jql
Normal file
@@ -0,0 +1,12 @@
|
||||
// 本文件用于,使用JQL语法操作项目关联的uniCloud空间的数据库,方便开发调试和远程数据库管理
|
||||
// 编写clientDB的js API(也支持常规js语法,比如var),可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法
|
||||
// 可以全部运行,也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码
|
||||
// 如果文档中存在多条JQL语句,只有最后一条语句生效
|
||||
// 如果混写了普通js,最后一条语句需是数据库操作语句
|
||||
// 此处代码运行不受DB Schema的权限控制,移植代码到实际业务中注意在schema中配好permission
|
||||
// 不支持clientDB的action
|
||||
// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database.html#limit
|
||||
// 详细JQL语法,请参考:https://uniapp.dcloud.net.cn/uniCloud/jql.html
|
||||
|
||||
// 下面示例查询uni-id-users表的所有数据
|
||||
db.collection('uni-id-users').get();
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"bsonType": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"permission": {
|
||||
"read": true,
|
||||
"create": false,
|
||||
"update": false,
|
||||
"delete": false
|
||||
},
|
||||
"properties": {
|
||||
"_id": {
|
||||
"description": "ID,系统自动生成"
|
||||
},
|
||||
"parent_id": {
|
||||
"bsonType": "string",
|
||||
"description": "父级部门ID",
|
||||
"parentKey": "_id"
|
||||
},
|
||||
"name": {
|
||||
"bsonType": "string",
|
||||
"description": "部门名称",
|
||||
"title": "部门名称",
|
||||
"trim": "both"
|
||||
},
|
||||
"level": {
|
||||
"bsonType": "int",
|
||||
"description": "部门层级,为提升检索效率而作的冗余设计"
|
||||
},
|
||||
"sort": {
|
||||
"bsonType": "int",
|
||||
"description": "部门在当前层级下的顺序,由小到大",
|
||||
"title": "显示顺序"
|
||||
},
|
||||
"manager_uid": {
|
||||
"bsonType": "string",
|
||||
"description": "部门主管的userid, 参考`uni-id-users` 表",
|
||||
"foreignKey": "uni-id-users._id"
|
||||
},
|
||||
"create_date": {
|
||||
"bsonType": "timestamp",
|
||||
"description": "部门创建时间",
|
||||
"forceDefaultValue": {
|
||||
"$env": "now"
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "0.1.0"
|
||||
}
|
||||
201
uni-im示例/uni_modules/Sansnn-uQRCode/LICENSE.md
Normal file
201
uni-im示例/uni_modules/Sansnn-uQRCode/LICENSE.md
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
392
uni-im示例/uni_modules/Sansnn-uQRCode/README.md
Normal file
392
uni-im示例/uni_modules/Sansnn-uQRCode/README.md
Normal file
@@ -0,0 +1,392 @@
|
||||
# 介绍
|
||||
|
||||
`uQRCode`是一款基于`Javascript`环境开发的二维码生成插件,适用所有`Javascript`运行环境的前端应用和`Node.js`应用。
|
||||
|
||||
`uQRCode`可扩展性高,它支持自定义渲染二维码,可通过`uQRCode API`得到二维码绘制关键信息后,使用`canvas`、`svg`或`js`操作`dom`的方式绘制二维码图案。还可自定义二维码样式,如随机颜色、圆点、方块、块与块之间的间距等。
|
||||
|
||||
欢迎加入群聊【uQRCode交流群】:[695070434](https://jq.qq.com/?_wv=1027&k=JRjzDqiw)。
|
||||
|
||||
# 设计器
|
||||
|
||||
uQRCode发布了配套的可视化设计器,可根据自己喜好在设计器中设计二维码样式,一键生成配置代码复制到项目中,详情请在微信小程序搜索“柚子二维码”,或扫描下方小程序码体验。
|
||||
|
||||

|
||||
|
||||
## 设计器模板示例
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# 快速上手
|
||||
|
||||
> 在`uni-app`中,我们更推荐使用组件方式来生成二维码,组件方式大大提高了页面的可读性以及避开了一些平台容易出问题的地方,当组件无法满足需求的时候,再考虑切换成原生方式。
|
||||
|
||||
官方文档:[https://uqrcode.cn/doc](https://uqrcode.cn/doc)。
|
||||
|
||||
github地址:[https://github.com/Sansnn/uQRCode](https://github.com/Sansnn/uQRCode)。
|
||||
|
||||
npm地址:[https://www.npmjs.com/package/uqrcodejs](https://www.npmjs.com/package/uqrcodejs)。
|
||||
|
||||
uni-app插件市场地址:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)。
|
||||
|
||||
## 原生方式
|
||||
|
||||
原生方式仅需要获取`uqrcode.js`文件便可使用。详细配置请移步到:文档 > [原生](https://uqrcode.cn/doc/document/native.html)。
|
||||
|
||||
### 安装
|
||||
|
||||
1. 通过`npm`安装,成功后即可使用`import`或`require`进行引用。
|
||||
``` bash
|
||||
# npm安装
|
||||
npm install uqrcodejs
|
||||
# 或者
|
||||
npm install @uqrcode/js
|
||||
```
|
||||
|
||||
2. 通过项目开源地址获取`uqrcode.js`,下载`uqrcode.js`后,将其复制到您项目指定目录,在页面中引入`uqrcode.js`文件即可开始使用。
|
||||
|
||||
### 引入
|
||||
|
||||
- 通过`import`引入。
|
||||
``` javascript
|
||||
// npm安装
|
||||
import UQRCode from 'uqrcodejs'; // npm install uqrcodejs
|
||||
// 或者
|
||||
import UQRCode from '@uqrcode/js'; // npm install @uqrcode/js
|
||||
```
|
||||
|
||||
- `Node.js`通过`require`引入。
|
||||
``` javascript
|
||||
// npm安装
|
||||
const UQRCode = require('uqrcodejs'); // npm install uqrcodejs
|
||||
// 或者
|
||||
const UQRCode = require('@uqrcode/js'); // npm install @uqrcode/js
|
||||
```
|
||||
|
||||
- 原生浏览器环境,在js脚本加载时添加到`window`。
|
||||
``` html
|
||||
<script type="text/javascript" src="uqrcode.js"></script>
|
||||
<script>
|
||||
var UQRCode = window.UQRCode;
|
||||
</script>
|
||||
```
|
||||
|
||||
### 简单用法
|
||||
|
||||
`uQRCode`基于`Canvas API`封装了一套方法,建议开发者使用`canvas`生成,一键调用,非常方便。以下是示例:
|
||||
|
||||
- HTML示例
|
||||
- DOM部分
|
||||
``` html
|
||||
<canvas id="qrcode" width="200" height="200"></canvas>
|
||||
```
|
||||
|
||||
- JS部分
|
||||
``` javascript
|
||||
// 获取uQRCode实例
|
||||
var qr = new UQRCode();
|
||||
// 设置二维码内容
|
||||
qr.data = "https://uqrcode.cn/doc";
|
||||
// 设置二维码大小,必须与canvas设置的宽高一致
|
||||
qr.size = 200;
|
||||
// 调用制作二维码方法
|
||||
qr.make();
|
||||
// 获取canvas元素
|
||||
var canvas = document.getElementById("qrcode");
|
||||
// 获取canvas上下文
|
||||
var canvasContext = canvas.getContext("2d");
|
||||
// 设置uQRCode实例的canvas上下文
|
||||
qr.canvasContext = canvasContext;
|
||||
// 调用绘制方法将二维码图案绘制到canvas上
|
||||
qr.drawCanvas();
|
||||
```
|
||||
|
||||
- uni-app示例
|
||||
- Template部分
|
||||
``` html
|
||||
<canvas id="qrcode" canvas-id="qrcode" style="width: 200px;height: 200px;"></canvas>
|
||||
```
|
||||
|
||||
- JS部分
|
||||
``` javascript
|
||||
onReady() {
|
||||
// 获取uQRCode实例
|
||||
var qr = new UQRCode();
|
||||
// 设置二维码内容
|
||||
qr.data = "https://uqrcode.cn/doc";
|
||||
// 设置二维码大小,必须与canvas设置的宽高一致
|
||||
qr.size = 200;
|
||||
// 调用制作二维码方法
|
||||
qr.make();
|
||||
// 获取canvas上下文
|
||||
var canvasContext = uni.createCanvasContext('qrcode', this); // 如果是组件,this必须传入
|
||||
// 设置uQRCode实例的canvas上下文
|
||||
qr.canvasContext = canvasContext;
|
||||
// 调用绘制方法将二维码图案绘制到canvas上
|
||||
qr.drawCanvas();
|
||||
}
|
||||
```
|
||||
|
||||
- 微信小程序,推荐使用Canvas 2D,关于Canvas 2D的使用请参考微信开放文档。
|
||||
|
||||
### 高级用法
|
||||
|
||||
考虑到部分平台可能不支持`canvas`,所以`uQRCode`并没有强制要求和`canvas`一起使用,您还可以选择其他方式来生成二维码,例如使用`js`操作`dom`进行绘制或是使用`svg`绘制等。以下是示例:
|
||||
|
||||
- uni-app v-for+view
|
||||
|
||||
```html
|
||||
<template>
|
||||
<view>
|
||||
<view class="qrcode">
|
||||
<view v-for="(row, rowI) in modules" :key="rowI" style="display: flex;flex-direction: row;">
|
||||
<view v-for="(col, colI) in row" :key="colI">
|
||||
<view v-if="col.isBlack" style="width: 10px;height: 10px;background-color: black;">
|
||||
<!-- 黑色码点 -->
|
||||
</view>
|
||||
<view v-else style="width: 10px;height: 10px;background-color: white;">
|
||||
<!-- 白色码点 -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UQRCode from '../../uni_modules/Sansnn-uQRCode/js_sdk/uqrcode/uqrcode.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
modules: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
const qr = new UQRCode();
|
||||
qr.data = 'uQRCode';
|
||||
qr.make();
|
||||
this.modules = qr.modules;
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
- js操作dom
|
||||
|
||||
``` html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>uQRCode二维码生成</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qrcode" style="position: relative;"></div>
|
||||
<script type="text/javascript" src="uqrcode.js"></script>
|
||||
<script>
|
||||
// 引入uQRCode
|
||||
var UQRCode = window.UQRCode;
|
||||
// 获取uQRCode实例
|
||||
var qr = new UQRCode();
|
||||
// 设置二维码内容
|
||||
qr.data = "https://uqrcode.cn/doc";
|
||||
// 设置二维码大小,必须与canvas设置的宽高一致
|
||||
qr.size = 200;
|
||||
// 设置二维码前景图,可以是路径
|
||||
qr.foregroundImageSrc =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAC3xJREFUeJztnd1vFNcZxodSJ3y3EL7SYIQwu15wI5FSAkqVkISKgEkuSIEC6127RrloL9r8D4n5UFUZp/9C24A/okqUOzCmSdoohQtkXIkiRS1VC7YQF41Kbe/unL7PzHt2z45ndnZmd1l75hzrSSwzMzvn+c15z8ee3dcwdIlkWaRlqSnF62a+4dDiiMtZ36cKyc183NQ3WS2sZ2IqWX/phwTWEDhuEKT5S0hLSctJK1grWasiLllPWe9l7MUSowTJDU7oopKVICSEZXwz3yKtJj1HWkdaT9pA2hgTbeA6r2MPVrMnEpCEI8HU1FpUGC18cbQEPB1r+Ea+Q2olbSFtJbWREqxkxCXr2cZ1hwebSM+zN2vYq+XsXYtRQ2uRJ8hWgaa4kl8ET0Ur30SK9F3STtL3SLtJL5P2kPZGXHu4rru57vCgg9TO3mxir1azd0uNUmuRUALBWKzAAOm1pBcM+4nYwTeBG3uNtJ/0FukQqZP0NuudiErWr5PrfID0JulVwwb1Enu0lT1byx6qUKpqJWoH3qLAQIzcbNhNFU/CKwzhMOld0o9JaVKW1EP6CamXdDqi6uU69nCdUffjpCPsyZvs0U72bDN7KKHI8OULRcIAQcQ9NDXQRYhCeNpF2ocXPXjw4M8uX748eP/+/b9NT08/ETEv8ABekCcXDx069FMGs489SzGUtezpEqPK0KWGKnRGiH8vMGVc+I1UKnXy3r17N5ttwHwvd+/e/bKjo+Mkt5bvG3bfAi/RD69gj2Ur8YQhO/Il3LzQKbVx09t35MiR9x4/fvzvZld2oRTy6l8HDhxAiHvdsPsVeInhMobGSw2fvkTtO5YxSYQqdE6Ih4cnJiY+b3YlF1q5ffv2p4Y9APiBYY/CELqe4wj0TKWwpYYrxLn1TBSjqf1Hjx79eYGK3w1sGz4VK/kVeHbs2LFfkIc/ZC/b2FtEoGcrhS01XKFJYdKHzghD28NjY2N/0BDCwSHvrnAreYU9RV/ybUfY8gSyVAlXmPRhnvHuw4cP/65hhIPy4MGDf5CHPzLsUdeLHLbWVAKi9h/LOcZtMezOHPONE25D22ZXfr7KWeAdeXiSw9ZO9nYte91iuPQjEgj6DwzJMInBLBNDXczA07p1hAeCQh52sZe7lH5EDn99geDgbYa9ToOlgayGURsU8rCbvdzN3voCUUdYmH9gJRPrMphx9mggNQPpYS/3sLcb2GvXCaITyEYFCEYHvRpIzUB62UsJZGO1QFbxwVgu2auB1B3IXvZ2I3sdGAiWm09rIDUDOc1eaiAaSEWlHQp7ntc1Kh0XRlEHMtQ1V2HPm3N+uvJxYRQSyoIB0j6Ymash/0onyBy3c5MkeUzS45haFFEg9pOLCk6LgsgJs0xPxKxIDbu1lNITn7l2hs7N0U/p/Bn6vf/OkEgM28dcuDMy59rhlbfuKzmUCdaSFxoQVNZZUHk/INlrZ+mo8tV/k34GCMI2BvLRnU/mXDt8MQlHLs5AMhWBdI+e00CeJpDtw9lQQD7SQBoBJCdSQ+FaSHVA5r6m/xExB6KOtBIj6boBMemUWTNntUIvTZP1pmnOuboG0gAgOKebBgQpeu3UYNZVHRd7ilA0kAYDwTHZ0TPWtXBdN7XTuTlqRc4zNZAGAelmIF73ZwPJayBOICUQ9evUqwYiNBAFCM3U6d+bBSTlASSngTSrhaTFZ1Pj4k+TE+LPk39lTYhPJ8et9bEYAslb85BmAYESCJmkJC9YQok4LC66AUGsbqfhpysQa42ri0ZKtY6yqrxPfj0oEd3l98pA/idmRM+1cyJ7vc9Tv/ziY5rgFQhJ6fzq5iGmOP+X34nM9Q+L18qQuki7fv9e8f4y1z4Q6bEPRfqPfSJ9g/597Az9rY+um41fyMKELFeA2bbhc1UQecAwTQtCECA4JmedW37tWfpv1/UPrPtDuHwi/kvwgM8Wjp+hR2X7pTgC4Se5UjGLP+V/81/LkhDKC/6GloJ7w7B31pwph02/YrJovUkVNyDVFJNNDA7EvRSB0HlJC0hOOJcY8zRZTGkg7sVUJP9gAxkuARkPCGS0z+q4k4MAMivKgJgxATLDz3mYH+eZCEMDAMKGDYyPVH0tvBUMIEkJhPqLvBBlr5WnMLb9UoRHWRjb908Mi4GJESvU1KZhC8YJ6pgTDCRNIylce8DnXBxzge7jjSvv88QvI341fkn00/UusHD9/vFhe6YePSAlJZRxfs0aknMFBXzA8+VWn4TrvYar44ICUvd9U04goc4PvyFuAQNJW+HhghU2Pqld1IGjz0CYkrsM0zRqCnc995DYf2eQW3TwXYzzHEjtoyy30uhdJ7Fd7Q1vmd4GVCzzBYjeBsRFA4kwEGzVyftMGPPFlaxgi4s4vGD6Xd1l4miaYpomhqUN17Hp1E1rHQlbdbKjZ0W3m66fE+e//K29ahsQCGCcvfUbmpWfcb+2i3AfOB7L720jJwPWdcED4XcMBzOe23QgLJXbS+gqyiqACNMyN1FhG5Cr6Pi2EfcJY2yAVLoG1p0KjnPr+RZuvRURIN4fLfMC4jfs1UBqAeK5tNFlvfWqgTxFIDsuZSt+tKyHOli87ZoXpbdhc9YnqJT3QzSQ+gCBaV8U90O5a+irMWolNPLB5gP8n0JYF+n1K+8XW5IGUicg1ZTPpyZEu/WhHu9VWw2kKUBcOv0KQDAl7L16TrQPZQKqy9px0jYS7jPr8QEyZzPdqcothF5umrDMWgshwX7+Y20D6o7f0ollnB+QyQnryW0LCoShlJZdqhP2is0QyFiuZeG7TnPWNrWCpz6bvE1AsmRQt/UBUfyOkJL0AVJLwagudkBMq+Kz4sWPs9b+3hSMdihFELJXz1trXnkIXx5g5kUuVxAD40MaSG1A8qIsNNDPDJmMz/p5rTfh/OzVPguCiaVhbCnFulbBFL8eL98G5Ni9FbogzM2aCFmnot2pP6HIPGt9IkRqRnxtPqF/6/asNBb4eq7iqzVmLJOKn6Cl3/uphST4Kb5AcMo/YVuoQXnxNb3ijsFgLWOBACk9ZUk5rEQ/MIw+ICO2Y9lkxP989BkpGvWkBruLn6BNKMNf/J4sqqs2DWWs19kazeV3RRW38TTgvCZJA5lnWjhAYiINZJ6pkUD018TWB0jor4nVX6TcWCCBv0hZf9V4Y4D0GAG/alx/GX9jgQT+Mn6drqJBMBiIM13FumqA6IQuDQDikdBFJgZzTegiociUR8hfWJbyaGpq6p+6lQSHgRIm5ZEKRCYFQ9bjYlKwGzdu6KRgIWCguCQFQ8K1qpKCqSOt9dyPICHi/uPHj+u0eQEgyALPkHLQmJs2Dx77ps2rlFiy89atW9d870CXsnLz5s1RpXUETiyphi2ZehWtxEq9unnz5mOPHj263+xKLpQyOTn5VWtrKzJp7zPKU6/KrNG+abzVsOWanLijo+OETk7sX+AREjkb7smJZevwDFfOsAVyiG9e6bs7OX33RZ2+2y5K+u5LnL6706hT+m61L1ET3Lca7gnukdRdJ7ivnOC+1QiZ4F6FIkOXhAK6aHKIg+joMWLAkPg1vgHMQrE0gCfjbdY7EZWsXyfX+QB78Kphr1W9xB5tZc/WKjDgqW/f4SxqBy+hoKkh/qGj38QvhriIySOeBADCOs3LfFN7I649XNfdXHd40MGebGWP4NVq9k6F4Ruq3IraUtDEEPfQGYE0wGAsjckjmuMWvgm0ngQrGXHJerZx3bewF8+zN2vYK3j2rBEwTLmVRUY5FNlaAAbzFFDHjB5PAMbV6/hG8FRsjIk2cJ3XsQer2ZOV7NESo9QqVBihgMiidvQSTItRgoOmiKdgBWsla1XEJesp672MvZAQWowSCBmiagKhlkUOqXAkIAkpjpL1l344IdQVhrM4X0SFpGpxxOWsr5cvTSleNxM36RK18n+GJEwNAYal3QAAAABJRU5ErkJggg==';
|
||||
// 调用制作二维码方法
|
||||
qr.make();
|
||||
|
||||
var drawModules = qr.getDrawModules();
|
||||
// 遍历drawModules创建dom元素
|
||||
var qrHtml = '';
|
||||
for (var i = 0; i < drawModules.length; i++) {
|
||||
var drawModule = drawModules[i];
|
||||
switch (drawModule.type) {
|
||||
case 'tile':
|
||||
/* 绘制小块 */
|
||||
qrHtml += `<div style="position: absolute;left: ${drawModule.x}px;top: ${drawModule.y}px;width: ${drawModule.width}px;height: ${drawModule.height}px;background: ${drawModule.color};"></div>`;
|
||||
break;
|
||||
case 'image':
|
||||
/* 绘制图像 */
|
||||
qrHtml += `<img style="position: absolute;left: ${drawModule.x}px;top: ${drawModule.y}px;width: ${drawModule.width}px;height: ${drawModule.height}px;" src="${drawModule.imageSrc}" />`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
document.getElementById('qrcode').innerHTML = qrHtml;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
- svg
|
||||
``` html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>uQRCode二维码生成</title>
|
||||
</head>
|
||||
<body>
|
||||
<svg id="qrcode" width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>
|
||||
<script type="text/javascript" src="uqrcode.js"></script>
|
||||
<script>
|
||||
// 引入uQRCode
|
||||
var UQRCode = window.UQRCode;
|
||||
// 获取uQRCode实例
|
||||
var qr = new UQRCode();
|
||||
// 设置二维码内容
|
||||
qr.data = "https://uqrcode.cn/doc";
|
||||
// 设置二维码大小,必须与canvas设置的宽高一致
|
||||
qr.size = 200;
|
||||
// 设置二维码前景图,可以是路径
|
||||
qr.foregroundImageSrc =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAC3xJREFUeJztnd1vFNcZxodSJ3y3EL7SYIQwu15wI5FSAkqVkISKgEkuSIEC6127RrloL9r8D4n5UFUZp/9C24A/okqUOzCmSdoohQtkXIkiRS1VC7YQF41Kbe/unL7PzHt2z45ndnZmd1l75hzrSSwzMzvn+c15z8ee3dcwdIlkWaRlqSnF62a+4dDiiMtZ36cKyc183NQ3WS2sZ2IqWX/phwTWEDhuEKT5S0hLSctJK1grWasiLllPWe9l7MUSowTJDU7oopKVICSEZXwz3yKtJj1HWkdaT9pA2hgTbeA6r2MPVrMnEpCEI8HU1FpUGC18cbQEPB1r+Ea+Q2olbSFtJbWREqxkxCXr2cZ1hwebSM+zN2vYq+XsXYtRQ2uRJ8hWgaa4kl8ET0Ur30SK9F3STtL3SLtJL5P2kPZGXHu4rru57vCgg9TO3mxir1azd0uNUmuRUALBWKzAAOm1pBcM+4nYwTeBG3uNtJ/0FukQqZP0NuudiErWr5PrfID0JulVwwb1Enu0lT1byx6qUKpqJWoH3qLAQIzcbNhNFU/CKwzhMOld0o9JaVKW1EP6CamXdDqi6uU69nCdUffjpCPsyZvs0U72bDN7KKHI8OULRcIAQcQ9NDXQRYhCeNpF2ocXPXjw4M8uX748eP/+/b9NT08/ETEv8ABekCcXDx069FMGs489SzGUtezpEqPK0KWGKnRGiH8vMGVc+I1UKnXy3r17N5ttwHwvd+/e/bKjo+Mkt5bvG3bfAi/RD69gj2Ur8YQhO/Il3LzQKbVx09t35MiR9x4/fvzvZld2oRTy6l8HDhxAiHvdsPsVeInhMobGSw2fvkTtO5YxSYQqdE6Ih4cnJiY+b3YlF1q5ffv2p4Y9APiBYY/CELqe4wj0TKWwpYYrxLn1TBSjqf1Hjx79eYGK3w1sGz4VK/kVeHbs2LFfkIc/ZC/b2FtEoGcrhS01XKFJYdKHzghD28NjY2N/0BDCwSHvrnAreYU9RV/ybUfY8gSyVAlXmPRhnvHuw4cP/65hhIPy4MGDf5CHPzLsUdeLHLbWVAKi9h/LOcZtMezOHPONE25D22ZXfr7KWeAdeXiSw9ZO9nYte91iuPQjEgj6DwzJMInBLBNDXczA07p1hAeCQh52sZe7lH5EDn99geDgbYa9ToOlgayGURsU8rCbvdzN3voCUUdYmH9gJRPrMphx9mggNQPpYS/3sLcb2GvXCaITyEYFCEYHvRpIzUB62UsJZGO1QFbxwVgu2auB1B3IXvZ2I3sdGAiWm09rIDUDOc1eaiAaSEWlHQp7ntc1Kh0XRlEHMtQ1V2HPm3N+uvJxYRQSyoIB0j6Ymash/0onyBy3c5MkeUzS45haFFEg9pOLCk6LgsgJs0xPxKxIDbu1lNITn7l2hs7N0U/p/Bn6vf/OkEgM28dcuDMy59rhlbfuKzmUCdaSFxoQVNZZUHk/INlrZ+mo8tV/k34GCMI2BvLRnU/mXDt8MQlHLs5AMhWBdI+e00CeJpDtw9lQQD7SQBoBJCdSQ+FaSHVA5r6m/xExB6KOtBIj6boBMemUWTNntUIvTZP1pmnOuboG0gAgOKebBgQpeu3UYNZVHRd7ilA0kAYDwTHZ0TPWtXBdN7XTuTlqRc4zNZAGAelmIF73ZwPJayBOICUQ9evUqwYiNBAFCM3U6d+bBSTlASSngTSrhaTFZ1Pj4k+TE+LPk39lTYhPJ8et9bEYAslb85BmAYESCJmkJC9YQok4LC66AUGsbqfhpysQa42ri0ZKtY6yqrxPfj0oEd3l98pA/idmRM+1cyJ7vc9Tv/ziY5rgFQhJ6fzq5iGmOP+X34nM9Q+L18qQuki7fv9e8f4y1z4Q6bEPRfqPfSJ9g/597Az9rY+um41fyMKELFeA2bbhc1UQecAwTQtCECA4JmedW37tWfpv1/UPrPtDuHwi/kvwgM8Wjp+hR2X7pTgC4Se5UjGLP+V/81/LkhDKC/6GloJ7w7B31pwph02/YrJovUkVNyDVFJNNDA7EvRSB0HlJC0hOOJcY8zRZTGkg7sVUJP9gAxkuARkPCGS0z+q4k4MAMivKgJgxATLDz3mYH+eZCEMDAMKGDYyPVH0tvBUMIEkJhPqLvBBlr5WnMLb9UoRHWRjb908Mi4GJESvU1KZhC8YJ6pgTDCRNIylce8DnXBxzge7jjSvv88QvI341fkn00/UusHD9/vFhe6YePSAlJZRxfs0aknMFBXzA8+VWn4TrvYar44ICUvd9U04goc4PvyFuAQNJW+HhghU2Pqld1IGjz0CYkrsM0zRqCnc995DYf2eQW3TwXYzzHEjtoyy30uhdJ7Fd7Q1vmd4GVCzzBYjeBsRFA4kwEGzVyftMGPPFlaxgi4s4vGD6Xd1l4miaYpomhqUN17Hp1E1rHQlbdbKjZ0W3m66fE+e//K29ahsQCGCcvfUbmpWfcb+2i3AfOB7L720jJwPWdcED4XcMBzOe23QgLJXbS+gqyiqACNMyN1FhG5Cr6Pi2EfcJY2yAVLoG1p0KjnPr+RZuvRURIN4fLfMC4jfs1UBqAeK5tNFlvfWqgTxFIDsuZSt+tKyHOli87ZoXpbdhc9YnqJT3QzSQ+gCBaV8U90O5a+irMWolNPLB5gP8n0JYF+n1K+8XW5IGUicg1ZTPpyZEu/WhHu9VWw2kKUBcOv0KQDAl7L16TrQPZQKqy9px0jYS7jPr8QEyZzPdqcothF5umrDMWgshwX7+Y20D6o7f0ollnB+QyQnryW0LCoShlJZdqhP2is0QyFiuZeG7TnPWNrWCpz6bvE1AsmRQt/UBUfyOkJL0AVJLwagudkBMq+Kz4sWPs9b+3hSMdihFELJXz1trXnkIXx5g5kUuVxAD40MaSG1A8qIsNNDPDJmMz/p5rTfh/OzVPguCiaVhbCnFulbBFL8eL98G5Ni9FbogzM2aCFmnot2pP6HIPGt9IkRqRnxtPqF/6/asNBb4eq7iqzVmLJOKn6Cl3/uphST4Kb5AcMo/YVuoQXnxNb3ijsFgLWOBACk9ZUk5rEQ/MIw+ICO2Y9lkxP989BkpGvWkBruLn6BNKMNf/J4sqqs2DWWs19kazeV3RRW38TTgvCZJA5lnWjhAYiINZJ6pkUD018TWB0jor4nVX6TcWCCBv0hZf9V4Y4D0GAG/alx/GX9jgQT+Mn6drqJBMBiIM13FumqA6IQuDQDikdBFJgZzTegiociUR8hfWJbyaGpq6p+6lQSHgRIm5ZEKRCYFQ9bjYlKwGzdu6KRgIWCguCQFQ8K1qpKCqSOt9dyPICHi/uPHj+u0eQEgyALPkHLQmJs2Dx77ps2rlFiy89atW9d870CXsnLz5s1RpXUETiyphi2ZehWtxEq9unnz5mOPHj263+xKLpQyOTn5VWtrKzJp7zPKU6/KrNG+abzVsOWanLijo+OETk7sX+AREjkb7smJZevwDFfOsAVyiG9e6bs7OX33RZ2+2y5K+u5LnL6706hT+m61L1ET3Lca7gnukdRdJ7ivnOC+1QiZ4F6FIkOXhAK6aHKIg+joMWLAkPg1vgHMQrE0gCfjbdY7EZWsXyfX+QB78Kphr1W9xB5tZc/WKjDgqW/f4SxqBy+hoKkh/qGj38QvhriIySOeBADCOs3LfFN7I649XNfdXHd40MGebGWP4NVq9k6F4Ruq3IraUtDEEPfQGYE0wGAsjckjmuMWvgm0ngQrGXHJerZx3bewF8+zN2vYK3j2rBEwTLmVRUY5FNlaAAbzFFDHjB5PAMbV6/hG8FRsjIk2cJ3XsQer2ZOV7NESo9QqVBihgMiidvQSTItRgoOmiKdgBWsla1XEJesp672MvZAQWowSCBmiagKhlkUOqXAkIAkpjpL1l344IdQVhrM4X0SFpGpxxOWsr5cvTSleNxM36RK18n+GJEwNAYal3QAAAABJRU5ErkJggg==';
|
||||
// 调用制作二维码方法
|
||||
qr.make();
|
||||
|
||||
var drawModules = qr.getDrawModules();
|
||||
// 遍历drawModules创建svg元素
|
||||
var qrHtml = '';
|
||||
for (var i = 0; i < drawModules.length; i++) {
|
||||
var drawModule = drawModules[i];
|
||||
switch (drawModule.type) {
|
||||
case 'tile':
|
||||
/* 绘制小块 */
|
||||
qrHtml += `<rect x="${drawModule.x}" y="${drawModule.y}" width="${drawModule.width}" height="${drawModule.height}" style="fill: ${drawModule.color};" />`;
|
||||
break;
|
||||
case 'image':
|
||||
/* 绘制图像 */
|
||||
qrHtml += `<image href="${drawModule.imageSrc}" x="${drawModule.x}" y="${drawModule.y}" width="${drawModule.width}" height="${drawModule.height}" />`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
document.getElementById('qrcode').innerHTML = qrHtml;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
> 更多用法大家自行探索咯,期待分享哟~
|
||||
|
||||
### 导出临时文件路径
|
||||
|
||||
原生方式基于`Canvas`的,请自行参阅各平台`Canvas`的导出方式。以下是部分示例:
|
||||
|
||||
- uni-app
|
||||
```javascript
|
||||
// 通过uni.createCanvasContext方式创建绘制上下文的,对应导出API为uni.canvasToTempFilePath
|
||||
// 调用完ctx.draw()方法后不能第一时间导出,否则会异常,需要有一定的延时
|
||||
setTimeout(() => {
|
||||
uni.canvasToTempFilePath(
|
||||
{
|
||||
canvasId: this.canvasId,
|
||||
fileType: this.fileType,
|
||||
width: this.canvasWidth,
|
||||
height: this.canvasHeight,
|
||||
success: res => {
|
||||
console.log(res);
|
||||
},
|
||||
fail: err => {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
// this // 组件内使用必传当前实例
|
||||
);
|
||||
}, 300);
|
||||
```
|
||||
|
||||
- Canvas2D
|
||||
```javascript
|
||||
// 得到base64
|
||||
console.log(canvas.toDataURL());
|
||||
// 得到buffer
|
||||
console.log(canvas.toBuffer());
|
||||
```
|
||||
|
||||
### 保存二维码到本地相册
|
||||
|
||||
必须在导出临时文件路径成功后再执行保存。uni-app通用保存方式(H5除外):
|
||||
```javascript
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: tempFilePath,
|
||||
success: res => {
|
||||
console.log(res);
|
||||
},
|
||||
fail: err => {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
H5可以通过设置`<a>`标签`href`属性的方式进行保存:
|
||||
```javascript
|
||||
const aEle = document.createElement('a');
|
||||
aEle.download = 'uQRCode'; // 设置下载的文件名,默认是'下载'
|
||||
aEle.href = tempFilePath;
|
||||
document.body.appendChild(aEle);
|
||||
aEle.click();
|
||||
aEle.remove(); // 下载之后把创建的元素删除
|
||||
```
|
||||
经过测试,PC端浏览器可以下载,部分安卓自带或第三方浏览器可以下载,安卓微信浏览器不适用,移动端iOS所有浏览器均不适用,差异较大,还是推荐各位导出文件给图片组件显示,然后提示用户通过长按图片进行保存这种方式。
|
||||
|
||||
## uni-app组件方式
|
||||
|
||||
### 安装
|
||||
|
||||
通过uni-app插件市场地址安装:[https://ext.dcloud.net.cn/plugin?id=1287](https://ext.dcloud.net.cn/plugin?id=1287)。详细配置请移步到:文档 > [uni-app组件](https://uqrcode.cn/doc/document/uni-app.html)。
|
||||
|
||||
### 引入
|
||||
|
||||
uni-app默认为easycom模式,可直接键入`<uqrcode>`标签。
|
||||
|
||||
### 简单用法
|
||||
|
||||
安装`uqrcode`组件后,在`template`中键入`<uqrcode/>`。设置`ref`属性可使用组件内部方法,`canvas-id`属性为组件内部的canvas组件标识,`value`属性为二维码生成对应内容,`options`为配置选项,可配置二维码样式,绘制Logo等,详见:[options](https://uqrcode.cn/doc/document/uni-app.html#options) 。
|
||||
|
||||
``` html
|
||||
<uqrcode ref="uqrcode" canvas-id="qrcode" value="https://uqrcode.cn/doc" :options="{ margin: 10 }"></uqrcode>
|
||||
```
|
||||
|
||||
### 导出临时文件路径
|
||||
|
||||
为了保证方法调用成功,请在 [complete](https://uqrcode.cn/doc/document/uni-app.html#complete) 事件返回`success=true`后调用。
|
||||
|
||||
```javascript
|
||||
// uqrcode为组件的ref名称
|
||||
this.$refs.uqrcode.toTempFilePath({
|
||||
success: res => {
|
||||
console.log(res);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 保存二维码到本地相册
|
||||
|
||||
为了保证方法调用成功,请在 [complete](https://uqrcode.cn/doc/document/uni-app.html#complete) 事件返回`success=true`后调用。
|
||||
|
||||
```javascript
|
||||
// uqrcode为组件的ref名称
|
||||
this.$refs.uqrcode.save({
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
icon: 'success',
|
||||
title: '保存成功'
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 更多使用说明请前往官方文档查看:[https://uqrcode.cn/doc](https://uqrcode.cn/doc)。
|
||||
12
uni-im示例/uni_modules/Sansnn-uQRCode/changelog.md
Normal file
12
uni-im示例/uni_modules/Sansnn-uQRCode/changelog.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## 4.0.6(2022-12-12)
|
||||
修复`getDrawModules`,第一次获取结果正常,后续获取`tile`模块不存在的问题;
|
||||
修复安卓type:normal因Canvas API使用了小数或为0的参数导致生成异常的问题(注:安卓非2d Canvas部分API参数不支持携带小数,部分API参数必须大于0)。
|
||||
## 4.0.1(2022-11-28)
|
||||
优化组件loading属性的表现;
|
||||
新增组件type选项normal,以便于在某些条件编译初始为type=2d时还可以选择使用非2d组件类型;
|
||||
修复组件条件编译在其他编辑器语法提示报错;
|
||||
修复原生对es5的支持。
|
||||
## 4.0.0(2022-11-21)
|
||||
v4版本源代码全面开放,开源地址:[https://github.com/Sansnn/uQRCode](https://github.com/Sansnn/uQRCode);
|
||||
|
||||
升级说明:v4为大版本更新,虽然已尽可能兼容上一代版本,但不可避免的还是存在一些细节差异,若更新后出现问题,请参考对照[v3 文档](https://uqrcode.cn/doc/v3),[v4 文档](https://uqrcode.cn/doc)进行修改。
|
||||
1
uni-im示例/uni_modules/Sansnn-uQRCode/common/cache.js
Normal file
1
uni-im示例/uni_modules/Sansnn-uQRCode/common/cache.js
Normal file
@@ -0,0 +1 @@
|
||||
export const cacheImageList = [];
|
||||
41
uni-im示例/uni_modules/Sansnn-uQRCode/common/queue.js
Normal file
41
uni-im示例/uni_modules/Sansnn-uQRCode/common/queue.js
Normal file
@@ -0,0 +1,41 @@
|
||||
function Queue() {
|
||||
let waitingQueue = this.waitingQueue = [];
|
||||
let isRunning = this.isRunning = false; // 记录是否有未完成的任务
|
||||
|
||||
function execute(task, resolve, reject) {
|
||||
task()
|
||||
.then((data) => {
|
||||
resolve(data);
|
||||
})
|
||||
.catch((e) => {
|
||||
reject(e);
|
||||
})
|
||||
.finally(() => {
|
||||
// 等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态
|
||||
if (waitingQueue.length) {
|
||||
const next = waitingQueue.shift();
|
||||
execute(next.task, next.resolve, next.reject);
|
||||
} else {
|
||||
isRunning = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.exec = function(task) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (isRunning) {
|
||||
waitingQueue.push({
|
||||
task,
|
||||
resolve,
|
||||
reject
|
||||
});
|
||||
} else {
|
||||
isRunning = true;
|
||||
execute(task, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* 队列实例,某些平台一起使用多个组件时需要通过队列逐一绘制,否则部分绘制方法异常,nvue端的iOS gcanvas尤其明显,在不通过队列绘制时会出现图片丢失的情况 */
|
||||
export const queueDraw = new Queue();
|
||||
export const queueLoadImage = new Queue();
|
||||
3
uni-im示例/uni_modules/Sansnn-uQRCode/common/types/cache.d.ts
vendored
Normal file
3
uni-im示例/uni_modules/Sansnn-uQRCode/common/types/cache.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare module '*/common/cache' {
|
||||
export const cacheImageList: Array;
|
||||
}
|
||||
4
uni-im示例/uni_modules/Sansnn-uQRCode/common/types/queue.d.ts
vendored
Normal file
4
uni-im示例/uni_modules/Sansnn-uQRCode/common/types/queue.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module '*/common/queue' {
|
||||
export const queueDraw: any;
|
||||
export const queueLoadImage: any;
|
||||
}
|
||||
1131
uni-im示例/uni_modules/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue
Normal file
1131
uni-im示例/uni_modules/Sansnn-uQRCode/components/u-qrcode/u-qrcode.vue
Normal file
File diff suppressed because one or more lines are too long
1131
uni-im示例/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue
Normal file
1131
uni-im示例/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode.vue
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,241 @@
|
||||
const isWeex = typeof WXEnvironment !== 'undefined';
|
||||
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
|
||||
const isWeexAndroid = isWeex && !isWeexIOS;
|
||||
|
||||
import GLmethod from '../context-webgl/GLmethod';
|
||||
|
||||
const GCanvasModule =
|
||||
(typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
|
||||
(typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};
|
||||
|
||||
let isDebugging = false;
|
||||
|
||||
let isComboDisabled = false;
|
||||
|
||||
const logCommand = (function () {
|
||||
const methodQuery = [];
|
||||
Object.keys(GLmethod).forEach(key => {
|
||||
methodQuery[GLmethod[key]] = key;
|
||||
})
|
||||
const queryMethod = (id) => {
|
||||
return methodQuery[parseInt(id)] || 'NotFoundMethod';
|
||||
}
|
||||
const logCommand = (id, cmds) => {
|
||||
const mId = cmds.split(',')[0];
|
||||
const mName = queryMethod(mId);
|
||||
console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
|
||||
}
|
||||
return logCommand;
|
||||
})();
|
||||
|
||||
function joinArray(arr, sep) {
|
||||
let res = '';
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (i !== 0) {
|
||||
res += sep;
|
||||
}
|
||||
res += arr[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const commandsCache = {}
|
||||
|
||||
const GBridge = {
|
||||
|
||||
callEnable: (ref, configArray) => {
|
||||
|
||||
commandsCache[ref] = [];
|
||||
|
||||
return GCanvasModule.enable({
|
||||
componentId: ref,
|
||||
config: configArray
|
||||
});
|
||||
},
|
||||
|
||||
callEnableDebug: () => {
|
||||
isDebugging = true;
|
||||
},
|
||||
|
||||
callEnableDisableCombo: () => {
|
||||
isComboDisabled = true;
|
||||
},
|
||||
|
||||
callSetContextType: function (componentId, context_type) {
|
||||
GCanvasModule.setContextType(context_type, componentId);
|
||||
},
|
||||
|
||||
callReset: function(id){
|
||||
GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
|
||||
},
|
||||
|
||||
render: isWeexIOS ? function (componentId) {
|
||||
return GCanvasModule.extendCallNative({
|
||||
contextId: componentId,
|
||||
type: 0x60000001
|
||||
});
|
||||
} : function (componentId) {
|
||||
return callGCanvasLinkNative(componentId, 0x60000001, 'render');
|
||||
},
|
||||
|
||||
render2d: isWeexIOS ? function (componentId, commands, callback) {
|
||||
|
||||
if (isDebugging) {
|
||||
console.log('>>> >>> render2d ===');
|
||||
console.log('>>> commands: ' + commands);
|
||||
}
|
||||
|
||||
GCanvasModule.render([commands, callback?true:false], componentId, callback);
|
||||
|
||||
} : function (componentId, commands,callback) {
|
||||
|
||||
if (isDebugging) {
|
||||
console.log('>>> >>> render2d ===');
|
||||
console.log('>>> commands: ' + commands);
|
||||
}
|
||||
|
||||
callGCanvasLinkNative(componentId, 0x20000001, commands);
|
||||
if(callback){
|
||||
callback();
|
||||
}
|
||||
},
|
||||
|
||||
callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) {
|
||||
|
||||
throw 'should not be here anymore ' + cmdArgs;
|
||||
|
||||
} : function (componentId, cmdArgs) {
|
||||
|
||||
throw 'should not be here anymore ' + cmdArgs;
|
||||
|
||||
},
|
||||
|
||||
|
||||
flushNative: isWeexIOS ? function (componentId) {
|
||||
|
||||
const cmdArgs = joinArray(commandsCache[componentId], ';');
|
||||
commandsCache[componentId] = [];
|
||||
|
||||
if (isDebugging) {
|
||||
console.log('>>> >>> flush native ===');
|
||||
console.log('>>> commands: ' + cmdArgs);
|
||||
}
|
||||
|
||||
const result = GCanvasModule.extendCallNative({
|
||||
"contextId": componentId,
|
||||
"type": 0x60000000,
|
||||
"args": cmdArgs
|
||||
});
|
||||
|
||||
const res = result && result.result;
|
||||
|
||||
if (isDebugging) {
|
||||
console.log('>>> result: ' + res);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
} : function (componentId) {
|
||||
|
||||
const cmdArgs = joinArray(commandsCache[componentId], ';');
|
||||
commandsCache[componentId] = [];
|
||||
|
||||
if (isDebugging) {
|
||||
console.log('>>> >>> flush native ===');
|
||||
console.log('>>> commands: ' + cmdArgs);
|
||||
}
|
||||
|
||||
const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);
|
||||
|
||||
if (isDebugging) {
|
||||
console.log('>>> result: ' + result);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
callNative: function (componentId, cmdArgs, cache) {
|
||||
|
||||
if (isDebugging) {
|
||||
logCommand(componentId, cmdArgs);
|
||||
}
|
||||
|
||||
commandsCache[componentId].push(cmdArgs);
|
||||
|
||||
if (!cache || isComboDisabled) {
|
||||
return GBridge.flushNative(componentId);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
texImage2D(componentId, ...args) {
|
||||
if (isWeexIOS) {
|
||||
if (args.length === 6) {
|
||||
const [target, level, internalformat, format, type, image] = args;
|
||||
GBridge.callNative(
|
||||
componentId,
|
||||
GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src
|
||||
)
|
||||
} else if (args.length === 9) {
|
||||
const [target, level, internalformat, width, height, border, format, type, image] = args;
|
||||
GBridge.callNative(
|
||||
componentId,
|
||||
GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' +
|
||||
+ format + ',' + type + ',' + (image ? image.src : 0)
|
||||
)
|
||||
}
|
||||
} else if (isWeexAndroid) {
|
||||
if (args.length === 6) {
|
||||
const [target, level, internalformat, format, type, image] = args;
|
||||
GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
|
||||
} else if (args.length === 9) {
|
||||
const [target, level, internalformat, width, height, border, format, type, image] = args;
|
||||
GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
|
||||
if (isWeexIOS) {
|
||||
if (arguments.length === 8) {
|
||||
GBridge.callNative(
|
||||
componentId,
|
||||
GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src
|
||||
)
|
||||
}
|
||||
} else if (isWeexAndroid) {
|
||||
GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
|
||||
}
|
||||
},
|
||||
|
||||
bindImageTexture(componentId, src, imageId) {
|
||||
GCanvasModule.bindImageTexture([src, imageId], componentId);
|
||||
},
|
||||
|
||||
perloadImage([url, id], callback) {
|
||||
GCanvasModule.preLoadImage([url, id], function (image) {
|
||||
image.url = url;
|
||||
image.id = id;
|
||||
callback(image);
|
||||
});
|
||||
},
|
||||
|
||||
measureText(text, fontStyle, componentId) {
|
||||
return GCanvasModule.measureText([text, fontStyle], componentId);
|
||||
},
|
||||
|
||||
getImageData (componentId, x, y, w, h, callback) {
|
||||
GCanvasModule.getImageData([x, y,w,h],componentId,callback);
|
||||
},
|
||||
|
||||
putImageData (componentId, data, x, y, w, h, callback) {
|
||||
GCanvasModule.putImageData([x, y,w,h,data],componentId,callback);
|
||||
},
|
||||
|
||||
toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){
|
||||
GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback);
|
||||
}
|
||||
}
|
||||
|
||||
export default GBridge;
|
||||
@@ -0,0 +1,18 @@
|
||||
class FillStyleLinearGradient {
|
||||
|
||||
constructor(x0, y0, x1, y1) {
|
||||
this._start_pos = { _x: x0, _y: y0 };
|
||||
this._end_pos = { _x: x1, _y: y1 };
|
||||
this._stop_count = 0;
|
||||
this._stops = [0, 0, 0, 0, 0];
|
||||
}
|
||||
|
||||
addColorStop = function (pos, color) {
|
||||
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
|
||||
this._stops[this._stop_count] = { _pos: pos, _color: color };
|
||||
this._stop_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default FillStyleLinearGradient;
|
||||
@@ -0,0 +1,8 @@
|
||||
class FillStylePattern {
|
||||
constructor(img, pattern) {
|
||||
this._style = pattern;
|
||||
this._img = img;
|
||||
}
|
||||
}
|
||||
|
||||
export default FillStylePattern;
|
||||
@@ -0,0 +1,17 @@
|
||||
class FillStyleRadialGradient {
|
||||
constructor(x0, y0, r0, x1, y1, r1) {
|
||||
this._start_pos = { _x: x0, _y: y0, _r: r0 };
|
||||
this._end_pos = { _x: x1, _y: y1, _r: r1 };
|
||||
this._stop_count = 0;
|
||||
this._stops = [0, 0, 0, 0, 0];
|
||||
}
|
||||
|
||||
addColorStop(pos, color) {
|
||||
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
|
||||
this._stops[this._stop_count] = { _pos: pos, _color: color };
|
||||
this._stop_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default FillStyleRadialGradient;
|
||||
@@ -0,0 +1,666 @@
|
||||
import FillStylePattern from './FillStylePattern';
|
||||
import FillStyleLinearGradient from './FillStyleLinearGradient';
|
||||
import FillStyleRadialGradient from './FillStyleRadialGradient';
|
||||
import GImage from '../env/image.js';
|
||||
import {
|
||||
ArrayBufferToBase64,
|
||||
Base64ToUint8ClampedArray
|
||||
} from '../env/tool.js';
|
||||
|
||||
export default class CanvasRenderingContext2D {
|
||||
|
||||
_drawCommands = '';
|
||||
|
||||
_globalAlpha = 1.0;
|
||||
|
||||
_fillStyle = 'rgb(0,0,0)';
|
||||
_strokeStyle = 'rgb(0,0,0)';
|
||||
|
||||
_lineWidth = 1;
|
||||
_lineCap = 'butt';
|
||||
_lineJoin = 'miter';
|
||||
|
||||
_miterLimit = 10;
|
||||
|
||||
_globalCompositeOperation = 'source-over';
|
||||
|
||||
_textAlign = 'start';
|
||||
_textBaseline = 'alphabetic';
|
||||
|
||||
_font = '10px sans-serif';
|
||||
|
||||
_savedGlobalAlpha = [];
|
||||
|
||||
timer = null;
|
||||
componentId = null;
|
||||
|
||||
_notCommitDrawImageCache = [];
|
||||
_needRedrawImageCache = [];
|
||||
_redrawCommands = '';
|
||||
_autoSaveContext = true;
|
||||
// _imageMap = new GHashMap();
|
||||
// _textureMap = new GHashMap();
|
||||
|
||||
constructor() {
|
||||
this.className = 'CanvasRenderingContext2D';
|
||||
//this.save()
|
||||
}
|
||||
|
||||
setFillStyle(value) {
|
||||
this.fillStyle = value;
|
||||
}
|
||||
|
||||
set fillStyle(value) {
|
||||
this._fillStyle = value;
|
||||
|
||||
if (typeof(value) == 'string') {
|
||||
this._drawCommands = this._drawCommands.concat("F" + value + ";");
|
||||
} else if (value instanceof FillStylePattern) {
|
||||
const image = value._img;
|
||||
if (!image.complete) {
|
||||
image.onload = () => {
|
||||
var index = this._needRedrawImageCache.indexOf(image);
|
||||
if (index > -1) {
|
||||
this._needRedrawImageCache.splice(index, 1);
|
||||
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||
this._redrawflush(true);
|
||||
}
|
||||
}
|
||||
this._notCommitDrawImageCache.push(image);
|
||||
} else {
|
||||
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||
}
|
||||
|
||||
//CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
|
||||
} else if (value instanceof FillStyleLinearGradient) {
|
||||
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
|
||||
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
|
||||
value._stop_count;
|
||||
for (var i = 0; i < value._stop_count; ++i) {
|
||||
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
|
||||
}
|
||||
this._drawCommands = this._drawCommands.concat(command + ";");
|
||||
} else if (value instanceof FillStyleRadialGradient) {
|
||||
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
|
||||
.toFixed(2) + "," +
|
||||
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," +
|
||||
value._stop_count;
|
||||
for (var i = 0; i < value._stop_count; ++i) {
|
||||
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
|
||||
}
|
||||
this._drawCommands = this._drawCommands.concat(command + ";");
|
||||
}
|
||||
}
|
||||
|
||||
get fillStyle() {
|
||||
return this._fillStyle;
|
||||
}
|
||||
|
||||
get globalAlpha() {
|
||||
return this._globalAlpha;
|
||||
}
|
||||
|
||||
setGlobalAlpha(value) {
|
||||
this.globalAlpha = value;
|
||||
}
|
||||
|
||||
set globalAlpha(value) {
|
||||
this._globalAlpha = value;
|
||||
this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
|
||||
get strokeStyle() {
|
||||
return this._strokeStyle;
|
||||
}
|
||||
|
||||
setStrokeStyle(value) {
|
||||
this.strokeStyle = value;
|
||||
}
|
||||
|
||||
set strokeStyle(value) {
|
||||
|
||||
this._strokeStyle = value;
|
||||
|
||||
if (typeof(value) == 'string') {
|
||||
this._drawCommands = this._drawCommands.concat("S" + value + ";");
|
||||
} else if (value instanceof FillStylePattern) {
|
||||
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
|
||||
} else if (value instanceof FillStyleLinearGradient) {
|
||||
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
|
||||
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
|
||||
value._stop_count;
|
||||
|
||||
for (var i = 0; i < value._stop_count; ++i) {
|
||||
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
|
||||
}
|
||||
this._drawCommands = this._drawCommands.concat(command + ";");
|
||||
} else if (value instanceof FillStyleRadialGradient) {
|
||||
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
|
||||
.toFixed(2) + "," +
|
||||
value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," +
|
||||
value._stop_count;
|
||||
|
||||
for (var i = 0; i < value._stop_count; ++i) {
|
||||
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
|
||||
}
|
||||
this._drawCommands = this._drawCommands.concat(command + ";");
|
||||
}
|
||||
}
|
||||
|
||||
get lineWidth() {
|
||||
return this._lineWidth;
|
||||
}
|
||||
|
||||
setLineWidth(value) {
|
||||
this.lineWidth = value;
|
||||
}
|
||||
|
||||
set lineWidth(value) {
|
||||
this._lineWidth = value;
|
||||
this._drawCommands = this._drawCommands.concat("W" + value + ";");
|
||||
}
|
||||
|
||||
get lineCap() {
|
||||
return this._lineCap;
|
||||
}
|
||||
|
||||
setLineCap(value) {
|
||||
this.lineCap = value;
|
||||
}
|
||||
|
||||
set lineCap(value) {
|
||||
this._lineCap = value;
|
||||
this._drawCommands = this._drawCommands.concat("C" + value + ";");
|
||||
}
|
||||
|
||||
get lineJoin() {
|
||||
return this._lineJoin;
|
||||
}
|
||||
|
||||
setLineJoin(value) {
|
||||
this.lineJoin = value
|
||||
}
|
||||
|
||||
set lineJoin(value) {
|
||||
this._lineJoin = value;
|
||||
this._drawCommands = this._drawCommands.concat("J" + value + ";");
|
||||
}
|
||||
|
||||
get miterLimit() {
|
||||
return this._miterLimit;
|
||||
}
|
||||
|
||||
setMiterLimit(value) {
|
||||
this.miterLimit = value
|
||||
}
|
||||
|
||||
set miterLimit(value) {
|
||||
this._miterLimit = value;
|
||||
this._drawCommands = this._drawCommands.concat("M" + value + ";");
|
||||
}
|
||||
|
||||
get globalCompositeOperation() {
|
||||
return this._globalCompositeOperation;
|
||||
}
|
||||
|
||||
set globalCompositeOperation(value) {
|
||||
|
||||
this._globalCompositeOperation = value;
|
||||
let mode = 0;
|
||||
switch (value) {
|
||||
case "source-over":
|
||||
mode = 0;
|
||||
break;
|
||||
case "source-atop":
|
||||
mode = 5;
|
||||
break;
|
||||
case "source-in":
|
||||
mode = 0;
|
||||
break;
|
||||
case "source-out":
|
||||
mode = 2;
|
||||
break;
|
||||
case "destination-over":
|
||||
mode = 4;
|
||||
break;
|
||||
case "destination-atop":
|
||||
mode = 4;
|
||||
break;
|
||||
case "destination-in":
|
||||
mode = 4;
|
||||
break;
|
||||
case "destination-out":
|
||||
mode = 3;
|
||||
break;
|
||||
case "lighter":
|
||||
mode = 1;
|
||||
break;
|
||||
case "copy":
|
||||
mode = 2;
|
||||
break;
|
||||
case "xor":
|
||||
mode = 6;
|
||||
break;
|
||||
default:
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
this._drawCommands = this._drawCommands.concat("B" + mode + ";");
|
||||
}
|
||||
|
||||
get textAlign() {
|
||||
return this._textAlign;
|
||||
}
|
||||
|
||||
setTextAlign(value) {
|
||||
this.textAlign = value
|
||||
}
|
||||
|
||||
set textAlign(value) {
|
||||
|
||||
this._textAlign = value;
|
||||
let Align = 0;
|
||||
switch (value) {
|
||||
case "start":
|
||||
Align = 0;
|
||||
break;
|
||||
case "end":
|
||||
Align = 1;
|
||||
break;
|
||||
case "left":
|
||||
Align = 2;
|
||||
break;
|
||||
case "center":
|
||||
Align = 3;
|
||||
break;
|
||||
case "right":
|
||||
Align = 4;
|
||||
break;
|
||||
default:
|
||||
Align = 0;
|
||||
}
|
||||
|
||||
this._drawCommands = this._drawCommands.concat("A" + Align + ";");
|
||||
}
|
||||
|
||||
get textBaseline() {
|
||||
return this._textBaseline;
|
||||
}
|
||||
|
||||
setTextBaseline(value) {
|
||||
this.textBaseline = value
|
||||
}
|
||||
|
||||
set textBaseline(value) {
|
||||
this._textBaseline = value;
|
||||
let baseline = 0;
|
||||
switch (value) {
|
||||
case "alphabetic":
|
||||
baseline = 0;
|
||||
break;
|
||||
case "middle":
|
||||
baseline = 1;
|
||||
break;
|
||||
case "top":
|
||||
baseline = 2;
|
||||
break;
|
||||
case "hanging":
|
||||
baseline = 3;
|
||||
break;
|
||||
case "bottom":
|
||||
baseline = 4;
|
||||
break;
|
||||
case "ideographic":
|
||||
baseline = 5;
|
||||
break;
|
||||
default:
|
||||
baseline = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
this._drawCommands = this._drawCommands.concat("E" + baseline + ";");
|
||||
}
|
||||
|
||||
get font() {
|
||||
return this._font;
|
||||
}
|
||||
|
||||
setFontSize(size) {
|
||||
var str = this._font;
|
||||
var strs = str.trim().split(/\s+/);
|
||||
for (var i = 0; i < strs.length; i++) {
|
||||
var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold",
|
||||
"bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900",
|
||||
"normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
|
||||
"semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
|
||||
];
|
||||
|
||||
if (-1 == values.indexOf(strs[i].trim())) {
|
||||
if (typeof size === 'string') {
|
||||
strs[i] = size;
|
||||
} else if (typeof size === 'number') {
|
||||
strs[i] = String(size) + 'px';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.font = strs.join(" ");
|
||||
}
|
||||
|
||||
set font(value) {
|
||||
this._font = value;
|
||||
this._drawCommands = this._drawCommands.concat("j" + value + ";");
|
||||
}
|
||||
|
||||
setTransform(a, b, c, d, tx, ty) {
|
||||
this._drawCommands = this._drawCommands.concat("t" +
|
||||
(a === 1 ? "1" : a.toFixed(2)) + "," +
|
||||
(b === 0 ? "0" : b.toFixed(2)) + "," +
|
||||
(c === 0 ? "0" : c.toFixed(2)) + "," +
|
||||
(d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
transform(a, b, c, d, tx, ty) {
|
||||
this._drawCommands = this._drawCommands.concat("f" +
|
||||
(a === 1 ? "1" : a.toFixed(2)) + "," +
|
||||
(b === 0 ? "0" : b.toFixed(2)) + "," +
|
||||
(c === 0 ? "0" : c.toFixed(2)) + "," +
|
||||
(d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";");
|
||||
}
|
||||
|
||||
resetTransform() {
|
||||
this._drawCommands = this._drawCommands.concat("m;");
|
||||
}
|
||||
|
||||
scale(a, d) {
|
||||
this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," +
|
||||
d.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
rotate(angle) {
|
||||
this._drawCommands = this._drawCommands
|
||||
.concat("r" + angle.toFixed(6) + ";");
|
||||
}
|
||||
|
||||
translate(tx, ty) {
|
||||
this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
save() {
|
||||
this._savedGlobalAlpha.push(this._globalAlpha);
|
||||
this._drawCommands = this._drawCommands.concat("v;");
|
||||
}
|
||||
|
||||
restore() {
|
||||
this._drawCommands = this._drawCommands.concat("e;");
|
||||
this._globalAlpha = this._savedGlobalAlpha.pop();
|
||||
}
|
||||
|
||||
createPattern(img, pattern) {
|
||||
if (typeof img === 'string') {
|
||||
var imgObj = new GImage();
|
||||
imgObj.src = img;
|
||||
img = imgObj;
|
||||
}
|
||||
return new FillStylePattern(img, pattern);
|
||||
}
|
||||
|
||||
createLinearGradient(x0, y0, x1, y1) {
|
||||
return new FillStyleLinearGradient(x0, y0, x1, y1);
|
||||
}
|
||||
|
||||
createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
|
||||
return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1);
|
||||
};
|
||||
|
||||
createCircularGradient = function(x0, y0, r0) {
|
||||
return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0);
|
||||
};
|
||||
|
||||
strokeRect(x, y, w, h) {
|
||||
this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";");
|
||||
}
|
||||
|
||||
|
||||
clearRect(x, y, w, h) {
|
||||
this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w +
|
||||
"," + h + ";");
|
||||
}
|
||||
|
||||
clip() {
|
||||
this._drawCommands = this._drawCommands.concat("p;");
|
||||
}
|
||||
|
||||
resetClip() {
|
||||
this._drawCommands = this._drawCommands.concat("q;");
|
||||
}
|
||||
|
||||
closePath() {
|
||||
this._drawCommands = this._drawCommands.concat("o;");
|
||||
}
|
||||
|
||||
moveTo(x, y) {
|
||||
this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
lineTo(x, y) {
|
||||
this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
quadraticCurveTo = function(cpx, cpy, x, y) {
|
||||
this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";");
|
||||
}
|
||||
|
||||
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) {
|
||||
this._drawCommands = this._drawCommands.concat(
|
||||
"z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," +
|
||||
x.toFixed(2) + "," + y.toFixed(2) + ";");
|
||||
}
|
||||
|
||||
arcTo(x1, y1, x2, y2, radius) {
|
||||
this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";");
|
||||
}
|
||||
|
||||
beginPath() {
|
||||
this._drawCommands = this._drawCommands.concat("b;");
|
||||
}
|
||||
|
||||
|
||||
fillRect(x, y, w, h) {
|
||||
this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w +
|
||||
"," + h + ";");
|
||||
}
|
||||
|
||||
rect(x, y, w, h) {
|
||||
this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";");
|
||||
}
|
||||
|
||||
fill() {
|
||||
this._drawCommands = this._drawCommands.concat("L;");
|
||||
}
|
||||
|
||||
stroke(path) {
|
||||
this._drawCommands = this._drawCommands.concat("x;");
|
||||
}
|
||||
|
||||
arc(x, y, radius, startAngle, endAngle, anticlockwise) {
|
||||
|
||||
let ianticlockwise = 0;
|
||||
if (anticlockwise) {
|
||||
ianticlockwise = 1;
|
||||
}
|
||||
|
||||
this._drawCommands = this._drawCommands.concat(
|
||||
"y" + x.toFixed(2) + "," + y.toFixed(2) + "," +
|
||||
radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise +
|
||||
";"
|
||||
);
|
||||
}
|
||||
|
||||
fillText(text, x, y) {
|
||||
let tmptext = text.replace(/!/g, "!!");
|
||||
tmptext = tmptext.replace(/,/g, "!,");
|
||||
tmptext = tmptext.replace(/;/g, "!;");
|
||||
this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;");
|
||||
}
|
||||
|
||||
strokeText = function(text, x, y) {
|
||||
let tmptext = text.replace(/!/g, "!!");
|
||||
tmptext = tmptext.replace(/,/g, "!,");
|
||||
tmptext = tmptext.replace(/;/g, "!;");
|
||||
this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;");
|
||||
}
|
||||
|
||||
measureText(text) {
|
||||
return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId);
|
||||
}
|
||||
|
||||
isPointInPath = function(x, y) {
|
||||
throw new Error('GCanvas not supported yet');
|
||||
}
|
||||
|
||||
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
if (typeof image === 'string') {
|
||||
var imgObj = new GImage();
|
||||
imgObj.src = image;
|
||||
image = imgObj;
|
||||
}
|
||||
if (image instanceof GImage) {
|
||||
if (!image.complete) {
|
||||
imgObj.onload = () => {
|
||||
var index = this._needRedrawImageCache.indexOf(image);
|
||||
if (index > -1) {
|
||||
this._needRedrawImageCache.splice(index, 1);
|
||||
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||
this._redrawflush(true);
|
||||
}
|
||||
}
|
||||
this._notCommitDrawImageCache.push(image);
|
||||
} else {
|
||||
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
|
||||
}
|
||||
var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh];
|
||||
var args = [];
|
||||
for (var arg in srcArgs) {
|
||||
if (typeof(srcArgs[arg]) != 'undefined') {
|
||||
args.push(srcArgs[arg]);
|
||||
}
|
||||
}
|
||||
this.__drawImage.apply(this, args);
|
||||
//this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
}
|
||||
}
|
||||
|
||||
__drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
const numArgs = arguments.length;
|
||||
|
||||
function drawImageCommands() {
|
||||
|
||||
if (numArgs === 3) {
|
||||
const x = parseFloat(sx) || 0.0;
|
||||
const y = parseFloat(sy) || 0.0;
|
||||
|
||||
return ("d" + image._id + ",0,0," +
|
||||
image.width + "," + image.height + "," +
|
||||
x + "," + y + "," + image.width + "," + image.height + ";");
|
||||
} else if (numArgs === 5) {
|
||||
const x = parseFloat(sx) || 0.0;
|
||||
const y = parseFloat(sy) || 0.0;
|
||||
const width = parseInt(sw) || image.width;
|
||||
const height = parseInt(sh) || image.height;
|
||||
|
||||
return ("d" + image._id + ",0,0," +
|
||||
image.width + "," + image.height + "," +
|
||||
x + "," + y + "," + width + "," + height + ";");
|
||||
} else if (numArgs === 9) {
|
||||
sx = parseFloat(sx) || 0.0;
|
||||
sy = parseFloat(sy) || 0.0;
|
||||
sw = parseInt(sw) || image.width;
|
||||
sh = parseInt(sh) || image.height;
|
||||
dx = parseFloat(dx) || 0.0;
|
||||
dy = parseFloat(dy) || 0.0;
|
||||
dw = parseInt(dw) || image.width;
|
||||
dh = parseInt(dh) || image.height;
|
||||
|
||||
return ("d" + image._id + "," +
|
||||
sx + "," + sy + "," + sw + "," + sh + "," +
|
||||
dx + "," + dy + "," + dw + "," + dh + ";");
|
||||
}
|
||||
}
|
||||
this._drawCommands += drawImageCommands();
|
||||
}
|
||||
|
||||
_flush(reserve, callback) {
|
||||
const commands = this._drawCommands;
|
||||
this._drawCommands = '';
|
||||
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
|
||||
this._needRender = false;
|
||||
}
|
||||
|
||||
_redrawflush(reserve, callback) {
|
||||
const commands = this._redrawCommands;
|
||||
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
|
||||
if (this._needRedrawImageCache.length == 0) {
|
||||
this._redrawCommands = '';
|
||||
}
|
||||
}
|
||||
|
||||
draw(reserve, callback) {
|
||||
if (!reserve) {
|
||||
this._globalAlpha = this._savedGlobalAlpha.pop();
|
||||
this._savedGlobalAlpha.push(this._globalAlpha);
|
||||
this._redrawCommands = this._drawCommands;
|
||||
this._needRedrawImageCache = this._notCommitDrawImageCache;
|
||||
if (this._autoSaveContext) {
|
||||
this._drawCommands = ("v;" + this._drawCommands);
|
||||
this._autoSaveContext = false;
|
||||
} else {
|
||||
this._drawCommands = ("e;X;v;" + this._drawCommands);
|
||||
}
|
||||
} else {
|
||||
this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache);
|
||||
this._redrawCommands += this._drawCommands;
|
||||
if (this._autoSaveContext) {
|
||||
this._drawCommands = ("v;" + this._drawCommands);
|
||||
this._autoSaveContext = false;
|
||||
}
|
||||
}
|
||||
this._notCommitDrawImageCache = [];
|
||||
if (this._flush) {
|
||||
this._flush(reserve, callback);
|
||||
}
|
||||
}
|
||||
|
||||
getImageData(x, y, w, h, callback) {
|
||||
CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) {
|
||||
res.data = Base64ToUint8ClampedArray(res.data);
|
||||
if (typeof(callback) == 'function') {
|
||||
callback(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
putImageData(data, x, y, w, h, callback) {
|
||||
if (data instanceof Uint8ClampedArray) {
|
||||
data = ArrayBufferToBase64(data);
|
||||
CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) {
|
||||
if (typeof(callback) == 'function') {
|
||||
callback(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
|
||||
CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight,
|
||||
fileType, quality,
|
||||
function(res) {
|
||||
if (typeof(callback) == 'function') {
|
||||
callback(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export default class WebGLActiveInfo {
|
||||
className = 'WebGLActiveInfo';
|
||||
|
||||
constructor({
|
||||
type, name, size
|
||||
}) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLBuffer';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLBuffer {
|
||||
className = name;
|
||||
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLFrameBuffer';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLFramebuffer {
|
||||
className = name;
|
||||
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
export default {
|
||||
"DEPTH_BUFFER_BIT": 256,
|
||||
"STENCIL_BUFFER_BIT": 1024,
|
||||
"COLOR_BUFFER_BIT": 16384,
|
||||
"POINTS": 0,
|
||||
"LINES": 1,
|
||||
"LINE_LOOP": 2,
|
||||
"LINE_STRIP": 3,
|
||||
"TRIANGLES": 4,
|
||||
"TRIANGLE_STRIP": 5,
|
||||
"TRIANGLE_FAN": 6,
|
||||
"ZERO": 0,
|
||||
"ONE": 1,
|
||||
"SRC_COLOR": 768,
|
||||
"ONE_MINUS_SRC_COLOR": 769,
|
||||
"SRC_ALPHA": 770,
|
||||
"ONE_MINUS_SRC_ALPHA": 771,
|
||||
"DST_ALPHA": 772,
|
||||
"ONE_MINUS_DST_ALPHA": 773,
|
||||
"DST_COLOR": 774,
|
||||
"ONE_MINUS_DST_COLOR": 775,
|
||||
"SRC_ALPHA_SATURATE": 776,
|
||||
"FUNC_ADD": 32774,
|
||||
"BLEND_EQUATION": 32777,
|
||||
"BLEND_EQUATION_RGB": 32777,
|
||||
"BLEND_EQUATION_ALPHA": 34877,
|
||||
"FUNC_SUBTRACT": 32778,
|
||||
"FUNC_REVERSE_SUBTRACT": 32779,
|
||||
"BLEND_DST_RGB": 32968,
|
||||
"BLEND_SRC_RGB": 32969,
|
||||
"BLEND_DST_ALPHA": 32970,
|
||||
"BLEND_SRC_ALPHA": 32971,
|
||||
"CONSTANT_COLOR": 32769,
|
||||
"ONE_MINUS_CONSTANT_COLOR": 32770,
|
||||
"CONSTANT_ALPHA": 32771,
|
||||
"ONE_MINUS_CONSTANT_ALPHA": 32772,
|
||||
"BLEND_COLOR": 32773,
|
||||
"ARRAY_BUFFER": 34962,
|
||||
"ELEMENT_ARRAY_BUFFER": 34963,
|
||||
"ARRAY_BUFFER_BINDING": 34964,
|
||||
"ELEMENT_ARRAY_BUFFER_BINDING": 34965,
|
||||
"STREAM_DRAW": 35040,
|
||||
"STATIC_DRAW": 35044,
|
||||
"DYNAMIC_DRAW": 35048,
|
||||
"BUFFER_SIZE": 34660,
|
||||
"BUFFER_USAGE": 34661,
|
||||
"CURRENT_VERTEX_ATTRIB": 34342,
|
||||
"FRONT": 1028,
|
||||
"BACK": 1029,
|
||||
"FRONT_AND_BACK": 1032,
|
||||
"TEXTURE_2D": 3553,
|
||||
"CULL_FACE": 2884,
|
||||
"BLEND": 3042,
|
||||
"DITHER": 3024,
|
||||
"STENCIL_TEST": 2960,
|
||||
"DEPTH_TEST": 2929,
|
||||
"SCISSOR_TEST": 3089,
|
||||
"POLYGON_OFFSET_FILL": 32823,
|
||||
"SAMPLE_ALPHA_TO_COVERAGE": 32926,
|
||||
"SAMPLE_COVERAGE": 32928,
|
||||
"NO_ERROR": 0,
|
||||
"INVALID_ENUM": 1280,
|
||||
"INVALID_VALUE": 1281,
|
||||
"INVALID_OPERATION": 1282,
|
||||
"OUT_OF_MEMORY": 1285,
|
||||
"CW": 2304,
|
||||
"CCW": 2305,
|
||||
"LINE_WIDTH": 2849,
|
||||
"ALIASED_POINT_SIZE_RANGE": 33901,
|
||||
"ALIASED_LINE_WIDTH_RANGE": 33902,
|
||||
"CULL_FACE_MODE": 2885,
|
||||
"FRONT_FACE": 2886,
|
||||
"DEPTH_RANGE": 2928,
|
||||
"DEPTH_WRITEMASK": 2930,
|
||||
"DEPTH_CLEAR_VALUE": 2931,
|
||||
"DEPTH_FUNC": 2932,
|
||||
"STENCIL_CLEAR_VALUE": 2961,
|
||||
"STENCIL_FUNC": 2962,
|
||||
"STENCIL_FAIL": 2964,
|
||||
"STENCIL_PASS_DEPTH_FAIL": 2965,
|
||||
"STENCIL_PASS_DEPTH_PASS": 2966,
|
||||
"STENCIL_REF": 2967,
|
||||
"STENCIL_VALUE_MASK": 2963,
|
||||
"STENCIL_WRITEMASK": 2968,
|
||||
"STENCIL_BACK_FUNC": 34816,
|
||||
"STENCIL_BACK_FAIL": 34817,
|
||||
"STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
|
||||
"STENCIL_BACK_PASS_DEPTH_PASS": 34819,
|
||||
"STENCIL_BACK_REF": 36003,
|
||||
"STENCIL_BACK_VALUE_MASK": 36004,
|
||||
"STENCIL_BACK_WRITEMASK": 36005,
|
||||
"VIEWPORT": 2978,
|
||||
"SCISSOR_BOX": 3088,
|
||||
"COLOR_CLEAR_VALUE": 3106,
|
||||
"COLOR_WRITEMASK": 3107,
|
||||
"UNPACK_ALIGNMENT": 3317,
|
||||
"PACK_ALIGNMENT": 3333,
|
||||
"MAX_TEXTURE_SIZE": 3379,
|
||||
"MAX_VIEWPORT_DIMS": 3386,
|
||||
"SUBPIXEL_BITS": 3408,
|
||||
"RED_BITS": 3410,
|
||||
"GREEN_BITS": 3411,
|
||||
"BLUE_BITS": 3412,
|
||||
"ALPHA_BITS": 3413,
|
||||
"DEPTH_BITS": 3414,
|
||||
"STENCIL_BITS": 3415,
|
||||
"POLYGON_OFFSET_UNITS": 10752,
|
||||
"POLYGON_OFFSET_FACTOR": 32824,
|
||||
"TEXTURE_BINDING_2D": 32873,
|
||||
"SAMPLE_BUFFERS": 32936,
|
||||
"SAMPLES": 32937,
|
||||
"SAMPLE_COVERAGE_VALUE": 32938,
|
||||
"SAMPLE_COVERAGE_INVERT": 32939,
|
||||
"COMPRESSED_TEXTURE_FORMATS": 34467,
|
||||
"DONT_CARE": 4352,
|
||||
"FASTEST": 4353,
|
||||
"NICEST": 4354,
|
||||
"GENERATE_MIPMAP_HINT": 33170,
|
||||
"BYTE": 5120,
|
||||
"UNSIGNED_BYTE": 5121,
|
||||
"SHORT": 5122,
|
||||
"UNSIGNED_SHORT": 5123,
|
||||
"INT": 5124,
|
||||
"UNSIGNED_INT": 5125,
|
||||
"FLOAT": 5126,
|
||||
"DEPTH_COMPONENT": 6402,
|
||||
"ALPHA": 6406,
|
||||
"RGB": 6407,
|
||||
"RGBA": 6408,
|
||||
"LUMINANCE": 6409,
|
||||
"LUMINANCE_ALPHA": 6410,
|
||||
"UNSIGNED_SHORT_4_4_4_4": 32819,
|
||||
"UNSIGNED_SHORT_5_5_5_1": 32820,
|
||||
"UNSIGNED_SHORT_5_6_5": 33635,
|
||||
"FRAGMENT_SHADER": 35632,
|
||||
"VERTEX_SHADER": 35633,
|
||||
"MAX_VERTEX_ATTRIBS": 34921,
|
||||
"MAX_VERTEX_UNIFORM_VECTORS": 36347,
|
||||
"MAX_VARYING_VECTORS": 36348,
|
||||
"MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
|
||||
"MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
|
||||
"MAX_TEXTURE_IMAGE_UNITS": 34930,
|
||||
"MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
|
||||
"SHADER_TYPE": 35663,
|
||||
"DELETE_STATUS": 35712,
|
||||
"LINK_STATUS": 35714,
|
||||
"VALIDATE_STATUS": 35715,
|
||||
"ATTACHED_SHADERS": 35717,
|
||||
"ACTIVE_UNIFORMS": 35718,
|
||||
"ACTIVE_ATTRIBUTES": 35721,
|
||||
"SHADING_LANGUAGE_VERSION": 35724,
|
||||
"CURRENT_PROGRAM": 35725,
|
||||
"NEVER": 512,
|
||||
"LESS": 513,
|
||||
"EQUAL": 514,
|
||||
"LEQUAL": 515,
|
||||
"GREATER": 516,
|
||||
"NOTEQUAL": 517,
|
||||
"GEQUAL": 518,
|
||||
"ALWAYS": 519,
|
||||
"KEEP": 7680,
|
||||
"REPLACE": 7681,
|
||||
"INCR": 7682,
|
||||
"DECR": 7683,
|
||||
"INVERT": 5386,
|
||||
"INCR_WRAP": 34055,
|
||||
"DECR_WRAP": 34056,
|
||||
"VENDOR": 7936,
|
||||
"RENDERER": 7937,
|
||||
"VERSION": 7938,
|
||||
"NEAREST": 9728,
|
||||
"LINEAR": 9729,
|
||||
"NEAREST_MIPMAP_NEAREST": 9984,
|
||||
"LINEAR_MIPMAP_NEAREST": 9985,
|
||||
"NEAREST_MIPMAP_LINEAR": 9986,
|
||||
"LINEAR_MIPMAP_LINEAR": 9987,
|
||||
"TEXTURE_MAG_FILTER": 10240,
|
||||
"TEXTURE_MIN_FILTER": 10241,
|
||||
"TEXTURE_WRAP_S": 10242,
|
||||
"TEXTURE_WRAP_T": 10243,
|
||||
"TEXTURE": 5890,
|
||||
"TEXTURE_CUBE_MAP": 34067,
|
||||
"TEXTURE_BINDING_CUBE_MAP": 34068,
|
||||
"TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
|
||||
"TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
|
||||
"TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
|
||||
"TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
|
||||
"TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
|
||||
"TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
|
||||
"MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
|
||||
"TEXTURE0": 33984,
|
||||
"TEXTURE1": 33985,
|
||||
"TEXTURE2": 33986,
|
||||
"TEXTURE3": 33987,
|
||||
"TEXTURE4": 33988,
|
||||
"TEXTURE5": 33989,
|
||||
"TEXTURE6": 33990,
|
||||
"TEXTURE7": 33991,
|
||||
"TEXTURE8": 33992,
|
||||
"TEXTURE9": 33993,
|
||||
"TEXTURE10": 33994,
|
||||
"TEXTURE11": 33995,
|
||||
"TEXTURE12": 33996,
|
||||
"TEXTURE13": 33997,
|
||||
"TEXTURE14": 33998,
|
||||
"TEXTURE15": 33999,
|
||||
"TEXTURE16": 34000,
|
||||
"TEXTURE17": 34001,
|
||||
"TEXTURE18": 34002,
|
||||
"TEXTURE19": 34003,
|
||||
"TEXTURE20": 34004,
|
||||
"TEXTURE21": 34005,
|
||||
"TEXTURE22": 34006,
|
||||
"TEXTURE23": 34007,
|
||||
"TEXTURE24": 34008,
|
||||
"TEXTURE25": 34009,
|
||||
"TEXTURE26": 34010,
|
||||
"TEXTURE27": 34011,
|
||||
"TEXTURE28": 34012,
|
||||
"TEXTURE29": 34013,
|
||||
"TEXTURE30": 34014,
|
||||
"TEXTURE31": 34015,
|
||||
"ACTIVE_TEXTURE": 34016,
|
||||
"REPEAT": 10497,
|
||||
"CLAMP_TO_EDGE": 33071,
|
||||
"MIRRORED_REPEAT": 33648,
|
||||
"FLOAT_VEC2": 35664,
|
||||
"FLOAT_VEC3": 35665,
|
||||
"FLOAT_VEC4": 35666,
|
||||
"INT_VEC2": 35667,
|
||||
"INT_VEC3": 35668,
|
||||
"INT_VEC4": 35669,
|
||||
"BOOL": 35670,
|
||||
"BOOL_VEC2": 35671,
|
||||
"BOOL_VEC3": 35672,
|
||||
"BOOL_VEC4": 35673,
|
||||
"FLOAT_MAT2": 35674,
|
||||
"FLOAT_MAT3": 35675,
|
||||
"FLOAT_MAT4": 35676,
|
||||
"SAMPLER_2D": 35678,
|
||||
"SAMPLER_CUBE": 35680,
|
||||
"VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
|
||||
"VERTEX_ATTRIB_ARRAY_SIZE": 34339,
|
||||
"VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
|
||||
"VERTEX_ATTRIB_ARRAY_TYPE": 34341,
|
||||
"VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
|
||||
"VERTEX_ATTRIB_ARRAY_POINTER": 34373,
|
||||
"VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
|
||||
"IMPLEMENTATION_COLOR_READ_TYPE": 35738,
|
||||
"IMPLEMENTATION_COLOR_READ_FORMAT": 35739,
|
||||
"COMPILE_STATUS": 35713,
|
||||
"LOW_FLOAT": 36336,
|
||||
"MEDIUM_FLOAT": 36337,
|
||||
"HIGH_FLOAT": 36338,
|
||||
"LOW_INT": 36339,
|
||||
"MEDIUM_INT": 36340,
|
||||
"HIGH_INT": 36341,
|
||||
"FRAMEBUFFER": 36160,
|
||||
"RENDERBUFFER": 36161,
|
||||
"RGBA4": 32854,
|
||||
"RGB5_A1": 32855,
|
||||
"RGB565": 36194,
|
||||
"DEPTH_COMPONENT16": 33189,
|
||||
"STENCIL_INDEX8": 36168,
|
||||
"DEPTH_STENCIL": 34041,
|
||||
"RENDERBUFFER_WIDTH": 36162,
|
||||
"RENDERBUFFER_HEIGHT": 36163,
|
||||
"RENDERBUFFER_INTERNAL_FORMAT": 36164,
|
||||
"RENDERBUFFER_RED_SIZE": 36176,
|
||||
"RENDERBUFFER_GREEN_SIZE": 36177,
|
||||
"RENDERBUFFER_BLUE_SIZE": 36178,
|
||||
"RENDERBUFFER_ALPHA_SIZE": 36179,
|
||||
"RENDERBUFFER_DEPTH_SIZE": 36180,
|
||||
"RENDERBUFFER_STENCIL_SIZE": 36181,
|
||||
"FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
|
||||
"FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
|
||||
"FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
|
||||
"FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
|
||||
"COLOR_ATTACHMENT0": 36064,
|
||||
"DEPTH_ATTACHMENT": 36096,
|
||||
"STENCIL_ATTACHMENT": 36128,
|
||||
"DEPTH_STENCIL_ATTACHMENT": 33306,
|
||||
"NONE": 0,
|
||||
"FRAMEBUFFER_COMPLETE": 36053,
|
||||
"FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
|
||||
"FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
|
||||
"FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
|
||||
"FRAMEBUFFER_UNSUPPORTED": 36061,
|
||||
"FRAMEBUFFER_BINDING": 36006,
|
||||
"RENDERBUFFER_BINDING": 36007,
|
||||
"MAX_RENDERBUFFER_SIZE": 34024,
|
||||
"INVALID_FRAMEBUFFER_OPERATION": 1286,
|
||||
"UNPACK_FLIP_Y_WEBGL": 37440,
|
||||
"UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
|
||||
"CONTEXT_LOST_WEBGL": 37442,
|
||||
"UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
|
||||
"BROWSER_DEFAULT_WEBGL": 37444
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
let i = 1;
|
||||
|
||||
const GLmethod = {};
|
||||
|
||||
GLmethod.activeTexture = i++; //1
|
||||
GLmethod.attachShader = i++;
|
||||
GLmethod.bindAttribLocation = i++;
|
||||
GLmethod.bindBuffer = i++;
|
||||
GLmethod.bindFramebuffer = i++;
|
||||
GLmethod.bindRenderbuffer = i++;
|
||||
GLmethod.bindTexture = i++;
|
||||
GLmethod.blendColor = i++;
|
||||
GLmethod.blendEquation = i++;
|
||||
GLmethod.blendEquationSeparate = i++; //10
|
||||
GLmethod.blendFunc = i++;
|
||||
GLmethod.blendFuncSeparate = i++;
|
||||
GLmethod.bufferData = i++;
|
||||
GLmethod.bufferSubData = i++;
|
||||
GLmethod.checkFramebufferStatus = i++;
|
||||
GLmethod.clear = i++;
|
||||
GLmethod.clearColor = i++;
|
||||
GLmethod.clearDepth = i++;
|
||||
GLmethod.clearStencil = i++;
|
||||
GLmethod.colorMask = i++; //20
|
||||
GLmethod.compileShader = i++;
|
||||
GLmethod.compressedTexImage2D = i++;
|
||||
GLmethod.compressedTexSubImage2D = i++;
|
||||
GLmethod.copyTexImage2D = i++;
|
||||
GLmethod.copyTexSubImage2D = i++;
|
||||
GLmethod.createBuffer = i++;
|
||||
GLmethod.createFramebuffer = i++;
|
||||
GLmethod.createProgram = i++;
|
||||
GLmethod.createRenderbuffer = i++;
|
||||
GLmethod.createShader = i++; //30
|
||||
GLmethod.createTexture = i++;
|
||||
GLmethod.cullFace = i++;
|
||||
GLmethod.deleteBuffer = i++;
|
||||
GLmethod.deleteFramebuffer = i++;
|
||||
GLmethod.deleteProgram = i++;
|
||||
GLmethod.deleteRenderbuffer = i++;
|
||||
GLmethod.deleteShader = i++;
|
||||
GLmethod.deleteTexture = i++;
|
||||
GLmethod.depthFunc = i++;
|
||||
GLmethod.depthMask = i++; //40
|
||||
GLmethod.depthRange = i++;
|
||||
GLmethod.detachShader = i++;
|
||||
GLmethod.disable = i++;
|
||||
GLmethod.disableVertexAttribArray = i++;
|
||||
GLmethod.drawArrays = i++;
|
||||
GLmethod.drawArraysInstancedANGLE = i++;
|
||||
GLmethod.drawElements = i++;
|
||||
GLmethod.drawElementsInstancedANGLE = i++;
|
||||
GLmethod.enable = i++;
|
||||
GLmethod.enableVertexAttribArray = i++; //50
|
||||
GLmethod.flush = i++;
|
||||
GLmethod.framebufferRenderbuffer = i++;
|
||||
GLmethod.framebufferTexture2D = i++;
|
||||
GLmethod.frontFace = i++;
|
||||
GLmethod.generateMipmap = i++;
|
||||
GLmethod.getActiveAttrib = i++;
|
||||
GLmethod.getActiveUniform = i++;
|
||||
GLmethod.getAttachedShaders = i++;
|
||||
GLmethod.getAttribLocation = i++;
|
||||
GLmethod.getBufferParameter = i++; //60
|
||||
GLmethod.getContextAttributes = i++;
|
||||
GLmethod.getError = i++;
|
||||
GLmethod.getExtension = i++;
|
||||
GLmethod.getFramebufferAttachmentParameter = i++;
|
||||
GLmethod.getParameter = i++;
|
||||
GLmethod.getProgramInfoLog = i++;
|
||||
GLmethod.getProgramParameter = i++;
|
||||
GLmethod.getRenderbufferParameter = i++;
|
||||
GLmethod.getShaderInfoLog = i++;
|
||||
GLmethod.getShaderParameter = i++; //70
|
||||
GLmethod.getShaderPrecisionFormat = i++;
|
||||
GLmethod.getShaderSource = i++;
|
||||
GLmethod.getSupportedExtensions = i++;
|
||||
GLmethod.getTexParameter = i++;
|
||||
GLmethod.getUniform = i++;
|
||||
GLmethod.getUniformLocation = i++;
|
||||
GLmethod.getVertexAttrib = i++;
|
||||
GLmethod.getVertexAttribOffset = i++;
|
||||
GLmethod.isBuffer = i++;
|
||||
GLmethod.isContextLost = i++; //80
|
||||
GLmethod.isEnabled = i++;
|
||||
GLmethod.isFramebuffer = i++;
|
||||
GLmethod.isProgram = i++;
|
||||
GLmethod.isRenderbuffer = i++;
|
||||
GLmethod.isShader = i++;
|
||||
GLmethod.isTexture = i++;
|
||||
GLmethod.lineWidth = i++;
|
||||
GLmethod.linkProgram = i++;
|
||||
GLmethod.pixelStorei = i++;
|
||||
GLmethod.polygonOffset = i++; //90
|
||||
GLmethod.readPixels = i++;
|
||||
GLmethod.renderbufferStorage = i++;
|
||||
GLmethod.sampleCoverage = i++;
|
||||
GLmethod.scissor = i++;
|
||||
GLmethod.shaderSource = i++;
|
||||
GLmethod.stencilFunc = i++;
|
||||
GLmethod.stencilFuncSeparate = i++;
|
||||
GLmethod.stencilMask = i++;
|
||||
GLmethod.stencilMaskSeparate = i++;
|
||||
GLmethod.stencilOp = i++; //100
|
||||
GLmethod.stencilOpSeparate = i++;
|
||||
GLmethod.texImage2D = i++;
|
||||
GLmethod.texParameterf = i++;
|
||||
GLmethod.texParameteri = i++;
|
||||
GLmethod.texSubImage2D = i++;
|
||||
GLmethod.uniform1f = i++;
|
||||
GLmethod.uniform1fv = i++;
|
||||
GLmethod.uniform1i = i++;
|
||||
GLmethod.uniform1iv = i++;
|
||||
GLmethod.uniform2f = i++; //110
|
||||
GLmethod.uniform2fv = i++;
|
||||
GLmethod.uniform2i = i++;
|
||||
GLmethod.uniform2iv = i++;
|
||||
GLmethod.uniform3f = i++;
|
||||
GLmethod.uniform3fv = i++;
|
||||
GLmethod.uniform3i = i++;
|
||||
GLmethod.uniform3iv = i++;
|
||||
GLmethod.uniform4f = i++;
|
||||
GLmethod.uniform4fv = i++;
|
||||
GLmethod.uniform4i = i++; //120
|
||||
GLmethod.uniform4iv = i++;
|
||||
GLmethod.uniformMatrix2fv = i++;
|
||||
GLmethod.uniformMatrix3fv = i++;
|
||||
GLmethod.uniformMatrix4fv = i++;
|
||||
GLmethod.useProgram = i++;
|
||||
GLmethod.validateProgram = i++;
|
||||
GLmethod.vertexAttrib1f = i++; //new
|
||||
GLmethod.vertexAttrib2f = i++; //new
|
||||
GLmethod.vertexAttrib3f = i++; //new
|
||||
GLmethod.vertexAttrib4f = i++; //new //130
|
||||
GLmethod.vertexAttrib1fv = i++; //new
|
||||
GLmethod.vertexAttrib2fv = i++; //new
|
||||
GLmethod.vertexAttrib3fv = i++; //new
|
||||
GLmethod.vertexAttrib4fv = i++; //new
|
||||
GLmethod.vertexAttribPointer = i++;
|
||||
GLmethod.viewport = i++;
|
||||
|
||||
export default GLmethod;
|
||||
@@ -0,0 +1,23 @@
|
||||
const GLtype = {};
|
||||
|
||||
[
|
||||
"GLbitfield",
|
||||
"GLboolean",
|
||||
"GLbyte",
|
||||
"GLclampf",
|
||||
"GLenum",
|
||||
"GLfloat",
|
||||
"GLint",
|
||||
"GLintptr",
|
||||
"GLsizei",
|
||||
"GLsizeiptr",
|
||||
"GLshort",
|
||||
"GLubyte",
|
||||
"GLuint",
|
||||
"GLushort"
|
||||
].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1));
|
||||
|
||||
export default GLtype;
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLProgram';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLProgram {
|
||||
className = name;
|
||||
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLRenderBuffer';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLRenderbuffer {
|
||||
className = name;
|
||||
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLShader';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLShader {
|
||||
className = name;
|
||||
|
||||
constructor(id, type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export default class WebGLShaderPrecisionFormat {
|
||||
className = 'WebGLShaderPrecisionFormat';
|
||||
|
||||
constructor({
|
||||
rangeMin, rangeMax, precision
|
||||
}) {
|
||||
this.rangeMin = rangeMin;
|
||||
this.rangeMax = rangeMax;
|
||||
this.precision = precision;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLTexture';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLTexture {
|
||||
className = name;
|
||||
|
||||
constructor(id, type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import {getTransferedObjectUUID} from './classUtils';
|
||||
|
||||
const name = 'WebGLUniformLocation';
|
||||
|
||||
function uuid(id) {
|
||||
return getTransferedObjectUUID(name, id);
|
||||
}
|
||||
|
||||
export default class WebGLUniformLocation {
|
||||
className = name;
|
||||
|
||||
constructor(id, type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
static uuid = uuid;
|
||||
|
||||
uuid() {
|
||||
return uuid(this.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function getTransferedObjectUUID(name, id) {
|
||||
return `${name.toLowerCase()}-${id}`;
|
||||
}
|
||||
74
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/env/canvas.js
vendored
Normal file
74
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/env/canvas.js
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
import GContext2D from '../context-2d/RenderingContext';
|
||||
import GContextWebGL from '../context-webgl/RenderingContext';
|
||||
|
||||
export default class GCanvas {
|
||||
|
||||
// static GBridge = null;
|
||||
|
||||
id = null;
|
||||
|
||||
_needRender = true;
|
||||
|
||||
constructor(id, { disableAutoSwap }) {
|
||||
this.id = id;
|
||||
|
||||
this._disableAutoSwap = disableAutoSwap;
|
||||
if (disableAutoSwap) {
|
||||
this._swapBuffers = () => {
|
||||
GCanvas.GBridge.render(this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getContext(type) {
|
||||
|
||||
let context = null;
|
||||
|
||||
if (type.match(/webgl/i)) {
|
||||
context = new GContextWebGL(this);
|
||||
|
||||
context.componentId = this.id;
|
||||
|
||||
if (!this._disableAutoSwap) {
|
||||
const render = () => {
|
||||
if (this._needRender) {
|
||||
GCanvas.GBridge.render(this.id);
|
||||
this._needRender = false;
|
||||
}
|
||||
}
|
||||
setInterval(render, 16);
|
||||
}
|
||||
|
||||
GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl
|
||||
} else if (type.match(/2d/i)) {
|
||||
context = new GContext2D(this);
|
||||
|
||||
context.componentId = this.id;
|
||||
|
||||
// const render = ( callback ) => {
|
||||
//
|
||||
// const commands = context._drawCommands;
|
||||
// context._drawCommands = '';
|
||||
//
|
||||
// GCanvas.GBridge.render2d(this.id, commands, callback);
|
||||
// this._needRender = false;
|
||||
// }
|
||||
// //draw方法触发
|
||||
// context._flush = render;
|
||||
// //setInterval(render, 16);
|
||||
|
||||
GCanvas.GBridge.callSetContextType(this.id, 0);
|
||||
} else {
|
||||
throw new Error('not supported context ' + type);
|
||||
}
|
||||
|
||||
return context;
|
||||
|
||||
}
|
||||
|
||||
reset() {
|
||||
GCanvas.GBridge.callReset(this.id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
96
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/env/image.js
vendored
Normal file
96
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/env/image.js
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
let incId = 1;
|
||||
|
||||
const noop = function () { };
|
||||
|
||||
class GImage {
|
||||
|
||||
static GBridge = null;
|
||||
|
||||
constructor() {
|
||||
this._id = incId++;
|
||||
this._width = 0;
|
||||
this._height = 0;
|
||||
this._src = undefined;
|
||||
this._onload = noop;
|
||||
this._onerror = noop;
|
||||
this.complete = false;
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._width;
|
||||
}
|
||||
set width(v) {
|
||||
this._width = v;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
set height(v) {
|
||||
this._height = v;
|
||||
}
|
||||
|
||||
get src() {
|
||||
return this._src;
|
||||
}
|
||||
|
||||
set src(v) {
|
||||
|
||||
if (v.startsWith('//')) {
|
||||
v = 'http:' + v;
|
||||
}
|
||||
|
||||
this._src = v;
|
||||
|
||||
GImage.GBridge.perloadImage([this._src, this._id], (data) => {
|
||||
if (typeof data === 'string') {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
if (data.error) {
|
||||
var evt = { type: 'error', target: this };
|
||||
this.onerror(evt);
|
||||
} else {
|
||||
this.complete = true;
|
||||
this.width = typeof data.width === 'number' ? data.width : 0;
|
||||
this.height = typeof data.height === 'number' ? data.height : 0;
|
||||
var evt = { type: 'load', target: this };
|
||||
this.onload(evt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener(name, listener) {
|
||||
if (name === 'load') {
|
||||
this.onload = listener;
|
||||
} else if (name === 'error') {
|
||||
this.onerror = listener;
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(name, listener) {
|
||||
if (name === 'load') {
|
||||
this.onload = noop;
|
||||
} else if (name === 'error') {
|
||||
this.onerror = noop;
|
||||
}
|
||||
}
|
||||
|
||||
get onload() {
|
||||
return this._onload;
|
||||
}
|
||||
|
||||
set onload(v) {
|
||||
this._onload = v;
|
||||
}
|
||||
|
||||
get onerror() {
|
||||
return this._onerror;
|
||||
}
|
||||
|
||||
set onerror(v) {
|
||||
this._onerror = v;
|
||||
}
|
||||
}
|
||||
|
||||
export default GImage;
|
||||
24
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js
vendored
Normal file
24
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/env/tool.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
export function ArrayBufferToBase64 (buffer) {
|
||||
var binary = '';
|
||||
var bytes = new Uint8ClampedArray(buffer);
|
||||
for (var len = bytes.byteLength, i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
export function Base64ToUint8ClampedArray(base64String) {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/\-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const rawData = atob(base64);
|
||||
const outputArray = new Uint8ClampedArray(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
}
|
||||
39
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/index.js
Normal file
39
uni-im示例/uni_modules/Sansnn-uQRCode/js_sdk/gcanvas/index.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import GCanvas from './env/canvas';
|
||||
import GImage from './env/image';
|
||||
|
||||
import GWebGLRenderingContext from './context-webgl/RenderingContext';
|
||||
import GContext2D from './context-2d/RenderingContext';
|
||||
|
||||
import GBridgeWeex from './bridge/bridge-weex';
|
||||
|
||||
export let Image = GImage;
|
||||
|
||||
export let WeexBridge = GBridgeWeex;
|
||||
|
||||
export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) {
|
||||
|
||||
const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge;
|
||||
|
||||
GBridge.callEnable(el.ref, [
|
||||
0, // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY
|
||||
-1, // hybridLayerType: 0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE
|
||||
false, // supportScroll
|
||||
false, // newCanvasMode
|
||||
1, // compatible
|
||||
'white',// clearColor
|
||||
false // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level
|
||||
]);
|
||||
|
||||
if (debug === true) {
|
||||
GBridge.callEnableDebug();
|
||||
}
|
||||
if (disableComboCommands) {
|
||||
GBridge.callEnableDisableCombo();
|
||||
}
|
||||
|
||||
var canvas = new GCanvas(el.ref, { disableAutoSwap });
|
||||
canvas.width = el.style.width;
|
||||
canvas.height = el.style.height;
|
||||
|
||||
return canvas;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "uqrcode",
|
||||
"version": "3.5.1",
|
||||
"description": "",
|
||||
"main": "uqrcode.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
80
uni-im示例/uni_modules/Sansnn-uQRCode/package.json
Normal file
80
uni-im示例/uni_modules/Sansnn-uQRCode/package.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"id": "Sansnn-uQRCode",
|
||||
"displayName": "uQRCode 全端二维码生成插件 支持nvue 支持nodejs服务端",
|
||||
"version": "4.0.6",
|
||||
"description": "uQRCode是一款基于Javascript环境开发的二维码生成插件,适用所有Javascript运行环境的前端应用和Node.js。",
|
||||
"keywords": [
|
||||
"二维码",
|
||||
"uQRCode",
|
||||
"qrcode",
|
||||
"qr"
|
||||
],
|
||||
"repository": "https://github.com/Sansnn/uQRCode",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/uqrcodejs",
|
||||
"type": "sdk-js"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
uni-im示例/uni_modules/uni-badge/changelog.md
Normal file
33
uni-im示例/uni_modules/uni-badge/changelog.md
Normal file
@@ -0,0 +1,33 @@
|
||||
## 1.2.2(2023-01-28)
|
||||
- 修复 运行/打包 控制台警告问题
|
||||
## 1.2.1(2022-09-05)
|
||||
- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
|
||||
## 1.2.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
|
||||
## 1.1.7(2021-11-08)
|
||||
- 优化 升级ui
|
||||
- 修改 size 属性默认值调整为 small
|
||||
- 修改 type 属性,默认值调整为 error,info 替换 default
|
||||
## 1.1.6(2021-09-22)
|
||||
- 修复 在字节小程序上样式不生效的 bug
|
||||
## 1.1.5(2021-07-30)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 1.1.4(2021-07-29)
|
||||
- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
|
||||
## 1.1.3(2021-06-24)
|
||||
- 优化 示例项目
|
||||
## 1.1.1(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 1.1.0(2021-05-12)
|
||||
- 新增 uni-badge 的 absolute 属性,支持定位
|
||||
- 新增 uni-badge 的 offset 属性,支持定位偏移
|
||||
- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
|
||||
- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
|
||||
- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
|
||||
## 1.0.7(2021-05-07)
|
||||
- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
|
||||
- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
|
||||
- 新增 uni-badge 属性 custom-style, 支持自定义样式
|
||||
## 1.0.6(2021-02-04)
|
||||
- 调整为uni_modules目录规范
|
||||
@@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<view class="uni-badge--x">
|
||||
<slot />
|
||||
<text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
|
||||
class="uni-badge" @click="onClick()">{{displayValue}}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Badge 数字角标
|
||||
* @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
|
||||
* @property {String} text 角标内容
|
||||
* @property {String} size = [normal|small] 角标内容
|
||||
* @property {String} type = [info|primary|success|warning|error] 颜色类型
|
||||
* @value info 灰色
|
||||
* @value primary 蓝色
|
||||
* @value success 绿色
|
||||
* @value warning 黄色
|
||||
* @value error 红色
|
||||
* @property {String} inverted = [true|false] 是否无需背景颜色
|
||||
* @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+
|
||||
* @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
|
||||
* @value rightTop 右上
|
||||
* @value rightBottom 右下
|
||||
* @value leftTop 左上
|
||||
* @value leftBottom 左下
|
||||
* @property {Array[number]} offset 距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px
|
||||
* @property {String} isDot = [true|false] 是否显示为一个小点
|
||||
* @event {Function} click 点击 Badge 触发事件
|
||||
* @example <uni-badge text="1"></uni-badge>
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'UniBadge',
|
||||
emits: ['click'],
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'error'
|
||||
},
|
||||
inverted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDot: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxNum: {
|
||||
type: Number,
|
||||
default: 99
|
||||
},
|
||||
absolute: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
offset: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [0, 0]
|
||||
}
|
||||
},
|
||||
text: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'small'
|
||||
},
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
width() {
|
||||
return String(this.text).length * 8 + 12
|
||||
},
|
||||
classNames() {
|
||||
const {
|
||||
inverted,
|
||||
type,
|
||||
size,
|
||||
absolute
|
||||
} = this
|
||||
return [
|
||||
inverted ? 'uni-badge--' + type + '-inverted' : '',
|
||||
'uni-badge--' + type,
|
||||
'uni-badge--' + size,
|
||||
absolute ? 'uni-badge--absolute' : ''
|
||||
].join(' ')
|
||||
},
|
||||
positionStyle() {
|
||||
if (!this.absolute) return {}
|
||||
let w = this.width / 2,
|
||||
h = 10
|
||||
if (this.isDot) {
|
||||
w = 5
|
||||
h = 5
|
||||
}
|
||||
const x = `${- w + this.offset[0]}px`
|
||||
const y = `${- h + this.offset[1]}px`
|
||||
|
||||
const whiteList = {
|
||||
rightTop: {
|
||||
right: x,
|
||||
top: y
|
||||
},
|
||||
rightBottom: {
|
||||
right: x,
|
||||
bottom: y
|
||||
},
|
||||
leftBottom: {
|
||||
left: x,
|
||||
bottom: y
|
||||
},
|
||||
leftTop: {
|
||||
left: x,
|
||||
top: y
|
||||
}
|
||||
}
|
||||
const match = whiteList[this.absolute]
|
||||
return match ? match : whiteList['rightTop']
|
||||
},
|
||||
dotStyle() {
|
||||
if (!this.isDot) return {}
|
||||
return {
|
||||
width: '10px',
|
||||
minWidth: '0',
|
||||
height: '10px',
|
||||
padding: '0',
|
||||
borderRadius: '10px'
|
||||
}
|
||||
},
|
||||
displayValue() {
|
||||
const {
|
||||
isDot,
|
||||
text,
|
||||
maxNum
|
||||
} = this
|
||||
return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" >
|
||||
$uni-primary: #2979ff !default;
|
||||
$uni-success: #4cd964 !default;
|
||||
$uni-warning: #f0ad4e !default;
|
||||
$uni-error: #dd524d !default;
|
||||
$uni-info: #909399 !default;
|
||||
|
||||
|
||||
$bage-size: 12px;
|
||||
$bage-small: scale(0.8);
|
||||
|
||||
.uni-badge--x {
|
||||
/* #ifdef APP-NVUE */
|
||||
// align-self: flex-start;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
display: inline-block;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-badge--absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.uni-badge--small {
|
||||
transform: $bage-small;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.uni-badge {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
font-feature-settings: "tnum";
|
||||
min-width: 20px;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
height: 20px;
|
||||
padding: 0 4px;
|
||||
line-height: 18px;
|
||||
color: #fff;
|
||||
border-radius: 100px;
|
||||
background-color: $uni-info;
|
||||
background-color: transparent;
|
||||
border: 1px solid #fff;
|
||||
text-align: center;
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
font-size: $bage-size;
|
||||
/* #ifdef H5 */
|
||||
z-index: 999;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
|
||||
&--info {
|
||||
color: #fff;
|
||||
background-color: $uni-info;
|
||||
}
|
||||
|
||||
&--primary {
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
|
||||
&--success {
|
||||
background-color: $uni-success;
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background-color: $uni-warning;
|
||||
}
|
||||
|
||||
&--error {
|
||||
background-color: $uni-error;
|
||||
}
|
||||
|
||||
&--inverted {
|
||||
padding: 0 5px 0 0;
|
||||
color: $uni-info;
|
||||
}
|
||||
|
||||
&--info-inverted {
|
||||
color: $uni-info;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&--primary-inverted {
|
||||
color: $uni-primary;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&--success-inverted {
|
||||
color: $uni-success;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&--warning-inverted {
|
||||
color: $uni-warning;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&--error-inverted {
|
||||
color: $uni-error;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
85
uni-im示例/uni_modules/uni-badge/package.json
Normal file
85
uni-im示例/uni_modules/uni-badge/package.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"id": "uni-badge",
|
||||
"displayName": "uni-badge 数字角标",
|
||||
"version": "1.2.2",
|
||||
"description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
|
||||
"keywords": [
|
||||
"",
|
||||
"badge",
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"数字角标",
|
||||
"徽章"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss"],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
uni-im示例/uni_modules/uni-badge/readme.md
Normal file
10
uni-im示例/uni_modules/uni-badge/readme.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## Badge 数字角标
|
||||
> **组件名:uni-badge**
|
||||
> 代码块: `uBadge`
|
||||
|
||||
数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
|
||||
|
||||
37
uni-im示例/uni_modules/uni-captcha/changelog.md
Normal file
37
uni-im示例/uni_modules/uni-captcha/changelog.md
Normal file
@@ -0,0 +1,37 @@
|
||||
## 0.6.4(2023-01-16)
|
||||
- 修复 部分情况下APP端无法获取验证码的问题
|
||||
## 0.6.3(2023-01-11)
|
||||
- 修复 抖音小程序无法显示的Bug
|
||||
- 修复 刷新时兼容 device_uuid
|
||||
## 0.6.1(2022-06-23)
|
||||
- 修复:部分返回值,不符合响应体规范的问题
|
||||
## 0.6.0(2022-05-27)
|
||||
- 新增:支持在`uni-config-center`中根据场景值配置
|
||||
- 修复:弹窗式验证码,输入内容后点击取消,重新打开验证码的值仍然存在的问题
|
||||
## 0.5.2(2022-05-19)
|
||||
- 修复在Vue3的兼容问题
|
||||
## 0.5.1(2022-05-18)
|
||||
- 修复在某些情况下微信小程序端验证码显示错误的问题
|
||||
## 0.5.0(2022-05-17)
|
||||
- 新增支持在`uni-captcha-co`->`config`配置验证码
|
||||
## 0.4.1(2022-05-16)
|
||||
- 新增示例项目
|
||||
## 0.4.0(2022-05-16)
|
||||
- 集成创建、刷新、显示验证码的云端一体验证码组件
|
||||
- 云对象`uni-captcha-co`集成获取验证码的api,`getImageCaptcha`
|
||||
## 0.3.1(2022-05-13)
|
||||
- 新增 返回值符合响应体规范
|
||||
## 0.3.0(2022-05-13)
|
||||
- 新增 支持 uni-config-center 配置
|
||||
## 0.2.2(2022-04-25)
|
||||
- 修复 0.2.1 版本引起的使用 image 组件验证码不显示的Bug
|
||||
## 0.2.1(2022-04-18)
|
||||
- 更新 优化字体
|
||||
## 0.2.0(2022-04-14)
|
||||
- 新增 使用 svg 表现形式更好
|
||||
- 新增 使用字体,可以任意替换默认字体
|
||||
- 新增 支持设置字体大小
|
||||
- 新增 支持忽略某些字符
|
||||
- 注意 更新之后请重新上传公共模块
|
||||
## 0.1.0(2021-03-01)
|
||||
- 调整为uni_modules目录规范
|
||||
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<view class="captcha-box">
|
||||
<view class="captcha-img-box">
|
||||
<uni-icons class="loding" size="20px" color="#BBB" v-if="loging" type="spinner-cycle"></uni-icons>
|
||||
<image class="captcha-img" :class="{opacity:loging}" @click="getImageCaptcha" :src="captchaBase64"
|
||||
mode="widthFix"></image>
|
||||
</view>
|
||||
<input @blur="focusCaptchaInput = false" :focus="focusCaptchaInput" type="text" class="captcha"
|
||||
:inputBorder="false" maxlength="4" v-model="val" placeholder="请输入验证码">
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
modelValue:String,
|
||||
value:String,
|
||||
scene: {
|
||||
type: String,
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
focus: {
|
||||
type: Boolean,
|
||||
default () {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
val:{
|
||||
get(){
|
||||
return this.value||this.modelValue
|
||||
},
|
||||
set(value){
|
||||
// console.log(value);
|
||||
// TODO 兼容 vue2
|
||||
// #ifdef VUE2
|
||||
this.$emit('input', value);
|
||||
// #endif
|
||||
|
||||
// TODO 兼容 vue3
|
||||
// #ifdef VUE3
|
||||
this.$emit('update:modelValue', value)
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
focusCaptchaInput: false,
|
||||
captchaBase64: "",
|
||||
loging: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
scene: {
|
||||
handler(scene) {
|
||||
if (scene) {
|
||||
this.getImageCaptcha(this.focus)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: 'scene不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
immediate:true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getImageCaptcha(focus = true) {
|
||||
this.loging = true
|
||||
if (focus) {
|
||||
this.val = ''
|
||||
this.focusCaptchaInput = true
|
||||
}
|
||||
const uniIdCo = uniCloud.importObject("uni-captcha-co", {
|
||||
customUI: true
|
||||
})
|
||||
uniIdCo.getImageCaptcha({
|
||||
scene: this.scene
|
||||
}).then(result => {
|
||||
// console.log(result);
|
||||
this.captchaBase64 = result.captchaBase64
|
||||
})
|
||||
.catch(e => {
|
||||
uni.showToast({
|
||||
title: e.message,
|
||||
icon: 'none'
|
||||
});
|
||||
}).finally(e => {
|
||||
this.loging = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.captcha-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.captcha-img-box,
|
||||
.captcha {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.captcha-img-box {
|
||||
position: relative;
|
||||
background-color: #FEFAE7;
|
||||
}
|
||||
|
||||
.captcha {
|
||||
background-color: #F8F8F8;
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
padding: 0 20rpx;
|
||||
margin-left: 20rpx;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.captcha-img-box,
|
||||
.captcha-img,
|
||||
.loding {
|
||||
height: 44px !important;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.captcha-img{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.loding {
|
||||
z-index: 9;
|
||||
color: #bbb;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
line-height: 45px;
|
||||
animation: rotate 1s linear infinite;
|
||||
}
|
||||
|
||||
.opacity {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg)
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg)
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="center">
|
||||
<view class="popup-captcha">
|
||||
<view class="content">
|
||||
<text class="title">{{title}}</text>
|
||||
<uni-captcha :focus="focus" :scene="scene" v-model="val"></uni-captcha>
|
||||
</view>
|
||||
<view class="button-box">
|
||||
<view @click="close" class="btn">取消</view>
|
||||
<view @click="confirm" class="btn confirm">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
focus: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
modelValue:String,
|
||||
value:String,
|
||||
scene: {
|
||||
type: String,
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
},
|
||||
computed:{
|
||||
val:{
|
||||
get(){
|
||||
return this.value||this.modelValue
|
||||
},
|
||||
set(value){
|
||||
// console.log(value);
|
||||
// TODO 兼容 vue2
|
||||
// #ifdef VUE2
|
||||
this.$emit('input', value);
|
||||
// #endif
|
||||
|
||||
// TODO 兼容 vue3
|
||||
// #ifdef VUE3
|
||||
this.$emit('update:modelValue', value)
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.focus = true
|
||||
this.val = ""
|
||||
this.$refs.popup.open()
|
||||
},
|
||||
close() {
|
||||
this.focus = false
|
||||
this.$refs.popup.close()
|
||||
},
|
||||
confirm() {
|
||||
if(!this.val){
|
||||
return uni.showToast({
|
||||
title: '请填写验证码',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
this.close()
|
||||
this.$emit('confirm')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef APP-NVUE */
|
||||
view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.popup-captcha {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
max-width: 600px;
|
||||
/* #endif */
|
||||
width: 600rpx;
|
||||
padding-bottom: 0;
|
||||
background-color: #FFF;
|
||||
border-radius: 10px;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.popup-captcha .content {
|
||||
padding: 1.3em 0.8em;
|
||||
}
|
||||
|
||||
.popup-captcha .title {
|
||||
text-align: center;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #111;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
height: 44px;
|
||||
border-top: solid 1px #eee;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.button-box ,.btn{
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
}
|
||||
.button-box .btn{
|
||||
flex: 1;
|
||||
margin: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
.button-box .confirm{
|
||||
color: #007aff;
|
||||
border-left: solid 1px #eee;
|
||||
}
|
||||
</style>
|
||||
81
uni-im示例/uni_modules/uni-captcha/package.json
Normal file
81
uni-im示例/uni_modules/uni-captcha/package.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"id": "uni-captcha",
|
||||
"displayName": "uni-captcha",
|
||||
"version": "0.6.4",
|
||||
"description": "云端一体图形验证码组件",
|
||||
"keywords": [
|
||||
"captcha",
|
||||
"图形验证码",
|
||||
"人机验证",
|
||||
"防刷",
|
||||
"防脚本"
|
||||
],
|
||||
"repository": "https://gitee.com/dcloud/uni-captcha",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "unicloud-template-function"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
uni-im示例/uni_modules/uni-captcha/readme.md
Normal file
3
uni-im示例/uni_modules/uni-captcha/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
<h2>
|
||||
文档已移至 <a href="https://uniapp.dcloud.io/uniCloud/uni-captcha.html" target="_blank">uni-captcha文档</a>
|
||||
</h2>
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "uni-captcha",
|
||||
"version": "0.6.4",
|
||||
"description": "uni-captcha",
|
||||
"main": "index.js",
|
||||
"homepage": "https://ext.dcloud.net.cn/plugin?id=4048",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitee.com/dcloud/uni-captcha"
|
||||
},
|
||||
"author": "DCloud",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
"image-captcha":{
|
||||
"width": 150, //图片宽度
|
||||
"height": 44, //图片高度
|
||||
"background": "#FFFAE8", //验证码背景色,设置空字符`''`不使用背景颜色
|
||||
// "size": 4, //验证码长度,最多 6 个字符
|
||||
// "noise": 4, //验证码干扰线条数
|
||||
// "color": false, //字体是否使用随机颜色,当设置`background`后恒为`true`
|
||||
// "fontSize": 40, //字体大小
|
||||
// "ignoreChars": '', //忽略那些字符
|
||||
// "mathExpr": false, //是否使用数学表达式
|
||||
// "mathMin": 1, //表达式所使用的最小数字
|
||||
// "mathMax": 9, //表达式所使用的最大数字
|
||||
// "mathOperator": '' //表达式所使用的运算符,支持 `+`、`-`。不传随机使用
|
||||
// "expiresDate":180 //验证码过期时间(s)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 开发文档: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
|
||||
//导入验证码公共模块
|
||||
const uniCaptcha = require('uni-captcha')
|
||||
//获取数据库对象
|
||||
const db = uniCloud.database();
|
||||
//获取数据表opendb-verify-codes对象
|
||||
const verifyCodes = db.collection('opendb-verify-codes')
|
||||
module.exports = {
|
||||
async getImageCaptcha({
|
||||
scene
|
||||
}) {
|
||||
//获取设备id
|
||||
let {
|
||||
deviceId,
|
||||
platform
|
||||
} = this.getClientInfo();
|
||||
//根据:设备id、场景值、状态,查找记录是否存在
|
||||
let res = await verifyCodes.where({
|
||||
scene,
|
||||
deviceId,
|
||||
state: 0
|
||||
}).limit(1).get()
|
||||
//如果已存在则调用刷新接口,反之调用插件接口
|
||||
let action = res.data.length ? 'refresh' : 'create'
|
||||
//执行并返回结果
|
||||
//导入配置,配置优先级说明:此处配置 > uni-config-center
|
||||
return await uniCaptcha[action]({
|
||||
scene, //来源客户端传递,表示:使用场景值,用于防止不同功能的验证码混用
|
||||
uniPlatform: platform
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "uni-captcha-co",
|
||||
"dependencies": {
|
||||
"uni-captcha": "file:../common/uni-captcha",
|
||||
"uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
|
||||
},
|
||||
"extensions": {
|
||||
"uni-cloud-jql": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"bsonType": "object",
|
||||
"properties": {
|
||||
"_id": {
|
||||
"description": "ID,系统自动生成"
|
||||
},
|
||||
"code": {
|
||||
"bsonType": "string",
|
||||
"description": "验证码"
|
||||
},
|
||||
"create_date": {
|
||||
"bsonType": "timestamp",
|
||||
"description": "创建时间"
|
||||
},
|
||||
"device_uuid": {
|
||||
"bsonType": "string",
|
||||
"description": "设备UUID,常用于图片验证码"
|
||||
},
|
||||
"email": {
|
||||
"bsonType": "string",
|
||||
"description": "邮箱"
|
||||
},
|
||||
"expired_date": {
|
||||
"bsonType": "timestamp",
|
||||
"description": "过期时间"
|
||||
},
|
||||
"ip": {
|
||||
"bsonType": "string",
|
||||
"description": "请求时客户端IP地址"
|
||||
},
|
||||
"mobile": {
|
||||
"bsonType": "string",
|
||||
"description": "手机号码"
|
||||
},
|
||||
"scene": {
|
||||
"bsonType": "string",
|
||||
"description": "使用验证码的场景,如:login, bind, unbind, pay"
|
||||
},
|
||||
"state": {
|
||||
"bsonType": "int",
|
||||
"description": "验证状态:0 未验证、1 已验证、2 已作废"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
||||
2
uni-im示例/uni_modules/uni-cloud-s2s/changelog.md
Normal file
2
uni-im示例/uni_modules/uni-cloud-s2s/changelog.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## 1.0.1(2023-03-02)
|
||||
- 修复 方法名错误
|
||||
83
uni-im示例/uni_modules/uni-cloud-s2s/package.json
Normal file
83
uni-im示例/uni_modules/uni-cloud-s2s/package.json
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "uni-cloud-s2s",
|
||||
"displayName": "服务空间与服务器安全通讯模块",
|
||||
"version": "1.0.1",
|
||||
"description": "用于解决服务空间与服务器通讯时互相信任问题",
|
||||
"keywords": [
|
||||
"安全通讯",
|
||||
"服务器请求云函数",
|
||||
"云函数请求服务器"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "unicloud-template-function",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "u",
|
||||
"vue3": "u"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
uni-im示例/uni_modules/uni-cloud-s2s/readme.md
Normal file
3
uni-im示例/uni_modules/uni-cloud-s2s/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# uni-cloud-s2s
|
||||
|
||||
文档见:[外部服务器如何与uniCloud安全通讯](https://uniapp.dcloud.net.cn/uniCloud/uni-cloud-s2s.html)
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "uni-cloud-s2s",
|
||||
"version": "1.0.1",
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
"author": "DCloud",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
|
||||
}
|
||||
}
|
||||
6
uni-im示例/uni_modules/uni-config-center/changelog.md
Normal file
6
uni-im示例/uni_modules/uni-config-center/changelog.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 0.0.3(2022-11-11)
|
||||
- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug
|
||||
## 0.0.2(2021-04-16)
|
||||
- 修改插件package信息
|
||||
## 0.0.1(2021-03-15)
|
||||
- 初始化项目
|
||||
81
uni-im示例/uni_modules/uni-config-center/package.json
Normal file
81
uni-im示例/uni_modules/uni-config-center/package.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"id": "uni-config-center",
|
||||
"displayName": "uni-config-center",
|
||||
"version": "0.0.3",
|
||||
"description": "uniCloud 配置中心",
|
||||
"keywords": [
|
||||
"配置",
|
||||
"配置中心"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "unicloud-template-function"
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../../scripts/dist"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
93
uni-im示例/uni_modules/uni-config-center/readme.md
Normal file
93
uni-im示例/uni_modules/uni-config-center/readme.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 为什么使用uni-config-center
|
||||
|
||||
实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构
|
||||
|
||||
```bash
|
||||
cloudfunctions
|
||||
└─────common 公共模块
|
||||
├─plugin-a // 插件A对应的目录
|
||||
│ ├─index.js
|
||||
│ ├─config.json // plugin-a对应的配置文件
|
||||
│ └─other-file.cert // plugin-a依赖的其他文件
|
||||
└─plugin-b // plugin-b对应的目录
|
||||
├─index.js
|
||||
└─config.json // plugin-b对应的配置文件
|
||||
```
|
||||
|
||||
假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。
|
||||
|
||||
uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下
|
||||
|
||||
```bash
|
||||
cloudfunctions
|
||||
└─────common 公共模块
|
||||
├─plugin-a // 插件A对应的目录
|
||||
│ └─index.js
|
||||
├─plugin-b // plugin-b对应的目录
|
||||
│ └─index.js
|
||||
└─uni-config-center
|
||||
├─index.js // config-center入口文件
|
||||
├─plugin-a
|
||||
│ ├─config.json // plugin-a对应的配置文件
|
||||
│ └─other-file.cert // plugin-a依赖的其他文件
|
||||
└─plugin-b
|
||||
└─config.json // plugin-b对应的配置文件
|
||||
```
|
||||
|
||||
使用uni-config-center后的优势
|
||||
|
||||
- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便
|
||||
- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持)
|
||||
|
||||
# 用法
|
||||
|
||||
在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common)
|
||||
|
||||
```js
|
||||
const createConfig = require('uni-config-center')
|
||||
|
||||
const uniIdConfig = createConfig({
|
||||
pluginId: 'uni-id', // 插件id
|
||||
defaultConfig: { // 默认配置
|
||||
tokenExpiresIn: 7200,
|
||||
tokenExpiresThreshold: 600,
|
||||
},
|
||||
customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并
|
||||
// defaudltConfig 默认配置
|
||||
// userConfig 用户配置
|
||||
return Object.assign(defaultConfig, userConfig)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// 以如下配置为例
|
||||
// {
|
||||
// "tokenExpiresIn": 7200,
|
||||
// "passwordErrorLimit": 6,
|
||||
// "bindTokenToDevice": false,
|
||||
// "passwordErrorRetryTime": 3600,
|
||||
// "app-plus": {
|
||||
// "tokenExpiresIn": 2592000
|
||||
// },
|
||||
// "service": {
|
||||
// "sms": {
|
||||
// "codeExpiresIn": 300
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 获取配置
|
||||
uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象
|
||||
uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200
|
||||
uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300
|
||||
uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600
|
||||
|
||||
// 获取文件绝对路径
|
||||
uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径
|
||||
|
||||
// 引用文件(require)
|
||||
uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。
|
||||
|
||||
// 判断是否包含某文件
|
||||
uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "uni-config-center",
|
||||
"version": "0.0.3",
|
||||
"description": "配置中心",
|
||||
"main": "index.js",
|
||||
"keywords": [],
|
||||
"author": "DCloud",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"passwordSecret": "passwordSecret-demo",
|
||||
"tokenSecret": "passwordSecret-demo",
|
||||
"requestAuthSecret":"testSecret",
|
||||
"passwordStrength": "",
|
||||
"tokenExpiresIn": 2592000,
|
||||
"tokenExpiresThreshold": 1600,
|
||||
"passwordErrorLimit": 6,
|
||||
"bindTokenToDevice": false,
|
||||
"passwordErrorRetryTime": 3600,
|
||||
"autoSetInviteCode": false,
|
||||
"forceInviteCode": false,
|
||||
"preferedAppPlatform": "app",
|
||||
"app": {
|
||||
"tokenExpiresIn": 2592000,
|
||||
"oauth": {
|
||||
"weixin": {
|
||||
"appid": "填写来源微信开放平台https://open.weixin.qq.com/创建的应用的appid",
|
||||
"appsecret": "填写来源微信开放平台https://open.weixin.qq.com/创建的应用的appsecret"
|
||||
},
|
||||
"apple": {
|
||||
"bundleId": "苹果开发者后台获取的bundleId"
|
||||
}
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"oauth": {
|
||||
"h5-weixin": {
|
||||
"appid": "微信浏览器内微信登录,所用的微信公众号appid",
|
||||
"appsecret": "微信公众号后台获取的appsecret"
|
||||
},
|
||||
"web-weixin": {
|
||||
"appid": "手机微信扫码登录,所用的微信开放平台(https://open.weixin.qq.com/)-网站应用的appid",
|
||||
"appsecret": "微信开放平台-网站应用的appsecret"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-weixin": {
|
||||
"oauth": {
|
||||
"weixin": {
|
||||
"appid": "微信小程序登录所用的appid、appsecret需要在对应的小程序管理控制台获取",
|
||||
"appsecret": "微信小程序后台获取的appsecret"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-alipay": {
|
||||
"oauth": {
|
||||
"alipay": {
|
||||
"appid": "支付宝小程序登录用到的appid、privateKey请参考支付宝小程序的文档进行设置或者获取,https://opendocs.alipay.com/open/291/105971#LDsXr",
|
||||
"privateKey": "支付宝小程序登录用到的appid、privateKey请参考支付宝小程序的文档进行设置或者获取,https://opendocs.alipay.com/open/291/105971#LDsXr"
|
||||
}
|
||||
}
|
||||
},
|
||||
"service": {
|
||||
"sms": {
|
||||
"name": "应用名称,对应短信模版的name",
|
||||
"codeExpiresIn": 300,
|
||||
"smsKey": "短信密钥key,开通短信服务处可以看到",
|
||||
"smsSecret": "短信密钥secret,开通短信服务处可以看到"
|
||||
},
|
||||
"univerify": {
|
||||
"appid": "当前应用的appid,使用云函数URL化,此项必须配置",
|
||||
"apiKey": "apiKey 和 apiSecret 在开发者中心获取,开发者中心:https://dev.dcloud.net.cn/uniLogin/index?type=0,文档:https://ask.dcloud.net.cn/article/37965",
|
||||
"apiSecret": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"customer_service_uids":false,
|
||||
"conversation_grade":0
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"schedule": {
|
||||
"__UNI__xxxxxx": {
|
||||
"enable": true,
|
||||
"h5-weixin": {
|
||||
"enable": false,
|
||||
"tasks": ["ticket"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipWhitelist": ["0.0.0.0"]
|
||||
}
|
||||
45
uni-im示例/uni_modules/uni-data-checkbox/changelog.md
Normal file
45
uni-im示例/uni_modules/uni-data-checkbox/changelog.md
Normal file
@@ -0,0 +1,45 @@
|
||||
## 1.0.3(2022-09-16)
|
||||
- 可以使用 uni-scss 控制主题色
|
||||
## 1.0.2(2022-06-30)
|
||||
- 优化 在 uni-forms 中的依赖注入方式
|
||||
## 1.0.1(2022-02-07)
|
||||
- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
|
||||
## 1.0.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
|
||||
## 0.2.5(2021-08-23)
|
||||
- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
|
||||
## 0.2.4(2021-08-17)
|
||||
- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
|
||||
## 0.2.3(2021-08-11)
|
||||
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
|
||||
## 0.2.2(2021-07-30)
|
||||
- 优化 在uni-forms组件,与label不对齐的问题
|
||||
## 0.2.1(2021-07-27)
|
||||
- 修复 单选默认值为0不能选中的Bug
|
||||
## 0.2.0(2021-07-13)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 0.1.11(2021-07-06)
|
||||
- 优化 删除无用日志
|
||||
## 0.1.10(2021-07-05)
|
||||
- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
|
||||
## 0.1.9(2021-07-05)
|
||||
- 修复 nvue 黑框样式问题
|
||||
## 0.1.8(2021-06-28)
|
||||
- 修复 selectedTextColor 属性不生效的Bug
|
||||
## 0.1.7(2021-06-02)
|
||||
- 新增 map 属性,可以方便映射text/value属性
|
||||
## 0.1.6(2021-05-26)
|
||||
- 修复 不关联服务空间的情况下组件报错的Bug
|
||||
## 0.1.5(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 0.1.4(2021-04-09)
|
||||
- 修复 nvue 下无法选中的问题
|
||||
## 0.1.3(2021-03-22)
|
||||
- 新增 disabled属性
|
||||
## 0.1.2(2021-02-24)
|
||||
- 优化 默认颜色显示
|
||||
## 0.1.1(2021-02-24)
|
||||
- 新增 支持nvue
|
||||
## 0.1.0(2021-02-18)
|
||||
- “暂无数据”显示居中
|
||||
@@ -0,0 +1,316 @@
|
||||
|
||||
const events = {
|
||||
load: 'load',
|
||||
error: 'error'
|
||||
}
|
||||
const pageMode = {
|
||||
add: 'add',
|
||||
replace: 'replace'
|
||||
}
|
||||
|
||||
const attrs = [
|
||||
'pageCurrent',
|
||||
'pageSize',
|
||||
'collection',
|
||||
'action',
|
||||
'field',
|
||||
'getcount',
|
||||
'orderby',
|
||||
'where'
|
||||
]
|
||||
|
||||
export default {
|
||||
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,821 @@
|
||||
<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 选中发生变化触发
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'uniDataChecklist',
|
||||
mixins: [uniCloud.mixinDatacom || {}],
|
||||
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)
|
||||
// fix by mehaotian is_reset 在 uni-forms 中定义
|
||||
// if(!this.is_reset){
|
||||
// this.is_reset = false
|
||||
// this.formItem && this.formItem.setValue(newVal)
|
||||
// }
|
||||
},
|
||||
modelValue(newVal) {
|
||||
this.dataList = this.getDataList(newVal);
|
||||
// if(!this.is_reset){
|
||||
// this.is_reset = false
|
||||
// this.formItem && this.formItem.setValue(newVal)
|
||||
// }
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataList: [],
|
||||
range: [],
|
||||
contentText: {
|
||||
contentdown: '查看更多',
|
||||
contentrefresh: '加载中',
|
||||
contentnomore: '没有更多'
|
||||
},
|
||||
isLocal:true,
|
||||
styles: {
|
||||
selectedColor: '#2979ff',
|
||||
selectedTextColor: '#666',
|
||||
},
|
||||
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) {
|
||||
// // 如果存在name添加默认值,否则formData 中不存在这个字段不校验
|
||||
// if(!this.is_reset){
|
||||
// this.is_reset = false
|
||||
// this.formItem.setValue(this.dataValue)
|
||||
// }
|
||||
// this.rename = this.formItem.name
|
||||
// this.form.inputChildrens.push(this)
|
||||
// }
|
||||
// }
|
||||
|
||||
if (this.localdata && this.localdata.length !== 0) {
|
||||
this.isLocal = true
|
||||
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:'#2979ff'
|
||||
if (this.selectedColor) {
|
||||
if (this.mode !== 'list') {
|
||||
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
|
||||
}
|
||||
if (this.mode === 'tag') {
|
||||
styles['background-color'] = item.selected? selectedColor:'#f5f5f5'
|
||||
}
|
||||
}
|
||||
let classles = ''
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
setStyleIcon(item) {
|
||||
let styles = {}
|
||||
let classles = ''
|
||||
if (this.selectedColor) {
|
||||
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
|
||||
styles['background-color'] = item.selected?selectedColor:'#fff'
|
||||
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
|
||||
|
||||
if(!item.selected && item.disabled){
|
||||
styles['background-color'] = '#F2F6FC'
|
||||
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
|
||||
}
|
||||
}
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
setStyleIconText(item) {
|
||||
let styles = {}
|
||||
let classles = ''
|
||||
if (this.selectedColor) {
|
||||
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
|
||||
if (this.mode === 'tag') {
|
||||
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
|
||||
} else {
|
||||
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
|
||||
}
|
||||
if(!item.selected && item.disabled){
|
||||
styles.color = '#999'
|
||||
}
|
||||
}
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
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 lang="scss">
|
||||
$uni-primary: #2979ff !default;
|
||||
$border-color: #DCDFE6;
|
||||
$disable:0.4;
|
||||
|
||||
@mixin flex {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-data-loading {
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
padding-left: 10px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.uni-data-checklist {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
flex: 1;
|
||||
// 多选样式
|
||||
.checklist-group {
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&.is-list {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.checklist-box {
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin: 5px 0;
|
||||
margin-right: 25px;
|
||||
|
||||
.hidden {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// 文字样式
|
||||
.checklist-content {
|
||||
@include flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.checklist-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-left: 5px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
// 多选样式
|
||||
.checkbox__inner {
|
||||
/* #ifndef APP-NVUE */
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
// 单选样式
|
||||
.radio__inner {
|
||||
@include flex;
|
||||
/* #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 $border-color;
|
||||
border-radius: 16px;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
|
||||
.radio__inner-icon {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 10px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认样式
|
||||
&.is--default {
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
.checkbox__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.radio__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
}
|
||||
.checklist-text {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
// 选中
|
||||
&.is-checked {
|
||||
.checkbox__inner {
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
.radio__inner {
|
||||
border-color: $uni-primary;
|
||||
.radio__inner-icon {
|
||||
opacity: 1;
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
.checklist-text {
|
||||
color: $uni-primary;
|
||||
}
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
.checkbox__inner {
|
||||
opacity: $disable;
|
||||
}
|
||||
|
||||
.checklist-text {
|
||||
opacity: $disable;
|
||||
}
|
||||
.radio__inner {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮样式
|
||||
&.is--button {
|
||||
margin-right: 10px;
|
||||
padding: 5px 10px;
|
||||
border: 1px $border-color solid;
|
||||
border-radius: 3px;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
border: 1px #eee solid;
|
||||
opacity: $disable;
|
||||
.checkbox__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
.radio__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
.checklist-text {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
border-color: $uni-primary;
|
||||
.checkbox__inner {
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.radio__inner {
|
||||
border-color: $uni-primary;
|
||||
|
||||
.radio__inner-icon {
|
||||
opacity: 1;
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.checklist-text {
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签样式
|
||||
&.is--tag {
|
||||
margin-right: 10px;
|
||||
padding: 5px 10px;
|
||||
border: 1px $border-color solid;
|
||||
border-radius: 3px;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
.checklist-text {
|
||||
margin: 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
opacity: $disable;
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
background-color: $uni-primary;
|
||||
border-color: $uni-primary;
|
||||
|
||||
.checklist-text {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 列表样式
|
||||
&.is--list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
padding: 10px 15px;
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
|
||||
&.is-list-border {
|
||||
border-top: 1px #eee solid;
|
||||
}
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
.checkbox__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
.checklist-text {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
.checkbox__inner {
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
.radio__inner {
|
||||
.radio__inner-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.checklist-text {
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
.checklist-content {
|
||||
.checkobx__list {
|
||||
opacity: 1;
|
||||
border-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
.checkbox__inner {
|
||||
opacity: $disable;
|
||||
}
|
||||
|
||||
.checklist-text {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
uni-im示例/uni_modules/uni-data-checkbox/package.json
Normal file
84
uni-im示例/uni_modules/uni-data-checkbox/package.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"id": "uni-data-checkbox",
|
||||
"displayName": "uni-data-checkbox 数据选择器",
|
||||
"version": "1.0.3",
|
||||
"description": "通过数据驱动的单选框和复选框",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"checkbox",
|
||||
"单选",
|
||||
"多选",
|
||||
"单选多选"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.1"
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-load-more","uni-scss"],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
uni-im示例/uni_modules/uni-data-checkbox/readme.md
Normal file
18
uni-im示例/uni_modules/uni-data-checkbox/readme.md
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
## DataCheckbox 数据驱动的单选复选框
|
||||
> **组件名:uni-data-checkbox**
|
||||
> 代码块: `uDataCheckbox`
|
||||
|
||||
|
||||
本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
|
||||
|
||||
1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
|
||||
2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
|
||||
3. 本组件合并了单选多选
|
||||
4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
|
||||
|
||||
在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
68
uni-im示例/uni_modules/uni-data-picker/changelog.md
Normal file
68
uni-im示例/uni_modules/uni-data-picker/changelog.md
Normal file
@@ -0,0 +1,68 @@
|
||||
## 1.0.9(2022-11-30)
|
||||
- 修复 v-for 为使用 key 值控制台 warning
|
||||
## 1.0.8(2022-09-16)
|
||||
- 可以使用 uni-scss 控制主题色
|
||||
## 1.0.7(2022-07-06)
|
||||
- 优化 pc端图标位置不正确的问题
|
||||
## 1.0.6(2022-07-05)
|
||||
- 优化 显示样式
|
||||
## 1.0.5(2022-07-04)
|
||||
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
|
||||
## 1.0.4(2022-04-19)
|
||||
- 修复 字节小程序 本地数据无法选择下一级的Bug
|
||||
## 1.0.3(2022-02-25)
|
||||
- 修复 nvue 不支持的 v-show 的 bug
|
||||
## 1.0.2(2022-02-25)
|
||||
- 修复 条件编译 nvue 不支持的 css 样式
|
||||
## 1.0.1(2021-11-23)
|
||||
- 修复 由上个版本引发的map、v-model等属性不生效的bug
|
||||
## 1.0.0(2021-11-19)
|
||||
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
|
||||
## 0.4.9(2021-10-28)
|
||||
- 修复 VUE2 v-model 概率无效的 bug
|
||||
## 0.4.8(2021-10-27)
|
||||
- 修复 v-model 概率无效的 bug
|
||||
## 0.4.7(2021-10-25)
|
||||
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
|
||||
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
|
||||
## 0.4.6(2021-10-19)
|
||||
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
|
||||
## 0.4.5(2021-09-26)
|
||||
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
|
||||
- 修复 readonly 为 true 时报错的 bug
|
||||
## 0.4.4(2021-09-26)
|
||||
- 修复 上一版本造成的 map 属性失效的 bug
|
||||
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
|
||||
## 0.4.3(2021-09-24)
|
||||
- 修复 某些情况下级联未触发的 bug
|
||||
## 0.4.2(2021-09-23)
|
||||
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
|
||||
- 新增 选项内容过长自动添加省略号
|
||||
## 0.4.1(2021-09-15)
|
||||
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
|
||||
## 0.4.0(2021-07-13)
|
||||
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 0.3.5(2021-06-04)
|
||||
- 修复 无法加载云端数据的问题
|
||||
## 0.3.4(2021-05-28)
|
||||
- 修复 v-model 无效问题
|
||||
- 修复 loaddata 为空数据组时加载时间过长问题
|
||||
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
|
||||
## 0.3.3(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 0.3.2(2021-04-22)
|
||||
- 修复 非树形数据有 where 属性查询报错的问题
|
||||
## 0.3.1(2021-04-15)
|
||||
- 修复 本地数据概率无法回显时问题
|
||||
## 0.3.0(2021-04-07)
|
||||
- 新增 支持云端非树形表结构数据
|
||||
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
|
||||
## 0.2.0(2021-03-15)
|
||||
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
|
||||
## 0.1.9(2021-03-09)
|
||||
- 修复 微信小程序某些情况下无法选择的问题
|
||||
## 0.1.8(2021-02-05)
|
||||
- 优化 部分样式在 nvue 上的兼容表现
|
||||
## 0.1.7(2021-02-05)
|
||||
- 调整为 uni_modules 目录规范
|
||||
@@ -0,0 +1,45 @@
|
||||
// #ifdef H5
|
||||
export default {
|
||||
name: 'Keypress',
|
||||
props: {
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const keyNames = {
|
||||
esc: ['Esc', 'Escape'],
|
||||
tab: 'Tab',
|
||||
enter: 'Enter',
|
||||
space: [' ', 'Spacebar'],
|
||||
up: ['Up', 'ArrowUp'],
|
||||
left: ['Left', 'ArrowLeft'],
|
||||
right: ['Right', 'ArrowRight'],
|
||||
down: ['Down', 'ArrowDown'],
|
||||
delete: ['Backspace', 'Delete', 'Del']
|
||||
}
|
||||
const listener = ($event) => {
|
||||
if (this.disable) {
|
||||
return
|
||||
}
|
||||
const keyName = Object.keys(keyNames).find(key => {
|
||||
const keyName = $event.key
|
||||
const value = keyNames[key]
|
||||
return value === keyName || (Array.isArray(value) && value.includes(keyName))
|
||||
})
|
||||
if (keyName) {
|
||||
// 避免和其他按键事件冲突
|
||||
setTimeout(() => {
|
||||
this.$emit(keyName, {})
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
document.addEventListener('keyup', listener)
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
document.removeEventListener('keyup', listener)
|
||||
})
|
||||
},
|
||||
render: () => {}
|
||||
}
|
||||
// #endif
|
||||
@@ -0,0 +1,554 @@
|
||||
<template>
|
||||
<view class="uni-data-tree">
|
||||
<view class="uni-data-tree-input" @click="handleInput">
|
||||
<slot :options="options" :data="inputSelected" :error="errorMessage">
|
||||
<view class="input-value" :class="{'input-value-border': border}">
|
||||
<text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
|
||||
<view v-else-if="loading && !isOpened" class="selected-area">
|
||||
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||
</view>
|
||||
<scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
|
||||
<view class="selected-list">
|
||||
<view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
|
||||
<text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
|
||||
class="input-split-line">{{split}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<text v-else class="selected-area placeholder">{{placeholder}}</text>
|
||||
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear"
|
||||
@click.stop="clear">
|
||||
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
|
||||
</view>
|
||||
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
|
||||
<view class="input-arrow"></view>
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
|
||||
<view class="uni-data-tree-dialog" v-if="isOpened">
|
||||
<view class="uni-popper__arrow"></view>
|
||||
<view class="dialog-caption">
|
||||
<view class="title-area">
|
||||
<text class="dialog-title">{{popupTitle}}</text>
|
||||
</view>
|
||||
<view class="dialog-close" @click="handleClose">
|
||||
<view class="dialog-close-plus" data-id="close"></view>
|
||||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||
</view>
|
||||
</view>
|
||||
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
|
||||
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
|
||||
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true"
|
||||
:map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
|
||||
</data-picker-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
|
||||
import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
|
||||
|
||||
/**
|
||||
* DataPicker 级联选择
|
||||
* @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||
* @property {String} popup-title 弹出窗口标题
|
||||
* @property {Array} localdata 本地数据,参考
|
||||
* @property {Boolean} border = [true|false] 是否有边框
|
||||
* @property {Boolean} readonly = [true|false] 是否仅读
|
||||
* @property {Boolean} preload = [true|false] 是否预加载数据
|
||||
* @value true 开启预加载数据,点击弹出窗口后显示已加载数据
|
||||
* @value false 关闭预加载数据,点击弹出窗口后开始加载数据
|
||||
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||
* @value true 启用分布查询,仅查询当前选中节点
|
||||
* @value false 关闭分布查询,一次查询出所有数据
|
||||
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||
* @property {String|DBCollectionString} collection 表名
|
||||
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||
* @property {String} orderby 排序字段及正序倒叙设置
|
||||
* @property {String|JQLString} where 查询条件
|
||||
* @event {Function} popupshow 弹出的选择窗口打开时触发此事件
|
||||
* @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
|
||||
*/
|
||||
export default {
|
||||
name: 'UniDataPicker',
|
||||
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
|
||||
mixins: [dataPicker],
|
||||
components: {
|
||||
DataPickerView
|
||||
},
|
||||
props: {
|
||||
options: {
|
||||
type: [Object, Array],
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
popupTitle: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
heightMobile: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
clearIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
split: {
|
||||
type: String,
|
||||
default: '/'
|
||||
},
|
||||
ellipsis: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpened: false,
|
||||
inputSelected: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form = this.getForm('uniForms')
|
||||
this.formItem = this.getForm('uniFormsItem')
|
||||
if (this.formItem) {
|
||||
if (this.formItem.name) {
|
||||
this.rename = this.formItem.name
|
||||
this.form.inputChildrens.push(this)
|
||||
}
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.load()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
clear() {
|
||||
this.inputSelected.splice(0)
|
||||
this._dispatchEvent([])
|
||||
},
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this.selectedIndex = 0
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
if (this.readonly) {
|
||||
this._processReadonly(this.localdata, this.dataValue)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLocaldata) {
|
||||
this.loadData()
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
} else if (!this.parentField && !this.selfField && this.hasValue) {
|
||||
this.getNodeData(() => {
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
})
|
||||
} else if (this.hasValue) {
|
||||
this.getTreePath(() => {
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
})
|
||||
}
|
||||
},
|
||||
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;
|
||||
},
|
||||
show() {
|
||||
this.isOpened = true
|
||||
setTimeout(() => {
|
||||
this.$refs.pickerView.updateData({
|
||||
treeData: this._treeData,
|
||||
selected: this.selected,
|
||||
selectedIndex: this.selectedIndex
|
||||
})
|
||||
}, 200)
|
||||
this.$emit('popupopened')
|
||||
},
|
||||
hide() {
|
||||
this.isOpened = false
|
||||
this.$emit('popupclosed')
|
||||
},
|
||||
handleInput() {
|
||||
if (this.readonly) {
|
||||
return
|
||||
}
|
||||
this.show()
|
||||
},
|
||||
handleClose(e) {
|
||||
this.hide()
|
||||
},
|
||||
onnodeclick(e) {
|
||||
this.$emit('nodeclick', e)
|
||||
},
|
||||
ondatachange(e) {
|
||||
this._treeData = this.$refs.pickerView._treeData
|
||||
},
|
||||
onchange(e) {
|
||||
this.hide()
|
||||
this.$nextTick(() => {
|
||||
this.inputSelected = e;
|
||||
})
|
||||
this._dispatchEvent(e)
|
||||
},
|
||||
_processReadonly(dataList, value) {
|
||||
var isTree = dataList.findIndex((item) => {
|
||||
return item.children
|
||||
})
|
||||
if (isTree > -1) {
|
||||
let inputValue
|
||||
if (Array.isArray(value)) {
|
||||
inputValue = value[value.length - 1]
|
||||
if (typeof inputValue === 'object' && inputValue.value) {
|
||||
inputValue = inputValue.value
|
||||
}
|
||||
} else {
|
||||
inputValue = value
|
||||
}
|
||||
this.inputSelected = this._findNodePath(inputValue, this.localdata)
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.hasValue) {
|
||||
this.inputSelected = []
|
||||
return
|
||||
}
|
||||
|
||||
let result = []
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
var val = value[i]
|
||||
var item = dataList.find((v) => {
|
||||
return v.value == val
|
||||
})
|
||||
if (item) {
|
||||
result.push(item)
|
||||
}
|
||||
}
|
||||
if (result.length) {
|
||||
this.inputSelected = result
|
||||
}
|
||||
},
|
||||
_filterForArray(data, valueArray) {
|
||||
var result = []
|
||||
for (let i = 0; i < valueArray.length; i++) {
|
||||
var value = valueArray[i]
|
||||
var found = data.find((item) => {
|
||||
return item.value == value
|
||||
})
|
||||
if (found) {
|
||||
result.push(found)
|
||||
}
|
||||
}
|
||||
return result
|
||||
},
|
||||
_dispatchEvent(selected) {
|
||||
let item = {}
|
||||
if (selected.length) {
|
||||
var value = new Array(selected.length)
|
||||
for (var i = 0; i < selected.length; i++) {
|
||||
value[i] = selected[i].value
|
||||
}
|
||||
item = selected[selected.length - 1]
|
||||
} else {
|
||||
item.value = ''
|
||||
}
|
||||
if (this.formItem) {
|
||||
this.formItem.setValue(item.value)
|
||||
}
|
||||
|
||||
this.$emit('input', item.value)
|
||||
this.$emit('update:modelValue', item.value)
|
||||
this.$emit('change', {
|
||||
detail: {
|
||||
value: selected
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style >
|
||||
.uni-data-tree {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: #DD524D;
|
||||
}
|
||||
|
||||
.input-value {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
font-size: 14px;
|
||||
/* line-height: 35px; */
|
||||
padding: 0 10px;
|
||||
padding-right: 5px;
|
||||
overflow: hidden;
|
||||
height: 35px;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.input-value-border {
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.selected-area {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
/* #ifndef APP-NVUE */
|
||||
margin-right: auto;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 40px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.selected-list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
/* padding: 0 5px; */
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
flex-direction: row;
|
||||
/* padding: 0 1px; */
|
||||
/* #ifndef APP-NVUE */
|
||||
white-space: nowrap;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: grey;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.input-split-line {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.arrow-area {
|
||||
position: relative;
|
||||
width: 20px;
|
||||
/* #ifndef APP-NVUE */
|
||||
margin-bottom: 5px;
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
transform: rotate(-45deg);
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.input-arrow {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-left: 1px solid #999;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
.uni-data-tree-cover {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, .4);
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.uni-data-tree-dialog {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 20%;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #FFFFFF;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
z-index: 102;
|
||||
overflow: hidden;
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 750rpx;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.dialog-caption {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
}
|
||||
|
||||
.title-area {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
margin: auto;
|
||||
/* #endif */
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
/* font-weight: bold; */
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.dialog-close-plus {
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background-color: #666;
|
||||
border-radius: 2px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.dialog-close-rotate {
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.picker-view {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon-clear {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* #ifdef H5 */
|
||||
@media all and (min-width: 768px) {
|
||||
.uni-data-tree-cover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-data-tree-dialog {
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
height: auto;
|
||||
min-height: 400px;
|
||||
max-height: 50vh;
|
||||
background-color: #fff;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
overflow: unset;
|
||||
}
|
||||
|
||||
.dialog-caption {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.icon-clear {
|
||||
/* margin-right: 5px; */
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-popper__arrow,
|
||||
.uni-popper__arrow::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 6px;
|
||||
}
|
||||
|
||||
.uni-popper__arrow {
|
||||
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
|
||||
top: -6px;
|
||||
left: 10%;
|
||||
margin-right: 3px;
|
||||
border-top-width: 0;
|
||||
border-bottom-color: #EBEEF5;
|
||||
}
|
||||
|
||||
.uni-popper__arrow::after {
|
||||
content: " ";
|
||||
top: 1px;
|
||||
margin-left: -6px;
|
||||
border-top-width: 0;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
@@ -0,0 +1,563 @@
|
||||
export default {
|
||||
props: {
|
||||
localdata: {
|
||||
type: [Array, Object],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
spaceInfo: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
collection: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
action: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
field: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
orderby: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
where: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
pageData: {
|
||||
type: String,
|
||||
default: 'add'
|
||||
},
|
||||
pageCurrent: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
getcount: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
getone: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
gettree: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
manual: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: [Array, String, Number],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
modelValue: {
|
||||
type: [Array, String, Number],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
preload: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
stepSearh: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selfField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
parentField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
map: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
text: "text",
|
||||
value: "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
errorMessage: '',
|
||||
loadMore: {
|
||||
contentdown: '',
|
||||
contentrefresh: '',
|
||||
contentnomore: ''
|
||||
},
|
||||
dataList: [],
|
||||
selected: [],
|
||||
selectedIndex: 0,
|
||||
page: {
|
||||
current: this.pageCurrent,
|
||||
size: this.pageSize,
|
||||
count: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLocaldata() {
|
||||
return !this.collection.length
|
||||
},
|
||||
postField() {
|
||||
let fields = [this.field];
|
||||
if (this.parentField) {
|
||||
fields.push(`${this.parentField} as parent_value`);
|
||||
}
|
||||
return fields.join(',');
|
||||
},
|
||||
dataValue() {
|
||||
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
|
||||
return isModelValue ? this.modelValue : this.value
|
||||
},
|
||||
hasValue() {
|
||||
if (typeof this.dataValue === 'number') {
|
||||
return true
|
||||
}
|
||||
return (this.dataValue != null) && (this.dataValue.length > 0)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$watch(() => {
|
||||
var al = [];
|
||||
['pageCurrent',
|
||||
'pageSize',
|
||||
'spaceInfo',
|
||||
'value',
|
||||
'modelValue',
|
||||
'localdata',
|
||||
'collection',
|
||||
'action',
|
||||
'field',
|
||||
'orderby',
|
||||
'where',
|
||||
'getont',
|
||||
'getcount',
|
||||
'gettree'
|
||||
].forEach(key => {
|
||||
al.push(this[key])
|
||||
});
|
||||
return al
|
||||
}, (newValue, oldValue) => {
|
||||
let needReset = false
|
||||
for (let i = 2; i < newValue.length; i++) {
|
||||
if (newValue[i] != oldValue[i]) {
|
||||
needReset = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (newValue[0] != oldValue[0]) {
|
||||
this.page.current = this.pageCurrent
|
||||
}
|
||||
this.page.size = this.pageSize
|
||||
|
||||
this.onPropsChange()
|
||||
})
|
||||
this._treeData = []
|
||||
},
|
||||
methods: {
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
},
|
||||
getCommand(options = {}) {
|
||||
/* eslint-disable no-undef */
|
||||
let db = uniCloud.database(this.spaceInfo)
|
||||
|
||||
const action = options.action || this.action
|
||||
if (action) {
|
||||
db = db.action(action)
|
||||
}
|
||||
|
||||
const collection = options.collection || this.collection
|
||||
db = db.collection(collection)
|
||||
|
||||
const where = options.where || this.where
|
||||
if (!(!where || !Object.keys(where).length)) {
|
||||
db = db.where(where)
|
||||
}
|
||||
|
||||
const field = options.field || this.field
|
||||
if (field) {
|
||||
db = db.field(field)
|
||||
}
|
||||
|
||||
const orderby = options.orderby || this.orderby
|
||||
if (orderby) {
|
||||
db = db.orderBy(orderby)
|
||||
}
|
||||
|
||||
const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
|
||||
const size = options.pageSize !== undefined ? options.pageSize : this.page.size
|
||||
const getCount = options.getcount !== undefined ? options.getcount : this.getcount
|
||||
const getTree = options.gettree !== undefined ? options.gettree : this.gettree
|
||||
|
||||
const getOptions = {
|
||||
getCount,
|
||||
getTree
|
||||
}
|
||||
if (options.getTreePath) {
|
||||
getOptions.getTreePath = options.getTreePath
|
||||
}
|
||||
|
||||
db = db.skip(size * (current - 1)).limit(size).get(getOptions)
|
||||
|
||||
return db
|
||||
},
|
||||
getNodeData(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
where: this._pathWhere()
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
this.selected = res.result.data
|
||||
callback && callback()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
getTreePath(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
getTreePath: {
|
||||
startWith: `${this.selfField}=='${this.dataValue}'`
|
||||
}
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
let treePath = []
|
||||
this._extractTreePath(res.result.data, treePath)
|
||||
this.selected = treePath
|
||||
callback && callback()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
loadData() {
|
||||
if (this.isLocaldata) {
|
||||
this._processLocalData()
|
||||
return
|
||||
}
|
||||
|
||||
if (this.dataValue != null) {
|
||||
this._loadNodeData((data) => {
|
||||
this._treeData = data
|
||||
this._updateBindData()
|
||||
this._updateSelected()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (this.stepSearh) {
|
||||
this._loadNodeData((data) => {
|
||||
this._treeData = data
|
||||
this._updateBindData()
|
||||
})
|
||||
} else {
|
||||
this._loadAllData((data) => {
|
||||
this._treeData = []
|
||||
this._extractTree(data, this._treeData, null)
|
||||
this._updateBindData()
|
||||
})
|
||||
}
|
||||
},
|
||||
_loadAllData(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
gettree: true,
|
||||
startwith: `${this.selfField}=='${this.dataValue}'`
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
callback(res.result.data)
|
||||
this.onDataChange()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
_loadNodeData(callback, pw) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
where: pw || this._postWhere(),
|
||||
pageSize: 500
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
callback(res.result.data)
|
||||
this.onDataChange()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
_pathWhere() {
|
||||
let result = []
|
||||
let where_field = this._getParentNameByField();
|
||||
if (where_field) {
|
||||
result.push(`${where_field} == '${this.dataValue}'`)
|
||||
}
|
||||
|
||||
if (this.where) {
|
||||
return `(${this.where}) && (${result.join(' || ')})`
|
||||
}
|
||||
|
||||
return result.join(' || ')
|
||||
},
|
||||
_postWhere() {
|
||||
let result = []
|
||||
let selected = this.selected
|
||||
let parentField = this.parentField
|
||||
if (parentField) {
|
||||
result.push(`${parentField} == null || ${parentField} == ""`)
|
||||
}
|
||||
if (selected.length) {
|
||||
for (var i = 0; i < selected.length - 1; i++) {
|
||||
result.push(`${parentField} == '${selected[i].value}'`)
|
||||
}
|
||||
}
|
||||
|
||||
let where = []
|
||||
if (this.where) {
|
||||
where.push(`(${this.where})`)
|
||||
}
|
||||
if (result.length) {
|
||||
where.push(`(${result.join(' || ')})`)
|
||||
}
|
||||
|
||||
return where.join(' && ')
|
||||
},
|
||||
_nodeWhere() {
|
||||
let result = []
|
||||
let selected = this.selected
|
||||
if (selected.length) {
|
||||
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
|
||||
}
|
||||
|
||||
if (this.where) {
|
||||
return `(${this.where}) && (${result.join(' || ')})`
|
||||
}
|
||||
|
||||
return result.join(' || ')
|
||||
},
|
||||
_getParentNameByField() {
|
||||
const fields = this.field.split(',');
|
||||
let where_field = null;
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const items = fields[i].split('as');
|
||||
if (items.length < 2) {
|
||||
continue;
|
||||
}
|
||||
if (items[1].trim() === 'value') {
|
||||
where_field = items[0].trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return where_field
|
||||
},
|
||||
_isTreeView() {
|
||||
return (this.parentField && this.selfField)
|
||||
},
|
||||
_updateSelected() {
|
||||
var dl = this.dataList
|
||||
var sl = this.selected
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
for (var i = 0; i < sl.length; i++) {
|
||||
var value = sl[i].value
|
||||
var dl2 = dl[i]
|
||||
for (var j = 0; j < dl2.length; j++) {
|
||||
var item2 = dl2[j]
|
||||
if (item2[valueField] === value) {
|
||||
sl[i].text = item2[textField]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_updateBindData(node) {
|
||||
const {
|
||||
dataList,
|
||||
hasNodes
|
||||
} = this._filterData(this._treeData, this.selected)
|
||||
|
||||
let isleaf = this._stepSearh === false && !hasNodes
|
||||
|
||||
if (node) {
|
||||
node.isleaf = isleaf
|
||||
}
|
||||
|
||||
this.dataList = dataList
|
||||
this.selectedIndex = dataList.length - 1
|
||||
|
||||
if (!isleaf && this.selected.length < dataList.length) {
|
||||
this.selected.push({
|
||||
value: null,
|
||||
text: "请选择"
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
isleaf,
|
||||
hasNodes
|
||||
}
|
||||
},
|
||||
_filterData(data, paths) {
|
||||
let dataList = []
|
||||
let hasNodes = true
|
||||
|
||||
dataList.push(data.filter((item) => {
|
||||
return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
|
||||
}))
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
var value = paths[i].value
|
||||
var nodes = data.filter((item) => {
|
||||
return item.parent_value === value
|
||||
})
|
||||
|
||||
if (nodes.length) {
|
||||
dataList.push(nodes)
|
||||
} else {
|
||||
hasNodes = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dataList,
|
||||
hasNodes
|
||||
}
|
||||
},
|
||||
_extractTree(nodes, result, parent_value) {
|
||||
let list = result || []
|
||||
let valueField = this.map.value
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i]
|
||||
|
||||
let child = {}
|
||||
for (let key in node) {
|
||||
if (key !== 'children') {
|
||||
child[key] = node[key]
|
||||
}
|
||||
}
|
||||
if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
|
||||
child.parent_value = parent_value
|
||||
}
|
||||
result.push(child)
|
||||
|
||||
let children = node.children
|
||||
if (children) {
|
||||
this._extractTree(children, result, node[valueField])
|
||||
}
|
||||
}
|
||||
},
|
||||
_extractTreePath(nodes, result) {
|
||||
let list = result || []
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i]
|
||||
|
||||
let child = {}
|
||||
for (let key in node) {
|
||||
if (key !== 'children') {
|
||||
child[key] = node[key]
|
||||
}
|
||||
}
|
||||
result.push(child)
|
||||
|
||||
let children = node.children
|
||||
if (children) {
|
||||
this._extractTreePath(children, result)
|
||||
}
|
||||
}
|
||||
},
|
||||
_findNodePath(key, nodes, path = []) {
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i]
|
||||
let children = node.children
|
||||
let text = node[textField]
|
||||
let value = node[valueField]
|
||||
|
||||
path.push({
|
||||
value,
|
||||
text
|
||||
})
|
||||
|
||||
if (value === key) {
|
||||
return path
|
||||
}
|
||||
|
||||
if (children) {
|
||||
const p = this._findNodePath(key, children, path)
|
||||
if (p.length) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
path.pop()
|
||||
}
|
||||
return []
|
||||
},
|
||||
_processLocalData() {
|
||||
this._treeData = []
|
||||
this._extractTree(this.localdata, this._treeData)
|
||||
|
||||
var inputValue = this.dataValue
|
||||
if (inputValue === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(inputValue)) {
|
||||
inputValue = inputValue[inputValue.length - 1]
|
||||
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
|
||||
inputValue = inputValue[this.map.value]
|
||||
}
|
||||
}
|
||||
|
||||
this.selected = this._findNodePath(inputValue, this.localdata)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
<template>
|
||||
<view class="uni-data-pickerview">
|
||||
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
|
||||
<view class="selected-list">
|
||||
<template v-for="(item,index) in selected">
|
||||
<view class="selected-item"
|
||||
:class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
|
||||
v-if="item.text" @click="handleSelect(index)">
|
||||
<text class="">{{item.text}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-c">
|
||||
<template v-for="(child, i) in dataList" >
|
||||
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
|
||||
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child" :key="j"
|
||||
@click="handleNodeClick(item, i, j)">
|
||||
<text class="item-text item-text-overflow">{{item[map.text]}}</text>
|
||||
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<view class="loading-cover" v-if="loading">
|
||||
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||
</view>
|
||||
<view class="error-message" v-if="errorMessage">
|
||||
<text class="error-text">{{errorMessage}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dataPicker from "./uni-data-picker.js"
|
||||
|
||||
/**
|
||||
* DataPickerview
|
||||
* @description uni-data-pickerview
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||
* @property {Array} localdata 本地数据,参考
|
||||
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||
* @value true 启用分布查询,仅查询当前选中节点
|
||||
* @value false 关闭分布查询,一次查询出所有数据
|
||||
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||
* @property {String|DBCollectionString} collection 表名
|
||||
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||
* @property {String} orderby 排序字段及正序倒叙设置
|
||||
* @property {String|JQLString} where 查询条件
|
||||
*/
|
||||
export default {
|
||||
name: 'UniDataPickerView',
|
||||
emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
|
||||
mixins: [dataPicker],
|
||||
props: {
|
||||
managedMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
ellipsis: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (this.managedMode) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.load()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this.selectedIndex = 0
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
if (this.isLocaldata) {
|
||||
this.loadData()
|
||||
} else if (this.dataValue.length) {
|
||||
this.getTreePath((res) => {
|
||||
this.loadData()
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelect(index) {
|
||||
this.selectedIndex = index
|
||||
},
|
||||
handleNodeClick(item, i, j) {
|
||||
if (item.disable) {
|
||||
return
|
||||
}
|
||||
const node = this.dataList[i][j]
|
||||
const text = node[this.map.text]
|
||||
const value = node[this.map.value]
|
||||
if (i < this.selected.length - 1) {
|
||||
this.selected.splice(i, this.selected.length - i)
|
||||
this.selected.push({
|
||||
text,
|
||||
value
|
||||
})
|
||||
} else if (i === this.selected.length - 1) {
|
||||
this.selected.splice(i, 1, {
|
||||
text,
|
||||
value
|
||||
})
|
||||
}
|
||||
|
||||
if (node.isleaf) {
|
||||
this.onSelectedChange(node, node.isleaf)
|
||||
return
|
||||
}
|
||||
|
||||
const {
|
||||
isleaf,
|
||||
hasNodes
|
||||
} = this._updateBindData()
|
||||
|
||||
if (!this._isTreeView() && !hasNodes) {
|
||||
this.onSelectedChange(node, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLocaldata && (!hasNodes || isleaf)) {
|
||||
this.onSelectedChange(node, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isleaf && !hasNodes) {
|
||||
this._loadNodeData((data) => {
|
||||
if (!data.length) {
|
||||
node.isleaf = true
|
||||
} else {
|
||||
this._treeData.push(...data)
|
||||
this._updateBindData(node)
|
||||
}
|
||||
this.onSelectedChange(node, node.isleaf)
|
||||
}, this._nodeWhere())
|
||||
return
|
||||
}
|
||||
|
||||
this.onSelectedChange(node, false)
|
||||
},
|
||||
updateData(data) {
|
||||
this._treeData = data.treeData
|
||||
this.selected = data.selected
|
||||
if (!this._treeData.length) {
|
||||
this.loadData()
|
||||
} else {
|
||||
//this.selected = data.selected
|
||||
this._updateBindData()
|
||||
}
|
||||
},
|
||||
onDataChange() {
|
||||
this.$emit('datachange')
|
||||
},
|
||||
onSelectedChange(node, isleaf) {
|
||||
if (isleaf) {
|
||||
this._dispatchEvent()
|
||||
}
|
||||
|
||||
if (node) {
|
||||
this.$emit('nodeclick', node)
|
||||
}
|
||||
},
|
||||
_dispatchEvent() {
|
||||
this.$emit('change', this.selected.slice(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-data-pickerview {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: #DD524D;
|
||||
}
|
||||
|
||||
.loading-cover {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
/* #ifndef APP-NVUE */
|
||||
margin: auto;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 15px;
|
||||
opacity: .9;
|
||||
z-index: 102;
|
||||
}
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
.selected-area {
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.selected-list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0 5px;
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
padding: 12px 0;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
white-space: nowrap;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.selected-item-text-overflow {
|
||||
width: 168px;
|
||||
/* fix nvue */
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 6em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.selected-item-active {
|
||||
border-bottom: 2px solid $uni-primary;
|
||||
}
|
||||
|
||||
.selected-item-text {
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
.tab-c {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 12px 15px;
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
/* flex: 1; */
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.item-text-overflow {
|
||||
width: 280px;
|
||||
/* fix nvue */
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 20em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.check {
|
||||
margin-right: 5px;
|
||||
border: 2px solid $uni-primary;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
height: 12px;
|
||||
width: 6px;
|
||||
transform-origin: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
transition: all 0.3s;
|
||||
/* #endif */
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
90
uni-im示例/uni_modules/uni-data-picker/package.json
Normal file
90
uni-im示例/uni_modules/uni-data-picker/package.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "uni-data-picker",
|
||||
"displayName": "uni-data-picker 数据驱动的picker选择器",
|
||||
"version": "1.0.9",
|
||||
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"picker",
|
||||
"级联",
|
||||
"省市区",
|
||||
""
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"uni-load-more",
|
||||
"uni-icons",
|
||||
"uni-scss"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
uni-im示例/uni_modules/uni-data-picker/readme.md
Normal file
22
uni-im示例/uni_modules/uni-data-picker/readme.md
Normal file
@@ -0,0 +1,22 @@
|
||||
## DataPicker 级联选择
|
||||
> **组件名:uni-data-picker**
|
||||
> 代码块: `uDataPicker`
|
||||
> 关联组件:`uni-data-pickerview`、`uni-load-more`。
|
||||
|
||||
|
||||
`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。
|
||||
|
||||
支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
|
||||
|
||||
候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
|
||||
|
||||
`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。
|
||||
|
||||
`<uni-data-picker>` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
|
||||
|
||||
`<uni-data-picker>` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
|
||||
|
||||
在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
10
uni-im示例/uni_modules/uni-dateformat/changelog.md
Normal file
10
uni-im示例/uni_modules/uni-dateformat/changelog.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## 1.0.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-dateformat](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
|
||||
## 0.0.5(2021-07-08)
|
||||
- 调整 默认时间不再是当前时间,而是显示'-'字符
|
||||
## 0.0.4(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 0.0.3(2021-02-04)
|
||||
- 调整为uni_modules目录规范
|
||||
- 修复 iOS 平台日期格式化出错的问题
|
||||
@@ -0,0 +1,200 @@
|
||||
// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型
|
||||
function pad(str, length = 2) {
|
||||
str += ''
|
||||
while (str.length < length) {
|
||||
str = '0' + str
|
||||
}
|
||||
return str.slice(-length)
|
||||
}
|
||||
|
||||
const parser = {
|
||||
yyyy: (dateObj) => {
|
||||
return pad(dateObj.year, 4)
|
||||
},
|
||||
yy: (dateObj) => {
|
||||
return pad(dateObj.year)
|
||||
},
|
||||
MM: (dateObj) => {
|
||||
return pad(dateObj.month)
|
||||
},
|
||||
M: (dateObj) => {
|
||||
return dateObj.month
|
||||
},
|
||||
dd: (dateObj) => {
|
||||
return pad(dateObj.day)
|
||||
},
|
||||
d: (dateObj) => {
|
||||
return dateObj.day
|
||||
},
|
||||
hh: (dateObj) => {
|
||||
return pad(dateObj.hour)
|
||||
},
|
||||
h: (dateObj) => {
|
||||
return dateObj.hour
|
||||
},
|
||||
mm: (dateObj) => {
|
||||
return pad(dateObj.minute)
|
||||
},
|
||||
m: (dateObj) => {
|
||||
return dateObj.minute
|
||||
},
|
||||
ss: (dateObj) => {
|
||||
return pad(dateObj.second)
|
||||
},
|
||||
s: (dateObj) => {
|
||||
return dateObj.second
|
||||
},
|
||||
SSS: (dateObj) => {
|
||||
return pad(dateObj.millisecond, 3)
|
||||
},
|
||||
S: (dateObj) => {
|
||||
return dateObj.millisecond
|
||||
},
|
||||
}
|
||||
|
||||
// 这都n年了iOS依然不认识2020-12-12,需要转换为2020/12/12
|
||||
function getDate(time) {
|
||||
if (time instanceof Date) {
|
||||
return time
|
||||
}
|
||||
switch (typeof time) {
|
||||
case 'string':
|
||||
{
|
||||
// 2020-12-12T12:12:12.000Z、2020-12-12T12:12:12.000
|
||||
if (time.indexOf('T') > -1) {
|
||||
return new Date(time)
|
||||
}
|
||||
return new Date(time.replace(/-/g, '/'))
|
||||
}
|
||||
default:
|
||||
return new Date(time)
|
||||
}
|
||||
}
|
||||
|
||||
export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') {
|
||||
if (!date && date !== 0) {
|
||||
return ''
|
||||
}
|
||||
date = getDate(date)
|
||||
const dateObj = {
|
||||
year: date.getFullYear(),
|
||||
month: date.getMonth() + 1,
|
||||
day: date.getDate(),
|
||||
hour: date.getHours(),
|
||||
minute: date.getMinutes(),
|
||||
second: date.getSeconds(),
|
||||
millisecond: date.getMilliseconds()
|
||||
}
|
||||
const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/
|
||||
let flag = true
|
||||
let result = format
|
||||
while (flag) {
|
||||
flag = false
|
||||
result = result.replace(tokenRegExp, function(matched) {
|
||||
flag = true
|
||||
return parser[matched](dateObj)
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function friendlyDate(time, {
|
||||
locale = 'zh',
|
||||
threshold = [60000, 3600000],
|
||||
format = 'yyyy/MM/dd hh:mm:ss'
|
||||
}) {
|
||||
if (time === '-') {
|
||||
return time
|
||||
}
|
||||
if (!time && time !== 0) {
|
||||
return ''
|
||||
}
|
||||
const localeText = {
|
||||
zh: {
|
||||
year: '年',
|
||||
month: '月',
|
||||
day: '天',
|
||||
hour: '小时',
|
||||
minute: '分钟',
|
||||
second: '秒',
|
||||
ago: '前',
|
||||
later: '后',
|
||||
justNow: '刚刚',
|
||||
soon: '马上',
|
||||
template: '{num}{unit}{suffix}'
|
||||
},
|
||||
en: {
|
||||
year: 'year',
|
||||
month: 'month',
|
||||
day: 'day',
|
||||
hour: 'hour',
|
||||
minute: 'minute',
|
||||
second: 'second',
|
||||
ago: 'ago',
|
||||
later: 'later',
|
||||
justNow: 'just now',
|
||||
soon: 'soon',
|
||||
template: '{num} {unit} {suffix}'
|
||||
}
|
||||
}
|
||||
const text = localeText[locale] || localeText.zh
|
||||
let date = getDate(time)
|
||||
let ms = date.getTime() - Date.now()
|
||||
let absMs = Math.abs(ms)
|
||||
if (absMs < threshold[0]) {
|
||||
return ms < 0 ? text.justNow : text.soon
|
||||
}
|
||||
if (absMs >= threshold[1]) {
|
||||
return formatDate(date, format)
|
||||
}
|
||||
let num
|
||||
let unit
|
||||
let suffix = text.later
|
||||
if (ms < 0) {
|
||||
suffix = text.ago
|
||||
ms = -ms
|
||||
}
|
||||
const seconds = Math.floor((ms) / 1000)
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
const hours = Math.floor(minutes / 60)
|
||||
const days = Math.floor(hours / 24)
|
||||
const months = Math.floor(days / 30)
|
||||
const years = Math.floor(months / 12)
|
||||
switch (true) {
|
||||
case years > 0:
|
||||
num = years
|
||||
unit = text.year
|
||||
break
|
||||
case months > 0:
|
||||
num = months
|
||||
unit = text.month
|
||||
break
|
||||
case days > 0:
|
||||
num = days
|
||||
unit = text.day
|
||||
break
|
||||
case hours > 0:
|
||||
num = hours
|
||||
unit = text.hour
|
||||
break
|
||||
case minutes > 0:
|
||||
num = minutes
|
||||
unit = text.minute
|
||||
break
|
||||
default:
|
||||
num = seconds
|
||||
unit = text.second
|
||||
break
|
||||
}
|
||||
|
||||
if (locale === 'en') {
|
||||
if (num === 1) {
|
||||
num = 'a'
|
||||
} else {
|
||||
unit += 's'
|
||||
}
|
||||
}
|
||||
|
||||
return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g,
|
||||
suffix)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<text>{{dateShow}}</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {friendlyDate} from './date-format.js'
|
||||
/**
|
||||
* Dateformat 日期格式化
|
||||
* @description 日期格式化组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3279
|
||||
* @property {Object|String|Number} date 日期对象/日期字符串/时间戳
|
||||
* @property {String} locale 格式化使用的语言
|
||||
* @value zh 中文
|
||||
* @value en 英文
|
||||
* @property {Array} threshold 应用不同类型格式化的阈值
|
||||
* @property {String} format 输出日期字符串时的格式
|
||||
*/
|
||||
export default {
|
||||
name: 'uniDateformat',
|
||||
props: {
|
||||
date: {
|
||||
type: [Object, String, Number],
|
||||
default () {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
locale: {
|
||||
type: String,
|
||||
default: 'zh',
|
||||
},
|
||||
threshold: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [0, 0]
|
||||
}
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: 'yyyy/MM/dd hh:mm:ss'
|
||||
},
|
||||
// refreshRate使用不当可能导致性能问题,谨慎使用
|
||||
refreshRate: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
refreshMark: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dateShow() {
|
||||
this.refreshMark
|
||||
return friendlyDate(this.date, {
|
||||
locale: this.locale,
|
||||
threshold: this.threshold,
|
||||
format: this.format
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
refreshRate: {
|
||||
handler() {
|
||||
this.setAutoRefresh()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh() {
|
||||
this.refreshMark++
|
||||
},
|
||||
setAutoRefresh() {
|
||||
clearInterval(this.refreshInterval)
|
||||
if (this.refreshRate) {
|
||||
this.refreshInterval = setInterval(() => {
|
||||
this.refresh()
|
||||
}, parseInt(this.refreshRate))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
88
uni-im示例/uni_modules/uni-dateformat/package.json
Normal file
88
uni-im示例/uni_modules/uni-dateformat/package.json
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"id": "uni-dateformat",
|
||||
"displayName": "uni-dateformat 日期格式化",
|
||||
"version": "1.0.0",
|
||||
"description": "日期格式化组件,可以将日期格式化为1分钟前、刚刚等形式",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"日期格式化",
|
||||
"时间格式化",
|
||||
"格式化时间",
|
||||
""
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss"],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
uni-im示例/uni_modules/uni-dateformat/readme.md
Normal file
11
uni-im示例/uni_modules/uni-dateformat/readme.md
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
### DateFormat 日期格式化
|
||||
> **组件名:uni-dateformat**
|
||||
> 代码块: `uDateformat`
|
||||
|
||||
|
||||
日期格式化组件。
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-dateformat)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user