魔方APP项目-05-注册功能实现,手机号唯一验证接口、客户端进行手机号验证、保存用户注册信息接口、客户端用户进行注册、使用云通讯发送短信,服务端实现发送短信验证码的api接口、客户端实现点击发送短信

用户模块

注册功能实现

1.手机号码唯一验证接口

在开发中,针对客户端提交的数据进行验证或提供模型数据转换格式成字典给客户端。可以使用Marshmallow模块来进行。

为了方便导包,所以我们设置当前language作为导包路径进行使用.
application.__init__.py代码:

import sys
...
def init_app(config_path):
    """全局初始化"""
    # 创建app应用对象
    app = Flask(__name__)
    # 项目根目录
    app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 加载导包路径
    sys.path.insert(0, os.path.join(app.BASE_DIR, 'application/utils/language'))
...

避免Pycharm飘红:
选择 language右键,点击 Make Directory asSources Root即可设置。

状态文件和服务端提示信息文件,
application.utils.language.message.代码:

class ErrorMessage():
    ok = 'ok'
    mobile_format_error = "手机号码格式有误!"
    mobile_is_use = "对不起,当前手机已经被注册!"

application.utils.language.status代码:

class APIStatus():
    CODE_OK = 1000  # 接口操作成功
    CODE_VALIDATE_ERROR = 1001  # 验证有误!

application.apps.users.marshmallow,代码:


from marshmallow import Schema, fields, validate, validates, ValidationError
from message import ErrorMessage as Message
from .models import User

class MobileSchema(Schema):
    mobile = fields.String(required=True, validate=validate.Regexp('^1[3-9]\d{9}$', error=Message.mobile_format_error))
    
    @validates('mobile')
    def validates_mobile(self, data):
        user = User.query.filter(User.mobile == data).first()
        if user is not None:
            raise ValidationError(message=Message.mobile_is_use)
        return data

application.apps.users.views,代码:


from application import jsonrpc, db
from .marshmallow import MobileSchema
from status import APIStatus as status
from message import ErrorMessage as Message
from marshmallow import ValidationError

@jsonrpc.method('User.mobile')
def mobile(mobile):
    """验证手机号码是否已经注册"""
    ms = MobileSchema()
    try:
        ms.load({'mobile': mobile})
        ret = {'errno': status.CODE_OK, 'errmsg': Message.ok}
    except ValidationError as e:
        ret = {'errno': status.CODE_VALIDATE_ERROR, 'errmsg': e.messages['mobile'][0]}
    return ret

@jsonrpc.method('User.register')
def register():
    """用户信息注册"""
    pass
    

postman测试接口:

2.客户端进行手机号验证

mfdemo
mfdemo/html/register.html

<!DOCTYPE html>
<html>
<head>
	<title>注册</title>
	<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
	<meta charset="utf-8">
	<link rel="stylesheet" href="../static/css/main.css">
	<script src="../static/js/vue.js"></script>
	<script src="../static/js/axios.js"></script>
	<script src="../static/js/main.js"></script>
</head>
<body>
	<div class="app" id="app">
    <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
    <div class="bg">
			<img src="../static/images/bg0.jpg">
		</div>
		<div class="form">
			<div class="form-title">
				<img src="../static/images/register.png">
				<img class="back" @click="back" src="../static/images/back.png">
			</div>
			<div class="form-data">
				<div class="form-data-bg">
					<img src="../static/images/bg1.png">
				</div>
				<div class="form-item">
					<label class="text">手机</label>
					<input type="text" v-model="mobile" @change='check_mobile' placeholder="请输入手机号">
				</div>
				<div class="form-item">
					<label class="text">验证码</label>
					<input type="text" class="code" name="code" placeholder="请输入验证码">
					<img class="refresh" src="../static/images/refresh.png">
				</div>
				<div class="form-item">
					<label class="text">密码</label>
					<input type="password" name="password" placeholder="请输入密码">
				</div>
				<div class="form-item">
					<label class="text">确认密码</label>
					<input type="password" name="password2" placeholder="请再次输入密码">
				</div>
				<div class="form-item">
					<input type="checkbox" class="agree" name="agree" checked>
					<label><span class="agree_text">同意磨方《用户协议》和《隐私协议》</span></label>
				</div>
				<div class="form-item">
					<img class="commit" @click="game.play_music('../static/mp3/btn1.mp3')" src="../static/images/commit.png"/>
				</div>
			</div>
		</div>
	</div>
	<script>
	apiready = function(){
		var game = new Game("../static/mp3/bg1.mp3");
		Vue.prototype.game = game;
		// 初始化axios
		axios.defaults.baseURL = 'http://192.168.20.158:5000/api'  // 服务端api接口网关地址
		axios.defaults.timeout = 2500;  // 请求超时时间
		axios.defaults.withCredentials = false;  // 跨域请求资源的情况下,忽略cookie的发送
		Vue.prototype.axios = axios;
		new Vue({
			el:"#app",
			data(){
				return {
					mobile: "",
          music_play:true,
					prev:{name:"",url:"",params:{}},
					current:{name:"register",url:"register.html","params":{}},
				}
			},
			watch:{
        music_play(){
          if(this.music_play){
            this.game.play_music("../static/mp3/bg1.mp3");
          }else{
            this.game.stop_music();
          }
        }
      },
			methods:{
				check_mobile(){
					// 验证手机号码
					this.axios.post("", {
						'jsonrpc': '2.0',
						'id': 1,
						'method': 'User.mobile',
						'params': {'mobile': this.mobile}
					}).then(response=>{
						this.game.print(response.data.result);
						if(response.data.result.errno != 1000){
							api.alert({
							    title: '错误提示',
							    msg: 'response.data.result.errmsg',
							});
							
						}
					}).catch(error=>{
						this.game.print(error.response.data.error);
					});
				},
				back(){
          // this.game.outWin();
          // this.game.outFrame();
          this.game.goGroup('user', 0);

				}
			}
		})
	}
	</script>
</body>
</html>

在客户单请求过程中, 我们需要设置id作为唯一标识, 同时, 将来在客户端项目中多个页面都会继续使用到上面的初始化代码,所以我们一并抽取这部分代码到另一个static/js/settings.js文件中.

function init(){
  var game = new Game("../static/mp3/bg1.mp3");
  Vue.prototype.game = game;
  // 初始化axios
  axios.defaults.baseURL = 'http://192.168.20.158:5000/api'  // 服务端api接口网关地址
  axios.defaults.timeout = 2500;  // 请求超时时间
  axios.defaults.withCredentials = false;  // 跨域请求资源的情况下,忽略cookie的发送
  Vue.prototype.axios = axios;
  Vue.prototype.uuid = UUID.generate;
}

注册页面调用init函数进行初始化.
mfdemo/html/register.html

<!DOCTYPE html>
<html>
<head>
	<title>注册</title>
	<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
	<meta charset="utf-8">
	<link rel="stylesheet" href="../static/css/main.css">
	<script src="../static/js/vue.js"></script>
	<script src="../static/js/axios.js"></script>
	<script src="../static/js/main.js"></script>
</head>
<body>
	<div class="app" id="app">
    <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
    <div class="bg">
			<img src="../static/images/bg0.jpg">
		</div>
		<div class="form">
			<div class="form-title">
				<img src="../static/images/register.png">
				<img class="back" @click="back" src="../static/images/back.png">
			</div>
			<div class="form-data">
				<div class="form-data-bg">
					<img src="../static/images/bg1.png">
				</div>
				<div class="form-item">
					<label class="text">手机</label>
					<input type="text" v-model="mobile" @change='check_mobile' placeholder="请输入手机号">
				</div>
				<div class="form-item">
					<label class="text">验证码</label>
					<input type="text" class="code" name="code" placeholder="请输入验证码">
					<img class="refresh" src="../static/images/refresh.png">
				</div>
				<div class="form-item">
					<label class="text">密码</label>
					<input type="password" name="password" placeholder="请输入密码">
				</div>
				<div class="form-item">
					<label class="text">确认密码</label>
					<input type="password" name="password2" placeholder="请再次输入密码">
				</div>
				<div class="form-item">
					<input type="checkbox" class="agree" name="agree" checked>
					<label><span class="agree_text">同意磨方《用户协议》和《隐私协议》</span></label>
				</div>
				<div class="form-item">
					<img class="commit" @click="game.play_music('../static/mp3/btn1.mp3')" src="../static/images/commit.png"/>
				</div>
			</div>
		</div>
	</div>
	<script src='../static/js/uuid.js'></script>
	<script src='../static/js/settings.js'></script>
	<script>
	apiready = function(){
		init();
		new Vue({
			el:"#app",
			data(){
				return {
					mobile: "",
          music_play:true,
					prev:{name:"",url:"",params:{}},
					current:{name:"register",url:"register.html","params":{}},
				}
			},
			watch:{
        music_play(){
          if(this.music_play){
            this.game.play_music("../static/mp3/bg1.mp3");
          }else{
            this.game.stop_music();
          }
        }
      },
			methods:{
				check_mobile(){
					// 验证手机号码
					this.axios.post("", {
						'jsonrpc': '2.0',
						'id': this.uuid(),
						'method': 'User.mobile',
						'params': {'mobile': this.mobile}
					}).then(response=>{
						this.game.print(response.data.result);
						if(response.data.result.errno != 1000){
							api.alert({
							    title: '错误提示',
							    msg: response.data.result.errmsg,
							});

						}
					}).catch(error=>{
						this.game.print(error.response.data.error);
					});
				},
				back(){
          // this.game.outWin();
          // this.game.outFrame();
          this.game.goGroup('user', 0);

				}
			}
		})
	}
	</script>
</body>
</html>

3.保存用户注册信息接口

创建Marshmallow构造器[暂时不涉及到手机验证码功能]
application.utils.language.message.py,代码:


class ErrorMessage():
    ok = 'ok'
    mobile_format_error = "手机号码格式有误!"
    mobile_is_use = "对不起,当前手机已经被注册!"
    username_is_use = "对不起,当前用户名已经被使用!"
    password_not_match = "密码和验证密码不匹配!"
    

marshmallow.py


from marshmallow import Schema, fields, validate, validates, ValidationError
from message import ErrorMessage as Message
from .models import User, db

class MobileSchema(Schema):
    mobile = fields.String(required=True, validate=validate.Regexp('^1[3-9]\d{9}$', error=Message.mobile_format_error))

    @validates('mobile')
    def validates_mobile(self, data):
        user = User.query.filter(User.mobile == data).first()
        if user is not None:
            raise ValidationError(message=Message.mobile_is_use)
        return data
    
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema, auto_field
from marshmallow import post_load, pre_load, validates_schema

class UserSchema(SQLAlchemyAutoSchema):
    mobile = auto_field(required=True, load_only=True)
    password = fields.String(required=True, load_only=True)
    password2 = fields.String(required=True, load_only=True)
    sms_code = fields.String(required=True, load_only=True)

    class Meta:
        model = User
        include_fk = True  # 启用外键关系
        include_relationships = True  # 模型关系外部属性
        fields = ['id', 'name', 'mobile', 'password', 'password2', 'sms_code']  # 如果要全换全部字段,就不要声明fields或exclude字段即可
        sql_session = db.session
        
        @post_load()
        def save_object(self, data, **kwargs):
            data.pop('password2')
            data.pop('sms_code')
            data['name'] = data['mobile']
            instance = User(**data)
            db.session.add(instance)
            db.session.commit()
            return instance
        
        @validates_schema
        def validate(self, data, **kwargs):
            # 校验密码和确认密码
            if data['password'] != data['password2']:
                raise ValidationError(message=Message.password_not_match, field_name='password')
            
            
            # todo 校验短信验证码
            
            return data
            

视图代码:
application.apps.users.views.py,代码:


from application import jsonrpc, db
from .marshmallow import MobileSchema, UserSchema
from status import APIStatus as status
from message import ErrorMessage as Message
from marshmallow import ValidationError

@jsonrpc.method('User.mobile')
def mobile(mobile):
    """验证手机号码是否已经注册"""
    ms = MobileSchema()
    try:
        ms.load({'mobile': mobile})
        ret = {'errno': status.CODE_OK, 'errmsg': Message.ok}
    except ValidationError as e:
        ret = {'errno': status.CODE_VALIDATE_ERROR, 'errmsg': e.messages['mobile'][0]}
    return ret

@jsonrpc.method('User.register')
def register(mobile, password, password2, sms_code):
    """用户信息注册"""
    
    try:
        ms = MobileSchema()
        ms.load({'mobile': mobile})
        
        us = UserSchema()
        user = us.load({
            'mobile': mobile,
            'password': password,
            'password2': password2,
            'sms_code': sms_code
        })
        data = {'errno': status.CODE_OK, 'errmsg': us.dump(user)}
    except ValidationError as e:
        data = {'errno': status.CODE_VALIDATE_ERROR, 'errmsg': e.messages}
    
    return data

4.客户端发送用户进行注册

mfdemo.html/register.html,代码:

<!DOCTYPE html>
<html>
<head>
	<title>注册</title>
	<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
	<meta charset="utf-8">
	<link rel="stylesheet" href="../static/css/main.css">
	<script src="../static/js/vue.js"></script>
	<script src="../static/js/axios.js"></script>
	<script src="../static/js/main.js"></script>
</head>
<body>
	<div class="app" id="app">
    <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
    <div class="bg">
			<img src="../static/images/bg0.jpg">
		</div>
		<div class="form">
			<div class="form-title">
				<img src="../static/images/register.png">
				<img class="back" @click="back" src="../static/images/back.png">
			</div>
			<div class="form-data">
				<div class="form-data-bg">
					<img src="../static/images/bg1.png">
				</div>
				<div class="form-item">
					<label class="text">手机</label>
					<input type="text" v-model="mobile" @change='check_mobile' placeholder="请输入手机号">
				</div>
				<div class="form-item">
					<label class="text">验证码</label>
					<input type="text" class="code" v-model='sms_code' placeholder="请输入验证码">
					<img class="refresh" src="../static/images/refresh.png">
				</div>
				<div class="form-item">
					<label class="text">密码</label>
					<input type="password" v-model='password' placeholder="请输入密码">
				</div>
				<div class="form-item">
					<label class="text">确认密码</label>
					<input type="password" v-model='password2' placeholder="请再次输入密码">
				</div>
				<div class="form-item">
					<input type="checkbox" class="agree" v-model='agree' checked>
					<label><span class="agree_text">同意磨方《用户协议》和《隐私协议》</span></label>
				</div>
				<div class="form-item">
					<img class="commit" @click='registerHandle' src="../static/images/commit.png"/>
				</div>
			</div>
		</div>
	</div>
	<script src='../static/js/uuid.js'></script>
	<script src='../static/js/settings.js'></script>
	<script>
	apiready = function(){
		init();
		new Vue({
			el:"#app",
			data(){
				return {
					mobile: "",
					password: "",
					password2: "",
					sms_code: "",
					agree: false,
          music_play:true,
					prev:{name:"",url:"",params:{}},
					current:{name:"register",url:"register.html","params":{}},
				}
			},
			watch:{
        music_play(){
          if(this.music_play){
            this.game.play_music("../static/mp3/bg1.mp3");
          }else{
            this.game.stop_music();
          }
        }
      },
			methods:{
				registerHandle(){
					// 注册处理
					this.game.play_music('../static/mp3/btn1.mp3');
					// 验证数据[双向验证]
					if (!/1[3-9]\d{9}/.test(this.mobile)) {
						api.alert({
						    title: '警告',
						    msg: '手机号码格式不正确!',
						});
						return;  // 阻止代码继续往下执行
					}
					if (this.password.length<3 || this.password.length>16){
						api.alert({
						    title: '警告',
						    msg: '密码长度必须在3-16个字符之间!',
						});
						return;
					}
					if (this.password != this.password2) {
						api.alert({
						    title: '警告',
						    msg: '密码和确认密码不匹配!',
						});
						return;
					}
					if (this.sms_code.length<1) {
						api.alert({
								title: '警告',
								msg: '验证码不能为空!',
						});
						return;
					}
					if (this.agree === false) {
						api.alert({
								title: '警告',
								msg: '对不起, 必须同意磨方的用户协议和隐私协议才能继续注册!',
						});
						return;
					}
					this.axios.post('',{
						'jsonrpc': '2.0',
						'id': this.uuid(),
						'method': 'User.register',
						'params': {
							'mobile': this.mobile,
							'sms_code': this.sms_code,
							'password': this.password,
							'password2': this.password2,
						}
					}).then(response=>{
						this.game.print(response.data.result);
						if (response.data.result.errno != 1000) {
							api.alert({
									title: '错误提示',
									msg: response.data.result.errmsg,
							});
						}else {
							// 注册成功!
							api.confirm({
							    title: '磨方提示',
							    msg: '注册成功',
							    buttons: ['返回首页', '个人中心']
							}, (ret, err)=>{
							    if(ret.buttonIndex == 1){
										// 跳转到首页 
										this.game.outGroup('user');
							    }else{
										// 跳转到个人中心
										this.game.goGroup('user', 2)   
							    }
							});
							
						}
					}).catch(error=>{
						this.game.print(console.error(.response.data.error);
					});
						
				},
				check_mobile(){
					// 验证手机号码
					this.axios.post("", {
						'jsonrpc': '2.0',
						'id': this.uuid(),
						'method': 'User.mobile',
						'params': {'mobile': this.mobile}
					}).then(response=>{
						this.game.print(response.data.result);
						if(response.data.result.errno != 1000){
							api.alert({
							    title: '错误提示',
							    msg: response.data.result.errmsg,
							});

						}
					}).catch(error=>{
						this.game.print(error.response.data.error);
					});
				},
				back(){
          // this.game.outWin();
          // this.game.outFrame();
          this.game.goGroup('user', 0);

				}
			}
		})
	}
	</script>
</body>
</html>

html/index.html,frames帧页面组中新增用户中心页面的user.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>首页</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta name="format-detection" content="telephone=no,email=no,date=no,address=no">
  <link rel="stylesheet" href="../static/css/main.css">
	<script src="../static/js/vue.js"></script>
	<script src="../static/js/main.js"></script>
</head>
<body>
  <div class="app" id="app">
    <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
    <div class="bg">
      <img src="../static/images/bg0.jpg">
    </div>
    <ul>
      <li><img class="module1" src="../static/images/image1.png"></li>
      <li><img class="module2" @click="gohome" src="../static/images/image2.png"></li>
      <li><img class="module3" src="../static/images/image3.png"></li>
      <li><img class="module4" src="../static/images/image4.png"></li>
    </ul>
  </div>
  <script>
	apiready = function(){
		var game = new Game("../static/mp3/bg1.mp3");
		// 允许ajax发送请求时附带cookie,设置为不允许
		Vue.prototype.game = game;
		new Vue({
			el:"#app",
			data(){
				return {
          music_play:true,  // 默认播放背景音乐
					prev:{name:"",url:"",params:{}}, // 上一页状态
					current:{name:"index",url:"index.html","params":{}}, // 下一页状态
          frames: [{
            name: 'login',
            url: './login.html',
          },{
            name: 'register',
            url: './register.html',
          },{
            name: 'user',
            url: './user.html',
          }]

        }
			},
      watch:{
        music_play(){
          if(this.music_play){
            this.game.play_music("../static/mp3/bg1.mp3");
          }else{
            this.game.stop_music();
          }
        }
      },
      created(){

      },
			methods:{
        gohome(){
          this.game.openGroup('user', this.frames, frames.length);
        }

			}
		})
	}
	</script>
</body>
</html>

5.使用云通讯发送短信

官方文档:https://www.yuntongxun.com/member/main

在登录后的平台上面获取一下信息:

ACCOUNT SID:
AUTH TOKEN : 
AppID(默认):
Rest URL(短信服务器): app.cloopen.com:8883

在开发过程中,把自己的或者同事的手机加入到测试号码中.
安装sdk

pip install ronglian_sms_sdk
①服务端实现发送短信验证码的api接口

application.settings.dev,配置文件中填写短信接口相关配置,代码:

    # 短信相关配置
    SMS_ACCOUNT_ID = "8aaf0708754a3ef2017563ddb22d0773"  # 接口主账号
    SMS_ACCOUNT_TOKEN = "0b41612bc8a8429d84b5d37f29178743"  # 认证token令牌
    SMS_APP_ID = "8aaf0708754a3ef2017563ddb3110779"  # 应用ID
    SMS_TEMPLATE_ID = 1  # 短信模板ID
    SMS_EXPIRE_TIME = 60 * 5  # 短信有效时间,单位:秒/s
    SMS_INTERVAL_TIME = 60  # 短信发送冷却时间,单位:秒/s

短信属于公共业务,所以把功能接口写在Home蓝图下。
application.utils.language.message.py,代码:


class ErrorMessage():
    ok = 'ok'
    mobile_format_error = "手机号码格式有误!"
    mobile_is_use = "对不起,当前手机已经被注册!"
    username_is_use = "对不起,当前用户名已经被使用!"
    password_not_match = "密码和验证密码不匹配!"
    sms_send_error = "短信发送失败!"
    sms_interval_time = "短信发送冷却中!"

application.utils.language.status.py,代码:


class APIStatus():
    CODE_OK = 1000  # 接口操作成功
    CODE_VALIDATE_ERROR = 1001  # 验证有误!
    CODE_SMS_ERROR = 1002  # 短信功能执行失败
    CODE_INTERVAL_TIME = 1003  # 短信发送冷却中

application.apps.home.views,代码:


from application import jsonrpc
import re, random, json
from status import APIStatus as status
from message import ErrorMessage as message
from ronglian_sms_sdk import SmsSDK
from flask import current_app
from application import redis

@jsonrpc.method(name='Home.sms')
def sms(mobile):
    """发送短信验证码"""
    # 验证手机
    if not re.match('^1[3-9]\d{9}$', mobile):
        return {'errno': status.CODE_VALIDATE_ERROR, 'errmsg': message.mobile_format_error}

    # 短信发送冷却时间
    ret = redis.get('int_%s' % mobile)
    if ret is not None:
        return {'errno': status.CODE_INTERVAL_TIME, 'errmsg': message.sms_interval_time}

    # 生成验证码
    sms_code = '%06d' % random.randint(0, 999999)
    # 发送短信
    sdk = SmsSDK(
        current_app.config.get('SMS_ACCOUNT_ID'),
        current_app.config.get('SMS_ACCOUNT_TOKEN'),
        current_app.config.get('SMS_APP_ID')
    )
    ret = sdk.sendMessage(
        current_app.config.get('SMS_TEMPLATE_ID'),
        mobile,
        (sms_code, current_app.config.get('SMS_EXPIRE_TIME') // 60)
    )
    result = json.loads(ret)
    if result['statusCode'] == '000000':
        pipe = redis.pipeline()
        pipe.multi()  # 开启事务
        # 保存短信记录到redis中
        pipe.setex('sms_%s' % mobile, current_app.config.get('SMS_EXPIRE_TIME'), sms_code)
        # 进行冷却倒计时
        pipe.setex('int_%s' % mobile, current_app.config.get('SMS_INTERVAL_TIME'), '_')
        pipe.execute()  # 提交事务
        # 返回结果
        return {'errno': status.CODE_OK, 'errmsg': message.ok}
    else:
        return {'errno': status.CODE_SMS_ERROR, 'errmsg': message.sms_send_error}

postman测试:

②客户端实现点击发送短信

mfdemo/html/register.html

<!DOCTYPE html>
<html>
<head>
	<title>注册</title>
	<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
	<meta charset="utf-8">
	<link rel="stylesheet" href="../static/css/main.css">
	<script src="../static/js/vue.js"></script>
	<script src="../static/js/axios.js"></script>
	<script src="../static/js/main.js"></script>
</head>
<body>
	<div class="app" id="app">
    <img class="music" :class="music_play?'music2':''" @click="music_play=!music_play" src="../static/images/player.png">
    <div class="bg">
			<img src="../static/images/bg0.jpg">
		</div>
		<div class="form">
			<div class="form-title">
				<img src="../static/images/register.png">
				<img class="back" @click="back" src="../static/images/back.png">
			</div>
			<div class="form-data">
				<div class="form-data-bg">
					<img src="../static/images/bg1.png">
				</div>
				<div class="form-item">
					<label class="text">手机</label>
					<input type="text" v-model="mobile" @change='check_mobile' placeholder="请输入手机号">
				</div>
				<div class="form-item">
					<label class="text">验证码</label>
					<input type="text" class="code" v-model='sms_code' placeholder="请输入验证码">
					<img class="refresh" @click='send' src="../static/images/refresh.png">
				</div>
				<div class="form-item">
					<label class="text">密码</label>
					<input type="password" v-model='password' placeholder="请输入密码">
				</div>
				<div class="form-item">
					<label class="text">确认密码</label>
					<input type="password" v-model='password2' placeholder="请再次输入密码">
				</div>
				<div class="form-item">
					<input type="checkbox" class="agree" v-model='agree' checked>
					<label><span class="agree_text">同意磨方《用户协议》和《隐私协议》</span></label>
				</div>
				<div class="form-item">
					<img class="commit" @click='registerHandle' src="../static/images/commit.png"/>
				</div>
			</div>
		</div>
	</div>
	<script src='../static/js/uuid.js'></script>
	<script src='../static/js/settings.js'></script>
	<script>
	apiready = function(){
		init();
		new Vue({
			el:"#app",
			data(){
				return {
					is_send: false,
					send_interval: 60,  // 短信发送冷却时间
					mobile: "",
					password: "",
					password2: "",
					sms_code: "",
					agree: false,
          music_play:true,
					prev:{name:"",url:"",params:{}},
					current:{name:"register",url:"register.html","params":{}},
				}
			},
			watch:{
        music_play(){
          if(this.music_play){
            this.game.play_music("../static/mp3/bg1.mp3");
          }else{
            this.game.stop_music();
          }
        }
      },
			methods:{
				send(){
					// 点击发送短信
					if (!/1[3-9]\d{9}/,test(this.mobile)) {
						api.alert({
								title: '警告',
								msg: '手机号码格式不正确!',
						});
						return;  // 阻止代码继续往下执行
				}
				if (this.is_send) {
					api.alert({
							title: '警告',
							msg: `短信发送冷却中,请${this.send_interval}秒之后重新点击发送!`,
					});
					return; 
				}
				this.axios.post('',{
					'jsonrpc': '2.0',
					'id': this.uuid(),
					'method': 'Home.sms',
					'params': {
						'mobile': this.mobile,
					}
				}).then(response=>{
					if (response.data.result.errno != 1000) {
						api.alert({
								title: '错误提示',
								msg: response.data.result.errmsg,
						});
					}else {
						this.is_send = true;  // 进入冷却状态
						this.send_interval = 60;
						var timer = setInterval(()=>{
							this.send_interval--;
							if (this.send_interval<1) {
								clearInterval(timer);
								this.is_send = false;  // 退出冷却状态
							}
						}, 1000);
					}
				}).catch(error=>{
					this.game.print(error.response.data.error);
				});
			},
				registerHandle(){
					// 注册处理
					this.game.play_music('../static/mp3/btn1.mp3');
					// 验证数据[双向验证]
					if (!/1[3-9]\d{9}/.test(this.mobile)) {
						api.alert({
						    title: '警告',
						    msg: '手机号码格式不正确!',
						});
						return;  // 阻止代码继续往下执行
					}
					if (this.password.length<3 || this.password.length>16){
						api.alert({
						    title: '警告',
						    msg: '密码长度必须在3-16个字符之间!',
						});
						return;
					}
					if (this.password != this.password2) {
						api.alert({
						    title: '警告',
						    msg: '密码和确认密码不匹配!',
						});
						return;
					}
					if (this.sms_code.length<1) {
						api.alert({
								title: '警告',
								msg: '验证码不能为空!',
						});
						return;
					}
					if (this.agree === false) {
						api.alert({
								title: '警告',
								msg: '对不起, 必须同意磨方的用户协议和隐私协议才能继续注册!',
						});
						return;
					}
					this.axios.post('',{
						'jsonrpc': '2.0',
						'id': this.uuid(),
						'method': 'User.register',
						'params': {
							'mobile': this.mobile,
							'sms_code': this.sms_code,
							'password': this.password,
							'password2': this.password2,
						}
					}).then(response=>{
						this.game.print(response.data.result);
						if (response.data.result.errno != 1000) {
							api.alert({
									title: '错误提示',
									msg: response.data.result.errmsg,
							});
						}else {
							// 注册成功!
							api.confirm({
							    title: '磨方提示',
							    msg: '注册成功',
							    buttons: ['返回首页', '个人中心']
							}, (ret, err)=>{
							    if(ret.buttonIndex == 1){
										// 跳转到首页
										this.game.outGroup('user');
							    }else{
										// 跳转到个人中心
										this.game.goGroup('user', 2)
							    }
							});

						}
					}).catch(error=>{
						this.game.print(error.response.data.error);
					});

				},
				check_mobile(){
					// 验证手机号码
					this.axios.post("", {
						'jsonrpc': '2.0',
						'id': this.uuid(),
						'method': 'User.mobile',
						'params': {'mobile': this.mobile}
					}).then(response=>{
						this.game.print(response.data.result);
						if(response.data.result.errno != 1000){
							api.alert({
							    title: '错误提示',
							    msg: response.data.result.errmsg,
							});

						}
					}).catch(error=>{
						this.game.print(error.response.data.error);
					});
				},
				back(){
          // this.game.outWin();
          // this.game.outFrame();
          this.game.goGroup('user', 0);

				}
			}
		})
	}
	</script>
</body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值