提交 54831c95 编写于 作者: A Anne_LXM

Merge branch 'jest-branch' of https://gitcode.net/dcloud/uni-starter into jest-branch

<template>
<view @click="onClick" :style="{width,height}" style="justify-content: center;">
<image v-if="cSrc" :style="{width,height}" :src="cSrc" :mode="mode"></image>
</view>
</template>
<script>
/**
* cloud-image
* @description 兼容普通资源和unicloud图片资源渲染的组件
* @property {String} mode 图片裁剪、缩放的模式。默认为widthFix,支持所有image组件的mode值
* @property {String} src 资源完了链接或uniCloud云存储资源的fileid
* @property {String} width 图片的宽,默认为:100rpx
* @property {String} height 图片的高,默认为:100rpx
* @event {Function} click 点击 cloud-image 触发事件
*/
export default {
name: "cloud-image",
emits:['click'],
props: {
mode: {
type:String,
default () {
return 'widthFix'
}
},
src: {
// type:String,
default () {
return ""
}
},
width: {
type:String,
default () {
return '100rpx'
}
},
height: {
type:String,
default () {
return '100rpx'
}
}
},
watch: {
src:{
handler(src) {
if (src&&src.substring(0, 8) == "cloud://") {
uniCloud.getTempFileURL({
fileList: [src]
}).then(res=>{
this.cSrc = res.fileList[0].tempFileURL
})
}else{
this.cSrc = src
}
},
immediate: true
}
},
methods:{
onClick(){
this.$emit('click')
}
},
data() {
return {
cSrc:false
};
}
}
</script>
\ No newline at end of file
......@@ -43,29 +43,32 @@
}
}
}
}
}
},
"quickapp": {
},
"mp-weixin": {
"appid": "",
"setting": {
"urlCheck": false
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"optimization" : {
"subPackages" : true
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
}
"usingComponents": true,
"optimization": {
"subPackages": true
}
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "2"
}
\ No newline at end of file
// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/hellodb?id=db-init
// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据
{
"uni-id-users": {
"data": [{
"_id": "_uni_starter_test_user_id",
"username": "uni-starter预置用户名",
"nickname": "测试用户昵称",
"avatar": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png",
"avatar": "https://unicloud.dcloud.net.cn/assets/logo.dca09351.png",
"mobile": "18888888888",
"mobile_confirmed": 1
}]
},
"uni-id-roles": {
"data": [{
"role_id": "admin",
"role_name": "超级管理员",
"permission": [],
"comment": "超级管理员拥有所有权限",
"create_date": 0
}]
},
"opendb-banner": {
"data": [{
"status": true,
......@@ -18,14 +29,13 @@
"name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg",
"extname": "jpg",
"fileType": "image",
"url": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/b88a7e17-35f0-4d0d-bc32-93f8909baf03.jpg",
"url": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg",
"size": 70880,
"image": {
"width": 500,
"height": 333,
"location": "blob:http://localhost:8081/a3bfaab4-7ee6-44d5-a171-dc8225d83598"
"height": 333
},
"path": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/b88a7e17-35f0-4d0d-bc32-93f8909baf03.jpg"
"path": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg"
},
"open_url": "https://www.dcloud.io/",
"title": "测试",
......@@ -39,14 +49,13 @@
"name": "094a9dc0-50c0-11eb-b680-7980c8a877b8.jpg",
"extname": "jpg",
"fileType": "image",
"url": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/9db94cb4-a5e0-4ed9-b356-b42a392b3112.jpg",
"url": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg",
"size": 70880,
"image": {
"width": 500,
"height": 333,
"location": "blob:http://localhost:8081/1a6f718a-4012-476a-9172-590fef2cc518"
"height": 333
},
"path": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/9db94cb4-a5e0-4ed9-b356-b42a392b3112.jpg"
"path": "https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg"
},
"open_url": "https://www.dcloud.io/",
"title": "",
......@@ -59,8 +68,8 @@
"data": [{
"title": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务",
"excerpt": "阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务",
"content": "<p>随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。</p>\n<p>阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。</p>\n<p>经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。</p>\n<p>经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!</p>\n<p>如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。</p>\n<div class=\"aw-comment-upload-img-list active\"><img class=\"img-polaroid\" width=\"100%\" src=\"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/b698232a-e608-4b2d-8019-8dc6bbf343a8.png\" /></div>\n<p><br />阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable</p>\n<p>&nbsp;</p>\n<p>集成uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。</p>\n<p>这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app的产品确实过硬。</p>\n<p>很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。</p>\n<p>自从uni-app推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。</p>\n<p>本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。</p>\n<p>后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。</p>\n<p>使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。</p>\n<p>DCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。</p>\n<p>进一步了解uni-app,详见:https://uniapp.dcloud.io</p>\n<p>欢迎扫码关注DCloud公众号,转发消息到朋友圈。<br /><img src=\"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-76ce2c5e-31c7-4d81-8fcf-ed1541ecbc6e/27302ea5-e369-4e6c-89b1-431408497b3d.jpg\" width=\"80%\" /></p>",
"avatar": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-aliyun-gacrhzeynhss7c6d04/249516a0-3941-11eb-899d-733ae62bed2f.jpg",
"content": "<p>随着微信、阿里、百度、头条、QQ纷纷推出小程序,开发者的开发维护成本持续上升,负担过重。这点已经成为共识,现在连小程序平台厂商也充分意识到了。</p>\n<p>阿里小程序团队,为了减轻开发者的负担,在官方的小程序开发者工具中整合了多端框架。</p>\n<p>经过阿里团队仔细评估,uni-app 在产品完成度、跨平台支持度、开发者社区、可持续发展等多方面优势明显,最终选定 uni-app内置于阿里小程序开发工具中,为开发者提供多端开发解决方案。</p>\n<p>经过之前1个月的公测,10月10日,阿里小程序正式发布0.70版开发者工具,通过 uni-app 实现多端开发,成为本次版本更新的亮点功能!</p>\n<p>如下图,在阿里小程序工具左侧主导航选择 uni-app,创建项目,即可开发。</p>\n<div class=\"aw-comment-upload-img-list active\"><img class=\"img-polaroid\" width=\"100%\" src=\"https://ask.dcloud.net.cn/uploads/article/20191014/56f7dc1bd5f265e824649f7cb4f78d5b.png\" /></div>\n<p><br />阿里小程序开发工具更新说明详见:https://docs.alipay.com/mini/ide/0.70-stable</p>\n<p>&nbsp;</p>\n<p>集成uni-app,这对于阿里团队而言,并不是一个容易做出的决定。毕竟 uni-app 是一个三方产品,要经过复杂的评审流程。</p>\n<p>这一方面突显出阿里团队以开发者需求为本的优秀价值观,另一方面也证明 uni-app的产品确实过硬。</p>\n<p>很多开发者都有多端需求,但又没有足够精力去了解、评估 uni-app,而处于观望态度。现在大家可以更放心的使用 uni-app 了,它没有让阿里失望,也不会让你失望。</p>\n<p>自从uni-app推出以来,DCloud也取得了高速的发展,目前拥有370万开发者,框架运行在4.6亿手机用户设备上,月活达到1.35亿(仅包括部分接入DCloud统计平台的数据)。并且数据仍在高速增长中,在市场占有率上处于遥遥领先的位置。</p>\n<p>本次阿里小程序工具集成 uni-app,会让 uni-app 继续快速爆发,取得更大的成功。</p>\n<p>后续DCloud还将深化与阿里的合作,在serverless等领域给开发者提供更多优质服务。</p>\n<p>使用多端框架开发各端应用,是多赢的模式。开发者减轻了负担,获得了更多新流量。而小程序平台厂商,也能保证自己平台上的各种应用可以被及时的更新。</p>\n<p>DCloud欢迎更多小程序平台厂商,与我们一起合作,为开发者、平台、用户的多赢而努力。</p>\n<p>进一步了解uni-app,详见:https://uniapp.dcloud.io</p>\n<p>欢迎扫码关注DCloud公众号,转发消息到朋友圈。<br /><img src=\"https://web-assets.dcloud.net.cn/unidoc/zh/weixin.jpg\" width=\"80%\" /></p>",
"avatar": "https://ask.dcloud.net.cn/uploads/article/20191014/56f7dc1bd5f265e824649f7cb4f78d5b.png",
"type": 0,
"user_id": "_uni_starter_test_user_id",
"comment_count": 0,
......@@ -69,98 +78,9 @@
"article_status": 1,
"publish_date": 1616092287006,
"last_modify_date": 1616092303031,
"create_time": "2021-03-19T08:25:06.109Z"
"create_date": 1616092287006
}]
},
"opendb-app-versions": {
"data": [{
"is_silently": false,
"is_mandatory": false,
"appid": "__UNI__03B096E",
"name": "uni-starter",
"title": "新增升级中心",
"contents": "新增升级中心",
"platform": [
"Android"
],
"version": "1.0.1",
"url": "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-3469aac7-a663-4c5d-8ee8-94275f8c09ab/3128d010-01c5-4121-a1d6-f3f919944a23.apk",
"stable_publish": false,
"type": "native_app",
"create_date": 1616771628150
}],
"index": [{
"IndexName": "appid",
"MgoKeySchema": {
"MgoIndexKeys": [{
"Name": "appid",
"Direction": "1"
}, {
"Name": "uni_platform",
"Direction": "1"
}, {
"Name": "create_env",
"Direction": "1"
}],
"MgoIsUnique": false
}
}, {
"IndexName": "查找上线发行应用",
"MgoKeySchema": {
"MgoIndexKeys": [{
"Name": "appid",
"Direction": "1"
}, {
"Name": "platform",
"Direction": "1"
}, {
"Name": "stable_publish",
"Direction": "1"
}, {
"Name": "uni_platform",
"Direction": "1"
}, {
"Name": "create_env",
"Direction": "1"
}],
"MgoIsUnique": false
}
}]
},
"opendb-verify-codes": {
"data": []
},
"opendb-app-list": {
"data": [],
"index": [{
"IndexName": "appid",
"MgoKeySchema": {
"MgoIndexKeys": [{
"Name": "appid",
"Direction": "1"
}],
"MgoIsUnique": true
}
}, {
"IndexName": "name",
"MgoKeySchema": {
"MgoIndexKeys": [{
"Name": "name",
"Direction": "1"
}],
"MgoIsUnique": false
}
}]
},
"uni-id-roles": {
"data": []
},
"uni-id-permissions": {
"data": []
},
"uni-id-log": {
"data": []
},
"opendb-admin-menus": {
"data": [{
"menu_id": "index",
......@@ -578,9 +498,15 @@
"create_date": 1667387078947
}
]
},
},
"uni-id-permissions": {},
"uni-id-log": {},
"uni-id-tag": {},
"uni-id-device": {},
"uni-id-scores": {},
"opendb-verify-codes": {},
"opendb-app-list": {},
"opendb-app-versions": {},
"opendb-device": {},
"opendb-department": {},
"opendb-sms-task": {},
......@@ -595,6 +521,7 @@
"uni-stat-app-platforms": {},
"uni-stat-error-logs": {},
"uni-stat-error-result": {},
"uni-stat-error-source-map": {},
"uni-stat-event-logs": {},
"uni-stat-event-result": {},
"uni-stat-events": {},
......@@ -608,8 +535,8 @@
"uni-stat-session-logs": {},
"uni-stat-share-logs": {},
"uni-stat-user-session-logs": {},
"uni-pay-orders": {},
"uni-stat-pay-result": {},
"uni-pay-orders": {},
"opendb-tempdata": {},
"opendb-feedback": {},
"opendb-news-categories": {},
......@@ -618,6 +545,5 @@
"opendb-search-hot": {},
"opendb-search-log": {},
"opendb-sign-in": {},
"read-news-log": {},
"uni-id-scores": {}
"read-news-log": {}
}
module.exports = {
trigger: {
// 监听 - 删除前
beforeDelete: async function(obj = {}) {
let {
collection,
operation,
where,
field
} = obj;
// 删除表记录前先删除云存储内的文件
const db = uniCloud.database();
const _ = db.command;
let getRes = await db.collection("uni-stat-error-source-map").where(where).limit(1000).get();
let list = getRes.data;
if (list && list.length > 0) {
let fileList = list.map((item, index) => {
return item.file_id;
});
try {
let deleteFileRes = await uniCloud.deleteFile({
fileList
});
// console.log('deleteFileRes: ', deleteFileRes)
} catch (err) {}
}
}
}
}
{
"bsonType": "object",
"description": "存储sourceMap文件资源地址",
"required": [],
"permission": {
"read": "'READ_UNI_STAT_ERROR_RESULT' in auth.permission",
"create": "'READ_UNI_STAT_ERROR_RESULT' in auth.permission",
"update": "'READ_UNI_STAT_ERROR_RESULT' in auth.permission",
"delete": "'READ_UNI_STAT_ERROR_RESULT' in auth.permission"
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"appid": {
"bsonType": "string",
"description": "应用ID"
},
"uni_platform": {
"title": "应用平台",
"bsonType": "string",
"description": "uni客户端平台,如:web、mp-weixin、mp-alipay、app等",
"trim": "both"
},
"version": {
"bsonType": "string",
"description": "客户端上报的应用版本号"
},
"file_id": {
"bsonType": "string",
"description": "fileID"
},
"url": {
"bsonType": "string",
"description": "文件外网url路径"
},
"name": {
"bsonType": "string",
"description": "文件名"
},
"size": {
"bsonType": "int",
"description": "文件大小"
},
"cloud_path": {
"bsonType": "string",
"description": "云端路径,通过该值识别是否是同一个文件"
},
"base": {
"bsonType": "string",
"description": "基础路径"
},
"create_time": {
"bsonType": "timestamp",
"description": "上传时间",
"forceDefaultValue": {
"$env": "now"
}
}
}
}
function checkIdCard (idCardNumber) {
export default function checkIdCard (idCardNumber) {
if (!idCardNumber || typeof idCardNumber !== 'string' || idCardNumber.length !== 18) return false
const coefficient = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
......@@ -12,5 +12,3 @@ function checkIdCard (idCardNumber) {
return checkCode[sum % 11].toString() === code.toLowerCase()
}
export default checkIdCard
......@@ -92,4 +92,4 @@ const mixin = {
}
}
export default mixin
export default mixin
......@@ -79,7 +79,7 @@ export const mutations = {
uni.removeStorageSync('uni_id_token');
uni.setStorageSync('uni_id_token_expired', 0)
uni.redirectTo({
url: `/${pagesJson.uniIdRouter && pagesJson.uniIdRouter.loginPage ? pagesJson.uniIdRouter.loginPage: 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`,
url: `/${pagesJson.uniIdRouter && pagesJson.uniIdRouter.loginPage ? 'uni_modules/uni-id-pages/pages/login/login-withoutpwd': ''}`,
});
uni.$emit('uni-id-pages-logout')
this.setUserInfo({},{cover:true})
......
......@@ -71,31 +71,8 @@
let avatar_file = {
extname: avatarUrl.split('.')[avatarUrl.split('.').length - 1],
name:'',
url:avatarUrl
url:''
}
// 裁剪
let filePath = await new Promise((callback) => {
wx.cropImage({
src:avatarUrl,
cropScale:"1:1",
success: res => {
callback(res.tempFilePath)
},
fail(e){
console.error(e)
uni.showModal({
content: 'wx.cropImage ' + e.errMsg,
showCancel: false,
confirmText:"跳过裁剪",
complete() {
callback(avatarUrl)
}
});
}
})
})
//上传到服务器
let cloudPath = this.userInfo._id + '' + Date.now()
avatar_file.name = cloudPath
......@@ -107,7 +84,7 @@
let {
fileID
} = await uniCloud.uploadFile({
filePath,
filePath:avatarUrl,
cloudPath,
fileType: "image"
});
......@@ -116,20 +93,20 @@
}catch(e){
console.error(e);
}
console.log('avatar_file',avatar_file);
this.setAvatarFile(avatar_file)
},
uploadAvatarImg(res) {
// #ifdef MP-WEIXIN
return false // 微信小程序走 bindchooseavatar方法
// #endif
// #ifndef MP-WEIXIN
if(!this.hasLogin){
return uni.navigateTo({
url:'/uni_modules/uni-id-pages/pages/login/login-withoutpwd'
})
}
const crop = {
quality: 100,
width: 600,
......@@ -192,6 +169,7 @@
this.setAvatarFile(avatar_file)
}
})
// #endif
}
}
}
......
<template>
<view>
<uni-captcha :focus="focusCaptchaInput" ref="captcha" scene="send-email-code" v-model="captcha" />
<view class="box">
<uni-easyinput :focus="focusEmailCodeInput" @blur="focusEmailCodeInput = false" type="number" class="input-box" :inputBorder="false" v-model="modelValue" maxlength="6"
placeholder="请输入邮箱验证码">
</uni-easyinput>
<view class="short-code-btn" hover-class="hover" @click="start">
<text class="inner-text" :class="reverseNumber==0?'inner-text-active':''">{{innerText}}</text>
</view>
</view>
</view>
</template>
<script>
function debounce(func, wait) {
let timer;
wait = wait || 500;
return function() {
let context = this;
let args = arguments;
if (timer) clearTimeout(timer);
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
if (callNow) func.apply(context, args);
}
}
/**
* email-code-form
* @description 获取邮箱验证码组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=
* @property {Number} count 倒计时时长 s
* @property {String} email 邮箱
* @property {String} type = [login-by-email-code|reset-pwd-by-email-code|bind-email] 验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定邮箱、unbind解绑邮箱
* @property {false} focusCaptchaInput = [true|false] 验证码输入框是否默认获取焦点
*/
export default {
name: "uni-email-code-form",
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
props: {
event: ['update:modelValue'],
/**
* 倒计时时长 s
*/
count: {
type: [String, Number],
default: 60
},
/**
* 邮箱
*/
email: {
type: [String],
default: ''
},
/*
验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定邮箱、unbind解绑邮箱
*/
type: {
type: String,
default () {
return 'register'
}
},
/*
验证码输入框是否默认获取焦点
*/
focusCaptchaInput: {
type: Boolean,
default () {
return false
}
},
},
data() {
return {
captcha: "",
reverseNumber: 0,
reverseTimer: null,
modelValue: "",
focusEmailCodeInput:false
};
},
watch: {
captcha(value, oldValue) {
if (value.length == 4 && oldValue.length != 4) {
this.start()
}
},
modelValue(value) {
// TODO 兼容 vue2
this.$emit('input', value);
// TODO 兼容 vue3
this.$emit('update:modelValue', value)
}
},
computed: {
innerText() {
if (this.reverseNumber == 0) return "获取邮箱验证码";
return "重新发送" + '(' + this.reverseNumber + 's)';
}
},
created() {
this.initClick();
},
methods: {
getImageCaptcha(focus) {
this.$refs.captcha.getImageCaptcha(focus)
},
initClick() {
this.start = debounce(() => {
if (this.reverseNumber != 0) return;
this.sendMsg();
})
},
sendMsg() {
if (this.captcha.length != 4) {
this.$refs.captcha.focusCaptchaInput = true
return uni.showToast({
title: '请先输入图形验证码',
icon: 'none',
duration: 3000
});
}
if(!this.email) return uni.showToast({
title: "请输入邮箱",
icon: 'none',
duration: 3000
});
let reg_email = /@/;
if (!reg_email.test(this.email)) return uni.showToast({
title: "邮箱格式错误",
icon: 'none',
duration: 3000
});
const uniIdCo = uniCloud.importObject("uni-id-co", {
customUI: true
})
console.log('sendEmailCode',{
"email": this.email,
"scene": this.type,
"captcha": this.captcha
});
uniIdCo.sendEmailCode({
"email": this.email,
"scene": this.type,
"captcha": this.captcha
}).then(result => {
uni.showToast({
title: "邮箱验证码发送成功",
icon: 'none',
duration: 3000
});
this.reverseNumber = Number(this.count);
this.getCode();
}).catch(e => {
if (e.code == "uni-id-invalid-mail-template") {
this.modelValue = "123456"
uni.showToast({
title: '已启动测试模式,详情【控制台信息】',
icon: 'none',
duration: 3000
});
console.warn(e.message);
} else {
this.getImageCaptcha()
this.captcha = ""
uni.showToast({
title: e.message,
icon: 'none',
duration: 3000
});
}
})
},
getCode() {
if (this.reverseNumber == 0) {
clearTimeout(this.reverseTimer);
this.reverseTimer = null;
return;
}
this.reverseNumber--;
this.reverseTimer = setTimeout(() => {
this.getCode();
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
.box {
position: relative;
margin-top: 10px;
}
.short-code-btn {
padding: 0;
position: absolute;
top: 0;
right: 8px;
width: 260rpx;
max-width: 130px;
height: 44px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.inner-text {
font-size: 14px;
color: #AAAAAA;
}
.inner-text-active {
color: #04498c;
}
.captcha {
width: 350rpx;
}
.input-box {
margin: 0;
padding: 4px;
background-color: #F8F8F8;
font-size: 14px;
}
.box ::v-deep .content-clear-icon {
margin-right: 100px;
}
.box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
</style>
<template>
<view>
<uni-captcha :focus="focusCaptchaInput" ref="captcha" scene="send-email-code" v-model="captcha" />
<view class="box">
<uni-easyinput :focus="focusEmailCodeInput" @blur="focusEmailCodeInput = false" type="number" class="input-box" :inputBorder="false" v-model="modelValue" maxlength="6"
placeholder="请输入邮箱验证码">
</uni-easyinput>
<view class="short-code-btn" hover-class="hover" @click="start">
<text class="inner-text" :class="reverseNumber==0?'inner-text-active':''">{{innerText}}</text>
</view>
</view>
</view>
</template>
<script>
function debounce(func, wait) {
let timer;
wait = wait || 500;
return function() {
let context = this;
let args = arguments;
if (timer) clearTimeout(timer);
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
if (callNow) func.apply(context, args);
}
}
/**
* email-code-form
* @description 获取邮箱验证码组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=
* @property {Number} count 倒计时时长 s
* @property {String} email 邮箱
* @property {String} type = [login-by-email-code|reset-pwd-by-email-code|bind-email] 验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定邮箱、unbind解绑邮箱
* @property {false} focusCaptchaInput = [true|false] 验证码输入框是否默认获取焦点
*/
export default {
name: "uni-email-code-form",
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
props: {
event: ['update:modelValue'],
/**
* 倒计时时长 s
*/
count: {
type: [String, Number],
default: 60
},
/**
* 邮箱
*/
email: {
type: [String],
default: ''
},
/*
验证码类型,用于防止不同功能的验证码混用,目前支持的类型login登录、register注册、bind绑定邮箱、unbind解绑邮箱
*/
type: {
type: String,
default () {
return 'register'
}
},
/*
验证码输入框是否默认获取焦点
*/
focusCaptchaInput: {
type: Boolean,
default () {
return false
}
},
},
data() {
return {
captcha: "",
reverseNumber: 0,
reverseTimer: null,
modelValue: "",
focusEmailCodeInput:false
};
},
watch: {
captcha(value, oldValue) {
if (value.length == 4 && oldValue.length != 4) {
this.start()
}
},
modelValue(value) {
// TODO 兼容 vue2
this.$emit('input', value);
// TODO 兼容 vue3
this.$emit('update:modelValue', value)
}
},
computed: {
innerText() {
if (this.reverseNumber == 0) return "获取邮箱验证码";
return "重新发送" + '(' + this.reverseNumber + 's)';
}
},
created() {
this.initClick();
},
methods: {
getImageCaptcha(focus) {
this.$refs.captcha.getImageCaptcha(focus)
},
initClick() {
this.start = debounce(() => {
if (this.reverseNumber != 0) return;
this.sendMsg();
})
},
sendMsg() {
if (this.captcha.length != 4) {
this.$refs.captcha.focusCaptchaInput = true
return uni.showToast({
title: '请先输入图形验证码',
icon: 'none',
duration: 3000
});
}
if(!this.email) return uni.showToast({
title: "请输入邮箱",
icon: 'none',
duration: 3000
});
let reg_email = /@/;
if (!reg_email.test(this.email)) return uni.showToast({
title: "邮箱格式错误",
icon: 'none',
duration: 3000
});
const uniIdCo = uniCloud.importObject("uni-id-co", {
customUI: true
})
console.log('sendEmailCode',{
"email": this.email,
"scene": this.type,
"captcha": this.captcha
});
uniIdCo.sendEmailCode({
"email": this.email,
"scene": this.type,
"captcha": this.captcha
}).then(result => {
uni.showToast({
title: "邮箱验证码发送成功",
icon: 'none',
duration: 3000
});
this.reverseNumber = Number(this.count);
this.getCode();
}).catch(e => {
if (e.code == "uni-id-invalid-mail-template") {
this.modelValue = "123456"
uni.showToast({
title: '已启动测试模式,详情【控制台信息】',
icon: 'none',
duration: 3000
});
console.warn(e.message);
} else {
this.getImageCaptcha()
this.captcha = ""
uni.showToast({
title: e.message,
icon: 'none',
duration: 3000
});
}
})
},
getCode() {
if (this.reverseNumber == 0) {
clearTimeout(this.reverseTimer);
this.reverseTimer = null;
return;
}
this.reverseNumber--;
this.reverseTimer = setTimeout(() => {
this.getCode();
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
.box {
position: relative;
margin-top: 10px;
}
.short-code-btn {
padding: 0;
position: absolute;
top: 0;
right: 8px;
width: 260rpx;
max-width: 130px;
height: 44px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.inner-text {
font-size: 14px;
color: #AAAAAA;
}
.inner-text-active {
color: #04498c;
}
.captcha {
width: 350rpx;
}
.input-box {
margin: 0;
padding: 4px;
background-color: #F8F8F8;
font-size: 14px;
}
.box ::v-deep .content-clear-icon {
margin-right: 100px;
}
.box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
</style>
{
"id": "uni-id-pages",
"displayName": "uni-id-pages",
"version": "1.1.1",
"version": "1.1.13",
"description": "云端一体简单、统一、可扩展的用户中心页面模版",
"keywords": [
"用户管理",
......
<!-- 网络链接内容展示页(uni-id-pages中用于展示隐私政策协议内容) -->
<template>
<view>
<web-view v-if="url" :src="url"></web-view>
</view>
</template>
<script>
export default {
onLoad({url,title}) {
if(url.substring(0, 4) != 'http'){
uni.showModal({
title:"错误",
content: '不是一个有效的网站链接,'+'"'+url+'"',
showCancel: false,
confirmText:"知道了",
complete: () => {
uni.navigateBack()
}
});
title = "页面路径错误"
}else{
this.url = url;
}
if(title){
uni.setNavigationBarTitle({title});
}
},
data() {
return {
url:null
};
}
}
</script>
<!-- 网络链接内容展示页(uni-id-pages中用于展示隐私政策协议内容) -->
<template>
<view>
<web-view v-if="url" :src="url"></web-view>
</view>
</template>
<script>
export default {
onLoad({url,title}) {
if(url.substring(0, 4) != 'http'){
uni.showModal({
title:"错误",
content: '不是一个有效的网站链接,'+'"'+url+'"',
showCancel: false,
confirmText:"知道了",
complete: () => {
uni.navigateBack()
}
});
title = "页面路径错误"
}else{
this.url = url;
}
if(title){
uni.setNavigationBarTitle({title});
}
},
data() {
return {
url:null
};
}
}
</script>
<!-- 短信验证码登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title">请输入验证码</text>
<text class="tip">先输入图形验证码,再获取短信验证码</text>
<uni-forms>
<uni-id-pages-sms-form focusCaptchaInput v-model="code" type="login-by-sms" ref="smsCode" :phone="phone">
</uni-id-pages-sms-form>
<button class="uni-btn send-btn" type="primary" @click="submit">登录</button>
</uni-forms>
<uni-popup-captcha @confirm="submit" v-model="captcha" scene="login-by-sms" ref="popup"></uni-popup-captcha>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
export default {
mixins: [mixin],
data() {
return {
"code": "",
"phone": "",
"captcha": "",
"logo": "/static/logo.png"
}
},
computed: {
tipText() {
return '验证码已通过短信发送至' + this.phone;
},
},
onLoad({
phoneNumber
}) {
this.phone = phoneNumber;
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
submit() { //完成并提交
const uniIdCo = uniCloud.importObject("uni-id-co", {
errorOptions: {
type: 'toast'
}
})
if (this.code.length != 6) {
this.$refs.smsCode.focusSmsCodeInput = true
return uni.showToast({
title: '验证码不能为空',
icon: 'none',
duration: 3000
});
}
uniIdCo.loginBySms({
"mobile": this.phone,
"code": this.code,
"captcha": this.captcha
}).then(e => {
this.loginSuccess(e)
}).catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
} else {
console.log(e.errMsg);
}
}).finally(e => {
this.captcha = ''
})
}
}
}
</script>
<style scoped lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
.tip {
margin-top: -15px;
margin-bottom: 15px;
}
.popup-captcha {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 20rpx;
background-color: #FFF;
border-radius: 2px;
flex-direction: column;
position: relative;
}
.popup-captcha .title {
font-weight: normal;
padding: 0;
padding-bottom: 15px;
color: #666;
}
.popup-captcha .close {
position: absolute;
bottom: -40px;
margin-left: -13px;
left: 50%;
}
.popup-captcha .uni-btn {
margin: 0;
}
</style>
<!-- 短信验证码登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title">请输入验证码</text>
<text class="tip">先输入图形验证码,再获取短信验证码</text>
<uni-forms>
<uni-id-pages-sms-form focusCaptchaInput v-model="code" type="login-by-sms" ref="smsCode" :phone="phone">
</uni-id-pages-sms-form>
<button class="uni-btn send-btn" type="primary" @click="submit">登录</button>
</uni-forms>
<uni-popup-captcha @confirm="submit" v-model="captcha" scene="login-by-sms" ref="popup"></uni-popup-captcha>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
export default {
mixins: [mixin],
data() {
return {
"code": "",
"phone": "",
"captcha": "",
"logo": "/static/logo.png"
}
},
computed: {
tipText() {
return '验证码已通过短信发送至' + this.phone;
},
},
onLoad({
phoneNumber
}) {
this.phone = phoneNumber;
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
submit() { //完成并提交
const uniIdCo = uniCloud.importObject("uni-id-co", {
errorOptions: {
type: 'toast'
}
})
if (this.code.length != 6) {
this.$refs.smsCode.focusSmsCodeInput = true
return uni.showToast({
title: '验证码不能为空',
icon: 'none',
duration: 3000
});
}
uniIdCo.loginBySms({
"mobile": this.phone,
"code": this.code,
"captcha": this.captcha
}).then(e => {
this.loginSuccess(e)
}).catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
} else {
console.log(e.errMsg);
}
}).finally(e => {
this.captcha = ''
})
}
}
}
</script>
<style scoped lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
.tip {
margin-top: -15px;
margin-bottom: 15px;
}
.popup-captcha {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 20rpx;
background-color: #FFF;
border-radius: 2px;
flex-direction: column;
position: relative;
}
.popup-captcha .title {
font-weight: normal;
padding: 0;
padding-bottom: 15px;
color: #666;
}
.popup-captcha .close {
position: absolute;
bottom: -40px;
margin-left: -13px;
left: 50%;
}
.popup-captcha .uni-btn {
margin: 0;
}
</style>
<!-- 免密登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title">请选择登录方式</text>
<!-- 快捷登录框 当url带参数时有效 -->
<template v-if="['apple','weixin', 'weixinMobile'].includes(type)">
<text class="tip">将根据第三方账号服务平台的授权范围获取你的信息</text>
<view class="quickLogin">
<image v-if="type !== 'weixinMobile'" @click="quickLogin" :src="imgSrc" mode="widthFix"
class="quickLoginBtn"></image>
<button v-else type="primary" open-type="getPhoneNumber" @getphonenumber="quickLogin"
class="uni-btn">微信授权手机号登录</button>
<uni-id-pages-agreements scope="register" ref="agreements"></uni-id-pages-agreements>
</view>
</template>
<template v-else>
<text class="tip">未注册的账号验证通过后将自动注册</text>
<view class="phone-box">
<view @click="chooseArea" class="area">+86</view>
<uni-easyinput :focus="focusPhone" @blur="focusPhone = false" class="input-box" type="number"
:inputBorder="false" v-model="phone" maxlength="11" placeholder="请输入手机号" />
</view>
<uni-id-pages-agreements scope="register" ref="agreements"></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="toSmsPage">获取验证码</button>
</template>
<!-- 固定定位的快捷登录按钮 -->
<uni-id-pages-fab-login ref="uniFabLogin"></uni-id-pages-fab-login>
</view>
</template>
<script>
let currentWebview; //当前窗口对象
import config from '@/uni_modules/uni-id-pages/config.js'
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
export default {
mixins: [mixin],
data() {
return {
type: "", //快捷登录方式
phone: "", //手机号码
focusPhone: false,
logo: "/static/logo.png"
}
},
computed: {
async loginTypes() { //读取配置的登录优先级
return config.loginTypes
},
isPhone() { //手机号码校验正则
return /^1\d{10}$/.test(this.phone);
},
imgSrc() { //大快捷登录按钮图
return this.type == 'weixin' ? '/uni_modules/uni-id-pages/static/login/weixin.png' :
'/uni_modules/uni-id-pages/static/app-plus/apple.png'
}
},
async onLoad(e) {
//获取通过url传递的参数type设置当前登录方式,如果没传递直接默认以配置的登录
let type = e.type || config.loginTypes[0]
this.type = type
// console.log("this.type: -----------",this.type);
if (type != 'univerify') {
this.focusPhone = true
}
this.$nextTick(() => {
//关闭重复显示的登录快捷方式
if (['weixin', 'apple'].includes(type)) {
this.$refs.uniFabLogin.servicesList = this.$refs.uniFabLogin.servicesList.filter(item =>
item.id != type)
}
})
uni.$on('uni-id-pages-setLoginType', type => {
this.type = type
})
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.toSmsPage()
}
};
// #endif
},
onUnload() {
uni.$off('uni-id-pages-setLoginType')
},
onReady() {
// 是否优先启动一键登录。即:页面一加载就启动一键登录
//#ifdef APP-PLUS
if (this.type == "univerify") {
const pages = getCurrentPages();
currentWebview = pages[pages.length - 1].$getAppWebview();
currentWebview.setStyle({
"top": "2000px" // 隐藏当前页面窗体
})
this.type == this.loginTypes[1]
// console.log('开始一键登录');
this.$refs.uniFabLogin.login_before('univerify')
}
//#endif
},
methods: {
showCurrentWebview(){
// 恢复当前页面窗体的显示 一键登录,默认不显示当前窗口
currentWebview.setStyle({
"top": 0
})
},
quickLogin(e) {
let options = {}
if (e.detail?.code) {
options.phoneNumberCode = e.detail.code
}
if (this.type === 'weixinMobile' && !e.detail?.code) return
this.$refs.uniFabLogin.login_before(this.type, true, options)
},
toSmsPage() {
if (!this.isPhone) {
this.focusPhone = true
return uni.showToast({
title: "手机号码格式不正确",
icon: 'none',
duration: 3000
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(this.toSmsPage)
}
// 发送验证吗
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-smscode?phoneNumber=' + this.phone
});
},
//去密码登录页
toPwdLogin() {
uni.navigateTo({
url: '../login/password'
})
},
chooseArea() {
uni.showToast({
title: '暂不支持其他国家',
icon: 'none',
duration: 3000
});
},
}
}
</script>
<style lang="scss" scoped>
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (min-width: 690px) {
.uni-content {
height: 350px;
}
}
.uni-content,
.quickLogin {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
/* #endif */
}
.phone-box {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
}
.area {
position: absolute;
left: 10px;
z-index: 9;
top: 12px;
font-size: 14px;
}
.area::after {
content: "";
border: 3px solid transparent;
border-top-color: #000;
top: 12px;
left: 3px;
position: relative;
}
/* #ifdef MP */
// 解决小程序端开启虚拟节点virtualHost引起的 class = input-box丢失的问题 [详情参考](https://uniapp.dcloud.net.cn/matter.html#%E5%90%84%E5%AE%B6%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6%E4%B8%8D%E5%90%8C-%E5%8F%AF%E8%83%BD%E5%AD%98%E5%9C%A8%E7%9A%84%E5%B9%B3%E5%8F%B0%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98)
.phone-box ::v-deep .uni-easyinput__content,
/* #endif */
.input-box {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
flex: 1;
padding-left: 45px;
margin-bottom: 10px;
border-radius: 0;
}
.quickLogin {
height: 350px;
align-items: center;
justify-content: center;
}
.quickLoginBtn {
margin: 20px 0;
width: 450rpx;
/* #ifndef APP-NVUE */
max-width: 230px;
/* #endif */
height: 82rpx;
}
.tip {
margin-top: -15px;
margin-bottom: 20px;
}
@media screen and (min-width: 690px) {
.quickLogin {
height: auto;
}
}
</style>
<!-- 免密登录页 -->
<template>
<view class="uni-content">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title">请选择登录方式</text>
<!-- 快捷登录框 当url带参数时有效 -->
<template v-if="['apple','weixin', 'weixinMobile'].includes(type)">
<text class="tip">将根据第三方账号服务平台的授权范围获取你的信息</text>
<view class="quickLogin">
<image v-if="type !== 'weixinMobile'" @click="quickLogin" :src="imgSrc" mode="widthFix"
class="quickLoginBtn"></image>
<button v-else type="primary" open-type="getPhoneNumber" @getphonenumber="quickLogin"
class="uni-btn">微信授权手机号登录</button>
<uni-id-pages-agreements scope="register" ref="agreements"></uni-id-pages-agreements>
</view>
</template>
<template v-else>
<text class="tip">未注册的账号验证通过后将自动注册</text>
<view class="phone-box">
<view @click="chooseArea" class="area">+86</view>
<uni-easyinput :focus="focusPhone" @blur="focusPhone = false" class="input-box" type="number"
:inputBorder="false" v-model="phone" maxlength="11" placeholder="请输入手机号" />
</view>
<uni-id-pages-agreements scope="register" ref="agreements"></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="toSmsPage">获取验证码</button>
</template>
<!-- 固定定位的快捷登录按钮 -->
<uni-id-pages-fab-login ref="uniFabLogin"></uni-id-pages-fab-login>
</view>
</template>
<script>
let currentWebview; //当前窗口对象
import config from '@/uni_modules/uni-id-pages/config.js'
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
export default {
mixins: [mixin],
data() {
return {
type: "", //快捷登录方式
phone: "", //手机号码
focusPhone: false,
logo: "/static/logo.png"
}
},
computed: {
async loginTypes() { //读取配置的登录优先级
return config.loginTypes
},
isPhone() { //手机号码校验正则
return /^1\d{10}$/.test(this.phone);
},
imgSrc() { //大快捷登录按钮图
return this.type == 'weixin' ? '/uni_modules/uni-id-pages/static/login/weixin.png' :
'/uni_modules/uni-id-pages/static/app-plus/apple.png'
}
},
async onLoad(e) {
//获取通过url传递的参数type设置当前登录方式,如果没传递直接默认以配置的登录
let type = e.type || config.loginTypes[0]
this.type = type
// console.log("this.type: -----------",this.type);
if (type != 'univerify') {
this.focusPhone = true
}
this.$nextTick(() => {
//关闭重复显示的登录快捷方式
if (['weixin', 'apple'].includes(type)) {
this.$refs.uniFabLogin.servicesList = this.$refs.uniFabLogin.servicesList.filter(item =>
item.id != type)
}
})
uni.$on('uni-id-pages-setLoginType', type => {
this.type = type
})
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.toSmsPage()
}
};
// #endif
},
onUnload() {
uni.$off('uni-id-pages-setLoginType')
},
onReady() {
// 是否优先启动一键登录。即:页面一加载就启动一键登录
//#ifdef APP-PLUS
if (this.type == "univerify") {
const pages = getCurrentPages();
currentWebview = pages[pages.length - 1].$getAppWebview();
currentWebview.setStyle({
"top": "2000px" // 隐藏当前页面窗体
})
this.type == this.loginTypes[1]
// console.log('开始一键登录');
this.$refs.uniFabLogin.login_before('univerify')
}
//#endif
},
methods: {
showCurrentWebview(){
// 恢复当前页面窗体的显示 一键登录,默认不显示当前窗口
currentWebview.setStyle({
"top": 0
})
},
quickLogin(e) {
let options = {}
if (e.detail?.code) {
options.phoneNumberCode = e.detail.code
}
if (this.type === 'weixinMobile' && !e.detail?.code) return
this.$refs.uniFabLogin.login_before(this.type, true, options)
},
toSmsPage() {
if (!this.isPhone) {
this.focusPhone = true
return uni.showToast({
title: "手机号码格式不正确",
icon: 'none',
duration: 3000
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(this.toSmsPage)
}
// 发送验证吗
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-smscode?phoneNumber=' + this.phone
});
},
//去密码登录页
toPwdLogin() {
uni.navigateTo({
url: '../login/password'
})
},
chooseArea() {
uni.showToast({
title: '暂不支持其他国家',
icon: 'none',
duration: 3000
});
},
}
}
</script>
<style lang="scss" scoped>
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (min-width: 690px) {
.uni-content {
height: 350px;
}
}
.uni-content,
.quickLogin {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
/* #endif */
}
.phone-box {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
}
.area {
position: absolute;
left: 10px;
z-index: 9;
top: 12px;
font-size: 14px;
}
.area::after {
content: "";
border: 3px solid transparent;
border-top-color: #000;
top: 12px;
left: 3px;
position: relative;
}
/* #ifdef MP */
// 解决小程序端开启虚拟节点virtualHost引起的 class = input-box丢失的问题 [详情参考](https://uniapp.dcloud.net.cn/matter.html#%E5%90%84%E5%AE%B6%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6%E4%B8%8D%E5%90%8C-%E5%8F%AF%E8%83%BD%E5%AD%98%E5%9C%A8%E7%9A%84%E5%B9%B3%E5%8F%B0%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98)
.phone-box ::v-deep .uni-easyinput__content,
/* #endif */
.input-box {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
flex: 1;
padding-left: 45px;
margin-bottom: 10px;
border-radius: 0;
}
.quickLogin {
height: 350px;
align-items: center;
justify-content: center;
}
.quickLoginBtn {
margin: 20px 0;
width: 450rpx;
/* #ifndef APP-NVUE */
max-width: 230px;
/* #endif */
height: 82rpx;
}
.tip {
margin-top: -15px;
margin-bottom: 20px;
}
@media screen and (min-width: 690px) {
.quickLogin {
height: auto;
}
}
</style>
......@@ -27,9 +27,9 @@
class="input-box" placeholder="再次输入密码" maxlength="20" type="password" v-model="formData.password2"
trim="both" />
</uni-forms-item>
<!-- <uni-forms-item>-->
<!-- <uni-captcha ref="captcha" scene="register" v-model="formData.captcha" />-->
<!-- </uni-forms-item>-->
<uni-forms-item>
<uni-captcha ref="captcha" scene="register" v-model="formData.captcha" />
</uni-forms-item>
<uni-id-pages-agreements scope="register" ref="agreements" ></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="submit">注册</button>
<button @click="navigateBack" class="register-back">返回</button>
......@@ -85,14 +85,14 @@
*/
submit() {
this.$refs.form.validate().then((res) => {
// if(this.formData.captcha.length != 4){
// this.$refs.captcha.focusCaptchaInput = true
// return uni.showToast({
// title: '请输入验证码',
// icon: 'none',
// duration: 3000
// });
// }
if(this.formData.captcha.length != 4){
this.$refs.captcha.focusCaptchaInput = true
return uni.showToast({
title: '请输入验证码',
icon: 'none',
duration: 3000
});
}
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(()=>{
this.submitForm(res)
......@@ -139,7 +139,7 @@
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
......@@ -152,7 +152,7 @@
padding: 30px 40px 60px;
max-height: 520px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
......@@ -161,12 +161,12 @@
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
.uni-content ::v-deep .uni-forms-item__label {
position: absolute;
left: -15px;
......
<!-- 邮箱验证码注册 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">邮箱验证码注册</text>
</match-media>
<uni-forms ref="form" :value="formData" :rules="rules" validate-trigger="submit" err-show-type="toast">
<uni-forms-item name="email" required>
<uni-easyinput :inputBorder="false" :focus="focusEmail" @blur="focusEmail = false"
class="input-box" placeholder="请输入邮箱" v-model="formData.email" trim="both" />
</uni-forms-item>
<uni-forms-item name="nickname">
<uni-easyinput :inputBorder="false" :focus="focusNickname" @blur="focusNickname = false" class="input-box" placeholder="请输入用户昵称"
v-model="formData.nickname" trim="both" />
</uni-forms-item>
<uni-forms-item name="password" v-model="formData.password" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword" @blur="focusPassword = false"
class="input-box" maxlength="20" :placeholder="'请输入' + (config.passwordStrength == 'weak'?'6':'8') + '-16位密码'" type="password"
v-model="formData.password" trim="both" />
</uni-forms-item>
<uni-forms-item name="password2" v-model="formData.password2" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword2" @blur="focusPassword2 =false"
class="input-box" placeholder="再次输入密码" maxlength="20" type="password" v-model="formData.password2"
trim="both" />
</uni-forms-item>
<uni-forms-item name="code" >
<uni-id-pages-email-form ref="shortCode" :email="formData.email" type="register" v-model="formData.code">
</uni-id-pages-email-form>
</uni-forms-item>
<uni-id-pages-agreements scope="register" ref="agreements" ></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="submit">注册</button>
<button @click="navigateBack" class="register-back">返回</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="registerByUserName">用户名密码注册</text>
<text class="link" @click="toLogin">已有账号?点此登录</text>
</view>
</match-media>
</uni-forms>
</view>
</template>
<script>
import rules from './validator.js';
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import config from '@/uni_modules/uni-id-pages/config.js'
import passwordMod from '@/uni_modules/uni-id-pages/common/password.js'
const uniIdCo = uniCloud.importObject("uni-id-co")
export default {
mixins: [mixin],
data() {
return {
formData: {
email: "",
nickname: "",
password: "",
password2: "",
code: ""
},
rules: {
email: {
rules: [{
required: true,
errorMessage: '请输入邮箱',
},{
format:'email',
errorMessage: '邮箱格式不正确',
}
]
},
nickname: {
rules: [{
minLength: 3,
maxLength: 32,
errorMessage: '昵称长度在 {minLength} 到 {maxLength} 个字符',
},
{
validateFunction: function(rule, value, data, callback) {
// console.log(value);
if (/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) {
callback('昵称不能是:手机号或邮箱')
};
if (/^\d+$/.test(value)) {
callback('昵称不能为纯数字')
};
if(/[\u4E00-\u9FA5\uF900-\uFA2D]{1,}/.test(value)){
callback('昵称不能包含中文')
}
return true
}
}
],
label: "昵称"
},
...passwordMod.getPwdRules(),
code: {
rules: [{
required: true,
errorMessage: '请输入邮箱验证码',
},
{
pattern: /^.{6}$/,
errorMessage: '邮箱验证码不正确',
}
]
}
},
focusEmail:false,
focusNickname:false,
focusPassword:false,
focusPassword2:false,
logo: "/static/logo.png"
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 触发表单提交
*/
submit() {
this.$refs.form.validate().then((res) => {
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(()=>{
this.submitForm(res)
})
}
this.submitForm(res)
}).catch((errors) => {
let key = errors[0].key
key = key.replace(key[0], key[0].toUpperCase())
// console.log(key);
this['focus'+key] = true
})
},
submitForm(params) {
uniIdCo.registerUserByEmail(this.formData).then(e => {
// console.log(e);
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
complete: (e) => {
// console.log(e);
}
})
})
.catch(e => {
// console.log(e);
console.log(e.message);
})
},
navigateBack() {
uni.navigateBack()
},
toLogin() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
},
registerByUserName() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/register/register'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
}
}
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
.uni-content ::v-deep .uni-forms-item__label {
position: absolute;
left: -15px;
}
button {
margin-top: 15px;
}
</style>
<!-- 邮箱验证码注册 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">邮箱验证码注册</text>
</match-media>
<uni-forms ref="form" :value="formData" :rules="rules" validate-trigger="submit" err-show-type="toast">
<uni-forms-item name="email" required>
<uni-easyinput :inputBorder="false" :focus="focusEmail" @blur="focusEmail = false"
class="input-box" placeholder="请输入邮箱" v-model="formData.email" trim="both" />
</uni-forms-item>
<uni-forms-item name="nickname">
<uni-easyinput :inputBorder="false" :focus="focusNickname" @blur="focusNickname = false" class="input-box" placeholder="请输入用户昵称"
v-model="formData.nickname" trim="both" />
</uni-forms-item>
<uni-forms-item name="password" v-model="formData.password" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword" @blur="focusPassword = false"
class="input-box" maxlength="20" :placeholder="'请输入' + (config.passwordStrength == 'weak'?'6':'8') + '-16位密码'" type="password"
v-model="formData.password" trim="both" />
</uni-forms-item>
<uni-forms-item name="password2" v-model="formData.password2" required>
<uni-easyinput :inputBorder="false" :focus="focusPassword2" @blur="focusPassword2 =false"
class="input-box" placeholder="再次输入密码" maxlength="20" type="password" v-model="formData.password2"
trim="both" />
</uni-forms-item>
<uni-forms-item name="code" >
<uni-id-pages-email-form ref="shortCode" :email="formData.email" type="register" v-model="formData.code">
</uni-id-pages-email-form>
</uni-forms-item>
<uni-id-pages-agreements scope="register" ref="agreements" ></uni-id-pages-agreements>
<button class="uni-btn" type="primary" @click="submit">注册</button>
<button @click="navigateBack" class="register-back">返回</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="registerByUserName">用户名密码注册</text>
<text class="link" @click="toLogin">已有账号?点此登录</text>
</view>
</match-media>
</uni-forms>
</view>
</template>
<script>
import rules from './validator.js';
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import config from '@/uni_modules/uni-id-pages/config.js'
import passwordMod from '@/uni_modules/uni-id-pages/common/password.js'
const uniIdCo = uniCloud.importObject("uni-id-co")
export default {
mixins: [mixin],
data() {
return {
formData: {
email: "",
nickname: "",
password: "",
password2: "",
code: ""
},
rules: {
email: {
rules: [{
required: true,
errorMessage: '请输入邮箱',
},{
format:'email',
errorMessage: '邮箱格式不正确',
}
]
},
nickname: {
rules: [{
minLength: 3,
maxLength: 32,
errorMessage: '昵称长度在 {minLength} 到 {maxLength} 个字符',
},
{
validateFunction: function(rule, value, data, callback) {
// console.log(value);
if (/^1\d{10}$/.test(value) || /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(value)) {
callback('昵称不能是:手机号或邮箱')
};
if (/^\d+$/.test(value)) {
callback('昵称不能为纯数字')
};
if(/[\u4E00-\u9FA5\uF900-\uFA2D]{1,}/.test(value)){
callback('昵称不能包含中文')
}
return true
}
}
],
label: "昵称"
},
...passwordMod.getPwdRules(),
code: {
rules: [{
required: true,
errorMessage: '请输入邮箱验证码',
},
{
pattern: /^.{6}$/,
errorMessage: '邮箱验证码不正确',
}
]
}
},
focusEmail:false,
focusNickname:false,
focusPassword:false,
focusPassword2:false,
logo: "/static/logo.png"
}
},
onReady() {
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 触发表单提交
*/
submit() {
this.$refs.form.validate().then((res) => {
if (this.needAgreements && !this.agree) {
return this.$refs.agreements.popup(()=>{
this.submitForm(res)
})
}
this.submitForm(res)
}).catch((errors) => {
let key = errors[0].key
key = key.replace(key[0], key[0].toUpperCase())
// console.log(key);
this['focus'+key] = true
})
},
submitForm(params) {
uniIdCo.registerUserByEmail(this.formData).then(e => {
// console.log(e);
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
complete: (e) => {
// console.log(e);
}
})
})
.catch(e => {
// console.log(e);
console.log(e.message);
})
},
navigateBack() {
uni.navigateBack()
},
toLogin() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
},
registerByUserName() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/register/register'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
}
}
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
.uni-content ::v-deep .uni-forms-item__label {
position: absolute;
left: -15px;
}
button {
margin-top: 15px;
}
</style>
<!-- 找回密码页 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">通过邮箱验证码找回密码</text>
</match-media>
<uni-forms ref="form" :value="formData" err-show-type="toast">
<uni-forms-item name="email">
<uni-easyinput :focus="focusEmail" @blur="focusEmail = false" class="input-box" :disabled="lock" :inputBorder="false"
v-model="formData.email" placeholder="请输入邮箱">
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="code">
<uni-id-pages-email-form ref="shortCode" :email="formData.email" type="reset-pwd-by-email" v-model="formData.code">
</uni-id-pages-email-form>
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password"
placeholder="请输入新密码"></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="password2">
<uni-easyinput :focus="focusPassword2" @blur="focusPassword2 = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password2"
placeholder="请再次输入新密码"></uni-easyinput>
</uni-forms-item>
<button class="uni-btn send-btn-box" type="primary" @click="submit">提交</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="retrieveByPhone">通过手机验证码找回密码</text>
<view></view>
<text class="link" @click="backLogin">返回登录</text>
</view>
</match-media>
</uni-forms>
<uni-popup-captcha @confirm="submit" v-model="formData.captcha" scene="reset-pwd-by-sms" ref="popup"></uni-popup-captcha>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import passwordMod from '@/uni_modules/uni-id-pages/common/password.js'
const uniIdCo = uniCloud.importObject("uni-id-co",{
errorOptions:{
type:'toast'
}
})
export default {
mixins: [mixin],
data() {
return {
lock: false,
focusEmail:true,
focusPassword:false,
focusPassword2:false,
formData: {
"email": "",
"code": "",
'password': '',
'password2': '',
"captcha": ""
},
rules: {
email: {
rules: [{
required: true,
errorMessage: '请输入邮箱',
},
{
format:'email',
errorMessage: '邮箱格式不正确',
}
]
},
code: {
rules: [{
required: true,
errorMessage: '请输入邮箱验证码',
},
{
pattern: /^.{6}$/,
errorMessage: '请输入6位验证码',
}
]
},
...passwordMod.getPwdRules()
},
logo: "/static/logo.png"
}
},
computed: {
isEmail() {
let reg_email = /@/;
let isEmail = reg_email.test(this.formData.email);
return isEmail;
},
isPwd() {
let reg_pwd = /^.{6,20}$/;
let isPwd = reg_pwd.test(this.formData.password);
return isPwd;
},
isCode() {
let reg_code = /^\d{6}$/;
let isCode = reg_code.test(this.formData.code);
return isCode;
}
},
onLoad(event) {
if (event && event.emailNumber) {
this.formData.email = event.emailNumber;
if(event.lock){
this.lock = event.lock //如果是已经登录的账号,点击找回密码就锁定指定的账号绑定的邮箱码
this.focusEmail = true
}
}
},
onReady() {
if (this.formData.email) {
this.$refs.shortCode.start();
}
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 完成并提交
*/
submit() {
this.$refs.form.validate()
.then(res => {
let {
email,
password: password,
captcha,
code
} = this.formData
uniIdCo.resetPwdByEmail({
email,
code,
password,
captcha
}).then(e => {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
complete: (e) => {
// console.log(e);
}
})
})
.catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
}
}).finally(e => {
this.formData.captcha = ""
})
}).catch(errors=>{
let key = errors[0].key
if(key == 'code'){
return this.$refs.shortCode.focusSmsCodeInput = true
}
key = key.replace(key[0], key[0].toUpperCase())
this['focus'+key] = true
})
},
retrieveByPhone() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/retrieve/retrieve'
})
},
backLogin () {
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
}
}
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
</style>
<!-- 找回密码页 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">通过邮箱验证码找回密码</text>
</match-media>
<uni-forms ref="form" :value="formData" err-show-type="toast">
<uni-forms-item name="email">
<uni-easyinput :focus="focusEmail" @blur="focusEmail = false" class="input-box" :disabled="lock" :inputBorder="false"
v-model="formData.email" placeholder="请输入邮箱">
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="code">
<uni-id-pages-email-form ref="shortCode" :email="formData.email" type="reset-pwd-by-email" v-model="formData.code">
</uni-id-pages-email-form>
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password"
placeholder="请输入新密码"></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="password2">
<uni-easyinput :focus="focusPassword2" @blur="focusPassword2 = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password2"
placeholder="请再次输入新密码"></uni-easyinput>
</uni-forms-item>
<button class="uni-btn send-btn-box" type="primary" @click="submit">提交</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="retrieveByPhone">通过手机验证码找回密码</text>
<view></view>
<text class="link" @click="backLogin">返回登录</text>
</view>
</match-media>
</uni-forms>
<uni-popup-captcha @confirm="submit" v-model="formData.captcha" scene="reset-pwd-by-sms" ref="popup"></uni-popup-captcha>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import passwordMod from '@/uni_modules/uni-id-pages/common/password.js'
const uniIdCo = uniCloud.importObject("uni-id-co",{
errorOptions:{
type:'toast'
}
})
export default {
mixins: [mixin],
data() {
return {
lock: false,
focusEmail:true,
focusPassword:false,
focusPassword2:false,
formData: {
"email": "",
"code": "",
'password': '',
'password2': '',
"captcha": ""
},
rules: {
email: {
rules: [{
required: true,
errorMessage: '请输入邮箱',
},
{
format:'email',
errorMessage: '邮箱格式不正确',
}
]
},
code: {
rules: [{
required: true,
errorMessage: '请输入邮箱验证码',
},
{
pattern: /^.{6}$/,
errorMessage: '请输入6位验证码',
}
]
},
...passwordMod.getPwdRules()
},
logo: "/static/logo.png"
}
},
computed: {
isEmail() {
let reg_email = /@/;
let isEmail = reg_email.test(this.formData.email);
return isEmail;
},
isPwd() {
let reg_pwd = /^.{6,20}$/;
let isPwd = reg_pwd.test(this.formData.password);
return isPwd;
},
isCode() {
let reg_code = /^\d{6}$/;
let isCode = reg_code.test(this.formData.code);
return isCode;
}
},
onLoad(event) {
if (event && event.emailNumber) {
this.formData.email = event.emailNumber;
if(event.lock){
this.lock = event.lock //如果是已经登录的账号,点击找回密码就锁定指定的账号绑定的邮箱码
this.focusEmail = true
}
}
},
onReady() {
if (this.formData.email) {
this.$refs.shortCode.start();
}
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 完成并提交
*/
submit() {
this.$refs.form.validate()
.then(res => {
let {
email,
password: password,
captcha,
code
} = this.formData
uniIdCo.resetPwdByEmail({
email,
code,
password,
captcha
}).then(e => {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
complete: (e) => {
// console.log(e);
}
})
})
.catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
}
}).finally(e => {
this.formData.captcha = ""
})
}).catch(errors=>{
let key = errors[0].key
if(key == 'code'){
return this.$refs.shortCode.focusSmsCodeInput = true
}
key = key.replace(key[0], key[0].toUpperCase())
this['focus'+key] = true
})
},
retrieveByPhone() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/retrieve/retrieve'
})
},
backLogin () {
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
}
}
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
</style>
<!-- 找回密码页 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">通过手机验证码找回密码</text>
</match-media>
<uni-forms ref="form" :value="formData" err-show-type="toast">
<uni-forms-item name="phone">
<uni-easyinput :focus="focusPhone" @blur="focusPhone = false" class="input-box" :disabled="lock" type="number" :inputBorder="false"
v-model="formData.phone" maxlength="11" placeholder="请输入手机号">
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="code">
<uni-id-pages-sms-form ref="shortCode" :phone="formData.phone" type="reset-pwd-by-sms" v-model="formData.code">
</uni-id-pages-sms-form>
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password"
placeholder="请输入新密码"></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="password2">
<uni-easyinput :focus="focusPassword2" @blur="focusPassword2 = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password2"
placeholder="请再次输入新密码"></uni-easyinput>
</uni-forms-item>
<button class="uni-btn send-btn-box" type="primary" @click="submit">提交</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="retrieveByEmail">通过邮箱验证码找回密码</text>
<view></view>
<text class="link" @click="backLogin">返回登录</text>
</view>
</match-media>
</uni-forms>
<uni-popup-captcha @confirm="submit" v-model="formData.captcha" scene="reset-pwd-by-sms" ref="popup"></uni-popup-captcha>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
const uniIdCo = uniCloud.importObject("uni-id-co",{
errorOptions:{
type:'toast'
}
})
export default {
mixins: [mixin],
data() {
return {
lock: false,
focusPhone:true,
focusPassword:false,
focusPassword2:false,
formData: {
"phone": "",
"code": "",
'password': '',
'password2': '',
"captcha": ""
},
rules: {
phone: {
rules: [{
required: true,
errorMessage: '请输入手机号',
},
{
pattern: /^1\d{10}$/,
errorMessage: '手机号码格式不正确',
}
]
},
code: {
rules: [{
required: true,
errorMessage: '请输入短信验证码',
},
{
pattern: /^.{6}$/,
errorMessage: '请输入6位验证码',
}
]
},
password: {
rules: [{
required: true,
errorMessage: '请输入新密码',
},
{
pattern: /^.{6,20}$/,
errorMessage: '密码为6 - 20位',
}
]
},
password2: {
rules: [{
required: true,
errorMessage: '请确认密码',
},
{
pattern: /^.{6,20}$/,
errorMessage: '密码为6 - 20位',
},
{
validateFunction: function(rule, value, data, callback) {
// console.log(value);
if (value != data.password) {
callback('两次输入密码不一致')
};
return true
}
}
]
}
},
logo: "/static/logo.png"
}
},
computed: {
isPhone() {
let reg_phone = /^1\d{10}$/;
let isPhone = reg_phone.test(this.formData.phone);
return isPhone;
},
isPwd() {
let reg_pwd = /^.{6,20}$/;
let isPwd = reg_pwd.test(this.formData.password);
return isPwd;
},
isCode() {
let reg_code = /^\d{6}$/;
let isCode = reg_code.test(this.formData.code);
return isCode;
}
},
onLoad(event) {
if (event && event.phoneNumber) {
this.formData.phone = event.phoneNumber;
if(event.lock){
this.lock = event.lock //如果是已经登录的账号,点击找回密码就锁定指定的账号绑定的手机号码
this.focusPhone = true
}
}
},
onReady() {
if (this.formData.phone) {
this.$refs.shortCode.start();
}
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 完成并提交
*/
submit() {
this.$refs.form.validate()
.then(res => {
let {
"phone": mobile,
"password": password,
captcha,
code
} = this.formData
uniIdCo.resetPwdBySms({
mobile,
code,
password,
captcha
}).then(e => {
uni.navigateBack()
})
.catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
}
}).finally(e => {
this.formData.captcha = ""
})
}).catch(errors=>{
let key = errors[0].key
if(key == 'code'){
return this.$refs.shortCode.focusSmsCodeInput = true
}
key = key.replace(key[0], key[0].toUpperCase())
this['focus'+key] = true
})
},
retrieveByEmail() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email'
})
},
backLogin () {
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
}
}
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
</style>
<!-- 找回密码页 -->
<template>
<view class="uni-content">
<match-media :min-width="690">
<view class="login-logo">
<image :src="logo"></image>
</view>
<!-- 顶部文字 -->
<text class="title title-box">通过手机验证码找回密码</text>
</match-media>
<uni-forms ref="form" :value="formData" err-show-type="toast">
<uni-forms-item name="phone">
<uni-easyinput :focus="focusPhone" @blur="focusPhone = false" class="input-box" :disabled="lock" type="number" :inputBorder="false"
v-model="formData.phone" maxlength="11" placeholder="请输入手机号">
</uni-easyinput>
</uni-forms-item>
<uni-forms-item name="code">
<uni-id-pages-sms-form ref="shortCode" :phone="formData.phone" type="reset-pwd-by-sms" v-model="formData.code">
</uni-id-pages-sms-form>
</uni-forms-item>
<uni-forms-item name="password">
<uni-easyinput :focus="focusPassword" @blur="focusPassword = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password"
placeholder="请输入新密码"></uni-easyinput>
</uni-forms-item>
<uni-forms-item name="password2">
<uni-easyinput :focus="focusPassword2" @blur="focusPassword2 = false" class="input-box" type="password" :inputBorder="false" v-model="formData.password2"
placeholder="请再次输入新密码"></uni-easyinput>
</uni-forms-item>
<button class="uni-btn send-btn-box" type="primary" @click="submit">提交</button>
<match-media :min-width="690">
<view class="link-box">
<text class="link" @click="retrieveByEmail">通过邮箱验证码找回密码</text>
<view></view>
<text class="link" @click="backLogin">返回登录</text>
</view>
</match-media>
</uni-forms>
<uni-popup-captcha @confirm="submit" v-model="formData.captcha" scene="reset-pwd-by-sms" ref="popup"></uni-popup-captcha>
</view>
</template>
<script>
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
const uniIdCo = uniCloud.importObject("uni-id-co",{
errorOptions:{
type:'toast'
}
})
export default {
mixins: [mixin],
data() {
return {
lock: false,
focusPhone:true,
focusPassword:false,
focusPassword2:false,
formData: {
"phone": "",
"code": "",
'password': '',
'password2': '',
"captcha": ""
},
rules: {
phone: {
rules: [{
required: true,
errorMessage: '请输入手机号',
},
{
pattern: /^1\d{10}$/,
errorMessage: '手机号码格式不正确',
}
]
},
code: {
rules: [{
required: true,
errorMessage: '请输入短信验证码',
},
{
pattern: /^.{6}$/,
errorMessage: '请输入6位验证码',
}
]
},
password: {
rules: [{
required: true,
errorMessage: '请输入新密码',
},
{
pattern: /^.{6,20}$/,
errorMessage: '密码为6 - 20位',
}
]
},
password2: {
rules: [{
required: true,
errorMessage: '请确认密码',
},
{
pattern: /^.{6,20}$/,
errorMessage: '密码为6 - 20位',
},
{
validateFunction: function(rule, value, data, callback) {
// console.log(value);
if (value != data.password) {
callback('两次输入密码不一致')
};
return true
}
}
]
}
},
logo: "/static/logo.png"
}
},
computed: {
isPhone() {
let reg_phone = /^1\d{10}$/;
let isPhone = reg_phone.test(this.formData.phone);
return isPhone;
},
isPwd() {
let reg_pwd = /^.{6,20}$/;
let isPwd = reg_pwd.test(this.formData.password);
return isPwd;
},
isCode() {
let reg_code = /^\d{6}$/;
let isCode = reg_code.test(this.formData.code);
return isCode;
}
},
onLoad(event) {
if (event && event.phoneNumber) {
this.formData.phone = event.phoneNumber;
if(event.lock){
this.lock = event.lock //如果是已经登录的账号,点击找回密码就锁定指定的账号绑定的手机号码
this.focusPhone = true
}
}
},
onReady() {
if (this.formData.phone) {
this.$refs.shortCode.start();
}
this.$refs.form.setRules(this.rules)
},
onShow() {
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
if (e && e.keyCode == 13) { //回车键的键值为13
this.submit()
}
};
// #endif
},
methods: {
/**
* 完成并提交
*/
submit() {
this.$refs.form.validate()
.then(res => {
let {
"phone": mobile,
"password": password,
captcha,
code
} = this.formData
uniIdCo.resetPwdBySms({
mobile,
code,
password,
captcha
}).then(e => {
uni.navigateBack()
})
.catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
}
}).finally(e => {
this.formData.captcha = ""
})
}).catch(errors=>{
let key = errors[0].key
if(key == 'code'){
return this.$refs.shortCode.focusSmsCodeInput = true
}
key = key.replace(key[0], key[0].toUpperCase())
this['focus'+key] = true
})
},
retrieveByEmail() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email'
})
},
backLogin () {
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
}
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-id-pages/common/login-page.scss";
@media screen and (max-width: 690px) {
.uni-content{
margin-top: 15px;
}
}
@media screen and (min-width: 690px) {
.uni-content{
padding: 30px 40px 40px;
max-height: 650px;
}
.link-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
margin-top: 10px;
}
.link {
font-size: 12px;
}
}
</style>
......@@ -41,15 +41,13 @@
}
},
onLoad(event) {},
onReady() {
this.uniToken = uni.getStorageSync('uni_id_token')
console.log("uniToken: ", this.uniToken);
},
onReady() {},
methods: {
/**
* 完成并提交
*/
async submit() {
submit() {
if(! /^1\d{10}$/.test(this.formData.mobile)){
this.focusMobile = true
return uni.showToast({
......@@ -68,7 +66,7 @@
}
const uniIdCo = uniCloud.importObject("uni-id-co")
return await uniIdCo.bindMobileBySms(this.formData).then(e => {
uniIdCo.bindMobileBySms(this.formData).then(e => {
uni.showToast({
title: e.errMsg,
icon: 'none',
......@@ -82,16 +80,13 @@
// #endif
mutations.setUserInfo(this.formData)
uni.navigateBack()
return e
}).catch(e => {
console.log(e);
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
}
return e
}).finally(e => {
this.formData.captcha = ""
return e
})
}
}
......
<!-- 图片裁剪页 -->
<template>
<view class="content" >
<limeClipper :width="options.width" :scale-ratio="2" :is-lock-width="false" :is-lock-height="false" :height="options.height" :image-url="path"
@success="successFn" @cancel="cancel" />
</view>
</template>
<script>
import limeClipper from './limeClipper/limeClipper.vue';
export default {
components: {limeClipper},
data() {return {path: '',options:{"width":600,"height":600}}},
onLoad({path,options}) {
this.path = path
// console.log('path-path-path-path',path);
if(options){
this.options = JSON.parse(options)
}
},
methods:{
successFn(e){
this.getOpenerEventChannel().emit('success',e.url)
uni.navigateBack()
},
cancel(){
uni.navigateBack()
}
}
}
</script>
<style>
.box{
width: 400rpx;
}
.mt{
margin-top: -10px;
}
<!-- 图片裁剪页 -->
<template>
<view class="content" >
<limeClipper :width="options.width" :scale-ratio="2" :is-lock-width="false" :is-lock-height="false" :height="options.height" :image-url="path"
@success="successFn" @cancel="cancel" />
</view>
</template>
<script>
import limeClipper from './limeClipper/limeClipper.vue';
export default {
components: {limeClipper},
data() {return {path: '',options:{"width":600,"height":600}}},
onLoad({path,options}) {
this.path = path
// console.log('path-path-path-path',path);
if(options){
this.options = JSON.parse(options)
}
},
methods:{
successFn(e){
this.getOpenerEventChannel().emit('success',e.url)
uni.navigateBack()
},
cancel(){
uni.navigateBack()
}
}
}
</script>
<style>
.box{
width: 400rpx;
}
.mt{
margin-top: -10px;
}
</style>
\ No newline at end of file
> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594)
##### 以下是作者写的插件介绍:
# Clipper 图片裁剪
> uniapp 图片裁剪,可用于图片头像等裁剪处理
> [查看更多](http://liangei.gitee.io/limeui/#/clipper) <br>
> Q群:458377637
## 平台兼容
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
| √ | √ | √ | 未测 | √ | √ | √ |
## 代码演示
### 基本用法
`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url``width``height`
```html
<image :src="url" v-if="url" mode="widthFix"></image>
<l-clipper v-if="show" @success="url = $event.url; show = false" @cancel="show = false" ></l-clipper>
<button @tap="show = true">裁剪</button>
```
```js
// 非uni_modules引入
import lClipper from '@/components/lime-clipper/'
// uni_modules引入
import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/'
export default {
components: {lClipper},
data() {
return {
show: false,
url: '',
}
}
}
```
### 传入图片
`image-url`可传入**相对路径****临时路径****本地路径****网络图片**<br>
* **当为网络地址时**
* H5:👉 需要解决跨域问题。 <br>
* 小程序:👉 需要配置 downloadFile 域名 <br>
```html
<image :src="url" v-if="url" mode="widthFix"></image>
<l-clipper v-if="show" :image-url="imageUrl" @success="url = $event.url; show = false" @cancel="show = false" ></l-clipper>
<button @tap="show = true">裁剪</button>
```
```js
export default {
components: {lClipper},
data() {
return {
imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg',
show: false,
url: '',
}
}
}
```
### 确定按钮颜色
样式变量名:`--l-clipper-confirm-color`
可放到全局样式的 `page` 里或节点的 `style`
```html
<l-clipper class="clipper" style="--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)" ></l-clipper>
```
```css
// css 中为组件设置 CSS 变量
.clipper {
--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
}
// 全局
page {
--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
}
```
### 使用插槽
共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。
```html
<image :src="url" v-if="url" mode="widthFix"></image>
<l-clipper
v-if="show"
:isLockWidth="isLockWidth"
:isLockHeight="isLockHeight"
:isLockRatio="isLockRatio"
:isLimitMove="isLimitMove"
:isDisableScale="isDisableScale"
:isDisableRotate="isDisableRotate"
:isShowCancelBtn="isShowCancelBtn"
:isShowPhotoBtn="isShowPhotoBtn"
:isShowRotateBtn="isShowRotateBtn"
:isShowConfirmBtn="isShowConfirmBtn"
@success="url = $event.url; show = false"
@cancel="show = false" >
<!-- 四个基本按钮插槽 -->
<view slot="cancel">取消</view>
<view slot="photo">选择图片</view>
<view slot="rotate">旋转</view>
<view slot="confirm">确定</view>
<!-- 默认插槽 -->
<view class="tools">
<view>显示取消按钮
<switch :checked="isShowCancelBtn" @change="isShowCancelBtn = $event.target.value" ></switch>
</view>
<view>显示选择图片按钮
<switch :checked="isShowPhotoBtn" @change="isShowPhotoBtn = $event.target.value" ></switch>
</view>
<view>显示旋转按钮
<switch :checked="isShowRotateBtn" @change="isShowRotateBtn = $event.target.value" ></switch>
</view>
<view>显示确定按钮
<switch :checked="isShowConfirmBtn" @change="isShowConfirmBtn = $event.target.value" ></switch>
</view>
<view>锁定裁剪框宽度
<switch :checked="isLockWidth" @change="isLockWidth = $event.target.value" ></switch>
</view>
<view>锁定裁剪框高度
<switch :checked="isLockHeight" @change="isLockHeight = $event.target.value" ></switch>
</view>
<view>锁定裁剪框比例
<switch :checked="isLockRatio" @change="isLockRatio = $event.target.value" ></switch>
</view>
<view>限制移动范围
<switch :checked="isLimitMove" @change="isLimitMove = $event.target.value" ></switch>
</view>
<view>禁止缩放
<switch :checked="isDisableScale" @change="isDisableScale = $event.target.value" ></switch>
</view>
<view>禁止旋转
<switch :checked="isDisableRotate" @change="isDisableRotate = $event.target.value" ></switch>
</view>
</view>
</l-clipper>
<button @tap="show = true">裁剪</button>
```
```js
export default {
components: {lClipper},
data() {
return {
show: false,
url: '',
isLockWidth: false,
isLockHeight: false,
isLockRatio: true,
isLimitMove: false,
isDisableScale: false,
isDisableRotate: false,
isShowCancelBtn: true,
isShowPhotoBtn: true,
isShowRotateBtn: true,
isShowConfirmBtn: true
}
}
}
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ------------- | ------------ | ---------------- | ------------ |
| image-url | 图片路径 | <em>string</em> | |
| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | <em>number</em> | `1` |
| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | <em>Object</em> | |
| width | 裁剪框宽度,单位为 `rpx` | <em>number</em> | `400` |
| height | 裁剪框高度 | <em>number</em> | `400` |
| min-width | 裁剪框最小宽度 | <em>number</em> | `200` |
| min-height |裁剪框最小高度 | <em>number</em> | `200` |
| max-width | 裁剪框最大宽度 | <em>number</em> | `600` |
| max-height | 裁剪框最大宽度 | <em>number</em> | `600` |
| min-ratio | 图片最小缩放比 | <em>number</em> | `0.5` |
| max-ratio | 图片最大缩放比 | <em>number</em> | `2` |
| rotate-angle | 旋转按钮每次旋转的角度 | <em>number</em> | `90` |
| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | <em>number</em> | `1` |
| is-lock-width | 是否锁定裁剪框宽度 | <em>boolean</em> | `false` |
| is-lock-height | 是否锁定裁剪框高度上 | <em>boolean</em> | `false` |
| is-lock-ratio | 是否锁定裁剪框比例 | <em>boolean</em> | `true` |
| is-disable-scale | 是否禁止缩放 | <em>boolean</em> | `false` |
| is-disable-rotate | 是否禁止旋转 | <em>boolean</em> | `false` |
| is-limit-move | 是否限制移动范围 | <em>boolean</em> | `false` |
| is-show-photo-btn | 是否显示选择图片按钮 | <em>boolean</em> | `true` |
| is-show-rotate-btn | 是否显示转按钮 | <em>boolean</em> | `true` |
| is-show-confirm-btn | 是否显示确定按钮 | <em>boolean</em> | `true` |
| is-show-cancel-btn | 是否显示关闭按钮 | <em>boolean</em> | `true` |
### 事件 Events
| 事件名 | 说明 | 回调 |
| ------- | ------------ | -------------- |
| success | 生成图片成功 | {`width`, `height`, `url`} |
| fail | 生成图片失败 | `error` |
| cancel | 关闭 | `false` |
| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} |
| change | 图片大小改变时触发 | {`width`, `height`} |
| rotate | 图片旋转时触发 | `angle` |
## 常见问题
> 1、H5端使用网络图片需要解决跨域问题。<br>
> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!<br>
> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签`<IMG/>`<br>
> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。<br>
> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。<br>
## 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。<br>
> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594)
##### 以下是作者写的插件介绍:
# Clipper 图片裁剪
> uniapp 图片裁剪,可用于图片头像等裁剪处理
> [查看更多](http://liangei.gitee.io/limeui/#/clipper) <br>
> Q群:458377637
## 平台兼容
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
| √ | √ | √ | 未测 | √ | √ | √ |
## 代码演示
### 基本用法
`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url``width``height`
```html
<image :src="url" v-if="url" mode="widthFix"></image>
<l-clipper v-if="show" @success="url = $event.url; show = false" @cancel="show = false" ></l-clipper>
<button @tap="show = true">裁剪</button>
```
```js
// 非uni_modules引入
import lClipper from '@/components/lime-clipper/'
// uni_modules引入
import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/'
export default {
components: {lClipper},
data() {
return {
show: false,
url: '',
}
}
}
```
### 传入图片
`image-url`可传入**相对路径****临时路径****本地路径****网络图片**<br>
* **当为网络地址时**
* H5:👉 需要解决跨域问题。 <br>
* 小程序:👉 需要配置 downloadFile 域名 <br>
```html
<image :src="url" v-if="url" mode="widthFix"></image>
<l-clipper v-if="show" :image-url="imageUrl" @success="url = $event.url; show = false" @cancel="show = false" ></l-clipper>
<button @tap="show = true">裁剪</button>
```
```js
export default {
components: {lClipper},
data() {
return {
imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg',
show: false,
url: '',
}
}
}
```
### 确定按钮颜色
样式变量名:`--l-clipper-confirm-color`
可放到全局样式的 `page` 里或节点的 `style`
```html
<l-clipper class="clipper" style="--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)" ></l-clipper>
```
```css
// css 中为组件设置 CSS 变量
.clipper {
--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
}
// 全局
page {
--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
}
```
### 使用插槽
共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。
```html
<image :src="url" v-if="url" mode="widthFix"></image>
<l-clipper
v-if="show"
:isLockWidth="isLockWidth"
:isLockHeight="isLockHeight"
:isLockRatio="isLockRatio"
:isLimitMove="isLimitMove"
:isDisableScale="isDisableScale"
:isDisableRotate="isDisableRotate"
:isShowCancelBtn="isShowCancelBtn"
:isShowPhotoBtn="isShowPhotoBtn"
:isShowRotateBtn="isShowRotateBtn"
:isShowConfirmBtn="isShowConfirmBtn"
@success="url = $event.url; show = false"
@cancel="show = false" >
<!-- 四个基本按钮插槽 -->
<view slot="cancel">取消</view>
<view slot="photo">选择图片</view>
<view slot="rotate">旋转</view>
<view slot="confirm">确定</view>
<!-- 默认插槽 -->
<view class="tools">
<view>显示取消按钮
<switch :checked="isShowCancelBtn" @change="isShowCancelBtn = $event.target.value" ></switch>
</view>
<view>显示选择图片按钮
<switch :checked="isShowPhotoBtn" @change="isShowPhotoBtn = $event.target.value" ></switch>
</view>
<view>显示旋转按钮
<switch :checked="isShowRotateBtn" @change="isShowRotateBtn = $event.target.value" ></switch>
</view>
<view>显示确定按钮
<switch :checked="isShowConfirmBtn" @change="isShowConfirmBtn = $event.target.value" ></switch>
</view>
<view>锁定裁剪框宽度
<switch :checked="isLockWidth" @change="isLockWidth = $event.target.value" ></switch>
</view>
<view>锁定裁剪框高度
<switch :checked="isLockHeight" @change="isLockHeight = $event.target.value" ></switch>
</view>
<view>锁定裁剪框比例
<switch :checked="isLockRatio" @change="isLockRatio = $event.target.value" ></switch>
</view>
<view>限制移动范围
<switch :checked="isLimitMove" @change="isLimitMove = $event.target.value" ></switch>
</view>
<view>禁止缩放
<switch :checked="isDisableScale" @change="isDisableScale = $event.target.value" ></switch>
</view>
<view>禁止旋转
<switch :checked="isDisableRotate" @change="isDisableRotate = $event.target.value" ></switch>
</view>
</view>
</l-clipper>
<button @tap="show = true">裁剪</button>
```
```js
export default {
components: {lClipper},
data() {
return {
show: false,
url: '',
isLockWidth: false,
isLockHeight: false,
isLockRatio: true,
isLimitMove: false,
isDisableScale: false,
isDisableRotate: false,
isShowCancelBtn: true,
isShowPhotoBtn: true,
isShowRotateBtn: true,
isShowConfirmBtn: true
}
}
}
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ------------- | ------------ | ---------------- | ------------ |
| image-url | 图片路径 | <em>string</em> | |
| quality | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理 | <em>number</em> | `1` |
| source | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明 | <em>Object</em> | |
| width | 裁剪框宽度,单位为 `rpx` | <em>number</em> | `400` |
| height | 裁剪框高度 | <em>number</em> | `400` |
| min-width | 裁剪框最小宽度 | <em>number</em> | `200` |
| min-height |裁剪框最小高度 | <em>number</em> | `200` |
| max-width | 裁剪框最大宽度 | <em>number</em> | `600` |
| max-height | 裁剪框最大宽度 | <em>number</em> | `600` |
| min-ratio | 图片最小缩放比 | <em>number</em> | `0.5` |
| max-ratio | 图片最大缩放比 | <em>number</em> | `2` |
| rotate-angle | 旋转按钮每次旋转的角度 | <em>number</em> | `90` |
| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰** | <em>number</em> | `1` |
| is-lock-width | 是否锁定裁剪框宽度 | <em>boolean</em> | `false` |
| is-lock-height | 是否锁定裁剪框高度上 | <em>boolean</em> | `false` |
| is-lock-ratio | 是否锁定裁剪框比例 | <em>boolean</em> | `true` |
| is-disable-scale | 是否禁止缩放 | <em>boolean</em> | `false` |
| is-disable-rotate | 是否禁止旋转 | <em>boolean</em> | `false` |
| is-limit-move | 是否限制移动范围 | <em>boolean</em> | `false` |
| is-show-photo-btn | 是否显示选择图片按钮 | <em>boolean</em> | `true` |
| is-show-rotate-btn | 是否显示转按钮 | <em>boolean</em> | `true` |
| is-show-confirm-btn | 是否显示确定按钮 | <em>boolean</em> | `true` |
| is-show-cancel-btn | 是否显示关闭按钮 | <em>boolean</em> | `true` |
### 事件 Events
| 事件名 | 说明 | 回调 |
| ------- | ------------ | -------------- |
| success | 生成图片成功 | {`width`, `height`, `url`} |
| fail | 生成图片失败 | `error` |
| cancel | 关闭 | `false` |
| ready | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} |
| change | 图片大小改变时触发 | {`width`, `height`} |
| rotate | 图片旋转时触发 | `angle` |
## 常见问题
> 1、H5端使用网络图片需要解决跨域问题。<br>
> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!<br>
> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签`<IMG/>`<br>
> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。<br>
> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。<br>
## 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。<br>
![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<style type="text/css">
.st0{fill:#606060;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
.st2{fill:#FFFFFF;}
</style>
<g>
<path class="st2" d="M11.6,11c0.4,0.4,0.6,0.9,0.6,1.5c0,0.6-0.2,1.1-0.6,1.4c-0.4,0.4-0.9,0.6-1.5,0.6c-0.6,0-1.1-0.2-1.5-0.6
c-0.4-0.4-0.6-0.9-0.6-1.4s0.2-1.1,0.6-1.5c0.4-0.4,0.9-0.6,1.5-0.6C10.8,10.4,11.2,10.6,11.6,11z M24.6,18.4V6.7H5.4v12l1.8-1.8
c0.3-0.3,0.6-0.4,1-0.4c0.4,0,0.7,0.1,1,0.4l1.8,1.8l5.8-7c0.3-0.3,0.6-0.5,1.1-0.5c0.4,0,0.8,0.2,1.1,0.5
C18.8,11.6,24.6,18.4,24.6,18.4z M25.6,5.7C25.9,6,26,6.3,26,6.7v16.1c0,0.4-0.1,0.7-0.4,1c-0.3,0.3-0.6,0.4-1,0.4H5.4
c-0.4,0-0.7-0.1-1-0.4c-0.3-0.3-0.4-0.6-0.4-1V6.7c0-0.4,0.1-0.7,0.4-1c0.3-0.3,0.6-0.4,1-0.4h19.3C25,5.3,25.3,5.4,25.6,5.7z"/>
<path class="st1" d="M24.3,21.5H5.7c-0.2,0-0.3-0.2-0.3-0.3V7c0-0.2,0.2-0.3,0.3-0.3h18.6c0.2,0,0.3,0.2,0.3,0.3v14.2
C24.6,21.3,24.5,21.5,24.3,21.5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<style type="text/css">
.st0{fill:#606060;}
.st1{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
.st2{fill:#FFFFFF;}
</style>
<g>
<path class="st2" d="M11.6,11c0.4,0.4,0.6,0.9,0.6,1.5c0,0.6-0.2,1.1-0.6,1.4c-0.4,0.4-0.9,0.6-1.5,0.6c-0.6,0-1.1-0.2-1.5-0.6
c-0.4-0.4-0.6-0.9-0.6-1.4s0.2-1.1,0.6-1.5c0.4-0.4,0.9-0.6,1.5-0.6C10.8,10.4,11.2,10.6,11.6,11z M24.6,18.4V6.7H5.4v12l1.8-1.8
c0.3-0.3,0.6-0.4,1-0.4c0.4,0,0.7,0.1,1,0.4l1.8,1.8l5.8-7c0.3-0.3,0.6-0.5,1.1-0.5c0.4,0,0.8,0.2,1.1,0.5
C18.8,11.6,24.6,18.4,24.6,18.4z M25.6,5.7C25.9,6,26,6.3,26,6.7v16.1c0,0.4-0.1,0.7-0.4,1c-0.3,0.3-0.6,0.4-1,0.4H5.4
c-0.4,0-0.7-0.1-1-0.4c-0.3-0.3-0.4-0.6-0.4-1V6.7c0-0.4,0.1-0.7,0.4-1c0.3-0.3,0.6-0.4,1-0.4h19.3C25,5.3,25.3,5.4,25.6,5.7z"/>
<path class="st1" d="M24.3,21.5H5.7c-0.2,0-0.3-0.2-0.3-0.3V7c0-0.2,0.2-0.3,0.3-0.3h18.6c0.2,0,0.3,0.2,0.3,0.3v14.2
C24.6,21.3,24.5,21.5,24.3,21.5z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30px" height="30px" viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
.st1{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M17.1,24.2h-12c-0.2,0-0.3-0.2-0.3-0.3v-9.3c0-0.2,0.2-0.3,0.3-0.3h12c0.2,0,0.3,0.2,0.3,0.3v9.3
C17.5,24.1,17.3,24.2,17.1,24.2z"/>
<path class="st0" d="M16.6,5.4c4.8,0,8.7,3.9,8.7,8.7"/>
<polyline class="st0" points="19.3,10.1 14.9,5.6 19.3,1.2 "/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30px" height="30px" viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
.st1{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M17.1,24.2h-12c-0.2,0-0.3-0.2-0.3-0.3v-9.3c0-0.2,0.2-0.3,0.3-0.3h12c0.2,0,0.3,0.2,0.3,0.3v9.3
C17.5,24.1,17.3,24.2,17.1,24.2z"/>
<path class="st0" d="M16.6,5.4c4.8,0,8.7,3.9,8.7,8.7"/>
<polyline class="st0" points="19.3,10.1 14.9,5.6 19.3,1.2 "/>
</g>
</svg>
.flex-auto {
flex: auto;
}
.bg-transparent {
background-color: rgba(0,0,0,0.9);
transition-duration: 0.35s;
}
.l-clipper {
width: 100vw;
height: calc(100vh - var(--window-top));
background-color: rgba(0,0,0,0.9);
position: fixed;
top: var(--window-top);
left: 0;
z-index: 1;
}
.l-clipper-mask {
position: relative;
z-index: 2;
pointer-events: none;
}
.l-clipper__content {
pointer-events: none;
position: absolute;
border: 1rpx solid rgba(255,255,255,0.3);
box-sizing: border-box;
box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh;
background: transparent;
}
.l-clipper__content::before,
.l-clipper__content::after {
content: '';
position: absolute;
border: 1rpx dashed rgba(255,255,255,0.3);
}
.l-clipper__content::before {
width: 100%;
top: 33.33%;
height: 33.33%;
border-left: none;
border-right: none;
}
.l-clipper__content::after {
width: 33.33%;
left: 33.33%;
height: 100%;
border-top: none;
border-bottom: none;
}
.l-clipper__edge {
position: absolute;
width: 34rpx;
height: 34rpx;
border: 6rpx solid #fff;
pointer-events: auto;
}
.l-clipper__edge::before {
content: '';
position: absolute;
width: 40rpx;
height: 40rpx;
background-color: transparent;
}
.l-clipper__edge:nth-child(1) {
left: -6rpx;
top: -6rpx;
border-bottom-width: 0 !important;
border-right-width: 0 !important;
}
.l-clipper__edge:nth-child(1):before {
top: -50%;
left: -50%;
}
.l-clipper__edge:nth-child(2) {
right: -6rpx;
top: -6rpx;
border-bottom-width: 0 !important;
border-left-width: 0 !important;
}
.l-clipper__edge:nth-child(2):before {
top: -50%;
left: 50%;
}
.l-clipper__edge:nth-child(3) {
left: -6rpx;
bottom: -6rpx;
border-top-width: 0 !important;
border-right-width: 0 !important;
}
.l-clipper__edge:nth-child(3):before {
bottom: -50%;
left: -50%;
}
.l-clipper__edge:nth-child(4) {
right: -6rpx;
bottom: -6rpx;
border-top-width: 0 !important;
border-left-width: 0 !important;
}
.l-clipper__edge:nth-child(4):before {
bottom: -50%;
left: 50%;
}
.l-clipper-image {
width: 100%;
border-style: none;
position: absolute;
top: 0;
left: 0;
z-index: 1;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transform-origin: center;
}
.l-clipper-canvas {
position: fixed;
z-index: 10;
left: -200vw;
top: -200vw;
pointer-events: none;
}
.l-clipper-tools {
position: fixed;
left: 0;
bottom: 10px;
width: 100%;
z-index: 99;
color: #fff;
}
.l-clipper-tools__btns {
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 20rpx 40rpx;
box-sizing: border-box;
}
.l-clipper-tools__btns .cancel {
width: 112rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
}
.l-clipper-tools__btns .confirm {
width: 112rpx;
height: 60rpx;
line-height: 60rpx;
background-color: #07c160;
border-radius: 6rpx;
text-align: center;
}
.l-clipper-tools__btns image {
display: block;
width: 60rpx;
height: 60rpx;
}
.l-clipper-tools__btns {
flex-direction: row;
}
.flex-auto {
flex: auto;
}
.bg-transparent {
background-color: rgba(0,0,0,0.9);
transition-duration: 0.35s;
}
.l-clipper {
width: 100vw;
height: calc(100vh - var(--window-top));
background-color: rgba(0,0,0,0.9);
position: fixed;
top: var(--window-top);
left: 0;
z-index: 1;
}
.l-clipper-mask {
position: relative;
z-index: 2;
pointer-events: none;
}
.l-clipper__content {
pointer-events: none;
position: absolute;
border: 1rpx solid rgba(255,255,255,0.3);
box-sizing: border-box;
box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh;
background: transparent;
}
.l-clipper__content::before,
.l-clipper__content::after {
content: '';
position: absolute;
border: 1rpx dashed rgba(255,255,255,0.3);
}
.l-clipper__content::before {
width: 100%;
top: 33.33%;
height: 33.33%;
border-left: none;
border-right: none;
}
.l-clipper__content::after {
width: 33.33%;
left: 33.33%;
height: 100%;
border-top: none;
border-bottom: none;
}
.l-clipper__edge {
position: absolute;
width: 34rpx;
height: 34rpx;
border: 6rpx solid #fff;
pointer-events: auto;
}
.l-clipper__edge::before {
content: '';
position: absolute;
width: 40rpx;
height: 40rpx;
background-color: transparent;
}
.l-clipper__edge:nth-child(1) {
left: -6rpx;
top: -6rpx;
border-bottom-width: 0 !important;
border-right-width: 0 !important;
}
.l-clipper__edge:nth-child(1):before {
top: -50%;
left: -50%;
}
.l-clipper__edge:nth-child(2) {
right: -6rpx;
top: -6rpx;
border-bottom-width: 0 !important;
border-left-width: 0 !important;
}
.l-clipper__edge:nth-child(2):before {
top: -50%;
left: 50%;
}
.l-clipper__edge:nth-child(3) {
left: -6rpx;
bottom: -6rpx;
border-top-width: 0 !important;
border-right-width: 0 !important;
}
.l-clipper__edge:nth-child(3):before {
bottom: -50%;
left: -50%;
}
.l-clipper__edge:nth-child(4) {
right: -6rpx;
bottom: -6rpx;
border-top-width: 0 !important;
border-left-width: 0 !important;
}
.l-clipper__edge:nth-child(4):before {
bottom: -50%;
left: 50%;
}
.l-clipper-image {
width: 100%;
border-style: none;
position: absolute;
top: 0;
left: 0;
z-index: 1;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transform-origin: center;
}
.l-clipper-canvas {
position: fixed;
z-index: 10;
left: -200vw;
top: -200vw;
pointer-events: none;
}
.l-clipper-tools {
position: fixed;
left: 0;
bottom: 10px;
width: 100%;
z-index: 99;
color: #fff;
}
.l-clipper-tools__btns {
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 20rpx 40rpx;
box-sizing: border-box;
}
.l-clipper-tools__btns .cancel {
width: 112rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
}
.l-clipper-tools__btns .confirm {
width: 112rpx;
height: 60rpx;
line-height: 60rpx;
background-color: #07c160;
border-radius: 6rpx;
text-align: center;
}
.l-clipper-tools__btns image {
display: block;
width: 60rpx;
height: 60rpx;
}
.l-clipper-tools__btns {
flex-direction: row;
}
......@@ -40,9 +40,8 @@
</template>
<script>
import checkIdCard from '@/uni_modules/uni-id-pages/common/check-id-card.js';
import checkIdCard from '@/uni_modules/uni-id-pages/common/check-id-card.js'
import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
import {
store,
mutations
......
......@@ -11,6 +11,11 @@
</uni-list-item>
<uni-list-item v-if="userInfo.email" class="item" title="电子邮箱" :rightText="userInfo.email">
</uni-list-item>
<!-- #ifdef APP -->
<!-- 如未开通实人认证服务,可以将实名认证入口注释 -->
<uni-list-item class="item" @click="realNameVerify" title="实名认证" :rightText="realNameStatus !== 2 ? '未认证': '已认证'" link>
</uni-list-item>
<!-- #endif -->
<uni-list-item v-if="hasPwd" class="item" @click="changePassword" title="修改密码" link>
</uni-list-item>
</uni-list>
......@@ -32,17 +37,24 @@
</view>
</template>
<script>
const uniIdCo = uniCloud.importObject("uni-id-co")
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
const uniIdCo = uniCloud.importObject("uni-id-co")
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
export default {
computed: {
userInfo() {
return store.userInfo
}
},
computed: {
userInfo() {
return store.userInfo
},
realNameStatus () {
if (!this.userInfo.realNameAuth) {
return 0
}
return this.userInfo.realNameAuth.authStatus
}
},
data() {
return {
univerifyStyle: {
......@@ -154,13 +166,12 @@
this.setNicknameIng = false
this.$refs.dialog.close()
} else {
this.setNicknameIng = true
this.$refs.dialog.open()
}
},
deactivate() {
deactivate(){
uni.navigateTo({
url: "/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate"
url:"/uni_modules/uni-id-pages/pages/userinfo/deactivate/deactivate"
})
},
async bindThirdAccount(provider) {
......@@ -170,7 +181,7 @@
alipay: 'ali_openid',
apple: 'apple_openid',
qq: 'qq_openid'
} [provider.toLowerCase()]
}[provider.toLowerCase()]
if (this.userInfo[bindField]) {
await uniIdCo['unbind' + provider]()
......@@ -197,6 +208,11 @@
}
})
}
},
realNameVerify () {
uni.navigateTo({
url: "/uni_modules/uni-id-pages/pages/userinfo/realname-verify/realname-verify"
})
}
}
}
......
# 文档已移至uni-id-pages文档[https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html)
关于插件更新的说明:
所有uni_modules,在HBuilderX里点右键都可以直接升级。或者在插件市场导入覆盖。
覆盖时HBuilderX会弹出代码差异比对,可以决定接受哪些更改、拒绝哪些更改。
当拒绝局部修改时,注意可能产生兼容性问题。
你需要二次开发uni-id-pages的前端页面,
- 如果改动不大,那么每次更新uni-id-pages时,在HBuilderX的对比界面对比一下就好
# 文档已移至uni-id-pages文档[https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html](https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html)
关于插件更新的说明:
所有uni_modules,在HBuilderX里点右键都可以直接升级。或者在插件市场导入覆盖。
覆盖时HBuilderX会弹出代码差异比对,可以决定接受哪些更改、拒绝哪些更改。
当拒绝局部修改时,注意可能产生兼容性问题。
你需要二次开发uni-id-pages的前端页面,
- 如果改动不大,那么每次更新uni-id-pages时,在HBuilderX的对比界面对比一下就好
- 如果改动较大,建议复制一套前端页面到自己工程的pages目录下,pages.json里只引用根目录pages下的页面,不引用uni_modules下的页面。然后每次uni-id-pages更新,你对比下比上一版uni-id-pages改了什么,看你是否需要再合并到你自己的pages里。pages.json里不引用uni_modules里的页面的话,打包时不会把这些页面打包进去,不影响发行后的包体积
\ No newline at end of file
const { ERROR } = require('./error')
function getHttpClientInfo () {
const requestId = this.getUniCloudRequestId()
const { clientIP, userAgent, source, secretType = 'none' } = this.getClientInfo()
const { clientInfo = {} } = JSON.parse(this.getHttpInfo().body)
return {
...clientInfo,
clientIP,
userAgent,
source,
secretType,
requestId
}
}
function getHttpUniIdToken () {
const { uniIdToken = '' } = JSON.parse(this.getHttpInfo().body)
return uniIdToken
}
function verifyHttpMethod () {
const { headers, httpMethod } = this.getHttpInfo()
if (!/^application\/json/.test(headers['content-type']) || httpMethod.toUpperCase() !== 'POST') {
throw {
errCode: ERROR.UNSUPPORTED_REQUEST,
errMsg: 'unsupported request'
}
}
}
function universal () {
if (this.getClientInfo().source === 'http') {
verifyHttpMethod.call(this)
this.getParams()[0] = JSON.parse(this.getHttpInfo().body).params
this.getUniversalClientInfo = getHttpClientInfo.bind(this)
this.getUniversalUniIdToken = getHttpUniIdToken.bind(this)
} else {
this.getUniversalClientInfo = this.getClientInfo
this.getUniversalUniIdToken = this.getUniIdToken
}
}
module.exports = universal
const { ERROR } = require('./error')
function getHttpClientInfo () {
const requestId = this.getUniCloudRequestId()
const { clientIP, userAgent, source, secretType = 'none' } = this.getClientInfo()
const { clientInfo = {} } = JSON.parse(this.getHttpInfo().body)
return {
...clientInfo,
clientIP,
userAgent,
source,
secretType,
requestId
}
}
function getHttpUniIdToken () {
const { uniIdToken = '' } = JSON.parse(this.getHttpInfo().body)
return uniIdToken
}
function verifyHttpMethod () {
const { headers, httpMethod } = this.getHttpInfo()
if (!/^application\/json/.test(headers['content-type']) || httpMethod.toUpperCase() !== 'POST') {
throw {
errCode: ERROR.UNSUPPORTED_REQUEST,
errMsg: 'unsupported request'
}
}
}
function universal () {
if (this.getClientInfo().source === 'http') {
verifyHttpMethod.call(this)
this.getParams()[0] = JSON.parse(this.getHttpInfo().body).params
this.getUniversalClientInfo = getHttpClientInfo.bind(this)
this.getUniversalUniIdToken = getHttpUniIdToken.bind(this)
} else {
this.getUniversalClientInfo = this.getClientInfo
this.getUniversalUniIdToken = this.getUniIdToken
}
}
module.exports = universal
......@@ -198,6 +198,52 @@ function getRuleCategory(rule) {
}
}
function isMatchUnionType(val, rule) {
if (!rule.children || rule.children.length === 0) {
return true
}
const children = rule.children
for (let i = 0; i < children.length; i++) {
const child = children[i]
const category = getRuleCategory(child)
let pass = false
switch (category) {
case 'base':
pass = isMatchBaseType(val, child)
break
case 'array':
pass = isMatchArrayType(val, child)
break
default:
break
}
if (pass) {
return true
}
}
return false
}
function isMatchBaseType(val, rule) {
if (typeof baseValidator[rule.type] !== 'function') {
throw new Error(`invalid schema type: ${rule.type}`)
}
const validateRes = baseValidator[rule.type](val)
if (validateRes && validateRes.errCode) {
return false
}
return true
}
function isMatchArrayType(arr, rule) {
if (getType(arr) !== 'array') {
return false
}
if (rule.children && rule.children.length && arr.some(item => !isMatchUnionType(item, rule))) {
return false
}
return true
}
// 特殊符号 https://www.ibm.com/support/pages/password-strength-rules ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
// const specialChar = '~!@#$%^&*_-+=`|\(){}[]:;"\'<>,.?/'
......@@ -274,57 +320,7 @@ class Validator {
return this.customValidator[type] || this.baseValidator[type]
}
_isMatchUnionType(val, rule) {
if (!rule.children || rule.children.length === 0) {
return true
}
const children = rule.children
for (let i = 0; i < children.length; i++) {
const child = children[i]
const category = getRuleCategory(child)
let pass = false
switch (category) {
case 'base':
pass = this._isMatchBaseType(val, child)
break
case 'array':
pass = this._isMatchArrayType(val, child)
break
default:
break
}
if (pass) {
return true
}
}
return false
}
_isMatchBaseType(val, rule) {
const method = this.getRealBaseValidator(rule.type)
if (typeof method !== 'function') {
throw new Error(`invalid schema type: ${rule.type}`)
}
const validateRes = method(val)
if (validateRes && validateRes.errCode) {
return false
}
return true
}
_isMatchArrayType(arr, rule) {
if (getType(arr) !== 'array') {
return false
}
if (rule.children && rule.children.length && arr.some(item => !this._isMatchUnionType(item, rule))) {
return false
}
return true
}
get validator() {
const _this = this
return new Proxy({}, {
get: (_, prop) => {
if (typeof prop !== 'string') {
......@@ -336,7 +332,7 @@ class Validator {
}
const rule = parseValidatorName(prop)
return function (val) {
if (!_this._isMatchUnionType(val, rule)) {
if (!isMatchUnionType(val, rule)) {
return {
errCode: ERROR.INVALID_PARAM
}
......
......@@ -180,21 +180,21 @@ module.exports = {
// }
// })
// // 新增规则同样可以在数组验证规则中使用
// this.validator.validate({
// this.validator.valdate({
// timestamp: 123456789
// }, {
// timestamp: 'timestamp'
// })
// this.validator.validate({
// this.validator.valdate({
// timestampList: [123456789, 123123123123]
// }, {
// timestampList: 'array<timestamp>'
// })
// // 甚至更复杂的写法
// this.validator.validate({
// timestamp: [123456789123123123, 123123123123]
// this.validator.valdate({
// timestamp: [123456789, 123123123123]
// }, {
// timestamp: 'timestamp|array<timestamp|number>'
// timestamp: 'timestamp|array<timestamp>'
// })
// 挂载uni-captcha到this上,方便后续调用
......
let lang = {
'zh-Hans': require('./zh-hans'),
en: require('./en')
}
function mergeLanguage (lang1, lang2) {
const localeList = Object.keys(lang1)
localeList.push(...Object.keys(lang2))
const result = {}
for (let i = 0; i < localeList.length; i++) {
const locale = localeList[i]
result[locale] = Object.assign({}, lang1[locale], lang2[locale])
}
return result
}
try {
const langPath = require.resolve('uni-config-center/uni-id/lang/index.js')
lang = mergeLanguage(lang, require(langPath))
} catch (error) { }
module.exports = lang
let lang = {
'zh-Hans': require('./zh-hans'),
en: require('./en')
}
function mergeLanguage (lang1, lang2) {
const localeList = Object.keys(lang1)
localeList.push(...Object.keys(lang2))
const result = {}
for (let i = 0; i < localeList.length; i++) {
const locale = localeList[i]
result[locale] = Object.assign({}, lang1[locale], lang2[locale])
}
return result
}
try {
const langPath = require.resolve('uni-config-center/uni-id/lang/index.js')
lang = mergeLanguage(lang, require(langPath))
} catch (error) { }
module.exports = lang
# 说明
# 说明
此目录内为uni-id-co基础能力,不建议直接修改。如果你发现有些逻辑加入会更好,或者此部分代码有Bug可以向我们提交PR,仓库地址:[]()。如果有特殊的需求也可以在[论坛](https://ask.dcloud.net.cn/)提出,我们可以讨论下如何实现。
\ No newline at end of file
const AlipayBase = require('../alipayBase')
const protocols = require('./protocols')
module.exports = class Auth extends AlipayBase {
constructor (options) {
super(options)
this._protocols = protocols
}
async code2Session (code) {
const result = await this._exec('alipay.system.oauth.token', {
grantType: 'authorization_code',
code
})
return result
}
}
const AlipayBase = require('../alipayBase')
const protocols = require('./protocols')
module.exports = class Auth extends AlipayBase {
constructor (options) {
super(options)
this._protocols = protocols
}
async code2Session (code) {
const result = await this._exec('alipay.system.oauth.token', {
grantType: 'authorization_code',
code
})
return result
}
}
module.exports = {
code2Session: {
// args (fromArgs) {
// return fromArgs
// },
returnValue: {
openid: 'userId'
}
}
}
module.exports = {
code2Session: {
// args (fromArgs) {
// return fromArgs
// },
returnValue: {
openid: 'userId'
}
}
}
const {
userCollection
} = require('../../common/constants')
const {
USER_STATUS
} = require('../../common/constants')
async function setUserStatus (uid, status) {
const updateData = {
status
}
if (status !== USER_STATUS.NORMAL) {
updateData.valid_token_date = Date.now()
}
await userCollection.doc(uid).update({
status
})
// TODO 此接口尚不完善,例如注销后其他客户端可能存在有效token,支持Redis后此处会补充额外逻辑
return {
errCode: 0
}
}
module.exports = {
setUserStatus
}
const {
userCollection
} = require('../../common/constants')
const {
USER_STATUS
} = require('../../common/constants')
async function setUserStatus (uid, status) {
const updateData = {
status
}
if (status !== USER_STATUS.NORMAL) {
updateData.valid_token_date = Date.now()
}
await userCollection.doc(uid).update({
status
})
// TODO 此接口尚不完善,例如注销后其他客户端可能存在有效token,支持Redis后此处会补充额外逻辑
return {
errCode: 0
}
}
module.exports = {
setUserStatus
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册