验证码

This commit is contained in:
2021-06-08 10:08:58 +08:00
parent a15512892c
commit bbd9fec7d9
10 changed files with 1341 additions and 62 deletions

View File

@@ -122,6 +122,49 @@ namespace Ewide.Core
[ErrorCodeItemMetadata("账号已冻结")]
D1017,
/// <summary>
/// 发送验证流程错误
/// </summary>
[ErrorCodeItemMetadata("发送验证流程错误")]
D1018,
/// <summary>
/// 没有可验证方式
/// </summary>
[ErrorCodeItemMetadata("没有可验证方式")]
D1019,
/// <summary>
/// 验证错误
/// </summary>
[ErrorCodeItemMetadata("验证错误")]
D1020,
/// <summary>
/// 绑定失败
/// </summary>
[ErrorCodeItemMetadata("绑定失败")]
D1021,
/// <summary>
/// 验证码失效
/// </summary>
[ErrorCodeItemMetadata("验证码失效")]
D1022,
/// <summary>
/// 请不要频繁发送验证码
/// </summary>
[ErrorCodeItemMetadata("请不要频繁发送验证码")]
D1023,
/// <summary>
/// 请不要频繁发送验证码
/// </summary>
[ErrorCodeItemMetadata("验证码发送失败")]
D1024,
/// <summary>
/// 父机构不存在
/// </summary>

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ewide.Core.Service
{
public class Usermailphone
{
/// <summary>
/// 绑定的值
/// </summary>
public string Target { get; set; }
/// <summary>
/// 发送验证码类型,1为发送给原邮箱2为发送给原手机号
/// </summary>
public int? Type { get; set; }
///<summary>
/// 第一次验证码
/// </summary>
public int? Orgcode { get; set; }
///<summary>
/// 第二次验证码
/// </summary>
public int? Code { get; set; }
}
}

View File

@@ -26,5 +26,8 @@ namespace Ewide.Core.Service
Task UpdateUser(UpdateUserInput input);
Task UpdateUserInfo(UserInput input);
Task UpdateUserPwd(ChangePasswordUserInput input);
Task<dynamic> SendCode(Usermailphone input);
Task<dynamic> CheckBindcode(Usermailphone input);
}
}

View File

@@ -1,4 +1,5 @@
using Ewide.Core.Service.Role;
using Ewide.Core.Util;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DataEncryption;
@@ -8,9 +9,11 @@ using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Ewide.Core.Service
@@ -23,15 +26,16 @@ namespace Ewide.Core.Service
{
private readonly IRepository<SysUser> _sysUserRep; // 用户表仓储
private readonly IUserManager _userManager;
private readonly ISysCacheService _sysCacheService;
private readonly ISysEmpService _sysEmpService;
private readonly IMemoryCache _iMemoryCache;
private readonly ISysUserDataScopeService _sysUserDataScopeService;
private readonly ISysUserRoleService _sysUserRoleService;
private readonly ISysUserAreaService _sysUserAreaService;
public SysUserService(IRepository<SysUser> sysUserRep,
IUserManager userManager,
IMemoryCache memoryCache,
ISysCacheService sysCacheService,
ISysEmpService sysEmpService,
ISysUserDataScopeService sysUserDataScopeService,
@@ -40,6 +44,7 @@ namespace Ewide.Core.Service
{
_sysUserRep = sysUserRep;
_userManager = userManager;
_iMemoryCache = memoryCache;
_sysCacheService = sysCacheService;
_sysEmpService = sysEmpService;
_sysUserDataScopeService = sysUserDataScopeService;
@@ -448,5 +453,204 @@ namespace Ewide.Core.Service
throw Oops.Oh(ErrorCode.D1013);
}
}
///<summary>
///发送验证码
/// </summary>
[HttpPost("/sysUser/SendCode")]
public async Task<dynamic> SendCode(Usermailphone input)
{
var Orgcode_Key = "ewide_Orgcode";
var Smscode_Key = "ewide_smscode";
var Mailcode_Key = "ewide_mailcode";
var Regex_phone = @"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$";
var Regex_Email = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
CodeHelper ch = new CodeHelper(_iMemoryCache);
//Type为1时给原手机号发送验证码
if(input.Type == 1)
{
try
{
return ch.SendSmscode(_userManager.User.Phone, Orgcode_Key);
}
catch (Exception e)
{
throw Oops.Oh(ErrorCode.D1018);
}
}
//Type为2时给原邮箱发送验证码
else if(input.Type == 2)
{
if(new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").IsMatch(_userManager.User.Email))
{
try
{
return ch.SendMail(_userManager.User.Email, Orgcode_Key);
}
catch (Exception e)
{
throw Oops.Oh(ErrorCode.D1018);
}
}
throw Oops.Oh("原邮箱错误");
}
//Type为null时则发验证码
else
{
//通过正则判断绑定类型
if(new Regex(Regex_phone).IsMatch(input.Target))
{
try
{
ch.SendSmscode(input.Target, Smscode_Key);
return true;
}
catch(Exception e)
{
throw Oops.Oh(ErrorCode.D1018);
}
}
if(new Regex(Regex_Email).IsMatch(input.Target))
{
try
{
ch.SendMail(input.Target, Mailcode_Key);
return true;
}
catch (Exception e)
{
throw Oops.Oh(ErrorCode.D1018);
}
}
throw Oops.Oh("格式错误");
}
}
///<summary>
///检验验证码并且绑定
/// </summary>
[HttpPost("/sysUser/CheckBindcode")]
public async Task<dynamic> CheckBindcode(Usermailphone input)
{
var Orgcode_Key = "ewide_Orgcode";
var Smscode_Key = "ewide_smscode";
var Mailcode_Key = "ewide_mailcode";
var Regex_phone = @"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$";
var Regex_Email = @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == _userManager.UserId);
CodeHelper ch = new CodeHelper(_iMemoryCache);
if(input.Type == 1)
{
if (ch.Checkcode(_userManager.User.Phone, input.Orgcode, Orgcode_Key))
{
return true;
};
throw Oops.Oh("验证错误");
}
else if(input.Type == 2)
{
if(ch.Checkcode(_userManager.User.Email, input.Orgcode, Orgcode_Key))
{
return true;
}
throw Oops.Oh("验证错误");
}
else
{
//为第一次绑定
if(string.IsNullOrEmpty(_userManager.User.Phone) && string.IsNullOrEmpty(_userManager.User.Email))
{
if(new Regex(Regex_phone).IsMatch(input.Target))
{
if (ch.Checkcode(input.Target,input.Code, Smscode_Key))
{
try
{
user.Phone = input.Target;
await user.UpdateIncludeNowAsync(new string[] {
nameof(SysUser.Phone)
}, true);
return "手机绑定成功";
}
catch
{
throw Oops.Oh("手机绑定错误");
}
}
throw Oops.Oh("验证码失效");
}
if(new Regex(Regex_Email).IsMatch(input.Target))
{
if (ch.Checkcode(input.Target, input.Code, Mailcode_Key))
{
try
{
user.Email = input.Target;
await user.UpdateIncludeNowAsync(new string[] {
nameof(SysUser.Email)
}, true);
return "邮箱绑定成功";
}
catch
{
throw Oops.Oh("邮箱绑定错误");
}
}
throw Oops.Oh("验证码失效");
}
throw Oops.Oh("号码格式不对");
}
else
{
bool CheckOrgPhone = ch.Checkcode(_userManager.User.Phone, input.Orgcode, Orgcode_Key);
bool CheckOrgEmail = ch.Checkcode(_userManager.User.Email, input.Orgcode, Orgcode_Key);
if (CheckOrgPhone || CheckOrgEmail)
{
if (new Regex(Regex_phone).IsMatch(input.Target))
{
if (ch.Checkcode(input.Target, input.Code, Smscode_Key))
{
try
{
user.Phone = input.Target;
await user.UpdateIncludeNowAsync(new string[] {
nameof(SysUser.Phone)
}, true);
return "手机改绑成功";
}
catch
{
throw Oops.Oh("手机绑定错误");
}
}
throw Oops.Oh("验证码失效");
}
if (new Regex(Regex_Email).IsMatch(input.Target))
{
if (ch.Checkcode(input.Target, input.Code, Mailcode_Key))
{
try
{
user.Email = input.Target;
await user.UpdateIncludeNowAsync(new string[] {
nameof(SysUser.Email)
}, true);
return "邮箱改绑成功";
}
catch
{
throw Oops.Oh("邮箱绑定错误");
}
}
throw Oops.Oh("验证码失效");
}
throw Oops.Oh("号码格式不对");
}
throw Oops.Oh("验证码失效");
}
}
}
}
}

View File

@@ -0,0 +1,252 @@
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Furion;
using Furion.FriendlyException;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Ewide.Core.Util
{
public class CodeHelper
{
private readonly IMemoryCache _IMemoryCache;
public CodeHelper(IMemoryCache IMemoryCache)
{
_IMemoryCache = IMemoryCache;
}
public static string Aliyun_AccessKey = App.Configuration["SmsHelper:Aliyun_AccessKey"];
public static string Aliyun_AccessSecret = App.Configuration["SmsHelper:Aliyun_AccessSecret"];
public static string Aliyun_Smscode_SignName = App.Configuration["SmsHelper:Aliyun_Smscode_SignName"];
public static string Aliyun_Smscode_TemplateCode = App.Configuration["SmsHelper:Aliyun_Smscode_TemplateCode"];
/// <summary>
/// 发送验证码间隔时间(秒)
/// </summary>
protected static int code_Countdown = 60;
/// <summary>
/// 验证code
/// </summary>
protected static string Orgcode_Key = "ewide_Orgcode";
///<summary>
///邮箱Code
/// </summary>
protected static string mailcode_Key = "ewide_mailcode";
///<summary>
///手机Code
/// </summary>
protected static string smscode_Key = "ewide_smscode";
/// <summary>
/// 将code存入缓存
/// </summary>
/// <param name="way">验证方式</param>
/// <param name="code">验证码</param>
/// <param name="type">code的类型</param>
public void Updatecode(string num, int code, string way)
{
var ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
_IMemoryCache.Set(
way + "_" + num, // code的类型_手机或者邮箱号码
code + "_" + (int)ts.TotalSeconds, // 1234567_TimeStamp
DateTime.UtcNow.AddMinutes(5)// 5分钟过期
);
}
/// <summary>
/// 判断是否含有code
/// </summary>
/// <param name="way"></param>
/// <param name="code"></param>
/// <param name="type"></param>
/// <returns></returns>
public bool Checkcode(string Target, int? code,string Key)
{
var cache = (string)_IMemoryCache.Get(Key + "_" + Target);// 获取匹配类型的code值
if (string.IsNullOrEmpty(cache))
{
return false;
}
return code == cache.Split('_').Select(p => int.Parse(p)).First();
}
/// <summary>
/// 判断是否含有code
/// </summary>
/// <param name="way"></param>
/// <param name="code"></param>
/// <param name="type"></param>
/// <returns></returns>
public bool Checkhavecode(string num, string way)
{
var cache = (string)_IMemoryCache.Get(way + "_" + num);// 获取匹配类型的code值
if (string.IsNullOrEmpty(cache))
{
return false;
}
return true;
}
/// <summary>
/// 删除相应缓存
/// </summary>
/// <param name="way"></param>
/// <param name="type"></param>
public void removecode(string way, string num){
_IMemoryCache.Remove(way + "_" + num);
}
/// <summary>
/// code60秒才可再次发送
/// </summary>
/// <param name="way">验证类型</param>
/// <param name="num">值</param>
/// <param name="coundown"></param>
/// <returns></returns>
public bool IscodeCountdown(string way, string num, int coundown = 60)
{
return GetSmscodeCountdown(way, num) < coundown;
}
/// <summary>
/// 发送验证码倒计时
/// </summary>
/// <param name="mobile"></param>
/// <returns></returns>
public int GetSmscodeCountdown(string way,string num)
{
var cache = (string)_IMemoryCache.Get(way + "_" + num);
if (String.IsNullOrEmpty(cache))
{
return code_Countdown;
}
var ts = cache.Split('_').Select(p => int.Parse(p)).Last();
var nowTs = (int)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
return nowTs - ts;
}
///<summary>
/// 发送手机验证码
///</summary>
public bool SendSmscode(string mobile, string way ,int length = 6)
{
if (!new Regex(@"^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$").IsMatch(mobile))
{
throw Oops.Oh(ErrorCode.D1011);
}
//if (IscodeCountdown(way, mobile, code_Countdown))
//{
// throw Oops.Oh(ErrorCode.D1023);
//}
IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", Aliyun_AccessKey, Aliyun_AccessSecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest
{
Method = Aliyun.Acs.Core.Http.MethodType.POST,
Domain = "dysmsapi.aliyuncs.com",
Version = "2017-05-25",
Action = "SendSms"
};
request.AddQueryParameters("PhoneNumbers", mobile);
request.AddQueryParameters("SignName", Aliyun_Smscode_SignName);
request.AddQueryParameters("TemplateCode", Aliyun_Smscode_TemplateCode);
var minValue = Convert.ToInt32("1".PadRight(length, '0'));
var maxValue = Convert.ToInt32("1".PadRight(length + 1, '0'));
var code = new Random().Next(minValue, maxValue);
var param = new { code };
request.AddQueryParameters("TemplateParam", JsonConvert.SerializeObject(param));
Updatecode(mobile, code,way);
try
{
CommonResponse response = client.GetCommonResponse(request);
var msg = System.Text.Encoding.UTF8.GetString(response.HttpResponse.Content);
var result = JsonConvert.DeserializeObject(msg);
var j = (JObject)result;
if(!"OK".Equals(j["Code"].ToString(), StringComparison.CurrentCultureIgnoreCase))
{
throw Oops.Oh("请不要频繁发送");
}
return true;
}
catch (ServerException e)
{
throw Oops.Oh(ErrorCode.D1024);
}catch(Exception e)
{
throw Oops.Oh("访问异常");
}
}
/// <summary>
/// 发送邮箱
/// </summary>
/// <param name="mail"></param>
/// <param name="length"></param>
/// <returns></returns>
public bool SendMail(string mail, string way,int length = 6)
{
if (!new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$").IsMatch(mail))
{
throw Oops.Oh("格式不对");
}
if (IscodeCountdown(mail, way, code_Countdown))
{
throw Oops.Oh("60秒后才能再次发送");
}
string account = App.Configuration["Mail:Account"];
string passWord = App.Configuration["Mail:PassWord"];
//var options = Options.Create(options: new MemoryCacheOptions());
//IMemoryCache cache = new MemoryCache(options);
SmtpClient smtpClient = new SmtpClient();
smtpClient.EnableSsl = true;
smtpClient.UseDefaultCredentials = false;
smtpClient.Host = App.Configuration["Mail:Host"];
smtpClient.Credentials = new System.Net.NetworkCredential(account, passWord);
smtpClient.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
MailMessage mailMessage = new MailMessage();
MailAddress fromAddr = new MailAddress(account);
mailMessage.From = fromAddr;
mailMessage.To.Add(mail);
mailMessage.Subject = App.Configuration["Mail:Subject"];
mailMessage.BodyEncoding = Encoding.UTF8;
mailMessage.IsBodyHtml = true;
mailMessage.Priority = MailPriority.Low;
var minValue = Convert.ToInt32("1".PadRight(length, '0'));
var maxValue = Convert.ToInt32("1".PadRight(length + 1, '0'));
var code = new Random().Next(minValue, maxValue);
var param = new { code };
Updatecode(mail, code, way);
try
{
var Message = "邮箱验证码为:" + code.ToString();
mailMessage.Body = Message;
smtpClient.Send(mailMessage);
return true;
}
catch
{
throw Oops.Oh(ErrorCode.xg1100);
}
}
}
}

View File

@@ -73,4 +73,16 @@ export default {
* 更新基本信息
*/
sysUserUpdateInfo: ['/sysUser/updateInfo', 'post'],
/**
* 发送验证码
*/
SendCode: ['/sysUser/SendCode', 'post'],
/**
* 绑定/验证
*/
CheckBindcode: ['/sysUser/CheckBindcode', 'post'],
}

View File

@@ -1,9 +1,10 @@
const SESSION_KEY = '__SESSION'
const SETTING_KEY = '__SETTINGS'
const GLOBAL_INFO_KEY = '__GLOBAL_INFO'
const COUNT_DWON_KEY = '__COUNT_DWON'
export {
SESSION_KEY,
SETTING_KEY,
GLOBAL_INFO_KEY,
COUNT_DWON_KEY
}

View File

@@ -46,6 +46,9 @@
>
<password />
</yo-modal-form>
<phone @ok="showSafety" ref="phone" />
<mail @ok="showSafety" ref="mail" />
</container>
</template>
<style lang="less" scoped>
@@ -57,16 +60,19 @@
background-color: @white;
}
}
</style>
<script>
import { doLogout } from '@/common/login';
import Password from './password';
import phone from './phone';
import mail from './mail';
export default {
components: {
Password,
phone,
mail,
},
data() {
@@ -102,8 +108,16 @@ export default {
},
created() {
const info = this.$root.global.info;
this.showSafety();
},
methods: {
onSetPasswordSuccess() {
doLogout();
},
showSafety() {
const info = this.$root.global.info;
this.data = [];
// 登录密码
this.data.push({
title: '登录密码',
@@ -141,7 +155,9 @@ export default {
</div>
),
done: !!info.phone,
action: () => {},
action: () => {
this.$refs.phone.OnOpen();
},
});
// 邮箱绑定
@@ -158,13 +174,10 @@ export default {
</div>
),
done: !!info.email,
action: () => {},
});
action: () => {
this.$refs.mail.OnOpen();
},
methods: {
onSetPasswordSuccess() {
doLogout();
});
},
},
};

View File

@@ -0,0 +1,360 @@
<template>
<!--
普通编辑窗体
v 1.2
2021-04-30
Lufthafen
-->
<a-modal
:footer="false"
:visible="visible"
@cancel="onResetFields"
class="yo-modal-form"
title="绑定邮箱"
>
<a-spin :spinning="loading">
<a-icon slot="indicator" spin type="loading" />
<div class="yo-form">
<div class="yo-form-group" v-if="this.type.length!==0">
<!-- 表单控件 -->
<!-- ... -->
<div style="padding: 20px 100px">
<a-steps :current="current">
<a-step :key="item.title" :title="item.title" v-for="item in steps" />
</a-steps>
</div>
<a-form-model :model="form" ref="form">
<!-- 发送给原邮箱号码验证码 -->
<div v-if="current===0">
<a-form-model-item label="选择验证方式">
<a-select style="width:300px" v-model="form.type">
<a-select-option
:key="item.Title"
:value="item.Value"
v-for="item in type"
>{{item.Title}}</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="验证码">
<a-input
placeholder="请输入六位验证码"
style="width: 185px; margin-right: 15px"
v-model="form.orgcode"
></a-input>
<a-button :loading="codeLoading" @click="sendcode()" v-if="sendOrNo">发送验证码</a-button>
<a-button disabled v-else>{{ countdown }}秒后重送</a-button>
</a-form-model-item>
</div>
<!-- 发送给绑定新邮箱号码-->
<div v-if="current===1">
<a-form-model-item label="新邮箱号码">
<a-input placeholder="请输入邮箱账号" style="width:300px" v-model="form.target"></a-input>
</a-form-model-item>
<a-form-model-item label="验证码">
<a-input
placeholder="请输入六位验证码"
style="width: 185px; margin-right: 15px"
v-model="form.code"
></a-input>
<a-button :loading="codeLoading" @click="sendcode()" v-if="sendOrNo">发送验证码</a-button>
<a-button disabled v-else>{{ countdown }}秒后重送</a-button>
</a-form-model-item>
</div>
</a-form-model>
<br />
<div class="steps-action" style="text-align:center">
<a-button :disabled="checkfirst" @click="next" type="primary" v-if="current == 0">下一步</a-button>
<a-button
:disabled="checkform"
:loading="completeLoading"
@click="complete"
type="primary"
v-if="current == 1"
>完成</a-button>
<a-button @click="prev" style="margin-left: 8px" v-if="current > 0">前一步</a-button>
</div>
<br />
</div>
<div class="yo-form-group" v-else>
<!-- 表单控件 -->
<!-- ... -->
<a-form-model :model="form" ref="form">
<a-form-model-item label="请输入邮箱">
<a-input placeholder="请输入邮箱号码" style="width:250px;" v-model="form.target"></a-input>
</a-form-model-item>
<a-form-model-item label="验证码">
<a-input
placeholder="请输入验证码"
style="width:140px;margin-right:15px"
v-model="form.code"
></a-input>
<a-button @click="sendcode()" v-if="sendOrNo">发送验证码</a-button>
<a-button disabled v-else>{{ countdown }}秒后重送</a-button>
</a-form-model-item>
</a-form-model>
<br />
<div style="text-align:center">
<a-button :disabled="checkform" @click="complete" type="primary">绑定</a-button>
</div>
<br />
</div>
</div>
</a-spin>
</a-modal>
</template>
<script>
/* 表单内容默认值 */
const defaultForm = {
target: '',
code: '',
type: null,
orgcode: '',
/* ... */
};
import app from '@/main';
import { COUNT_DWON_KEY } from '@/common/storage';
export default {
data() {
return {
/** 表单数据 */
form: {},
/** 验证格式 */
rules: {
/* ... */
},
current: 0,
steps: [
{
title: '验证',
},
{
title: '绑定',
},
],
/** 加载异步数据状态 */
loading: false,
countdown: 0,
type: [],
sendOrNo: true,
codeLoading: false,
completeLoading: false,
visible: false,
checkform: true,
checkfirst: true,
/** 其他成员属性 */
/* ... */
};
},
methods: {
/**
* 必要的方法
* 在打开编辑页时允许填充数据
*/
onFillData(params) {
/** 将默认数据覆盖到form */
this.form = this.$_.cloneDeep({
...defaultForm,
//...params.record,
/** 在此处添加其他默认数据转换 */
/* ... */
});
if (this.type.length != 0) {
this.form.type = this.type[0].Value;
}
},
/**
* 必要方法
* 验证表单并获取表单数据
*/
// onGetData() {
// return new Promise((reslove, reject) => {
// this.$refs.form.validate((valid) => {
// if (valid) {
// const record = this.$_.cloneDeep(this.form);
// /** 验证通过后可以对数据进行转换得到想要提交的格式 */
// /* ... */
// reslove(record);
// } else {
// reject();
// }
// });
// });
// },
/**
* 必要的方法
* 在外部窗口进行保存时调用表单验证
*/
// onValidate(callback) {
// this.$refs.form.validate(callback);
// },
/**
* 必要的方法
* 在外部窗口关闭或重置时对表单验证进行初始化
*/
onResetFields() {
setTimeout(() => {
this.$refs.form.resetFields();
this.current = 0;
this.visible = false;
window.localStorage.removeItem(COUNT_DWON_KEY);
/** 在这里可以初始化当前组件中其他属性 */
/* ... */
}, 300);
},
/**
* 必要方法
* 加载当前表单中所需要的异步数据
*/
async onInit(params) {
this.loading = true;
this.type = [];
/** 可以在这里await获取一些异步数据 */
const info = this.$root.global.info;
info.phone &&
this.type.push({
Title: '使用手机号' + info.phone + '进行验证',
Value: 1,
});
info.email &&
this.type.push({
Title: '使用邮箱' + info.email + '进行验证',
Value: 2,
});
this.onFillData();
this.showcountdown();
/* ... */
this.loading = false;
},
/** 当前组件的其他方法 */
/* ... */
SendOrgSms() {
this.$api.SendOrgSms().then((res) => {
if (res) {
this.addTime();
this.showcountdown();
}
});
},
/**
* 将倒计时添加入到本地
*/
addTime() {
const now = Date.now();
var date = now + 60 * 1000 + 500;
window.localStorage.setItem(COUNT_DWON_KEY, date);
},
/**
* 下一步
*/
next() {
this.loading = true;
this.$api
.CheckBindcode(this.form)
.then((res) => {
if (res.data) {
window.localStorage.removeItem(COUNT_DWON_KEY);
this.form.type = null;
this.current++;
}
})
.finally(() => {
this.loading = false;
});
},
/**
* 完成
*/
complete() {
this.completeLoading = true;
this.$api
.CheckBindcode(this.form)
.then((res) => {
if (res.data) {
window.localStorage.removeItem(COUNT_DWON_KEY);
var num = this.form.target;
num = num.replace(/(\w?)(\w+)(\w)(@\w+\.[a-z]+(\.[a-z]+)?)/, '$1****$4');
app.$set(app.global.info, 'email', num);
this.$message.success('改绑完成');
this.onResetFields();
this.$emit('ok', 100, 100);
}
})
.finally(() => {
this.completeLoading = false;
});
},
/**
* 发送验证码
*/
sendcode() {
this.codeLoading = true;
var reg = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
if (!reg.test(this.form.target) && this.form.type != '1' && this.form.type != '2') {
this.$message.warning('请输入正确的邮箱');
this.codeLoading = false;
return;
}
this.$api
.SendCode(this.form)
.then((res) => {
if (res.success) {
this.addTime();
this.showcountdown();
}
})
.finally(() => {
this.codeLoading = false;
});
},
//打开弹窗
OnOpen() {
this.onInit();
this.visible = true;
},
/**
* 向前异步
*/
prev() {
window.localStorage.removeItem(COUNT_DWON_KEY);
this.form = {
target: '',
code: '',
type: this.type[0].Value,
orgcode: '',
};
this.current--;
},
/**
* 显示倒计时
*/
showcountdown() {
let _this = this;
var Furdate = window.localStorage.getItem(COUNT_DWON_KEY);
var nowdate = new Date().getTime();
if (Furdate >= nowdate) {
this.sendOrNo = false;
this.countdown = parseInt((Furdate - nowdate) / 1000);
setTimeout(() => {
_this.showcountdown();
}, 1000);
} else {
this.sendOrNo = true;
}
},
},
watch: {
form: {
deep: true,
handler: function (newVal, oldVal) {
this.checkform = !(newVal.target != '' && newVal.code != '');
this.checkfirst = !(newVal.orgcode != '');
},
},
},
};
</script>

View File

@@ -0,0 +1,360 @@
<template>
<!--
普通编辑窗体
v 1.2
2021-04-30
Lufthafen
-->
<a-modal
:footer="false"
:visible="visible"
@cancel="onResetFields"
class="yo-modal-form"
title="绑定邮箱"
>
<a-spin :spinning="loading">
<a-icon slot="indicator" spin type="loading" />
<div class="yo-form">
<div class="yo-form-group" v-if="this.type.length!==0">
<!-- 表单控件 -->
<!-- ... -->
<div style="padding: 20px 100px">
<a-steps :current="current">
<a-step :key="item.title" :title="item.title" v-for="item in steps" />
</a-steps>
</div>
<a-form-model :model="form" ref="form">
<!-- 发送给原邮箱号码验证码 -->
<div v-if="current===0">
<a-form-model-item label="选择验证方式">
<a-select style="width:300px" v-model="form.type">
<a-select-option
:key="item.Title"
:value="item.Value"
v-for="item in type"
>{{item.Title}}</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="验证码">
<a-input
placeholder="请输入六位验证码"
style="width: 185px; margin-right: 15px"
v-model="form.orgcode"
></a-input>
<a-button :loading="codeLoading" @click="sendcode()" v-if="sendOrNo">发送验证码</a-button>
<a-button disabled v-else>{{ countdown }}秒后重送</a-button>
</a-form-model-item>
</div>
<!-- 发送给绑定新邮箱号码-->
<div v-if="current===1">
<a-form-model-item label="新手机号码">
<a-input placeholder="请输入手机号码" style="width:300px" v-model="form.target"></a-input>
</a-form-model-item>
<a-form-model-item label="验证码">
<a-input
placeholder="请输入六位验证码"
style="width: 185px; margin-right: 15px"
v-model="form.code"
></a-input>
<a-button :loading="codeLoading" @click="sendcode()" v-if="sendOrNo">发送验证码</a-button>
<a-button disabled v-else>{{ countdown }}秒后重送</a-button>
</a-form-model-item>
</div>
</a-form-model>
<br />
<div class="steps-action" style="text-align:center">
<a-button :disabled="checkfirst" @click="next" type="primary" v-if="current == 0">下一步</a-button>
<a-button
:disabled="checkform"
:loading="completeLoading"
@click="complete"
type="primary"
v-if="current == 1"
>完成</a-button>
<a-button @click="prev" style="margin-left: 8px" v-if="current > 0">前一步</a-button>
</div>
<br />
</div>
<div class="yo-form-group" v-else>
<!-- 表单控件 -->
<!-- ... -->
<a-form-model :model="form" ref="form">
<a-form-model-item label="请输入手机号码">
<a-input placeholder="请输入手机号码" style="width:250px;" v-model="form.target"></a-input>
</a-form-model-item>
<a-form-model-item label="验证码">
<a-input
placeholder="请输入验证码"
style="width:140px;margin-right:15px"
v-model="form.code"
></a-input>
<a-button @click="sendcode()" v-if="sendOrNo">发送验证码</a-button>
<a-button disabled v-else>{{ countdown }}秒后重送</a-button>
</a-form-model-item>
</a-form-model>
<br />
<div style="text-align:center">
<a-button :disabled="checkform" @click="complete" type="primary">绑定</a-button>
</div>
<br />
</div>
</div>
</a-spin>
</a-modal>
</template>
<script>
/* 表单内容默认值 */
const defaultForm = {
target: '',
code: '',
type: null,
orgcode: '',
/* ... */
};
import app from '@/main';
import { COUNT_DWON_KEY } from '@/common/storage';
export default {
data() {
return {
/** 表单数据 */
form: {},
/** 验证格式 */
rules: {
/* ... */
},
current: 0,
steps: [
{
title: '验证',
},
{
title: '绑定',
},
],
/** 加载异步数据状态 */
loading: false,
countdown: 0,
type: [],
sendOrNo: true,
codeLoading: false,
completeLoading: false,
visible: false,
checkform: true,
checkfirst: true,
/** 其他成员属性 */
/* ... */
};
},
methods: {
/**
* 必要的方法
* 在打开编辑页时允许填充数据
*/
onFillData(params) {
/** 将默认数据覆盖到form */
this.form = this.$_.cloneDeep({
...defaultForm,
//...params.record,
/** 在此处添加其他默认数据转换 */
/* ... */
});
if (this.type.length != 0) {
this.form.type = this.type[0].Value;
}
},
/**
* 必要方法
* 验证表单并获取表单数据
*/
// onGetData() {
// return new Promise((reslove, reject) => {
// this.$refs.form.validate((valid) => {
// if (valid) {
// const record = this.$_.cloneDeep(this.form);
// /** 验证通过后可以对数据进行转换得到想要提交的格式 */
// /* ... */
// reslove(record);
// } else {
// reject();
// }
// });
// });
// },
/**
* 必要的方法
* 在外部窗口进行保存时调用表单验证
*/
// onValidate(callback) {
// this.$refs.form.validate(callback);
// },
/**
* 必要的方法
* 在外部窗口关闭或重置时对表单验证进行初始化
*/
onResetFields() {
setTimeout(() => {
this.$refs.form.resetFields();
this.current = 0;
this.visible = false;
window.localStorage.removeItem(COUNT_DWON_KEY);
/** 在这里可以初始化当前组件中其他属性 */
/* ... */
}, 300);
},
/**
* 必要方法
* 加载当前表单中所需要的异步数据
*/
async onInit(params) {
this.loading = true;
this.type = [];
/** 可以在这里await获取一些异步数据 */
const info = this.$root.global.info;
info.phone &&
this.type.push({
Title: '使用手机号' + info.phone + '进行验证',
Value: 1,
});
info.email &&
this.type.push({
Title: '使用邮箱' + info.email + '进行验证',
Value: 2,
});
this.onFillData();
this.showcountdown();
/* ... */
this.loading = false;
},
/** 当前组件的其他方法 */
/* ... */
SendOrgSms() {
this.$api.SendOrgSms().then((res) => {
if (res) {
this.addTime();
this.showcountdown();
}
});
},
/**
* 将倒计时添加入到本地
*/
addTime() {
const now = Date.now();
var date = now + 60 * 1000 + 500;
window.localStorage.setItem(COUNT_DWON_KEY, date);
},
/**
* 下一步
*/
next() {
this.loading = true;
this.$api
.CheckBindcode(this.form)
.then((res) => {
if (res.data) {
window.localStorage.removeItem(COUNT_DWON_KEY);
this.form.type = null;
this.current++;
}
})
.finally(() => {
this.loading = false;
});
},
/**
* 完成
*/
complete() {
this.completeLoading = true;
this.$api
.CheckBindcode(this.form)
.then((res) => {
if (res.data) {
window.localStorage.removeItem(COUNT_DWON_KEY);
var num = this.form.target;
num = num.replace(/^(\d{3})\d{3}(\d+)/, '$1****$2');
app.$set(app.global.info, 'phone', num);
this.$message.success('改绑完成');
this.onResetFields();
this.$emit('ok', 100, 100);
}
})
.finally(() => {
this.completeLoading = false;
});
},
/**
* 发送验证码
*/
sendcode() {
this.codeLoading = true;
var reg = /^((13[0-9])|(14[5,7])|(15[^4,\\D])|(17[0,1,3,6-8])|(18[0-9])|(19[8,9])|(166))[0-9]{8}$/;
if (!reg.test(this.form.target) && this.form.type != '1' && this.form.type != '2') {
this.$message.warning('请输入正确的手机号');
this.codeLoading = false;
return;
}
this.$api
.SendCode(this.form)
.then((res) => {
if (res.success) {
this.addTime();
this.showcountdown();
}
})
.finally(() => {
this.codeLoading = false;
});
},
//打开弹窗
OnOpen() {
this.onInit();
this.visible = true;
},
/**
* 向前异步
*/
prev() {
window.localStorage.removeItem(COUNT_DWON_KEY);
this.form = {
target: '',
code: '',
type: this.type[0].Value,
orgcode: '',
};
this.current--;
},
/**
* 显示倒计时
*/
showcountdown() {
let _this = this;
var Furdate = window.localStorage.getItem(COUNT_DWON_KEY);
var nowdate = new Date().getTime();
if (Furdate >= nowdate) {
this.sendOrNo = false;
this.countdown = parseInt((Furdate - nowdate) / 1000);
setTimeout(() => {
_this.showcountdown();
}, 1000);
} else {
this.sendOrNo = true;
}
},
},
watch: {
form: {
deep: true,
handler: function (newVal, oldVal) {
this.checkform = !(newVal.target != '' && newVal.code != '');
this.checkfirst = !(newVal.orgcode != '');
},
},
},
};
</script>