提交 ff810503 编写于 作者: DCloud_JSON's avatar DCloud_JSON

1.1.0

上级 118ea01d
......@@ -107,7 +107,7 @@
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "",
"appid" : "wx1002f172d7719592",
"setting" : {
"urlCheck" : false
},
......
......@@ -23,13 +23,15 @@
"style": {
"navigationBarTitleText": "绑定手机号码"
}
},
},
// #ifndef MP-WEIXIN
{
"path": "uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage",
"style": {
"navigationBarTitleText": ""
}
},
},
// #endif
{
"path": "uni_modules/uni-id-pages/pages/login/login-withoutpwd",
"style": {
......@@ -53,14 +55,16 @@
"style": {
"navigationBarTitleText": "注册"
}
},
},
// #ifndef MP-WEIXIN
{
"path": "uni_modules/uni-id-pages/pages/register/register-admin",
"style": {
"navigationBarTitleText": "注册管理员账号",
"enablePullDownRefresh": false
}
},
},
// #endif
{
"path": "uni_modules/uni-id-pages/pages/register/register-by-email",
"style": {
......
......@@ -43,7 +43,9 @@
})
} else {
uni.navigateTo({
url: "/uni_modules/uni-id-pages/pages/login/login-withoutpwd?type=" + this.loginType
url: "/uni_modules/uni-id-pages/pages/login/login-withoutpwd?type=" + this.loginType,
animationType:"none",
animationDuration:0
})
}
},
......
## 1.1.1(2023-02-02)
- 修复 Vue3下 一键登录条款勾选框选中状态未同步到页面 的问题
## 1.1.0(2023-01-31)
- 【重要】优化 小程序端资源包大小(运行时大小为:731KB,发行后为:583KB;注:可以直接将本插件作为分包使用)
- 更新 微信小程序端 上传头像功能 用`wx.cropImage`实现图片裁剪
- 修复 选择一键登录时会先显示 非密码登录页面的问题
- 修复 一键登录 点击右上角的关闭按钮没有返回上一页的问题
## 1.0.41(2023-01-16)
- 优化 压缩依赖的文件资源大小
## 1.0.40(2023-01-16)
......
......@@ -67,7 +67,8 @@ let mixin = {
}
}
},
set(agree) {
set(agree) {
console.log('set(agree)',agree);
if (this.$refs.agreements) {
this.$refs.agreements.isAgree = agree
} else {
......
<template>
<view @click="onClick" :style="{width,height}">
<view @click="onClick" :style="{width,height}" style="justify-content: center;">
<image v-if="cSrc" :style="{width,height}" :src="cSrc" :mode="mode"></image>
</view>
</template>
......@@ -46,13 +46,10 @@
watch: {
src:{
handler(src) {
// console.log(src);
// console.log(src.substring(0, 8));
if (src&&src.substring(0, 8) == "cloud://") {
uniCloud.getTempFileURL({
fileList: [src]
}).then(res=>{
// console.log(res);
this.cSrc = res.fileList[0].tempFileURL
})
}else{
......@@ -61,9 +58,6 @@
},
immediate: true
}
},
async mounted() {
},
methods:{
onClick(){
......
......@@ -67,7 +67,6 @@
},
methods: {
popupConfirm(){
// console.log("popupConfirm");
this.isAgree = true
retryFun()
// this.$emit('popupConfirm')
......
......@@ -48,7 +48,6 @@
async mounted() {
// #ifdef H5
this.isPC = !['ios', 'android'].includes(uni.getSystemInfoSync().platform);
// console.log(' this.isPC', this.isPC, uni.getSystemInfoSync().platform);
// #endif
},
computed: {
......@@ -68,7 +67,6 @@
mutations.updateUserInfo({avatar_file})
},
uploadAvatarImg(res) {
// console.log(this.hasLogin);
if(!this.hasLogin){
return uni.navigateTo({
url:'/uni_modules/uni-id-pages/pages/login/login-withoutpwd'
......@@ -84,7 +82,6 @@
count: 1,
crop,
success: async (res) => {
// console.log(res);
let tempFile = res.tempFiles[0],
avatar_file = {
// #ifdef H5
......@@ -95,10 +92,12 @@
// #endif
},
filePath = res.tempFilePaths[0]
//非app端剪裁头像,app端用内置的原生裁剪
// #ifndef APP-PLUS
//非app端用前端组件剪裁头像,app端用内置的原生裁剪
if (!this.isPC) {
filePath = await new Promise((callback) => {
filePath = await new Promise((callback) => {
// #ifdef H5
if (!this.isPC) {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage?path=' +
filePath + `&options=${JSON.stringify(crop)}`,
......@@ -112,10 +111,32 @@
// console.log(e);
}
});
}
// #endif
// #ifdef MP-WEIXIN
wx.cropImage({
src:filePath,
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(filePath)
}
});
}
})
}
// #endif
})
// #endif
// console.log(this.userInfo);
let cloudPath = this.userInfo._id + '' + Date.now()
avatar_file.name = cloudPath
uni.showLoading({
......@@ -129,9 +150,7 @@
cloudPath,
fileType: "image"
});
// console.log(result)
avatar_file.url = fileID
// console.log({avatar_file});
uni.hideLoading()
this.setAvatarFile(avatar_file)
}
......
......@@ -41,13 +41,11 @@
uniCloud.importObject("uni-id-co",{
customUI:true
}).loginByWeixin({code}).then(e=>{
// console.log(e);
resolve()
}).catch(e=>{
console.log(e);
reject()
}).finally(e=>{
// console.log(e);
uni.hideLoading()
})
},
......@@ -61,13 +59,10 @@
})
},
async bindMobileByMpWeixin(e) {
// console.log(e);
if (e.detail.errMsg == "getPhoneNumber:ok") {
// console.log(e.detail);
//检查登录信息是否过期,否则通过重新登录刷新session_key
await this.beforeGetphonenumber()
uniIdCo.bindMobileByMpWeixin(e.detail).then(e => {
// console.log(e);
this.$emit('success')
}).finally(e => {
this.closeMe()
......@@ -157,8 +152,8 @@
.agree::after {
border: none;
}
/* #endif */
.agree:active {
background-color: #F5F5F6;
}
......
......@@ -141,7 +141,6 @@
const uniIdCo = uniCloud.importObject("uni-id-co", {
customUI: true
})
// console.log('uniIdCo', uniIdCo)
console.log('sendEmailCode',{
"email": this.email,
"scene": this.type,
......@@ -152,7 +151,6 @@
"scene": this.type,
"captcha": this.captcha
}).then(result => {
// console.log(result.code);
uni.showToast({
title: "邮箱验证码发送成功",
icon: 'none',
......@@ -161,7 +159,6 @@
this.reverseNumber = Number(this.count);
this.getCode();
}).catch(e => {
// console.log(JSON.stringify(e));
if (e.code == "uni-id-invalid-mail-template") {
this.modelValue = "123456"
uni.showToast({
......
......@@ -2,7 +2,7 @@
<view>
<view class="fab-login-box">
<view class="item" v-for="(item,index) in servicesList" :key="index"
@click="item.path?navigateTo(item.path):login_before(item.id,false)">
@click="item.path?toPage(item.path):login_before(item.id,false)">
<image class="logo" :src="item.logo" mode="scaleToFill"></image>
<text class="login-title">{{item.text}}</text>
</view>
......@@ -15,15 +15,8 @@
<script>
import config from '@/uni_modules/uni-id-pages/config.js'
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回
import {
store,
mutations
} from '@/uni_modules/uni-id-pages/common/store.js'
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
import {store,mutations} from '@/uni_modules/uni-id-pages/common/store.js'
let allServicesList = []
export default {
computed: {
agreements() {
......@@ -49,7 +42,6 @@
return this.getParentComponent().agree
},
set(agree) {
// console.log('setAgree', agree);
return this.getParentComponent().agree = agree
}
}
......@@ -59,65 +51,67 @@
servicesList: [{
"id": "username",
"text": "账号登录",
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/user.png",
"logo": "/uni_modules/uni-id-pages/static/login/uni-fab-login/user.png",
"path": "/uni_modules/uni-id-pages/pages/login/login-withpwd"
},
{
"id": "smsCode",
"text": "短信验证码",
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/sms.png",
"logo": "/uni_modules/uni-id-pages/static/login/uni-fab-login/sms.png",
"path": "/uni_modules/uni-id-pages/pages/login/login-withoutpwd?type=smsCode"
},
{
"id": "weixin",
"text": "微信登录",
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/weixin.png",
},
"logo": "/uni_modules/uni-id-pages/static/login/uni-fab-login/weixin.png",
},
// #ifndef MP-WEIXIN
{
"id": "apple",
"text": "苹果登录",
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/apple.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/apple.png",
},
{
"id": "univerify",
"text": "一键登录",
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/univerify.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/univerify.png",
},
{
"id": "taobao",
"text": "淘宝登录", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/taobao.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/taobao.png",
},
{
"id": "facebook",
"text": "脸书登录", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/facebook.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/facebook.png",
},
{
"id": "alipay",
"text": "支付宝登录", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/alipay.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/alipay.png",
},
{
"id": "qq",
"text": "QQ登录", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/qq.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/qq.png",
},
{
"id": "google",
"text": "谷歌登录", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/google.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/google.png",
},
{
"id": "douyin",
"text": "抖音登录", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/douyin.png",
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/douyin.png",
},
{
"id": "sinaweibo",
"text": "新浪微博", //暂未提供该登录方式的接口示例
"logo": "/uni_modules/uni-id-pages/static/uni-fab-login/sinaweibo.png",
}
"logo": "/uni_modules/uni-id-pages/static/app-plus/uni-fab-login/sinaweibo.png",
}
// #endif
],
univerifyStyle: { //一键登录弹出窗的样式配置参数
"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
......@@ -189,7 +183,6 @@
let path = item.path ? item.path.split('?')[0] : '';
return path != this.getRoute(1)
})
//console.log('servicesList', servicesList, this.servicesList);
},
methods: {
getParentComponent(){
......@@ -206,24 +199,23 @@
},
getRoute(n = 0) {
let pages = getCurrentPages();
// console.log('route-pages-length', pages.length);
if (n > pages.length) {
return ''
}
return '/' + pages[pages.length - n].route
},
navigateTo(path) {
toPage(path,index = 0) {
let type = ['navigateTo','redirectTo'][index]
//console.log('比较', this.getRoute(1),this.getRoute(2), path)
if (this.getRoute(1) == path.split('?')[0] && this.getRoute(1) ==
'/uni_modules/uni-id-pages/pages/login/login-withoutpwd') {
//如果要被打开的页面已经打开,且这个页面是 /uni_modules/uni-id-pages/pages/index/index 则把类型参数传给他
let type = path.split('?')[1].split('=')[1]
uni.$emit('uni-id-pages-set-login-type', type)
let loginType = path.split('?')[1].split('=')[1]
uni.$emit('uni-id-pages-setLoginType', loginType)
} else if (this.getRoute(2) == path) { // 如果上一个页面就是,马上要打开的页面,直接返回。防止重复开启
uni.navigateBack();
} else if (this.getRoute(1) != path) {
//console.log(3);
uni.navigateTo({
uni[type]({
url: path,
animationType: 'slide-in-left',
complete(e) {
......@@ -248,7 +240,7 @@
].includes(type)) {
return uni.showToast({
title: '该登录方式暂未实现,欢迎提交pr',
icon: 'none',
icon: 'none',
duration: 3000
});
}
......@@ -265,7 +257,7 @@
}else{
return uni.showToast({
title: '当前设备不支持此登录,请选择其他登录方式',
icon: 'none',
icon: 'none',
duration: 3000
});
}
......@@ -288,19 +280,16 @@
) {
return uni.showToast({
title: '当前设备不支持此登录,请选择其他登录方式',
icon: 'none',
icon: 'none',
duration: 3000
});
}
//判断是否需要弹出隐私协议授权框
// console.log(type, this.agree);
let needAgreements = (config?.agreements?.scope || []).includes('register')
// console.log({needAgreements});
if (type != 'univerify' && needAgreements && !this.agree) {
let agreementsRef = this.getParentComponent().$refs.agreements
return agreementsRef.popup(() => {
// console.log(type, navigateBack);
this.login_before(type, navigateBack, options)
})
}
......@@ -312,7 +301,6 @@
document.domain +
(window.location.href.includes('#')?'/#':'') +
'/uni_modules/uni-id-pages/pages/login/login-withoutpwd?is_weixin_redirect=true&type=weixin'
// console.log('redirectUrl----',redirectUrl);
let ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger'){
// console.log('在微信公众号内');
......@@ -335,32 +323,40 @@
uni.showLoading({
mask: true
})
if (type == 'univerify') {
let univerifyManager = uni.getUniverifyManager()
let clickAnotherButtons = false
let onButtonsClickFn = async res => {
// console.log('点击了第三方登录,provider:', res, res.provider, this.univerifyStyle.buttons.list);
//同步一键登录弹出层隐私协议框是否打勾
let agree = (await uni.getCheckBoxState())[1].state
//console.log('agree',agree);
this.agree = agree
console.log('点击了第三方登录,provider:', res, res.provider, this.univerifyStyle.buttons.list);
clickAnotherButtons = true
let checkBoxState = await uni.getCheckBoxState();
// 同步一键登录弹出层隐私协议框是否打勾
// #ifdef VUE2
this.agree = checkBoxState[1].state
// #endif
// #ifdef VUE3
this.agree = checkBoxState.state
// #endif
let {
path
} = this.univerifyStyle.buttons.list[res.index]
if (path) {
this.navigateTo(path)
if (path) {
if( this.getRoute(1).includes('login-withoutpwd') && path.includes('login-withoutpwd') ){
this.getParentComponent().showCurrentWebview()
}
this.toPage(path,1)
closeUniverify()
} else {
if (agree) {
if (this.agree) {
closeUniverify()
setTimeout(() => {
//console.log('login_before');
this.login_before(res.provider)
}, 500)
} else {
//console.log("你未同意隐私政策协议");
uni.showToast({
title: "你未同意隐私政策协议",
icon: 'none',
icon: 'none',
duration: 3000
});
}
......@@ -379,32 +375,34 @@
return univerifyManager.login({
"univerifyStyle": this.univerifyStyle,
success: res => {
// console.log('login success', res)
this.login(res.authResult, 'univerify')
},
fail(err) {
uni.showToast({
title: JSON.stringify(err),
icon: 'none',
duration: 3000
});
console.log(err)
if(!clickAnotherButtons){
uni.navigateBack()
}
// uni.showToast({
// title: JSON.stringify(err),
// icon: 'none',
// duration: 3000
// });
},
complete: async e => {
// console.log(e);
uni.hideLoading()
//同步一键登录弹出层隐私协议框是否打勾
this.agree = (await uni.getCheckBoxState())[1].state
// this.agree = (await uni.getCheckBoxState())[1].state
// 取消订阅自定义按钮点击事件
univerifyManager.offButtonsClick(onButtonsClickFn)
}
})
}
if (type === 'weixinMobile') {
return this.login({
phoneCode: options.phoneNumberCode
}, type)
}
if (type === 'weixinMobile') {
return this.login({
phoneCode: options.phoneNumberCode
}, type)
}
uni.login({
"provider": type,
......@@ -413,7 +411,6 @@
"univerifyStyle": this.univerifyStyle,
// #endif
success: async e => {
// console.log(e);
if (type == 'apple') {
let res = await this.getUserInfo({
provider: "apple"
......@@ -440,16 +437,15 @@
customUI:true
})
uniIdCo[action](params).then(result => {
// console.log("login-result", result);
uni.showToast({
title: '登录成功',
icon: 'none',
icon: 'none',
duration: 2000
});
// #ifdef MP-WEIXIN
//如果是微信小程序端的微信登录,且为首次登录,就弹出获取微信昵称+头像用于绑定资料
if (['weixin', 'weixinMobile'].includes(type) && result.type == "register") {
mutations.loginSuccess({
mutations.loginSuccess({
...result,
showToast: false,
autoBack: false
......@@ -463,7 +459,6 @@
mutations.loginSuccess(result)
})
.catch(e=>{
// console.log(e);
uni.showModal({
content: e.message,
confirmText:"知道了",
......@@ -513,7 +508,6 @@
box-sizing: border-box;
flex-direction: column;
}
/* #endif */
.fab-login-box {
......@@ -552,8 +546,6 @@
/* #endif */
.logo {
width: 60rpx;
height: 60rpx;
......@@ -563,7 +555,6 @@
border: solid 1px #F6F6F6;
}
.login-title {
text-align: center;
margin-top: 6px;
......
......@@ -146,7 +146,6 @@
"scene": this.type,
"captcha": this.captcha
}).then(result => {
// console.log(result.code);
uni.showToast({
title: "短信验证码发送成功",
icon: 'none',
......@@ -155,7 +154,6 @@
this.reverseNumber = Number(this.count);
this.getCode();
}).catch(e => {
// console.log(JSON.stringify(e));
if (e.code == "uni-id-invalid-sms-template-id") {
this.modelValue = "123456"
uni.showToast({
......@@ -209,7 +207,6 @@
/* #endif */
justify-content: center;
align-items: center;
}
.inner-text {
......
......@@ -31,12 +31,10 @@
uni.getUserProfile({
desc: "用于设置账户昵称和头像",
complete: (e) => {
// console.log("getUserProfile:", e);
callBack(e)
}
})
})
// console.log("userInfo", res.userInfo);
if(res.errMsg != "getUserProfile:ok"){
return this.closeMe()
}
......@@ -46,10 +44,10 @@
uni.downloadFile({
url: avatarUrl,
success: (res) => {
if (res.statusCode === 200) {
if (res.statusCode === 200) {
// console.log('下载成功');
callBack(res.tempFilePath)
}
callBack(res.tempFilePath)
}
callBack()
},
fail: (err) => {
......@@ -62,13 +60,11 @@
})
const extName = tempFilePath.split('.').pop() || 'jpg'
const cloudPath = 'user/avatar/'+ userId+'/'+Date.now()+'-avatar.'+extName;
// console.log(tempFilePath);
const result = await uniCloud.uploadFile({
filePath: tempFilePath,
cloudPath,
fileType:'image'
});
// console.log("上传成功",{result});
let userInfo = {
"nickname":nickName,
"avatar_file":{
......@@ -89,7 +85,6 @@
})
},
doUpdate(data,callback){
// console.log('dododo',data);
// 使用 clientDB 提交数据
usersTable.where('_id==$env.uid').update(data).then((res) => {
callback(res)
......
{
"name": "uni-id-pages",
"version": "1.0.19",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.0.19",
"dependencies": {
"jweixin-module": "^1.6.0"
},
"engines": {
"HBuilderX": "^3.4.17"
}
},
"node_modules/jweixin-module": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
"integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
}
},
"dependencies": {
"jweixin-module": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
"integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
}
}
}
{
"id": "uni-id-pages",
"displayName": "uni-id-pages",
"version": "1.0.41",
"version": "1.1.0",
"description": "云端一体简单、统一、可扩展的用户中心页面模版",
"keywords": [
"用户管理",
......
......@@ -20,7 +20,6 @@
});
title = "页面路径错误"
}else{
// console.log(url,title);
this.url = url;
}
if(title){
......@@ -34,7 +33,3 @@
}
}
</script>
<style lang="scss">
</style>
......@@ -38,7 +38,6 @@
this.phone = phoneNumber;
},
onShow() {
// console.log('onShow');
// #ifdef H5
document.onkeydown = event => {
var e = event || window.event;
......@@ -68,14 +67,12 @@
"code": this.code,
"captcha": this.captcha
}).then(e => {
// console.log(e);
this.loginSuccess(e)
}).catch(e => {
if (e.errCode == 'uni-id-captcha-required') {
this.$refs.popup.open()
} else {
console.log(e.errMsg);
// console.log(e.errCode);
}
}).finally(e => {
this.captcha = ''
......
<!-- 免密登录页 -->
<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 '/uni_modules/uni-id-pages/static/login/' + this.type + '.png'
}
},
async onLoad(e) {
// console.log(e);
//获取通过url传递的参数type设置当前登录方式,如果没传递直接默认以配置的登录
let type = e.type || config.loginTypes[0]
this.type = 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-set-login-type', 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-set-login-type')
},
onReady() {
//是否优先启动一键登录。即:页面一加载就启动一键登录
//#ifdef APP-PLUS
if (this.type == "univerify") {
this.type == this.loginTypes[1]
// console.log('开始一键登录');
setTimeout(() => {
this.$refs.uniFabLogin.login_before('univerify')
}, 100)
}
//#endif
},
<!-- 免密登录页 -->
<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: {
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() {
// console.log('toSmsPage',this.agree);
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'
showCurrentWebview(){
// 恢复当前页面窗体的显示 一键登录,默认不显示当前窗口
currentWebview.setStyle({
"top": 0
})
},
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 {
// width: 650rpx;
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;
}
}
},
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>
......@@ -108,12 +108,9 @@
},
submitForm(params) {
uniIdCo.registerAdmin(this.formData).then(e => {
// console.log(e);
uni.navigateBack()
})
.catch(e => {
// console.log(e);
// console.log(e.message);
//更好的体验:登录错误,直接刷新验证码
this.$refs.captcha.getImageCaptcha()
uni.showModal({
......
......@@ -109,17 +109,14 @@
}).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.registerUser(this.formData).then(e => {
// console.log(e);
this.loginSuccess(e)
})
.catch(e => {
// console.log(e);
console.log(e.message);
//更好的体验:登录错误,直接刷新验证码
this.$refs.captcha.getImageCaptcha()
......
......@@ -137,8 +137,6 @@
* 完成并提交
*/
submit() {
// console.log("formData", this.formData);
// console.log('rules', this.rules);
this.$refs.form.validate()
.then(res => {
let {
......@@ -153,7 +151,6 @@
password,
captcha
}).then(e => {
// console.log(e);
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
complete: (e) => {
......@@ -171,11 +168,9 @@
}).catch(errors=>{
let key = errors[0].key
if(key == 'code'){
// console.log(this.$refs.shortCode);
return this.$refs.shortCode.focusSmsCodeInput = true
}
key = key.replace(key[0], key[0].toUpperCase())
// console.log(key,'focus'+key);
this['focus'+key] = true
})
},
......
......@@ -166,8 +166,6 @@
* 完成并提交
*/
submit() {
// console.log("formData", this.formData);
// console.log('rules', this.rules);
this.$refs.form.validate()
.then(res => {
let {
......@@ -182,7 +180,6 @@
password,
captcha
}).then(e => {
// console.log(e);
uni.navigateBack()
})
.catch(e => {
......@@ -195,11 +192,9 @@
}).catch(errors=>{
let key = errors[0].key
if(key == 'code'){
// console.log(this.$refs.shortCode);
return this.$refs.shortCode.focusSmsCodeInput = true
}
key = key.replace(key[0], key[0].toUpperCase())
// console.log(key,'focus'+key);
this['focus'+key] = true
})
},
......@@ -208,11 +203,11 @@
url: '/uni_modules/uni-id-pages/pages/retrieve/retrieve-by-email'
})
},
backLogin () {
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
}
backLogin () {
uni.redirectTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd'
})
}
}
}
</script>
......
......@@ -65,10 +65,8 @@
});
}
// console.log(this.formData);
const uniIdCo = uniCloud.importObject("uni-id-co")
uniIdCo.bindMobileBySms(this.formData).then(e => {
// console.log(e);
uni.showToast({
title: e.errMsg,
icon: 'none',
......
......@@ -82,8 +82,6 @@
* 完成并提交
*/
submit() {
// console.log("formData", this.formData);
// console.log('rules', this.rules);
this.$refs.form.validate()
.then(res => {
let {
......@@ -94,7 +92,6 @@
oldPassword,
newPassword
}).then(e => {
// console.log(e);
uni.removeStorageSync('uni_id_token');
uni.setStorageSync('uni_id_token_expired', 0)
uni.redirectTo({
......@@ -109,7 +106,6 @@
}).catch(errors => {
let key = errors[0].key
key = key.replace(key[0], key[0].toUpperCase())
// console.log(key, 'focus' + key);
this['focus' + key] = true
})
}
......
......@@ -39,11 +39,8 @@
content: '已经仔细阅读注销提示,知晓可能带来的后果,并确认要注销',
complete: (e) => {
if (e.confirm) {
const db = uniCloud.database();
const uniIdco = uniCloud.importObject("uni-id-co");
uniIdco.closeAccount().then((e) => {
// console.log(e);
uni.showToast({
title: '注销成功',
duration: 3000
......
......@@ -115,7 +115,6 @@ export default {
this.$refs.popup.open()
} else {
console.log(e.errMsg);
// console.log(e.errCode);
}
}).finally(e => {
this.formData.captcha = ''
......
......@@ -14,9 +14,11 @@
<uni-list-item v-if="hasPwd" class="item" @click="changePassword" title="修改密码" link>
</uni-list-item>
</uni-list>
<!-- #ifndef MP -->
<uni-list class="mt10">
<uni-list-item @click="deactivate" title="注销账号" link="navigateTo"></uni-list-item>
</uni-list>
<!-- #endif -->
<uni-popup ref="dialog" type="dialog">
<uni-popup-dialog mode="input" :value="userInfo.nickname" @confirm="setNickname" title="设置昵称"
placeholder="请输入要设置的昵称">
......@@ -30,8 +32,6 @@
</view>
</template>
<script>
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users')
const uniIdCo = uniCloud.importObject("uni-id-co")
import {
store,
......@@ -82,12 +82,12 @@
}
})
},
logout(){
mutations.logout()
},
bindMobileSuccess(){
mutations.updateUserInfo()
},
logout(){
mutations.logout()
},
bindMobileSuccess(){
mutations.updateUserInfo()
},
changePassword(){
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd',
......@@ -123,9 +123,7 @@
"provider": 'univerify',
"univerifyStyle": this.univerifyStyle,
success: async e => {
// console.log(e.authResult);
uniIdCo.bindMobileByUniverify(e.authResult).then(res => {
// console.log(res);
mutations.updateUserInfo()
}).catch(e => {
console.log(e);
......@@ -148,7 +146,6 @@
})
},
setNickname(nickname) {
// console.log(nickname);
if (nickname) {
mutations.updateUserInfo({nickname})
this.$refs.dialog.close()
......
......@@ -18,13 +18,13 @@
"style": {
"navigationBarTitleText": "绑定手机号码"
}
},
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage",
"style": {
"navigationBarTitleText": ""
}
},
},
{
"path": "uni_modules/uni-id-pages/pages/login/login-withoutpwd",
"style": {
......@@ -81,14 +81,15 @@
"navigationBarTitleText": "修改密码",
"enablePullDownRefresh": false
}
},{
},
{
"path": "uni_modules/uni-id-pages/pages/register/register-admin",
"style": {
"navigationBarTitleText": "注册管理员账号",
"enablePullDownRefresh": false
}
},{
},
{
"path": "uni_modules/uni-id-pages/pages/userinfo/set-pwd/set-pwd",
"style": {
"navigationBarTitleText": "设置密码",
......
const assert = require('assert')
const {
Validator
} = require('./validator')
const {
ERROR
} = require('./error')
const {
getType
} = require('./utils')
const testCaseList = [{
value: {
username: 'uname'
},
schema: {
username: 'username'
},
expected: undefined
}, {
value: {
username: '123456'
},
schema: {
username: 'username'
},
expected: {
errCode: ERROR.INVALID_USERNAME
}
}, {
value: {
username: '数字天堂'
},
schema: {
username: 'username'
},
expected: {
errCode: ERROR.INVALID_USERNAME
}
}, {
value: {
password: '123456abc'
},
schema: {
password: 'password'
}
}, {
value: {
password: '123456def'
},
schema: {
password: 'password'
},
mixin: [{
type: 'password',
handler: function (password) {
if (typeof password !== 'string' || password.length < 10) {
return {
errCode: ERROR.INVALID_PASSWORD
}
}
}
}],
expected: {
errCode: ERROR.INVALID_PASSWORD
}
}, {
value: {
numberOrString: '123456'
},
schema: {
numberOrString: 'number|string'
}
}, {
value: {
numberOrString: 123456
},
schema: {
numberOrString: 'number|string'
}
}, {
value: {
numberOrString: '123456'
},
schema: {
numberOrString: 'string|number'
}
}, {
value: {
numberOrString: 123456
},
schema: {
numberOrString: 'string|number'
}
}, {
value: {
numberOrString: ['123456']
},
schema: {
numberOrString: 'array<number|string>'
}
}, {
value: {
numberOrString: [123456]
},
schema: {
numberOrString: 'array<number|string>'
}
}, {
value: {
numberOrString: [123456, '123456']
},
schema: {
numberOrString: 'array<number|string>'
}
}, {
value: {
numberOrString: ['123456']
},
schema: {
numberOrString: 'array<string|number>'
}
}, {
value: {
numberOrString: [123456]
},
schema: {
numberOrString: 'array<string|number>'
}
}, {
value: {
numberOrString: [123456, '123456']
},
schema: {
numberOrString: 'array<string|number>'
}
}, {
value: {
numberOrString: ['123456']
},
mixin: [{
type: '1to6',
handler: function (val) {
if (val !== '123456') {
return {
errCode: ERROR.INVALID_PARAM
}
}
}
}],
schema: {
numberOrString: 'array<number|1to6>'
}
}, {
value: {
username: ''
},
schema: {
username: {
required: false,
type: 'username'
}
}
}, {
value: {
username: ' '
},
schema: {
username: {
required: false,
type: 'username'
}
}
}, {
value: {
username: ' '
},
schema: {
username: 'username'
},
expected: {
errCode: ERROR.PARAM_REQUIRED
}
}, {
value: {
username: ''
},
schema: {
username: 'username'
},
expected: {
errCode: ERROR.PARAM_REQUIRED
}
}, {
value: {
mobile: '18811112222'
},
schema: {
mobile: 'mobile'
}
}, {
value: {
mobile: '18811112222'
},
schema: {
mobile: {
required: false,
type: 'mobile'
}
}
}, {
value: {
mobile: ''
},
schema: {
mobile: 'mobile'
},
expected: {
errCode: ERROR.PARAM_REQUIRED
}
}, {
value: {
mobile: ''
},
schema: {
mobile: {
required: false,
type: 'mobile'
}
}
}, {
value: {
mobile: '123456'
},
schema: {
mobile: 'mobile'
},
expected: {
errCode: ERROR.INVALID_MOBILE
}
}, {
value: {
email: 'test@dcloud.io'
},
schema: {
email: 'email'
}
}, {
value: {
email: 'test@dcloud.io'
},
schema: {
email: {
required: false,
type: 'email'
}
}
}, {
value: {
email: ''
},
schema: {
email: 'email'
},
expected: {
errCode: ERROR.PARAM_REQUIRED
}
}, {
value: {
email: ''
},
schema: {
email: {
required: false,
type: 'email'
}
}
}, {
value: {
email: 'test'
},
schema: {
email: 'email'
},
expected: {
errCode: ERROR.INVALID_EMAIL
}
}]
function execTestCase ({
value = {},
schema = {},
mixin = [],
expected = undefined,
error = ''
} = {}) {
const validator = new Validator()
for (let i = 0; i < mixin.length; i++) {
const {
type,
handler
} = mixin[i]
validator.mixin(type, handler)
}
let validateResult,
validateError
try {
validateResult = validator.validate(value, schema)
} catch (err) {
validateError = err
}
const tag = JSON.stringify({ value, schema })
if (error) {
if (typeof error === 'string') {
assert.strictEqual(validateError.message.indexOf(error) > -1, true, `[${tag}] error message error`)
} else if (getType(error) === 'regexp') {
assert.strictEqual(error.test(validateError), true, `[${tag}] error message error`)
} else {
throw new Error(`[${tag}] invalid test case`)
}
return
}
if (expected === undefined) {
assert.strictEqual(validateResult, undefined, `[${tag}] validate result error`)
return
}
const expectedKeys = Object.keys(expected)
let passResultCheck = true
for (let i = 0; i < expectedKeys.length; i++) {
const key = expectedKeys[i]
if (expected[key] !== validateResult[key]) {
passResultCheck = false
break
}
}
assert.strictEqual(passResultCheck, true, `[${tag}] validate result error`)
}
for (let i = 0; i < testCaseList.length; i++) {
console.log(`test case: ${i}`)
execTestCase(testCaseList[i])
console.log(`test case: ${i}, pass`)
}
......@@ -32,7 +32,7 @@
"title": "头像地址",
"trim": "both",
"permission": {
"read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission",
"read": true,
"write": "doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission"
}
},
......@@ -41,7 +41,7 @@
"description": "用file类型方便使用uni-file-picker组件",
"title": "头像文件",
"permission": {
"read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission",
"read": true,
"write": "doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission"
}
},
......@@ -209,7 +209,7 @@
"title": "昵称",
"trim": "both",
"permission": {
"read": "doc._id == auth.uid || 'READ_UNI_ID_USERS' in auth.permission",
"read": true,
"write": "doc._id == auth.uid || 'CREATE_UNI_ID_USERS' in auth.permission || 'UPDATE_UNI_ID_USERS' in auth.permission"
}
},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册