一.昨日回顾
1 git操作
2 git add .
3 git commit -m "注释"
4 fetch和pull
-git fetch 相当于是从远程获取最新到本地,不会自动merge
-git pull 相当于从远程获取最新版本并merge到本地
-在实际应用中,git fetch更安全一些
5 变基:优化分支日志
6 ssh和https连接方式:公司常用(gitlab),领导会问你要一个公钥,给你一个地址
7 连接远程分支
git add .
git commit -m '详细写'
git pull origin dev/master
有冲突解决冲突,没有冲突直接提交
git push origin dev(确认好自己在哪个分支上)
8 冲突出现原因
-多个人开发同一分支
-不同分支合并
二.今日内容
1.登录注册前端页面
1.1Login.vue
< template>
< div class = " login" >
< div class = " box" >
< i class = " el-icon-close" @click = " close_login" > </ i>
< div class = " content" >
< div class = " nav" >
< span :class = " {active: login_method === ' is_pwd' }"
@click = " change_login_method(' is_pwd' )" > 密码登录</ span>
< span :class = " {active: login_method === ' is_sms' }"
@click = " change_login_method(' is_sms' )" > 短信登录</ span>
</ div>
< el-form v-if = " login_method === ' is_pwd' " >
< el-input
placeholder = " 用户名/手机号/邮箱"
prefix-icon = " el-icon-user"
v-model = " username"
clearable >
</ el-input>
< el-input
placeholder = " 密码"
prefix-icon = " el-icon-key"
v-model = " password"
clearable
show-password >
</ el-input>
< el-button type = " primary" @click = " login_pwd" > 登录</ el-button>
</ el-form>
< el-form v-if = " login_method === ' is_sms' " >
< el-input
placeholder = " 手机号"
prefix-icon = " el-icon-phone-outline"
v-model = " mobile"
clearable
@blur = " check_mobile" >
</ el-input>
< el-input
placeholder = " 验证码"
prefix-icon = " el-icon-chat-line-round"
v-model = " sms"
clearable >
< template slot = " append" >
< span class = " sms" @click = " send_sms" > {{ sms_interval }}</ span>
</ template>
</ el-input>
< el-button type = " primary" > 登录</ el-button>
</ el-form>
< div class = " foot" >
< span @click = " go_register" > 立即注册</ span>
</ div>
</ div>
</ div>
</ div>
</ template>
< script>
export default {
name: "Login" ,
data ( ) {
return {
username: '' ,
password: '' ,
mobile: '' ,
sms: '' ,
login_method: 'is_pwd' ,
sms_interval: '获取验证码' ,
is_send: false ,
}
} ,
methods: {
close_login ( ) {
this . $emit ( 'close' )
} ,
go_register ( ) {
this . $emit ( 'go' )
} ,
change_login_method ( method) {
this . login_method = method;
} ,
check_mobile ( ) {
if ( ! this . mobile) return ;
if ( ! this . mobile. match ( /^1[3-9][0-9]{9}$/ ) ) {
this . $message ( {
message: '手机号有误' ,
type: 'warning' ,
duration: 1000 ,
onClose: ( ) => {
this . mobile = '' ;
}
} ) ;
return false ;
}
this . is_send = true ;
} ,
send_sms ( ) {
if ( ! this . is_send) return ;
this . is_send = false ;
let sms_interval_time = 60 ;
this . sms_interval = "发送中..." ;
let timer = setInterval ( ( ) => {
if ( sms_interval_time <= 1 ) {
clearInterval ( timer) ;
this . sms_interval = "获取验证码" ;
this . is_send = true ;
} else {
sms_interval_time -= 1 ;
this . sms_interval = ` ${ sms_interval_time} 秒后再发` ;
}
} , 1000 ) ;
} ,
login_pwd ( ) {
this . $axios. post ( this . $settings. base_url + '/user/login/' , {
username: this . username,
password: this . password
} ) . then ( item => {
console. log ( item. data)
if ( item. data. status == 0 ) {
this . $cookies. set ( 'username' , item. data. username, '7d' )
this . $cookies. set ( 'token' , item. data. token, '7d' )
this . $cookies. set ( 'icon' , item. data. icon, '7d' )
this . $cookies. set ( 'id' , item. data. id, '7d' )
this . close_login ( )
} else {
this . $message ( {
message: item. data. msg,
type: 'error' ,
duration: 1000 ,
onClose: ( ) => {
this . password = '' ;
this . username = '' ;
}
} ) ;
}
} )
}
}
}
</ script>
< style scoped >
.login {
width : 100vw;
height : 100vh;
position : fixed;
top : 0;
left : 0;
z-index : 10;
background-color : rgba ( 0, 0, 0, 0.3) ;
}
.box {
width : 400px;
height : 420px;
background-color : white;
border-radius : 10px;
position : relative;
top : calc ( 50vh - 210px) ;
left : calc ( 50vw - 200px) ;
}
.el-icon-close {
position : absolute;
font-weight : bold;
font-size : 20px;
top : 10px;
right : 10px;
cursor : pointer;
}
.el-icon-close:hover {
color : darkred;
}
.content {
position : absolute;
top : 40px;
width : 280px;
left : 60px;
}
.nav {
font-size : 20px;
height : 38px;
border-bottom : 2px solid darkgrey;
}
.nav > span {
margin : 0 20px 0 35px;
color : darkgrey;
user-select : none;
cursor : pointer;
padding-bottom : 10px;
border-bottom : 2px solid darkgrey;
}
.nav > span.active {
color : black;
border-bottom : 3px solid black;
padding-bottom : 9px;
}
.el-input, .el-button {
margin-top : 40px;
}
.el-button {
width : 100%;
font-size : 18px;
}
.foot > span {
float : right;
margin-top : 20px;
color : orange;
cursor : pointer;
}
.sms {
color : orange;
cursor : pointer;
display : inline-block;
width : 70px;
text-align : center;
user-select : none;
}
</ style>
1.2Register.vue
< template>
< div class = " register" >
< div class = " box" >
< i class = " el-icon-close" @click = " close_register" > </ i>
< div class = " content" >
< div class = " nav" >
< span class = " active" > 新用户注册</ span>
</ div>
< el-form>
< el-input
placeholder = " 手机号"
prefix-icon = " el-icon-phone-outline"
v-model = " mobile"
clearable
@blur = " check_mobile" >
</ el-input>
< el-input
placeholder = " 密码"
prefix-icon = " el-icon-key"
v-model = " password"
clearable
show-password >
</ el-input>
< el-input
placeholder = " 验证码"
prefix-icon = " el-icon-chat-line-round"
v-model = " sms"
clearable >
< template slot = " append" >
< span class = " sms" @click = " send_sms" > {{ sms_interval }}</ span>
</ template>
</ el-input>
< el-button type = " primary" > 注册</ el-button>
</ el-form>
< div class = " foot" >
< span @click = " go_login" > 立即登录</ span>
</ div>
</ div>
</ div>
</ div>
</ template>
< script>
export default {
name: "Register" ,
data ( ) {
return {
mobile: '' ,
password: '' ,
sms: '' ,
sms_interval: '获取验证码' ,
is_send: false ,
}
} ,
methods: {
close_register ( ) {
this . $emit ( 'close' , false )
} ,
go_login ( ) {
this . $emit ( 'go' )
} ,
check_mobile ( ) {
if ( ! this . mobile) return ;
if ( ! this . mobile. match ( /^1[3-9][0-9]{9}$/ ) ) {
this . $message ( {
message: '手机号有误' ,
type: 'warning' ,
duration: 1000 ,
onClose: ( ) => {
this . mobile = '' ;
}
} ) ;
return false ;
}
this . is_send = true ;
} ,
send_sms ( ) {
if ( ! this . is_send) return ;
this . is_send = false ;
let sms_interval_time = 60 ;
this . sms_interval = "发送中..." ;
let timer = setInterval ( ( ) => {
if ( sms_interval_time <= 1 ) {
clearInterval ( timer) ;
this . sms_interval = "获取验证码" ;
this . is_send = true ;
} else {
sms_interval_time -= 1 ;
this . sms_interval = ` ${ sms_interval_time} 秒后再发` ;
}
} , 1000 ) ;
}
}
}
</ script>
< style scoped >
.register {
width : 100vw;
height : 100vh;
position : fixed;
top : 0;
left : 0;
z-index : 10;
background-color : rgba ( 0, 0, 0, 0.3) ;
}
.box {
width : 400px;
height : 480px;
background-color : white;
border-radius : 10px;
position : relative;
top : calc ( 50vh - 240px) ;
left : calc ( 50vw - 200px) ;
}
.el-icon-close {
position : absolute;
font-weight : bold;
font-size : 20px;
top : 10px;
right : 10px;
cursor : pointer;
}
.el-icon-close:hover {
color : darkred;
}
.content {
position : absolute;
top : 40px;
width : 280px;
left : 60px;
}
.nav {
font-size : 20px;
height : 38px;
border-bottom : 2px solid darkgrey;
}
.nav > span {
margin-left : 90px;
color : darkgrey;
user-select : none;
cursor : pointer;
padding-bottom : 10px;
border-bottom : 2px solid darkgrey;
}
.nav > span.active {
color : black;
border-bottom : 3px solid black;
padding-bottom : 9px;
}
.el-input, .el-button {
margin-top : 40px;
}
.el-button {
width : 100%;
font-size : 18px;
}
.foot > span {
float : right;
margin-top : 20px;
color : orange;
cursor : pointer;
}
.sms {
color : orange;
cursor : pointer;
display : inline-block;
width : 70px;
text-align : center;
user-select : none;
}
</ style>
1.3Header.vue
< template>
< div class = " header" >
< div class = " slogan" >
< p> 老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</ p>
</ div>
< div class = " nav" >
< ul class = " left-part" >
< li class = " logo" >
< router-link to = " /" >
< img src = " ../assets/img/head-logo.svg" alt = " " >
</ router-link>
</ li>
< li class = " ele" >
< span @click = " goPage(' /free-course' )" :class = " {active: url_path === ' /free-course' }" > 免费课</ span>
</ li>
< li class = " ele" >
< span @click = " goPage(' /actual-course' )" :class = " {active: url_path === ' /actual-course' }" > 实战课</ span>
</ li>
< li class = " ele" >
< span @click = " goPage(' /light-course' )" :class = " {active: url_path === ' /light-course' }" > 轻课</ span>
</ li>
</ ul>
< div class = " right-part" >
< div v-if = " username" >
< span> {{username}}</ span> |
< span @click = " logout" > 注销</ span>
</ div>
< div v-else >
< span @click = " put_login" > 登录</ span> |
< span @click = " put_register" > 注册</ span>
< Login v-if = " is_login" @close = " close_login" @go = " put_register" />
< Register v-if = " is_register" @close = " close_register" @go = " put_login" />
</ div>
</ div>
</ div>
</ div>
</ template>
< script>
import Login from "./Login" ;
import Register from "./Register" ;
export default {
name: "Header" ,
data ( ) {
return {
url_path: sessionStorage. url_path || '/' ,
is_login: false ,
is_register: false ,
username: '' ,
}
} ,
methods: {
goPage ( url_path) {
if ( this . url_path !== url_path) {
this . $router. push ( url_path) ;
}
sessionStorage. url_path = url_path;
} ,
put_login ( ) {
this . is_login = true ;
this . is_register = false ;
} ,
put_register ( ) {
this . is_login = false ;
this . is_register = true ;
} ,
close_login ( ) {
this . is_login = false ;
this . username = this . $cookies. get ( 'username' )
} ,
close_register ( ) {
this . is_register = false ;
} ,
logout ( ) {
this . $cookies. remove ( 'username' )
this . $cookies. remove ( 'token' )
this . $cookies. remove ( 'icon' )
this . $cookies. remove ( 'id' )
this . username = '' ;
}
} ,
created ( ) {
this . username = this . $cookies. get ( 'username' )
} ,
components: {
Login,
Register,
}
}
</ script>
< style scoped >
.header {
background-color : white;
box-shadow : 0 0 5px 0 #aaa;
}
.header:after {
content : "" ;
display : block;
clear : both;
}
.slogan {
background-color : #eee;
height : 40px;
}
.slogan p {
width : 1200px;
margin : 0 auto;
color : #aaa;
font-size : 13px;
line-height : 40px;
}
.nav {
background-color : white;
user-select : none;
width : 1200px;
margin : 0 auto;
}
.nav ul {
padding : 15px 0;
float : left;
}
.nav ul:after {
clear : both;
content : '' ;
display : block;
}
.nav ul li {
float : left;
}
.logo {
margin-right : 20px;
}
.ele {
margin : 0 20px;
}
.ele span {
display : block;
font : 15px/36px '微软雅黑' ;
border-bottom : 2px solid transparent;
cursor : pointer;
}
.ele span:hover {
border-bottom-color : orange;
}
.ele span.active {
color : orange;
border-bottom-color : orange;
}
.right-part {
float : right;
}
.right-part .line {
margin : 0 10px;
}
.right-part span {
line-height : 68px;
cursor : pointer;
}
</ style>
2.多方式登录接口
1 多方式登录接口
2 短信登录接口
3 短信注册接口
4 验证手机号是否存在接口
5 发送短信验证码接口
3.手机号是否存在接口
from rest_framework. routers import SimpleRouter
router= SimpleRouter( )
router. register( '' , views. LoginView, basename= 'loginview' )
urlpatterns = [
]
urlpatterns+= router. urls
class LoginView ( ViewSet) :
@action( methods= [ 'get' , ] , detail= False )
def check_mobile ( self, request, * args, ** kwargs) :
mobile= request. GET. get( 'mobile' )
import re
if re. match( r'^1[3-9][0-9]{9}$' , mobile) :
user= models. User. objects. filter ( mobile= mobile) . first( )
if user:
return APIResponse( msg= '手机号存在' )
else :
return APIResponse( status= 1 , msg= '手机号未注册' )
else :
return APIResponse( status= 2 , msg= '手机号不合法' )
3.1路由层user/urls.py
from django. urls import path
from user import views
from rest_framework. routers import SimpleRouter
router= SimpleRouter( )
router. register( '' , views. LoginView, basename= 'loginview' )
urlpatterns = [
]
urlpatterns+= router. urls
3.2user/serializer.py
from rest_framework import serializers
from . import models
from rest_framework. exceptions import ValidationError
from rest_framework_jwt. utils import jwt_payload_handler, jwt_encode_handler
from django. conf import settings
class LoginSerialzer ( serializers. ModelSerializer) :
username = serializers. CharField( )
class Meta :
model = models. User
fields = [ 'id' , 'username' , 'icon' , 'password' ]
extra_kwargs = {
'password' : { 'write_only' : True } ,
'username' : { 'write_only' : True } ,
}
def _get_user ( self, attrs) :
username = attrs. get( 'username' )
password = attrs. get( 'password' )
import re
if re. match( r'^1[3-9][0-9]{9}$' , username) :
user = models. User. objects. filter ( mobile= username, is_active= True ) . first( )
elif re. match( r'^.+@.+$' , username) :
user = models. User. objects. filter ( email= username, is_active= True ) . first( )
else :
user = models. User. objects. filter ( username= username, is_active= True ) . first( )
if user and user. check_password( password) :
return user
raise ValidationError( '用户名或密码错误' )
def _get_token ( self, user) :
payload = jwt_payload_handler( user)
token = jwt_encode_handler( payload)
return token
def validate ( self, attrs) :
user = self. _get_user( attrs)
request = self. context[ 'request' ]
icon = 'http://%s%s%s' % ( request. META[ 'HTTP_HOST' ] , settings. MEDIA_URL, user. icon)
token = self. _get_token( user)
self. context[ 'token' ] = token
self. context[ 'user' ] = user
self. context[ 'icon' ] = icon
return attrs
3.3settings/dev.py
import datetime
JWT_AUTH = {
'JWT_EXPIRATION_DELTA' : datetime. timedelta( days= 7 ) ,
}
3.4user/views.py
from django. shortcuts import render
from django. http import JsonResponse
from rest_framework. viewsets import ViewSet
from rest_framework. decorators import action
from . import serializer
from utils. response import APIResponse
from rest_framework. response import Response
from . import models
class LoginView ( ViewSet) :
@action( methods= [ 'post' , ] , detail= False )
def login ( self, request, * args, ** kwargs) :
ser = serializer. LoginSerialzer( data= request. data, context= { 'request' : request} )
if ser. is_valid( ) :
token = ser. context[ 'token' ]
user = ser. context[ 'user' ]
icon = ser. context[ 'icon' ]
return APIResponse( token= token, username= user. username, icon= icon, id = user. id )
else :
return APIResponse( status= 1 , msg= '用户名或密码错误' )
@action( methods= [ 'get' , ] , detail= False )
def check_mobile ( self, request, * args, ** kwargs) :
mobile= request. GET. get( 'mobile' )
import re
if re. match( r'^1[3-9][0-9]{9}$' , mobile) :
user= models. User. objects. filter ( mobile= mobile) . first( )
if user:
return APIResponse( msg= '手机号存在' )
else :
return APIResponse( status= 1 , msg= '手机号未注册' )
else :
return APIResponse( status= 1 , msg= '手机号不合法' )
4.短信验证码接口
1 阿里大于短信, 腾讯的短信平台
2 充钱买短信, 腾讯给你提供接口, 向他们接口发送请求, 腾讯给你手机发短信
3 使用腾讯短信平台步骤
创建短信签名: 申请一个公众号, 把公众号的截图上传, 申请后台审核
创建短信正文模板:填写模板,通过审核
等待审核 :通过以后
发送短信:https: // cloud. tencent. com/ document/ product/ 382 / 11672
4 api和sdk的区别
- api是一堆http的接口,有了接口就可以调用接口发短信,跟语言无关
- sdk: 软件开发工具包,分语言,这个公司,帮你使用python封装好了,只需要调用它的固定的方法,就能完 成发短信
5 使用腾讯短信提供的sdk
pip install qcloudsms_py
appid = 1400009099
appkey = "9ff91d87c2cd7cd0ea762f141975d1df37481d48700d70ac37470aefc60f9bad"
phone_numbers = [ "21212313123" , "12345678902" , "12345678903" ]
template_id = 7839
sms_sign = "腾讯云"
from qcloudsms_py import SmsSingleSender
from qcloudsms_py. httpclient import HTTPError
ssender = SmsSingleSender( appid, appkey)
params = [ "5678" ]
try :
result = ssender. send_with_param( 86 , phone_numbers[ 0 ] ,
template_id, params, sign= sms_sign, extend= "" , ext= "" )
except HTTPError as e:
print ( e)
except Exception as e:
print ( e)
print ( result)