前倾回顾
# 1 用户板块相关接口
- 验证手机号是否存在
- 多方式登录接口
- 发送短信接口(发送登录和发送注册短信使用同一个接口)
- 短信登录接口
- 短信注册接口
# 2 验证手机号是否存在
-请求地址,编码格式,携带的数据---》后端写接口人定的
-地址:/api/v1/user/mobile/check_mobile/
-post请求
-请求体:{mobile:手机号}
-自动生成路由---》视图类--》 def mobile(self, request)
-@action(methods=['post'], detail=False, url_path='check_mobile')
# 3 多方式登录
-请求地址,编码格式,携带的数据---》后端写接口人定的
-地址:/api/v1/user/login/mul_login/
-请求方式:post
-编码格式:json
-请求体:{username:用户名/手机号/邮箱,password:}
-自动生成路由:
router.register('login', UserLoginView, 'login')
-写了个视图类:
class UserLoginView(GenericViewSet):
@action(methods=['POST'], detail=False)
def mul_login(self,request):
# ser=MulLoginSerializer(data=request.data)
ser = self.get_serializer(data=request.data, context={'request': request})
ser.is_valid(raise_exception=True) # 字段自己[继承ModelSerializer,没有重写username],局部钩子[没有],全局钩子[重点写的]
token
username ser.context.get('username')
icon
return 给前端
- 序列化类:只做 校验
class MulLoginSerializer(serializer.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate(self, attrs):
user = self._get_user(attrs)
token = self._get_token(user)
self._set_context(token, user)
return attrs
# 4 发送短信接口
-第三方发送短信:腾讯云短信
-发短信:直接复制---》测试
-封装:以后任意项目直接把包复制过去,导入就能使用
-settings.py # 配置信息---》在项目的配置文件中配置
-__init__.py # 注册了一下 想给外部用的函数
-sms.py # 获取随机验证码 发送短信
-发送短信接口:
get:/api/v1/user/mobile/send_sms/?mobile=ssss
# 5 短信登录接口
-{mobile ,code }
-视图类,跟之前一模一样
-序列化类中:只有校验用户不一样 签发token,放context都是一样
# 6 注册接口
-{mobile,code,password}
-注册接口不带密码---》也能注册成功---》发个短信--》让它及时修改密码
-生成默认密码---》第一次不允许登录
-手机号+验证码 如果注册过就登录,如果没注册过,就注册并且登录成功--》作业
前端注册页面分析
# 登录,注册,都写成组件----》在任意页面中,都能点击显示登录模态框
# 写好的组件,应该放在那个组件中----》不是【页面组件】(小组件)
如果我们想写简单---》登录注册做成页面组件--》点击路由跳转即可
放在Header.vue中,以后任意页面组件都会引入Header---》都会有登录注册的按钮
# 点击登录按钮,把Login.vue 通过定位,占满全屏,透明度设为 0.5 ,纯黑色背景,覆盖在组件上
# 在Login.vue点关闭,要把Login.vue隐藏起来,父子通信之子传父,自定义事件
Header.vue
## 页面中
<span @click="go_login">登录</span>
<Login v-if="login_show" @close_login="close_login"></Login>
## data
login_show: false
### methods
go_login() {
this.login_show = true
},
close_login() {
this.login_show = false
}
Login.vue
<template>
<div class="login">
<span @click="close">X</span>
</div>
</template>
<script>
export default {
name: "Login",
methods: {
close() {
this.$emit('close_login')
}
}
}
</script>
<style scoped>
.login {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 10;
background-color: rgba(0, 0, 0, 0.5);
}
</style>
登录前端
Login.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">登录</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 @click="mobile_login" 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;
// js正则:/正则语法/
// '字符串'.match(/正则语法/)
if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
this.$message({
message: '手机号有误',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
}
});
return false;
}
// 后台校验手机号是否已存在
this.$axios({
url: this.$settings.base_url + '/user/mobile/',
method: 'post',
data: {
mobile: this.mobile
}
}).then(response => {
let result = response.data.result;
if (result) {
this.$message({
message: '账号正常',
type: 'success',
duration: 1000,
});
// 发生验证码按钮才可以被点击
this.is_send = true;
} else {
this.$message({
message: '账号不存在',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
}
})
}
}).catch(() => {
});
},
send_sms() {
// this.is_send必须允许发生验证码,才可以往下执行逻辑
if (!this.is_send) return;
// 按钮点一次立即禁用
this.is_send = false;
let sms_interval_time = 60;
this.sms_interval = "发送中...";
// 定时器: setInterval(fn, time, args)
// 往后台发送验证码
this.$axios({
url: this.$settings.base_url + '/user/sms/',
method: 'get',
params: {
mobile: this.mobile
}
}).then(response => {
let result = response.data.result;
if (result) { // 发送成功
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);
} else { // 发送失败
this.sms_interval = "重新获取";
this.is_send = true;
this.$message({
message: '短信发送失败',
type: 'warning',
duration: 3000
});
}
}).catch(() => {
this.sms_interval = "频率过快";
this.is_send = true;
})
},
login() {
// 用户名密码不能为空
if (!(this.username && this.password)) {
this.$message({
message: '请填好账号密码',
type: 'warning',
duration: 1500
});
return false // 直接结束逻辑
}
// 发送ajax请求登录
this.$axios.post('/user/login/mul_login/', {
username: this.username,
password: this.password
}).then(res => {
// 取出用户名,token和 icon,存到 cookie中
this.$cookies.set('token', res.token,'7d')
this.$cookies.set('username', res.username,'7d')
this.$cookies.set('icon', res.icon,'7d')
//模态框关掉
this.$emit('close')
}).catch(res => {
// console.log(res)
this.$message.error(res);
})
},
mobile_login() {
if (!(this.mobile && this.sms)) {
this.$message({
message: '请填好手机与验证码',
type: 'warning',
duration: 1500
});
return false // 直接结束逻辑
}
this.$axios({
url: this.$settings.base_url + '/user/mobile/login/',
method: 'post',
data: {
mobile: this.mobile,
code: this.sms,
}
}).then(response => {
let username = response.data.result.username;
let token = response.data.result.token;
let user_id = response.data.result.id;
this.$cookies.set('username', username, '7d');
this.$cookies.set('token', token, '7d');
this.$cookies.set('user_id', user_id, '7d');
this.$emit('success', response.data.result);
}).catch(error => {
console.log(error.response.data)
})
}
}
}
</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>
Header.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 && username.length>0">
<span>{{ username }}</span>
<span class="line">|</span>
<span @click="logout">退出</span>
</div>
<div v-else>
<span @click="go_login">登录</span>
<span class="line">|</span>
<span>注册</span>
</div>
</div>
<Login v-if="login_show" @close="close_login"></Login>
</div>
</div>
</template>
<script>
import Login from "@/components/Login";
export default {
name: "Header",
data() {
return {
url_path: sessionStorage.url_path || '/',
login_show: false, // 控制Login.vue 是否显示
username: '',
icon: ''
}
},
methods: {
logout() {
console.log('sdsafss')
// 清除cookie
this.$cookies.set('username', '')
this.$cookies.set('icon', '')
this.$cookies.set('token', '')
// this.username和this.icon 值为空
this.username = ''
this.icon = ''
},
go_login() { // Header 组件中按钮点击触发
this.login_show = true
},
close_login() { // 子[Login.vue] 传父[Header.vue]-->控制不显示
this.login_show = false
// 取一下cookie中有没有用户名,如果有,说明用户登录了,就显示用户名
this.username = this.$cookies.get('username')
this.icon = this.$cookies.get('icon')
},
goPage(url_path) {
if (this.url_path !== url_path) {
this.$router.push(url_path);
}
sessionStorage.url_path = url_path;
},
},
created() {
sessionStorage.url_path = this.$route.path;
this.url_path = this.$route.path;
this.username = this.$cookies.get('username')
this.icon = this.$cookies.get('icon')
},
components: {
Login
}
}
</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;
display: block;
}
.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;
}
.search {
float: right;
position: relative;
margin-top: 22px;
margin-right: 10px;
}
.search input, .search button {
border: none;
outline: none;
background-color: white;
}
.search input {
border-bottom: 1px solid #eeeeee;
}
.search input:focus {
border-bottom-color: orange;
}
.search input:focus + button {
color: orange;
}
.search .tips {
position: absolute;
bottom: 3px;
left: 0;
}
.search .tips span {
border-radius: 11px;
background-color: #eee;
line-height: 22px;
display: inline-block;
padding: 0 7px;
margin-right: 3px;
cursor: pointer;
color: #aaa;
font-size: 14px;
}
.search .tips span:hover {
color: orange;
}
</style>
注册前端
Register.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 @click="register" 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')
},
go_login() {
this.$emit('go')
},
check_mobile() {
if (!this.mobile) return;
// js正则:/正则语法/
// '字符串'.match(/正则语法/)
if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
this.$message({
message: '手机号有误',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
}
});
return false;
}
// 后台校验手机号是否已存在
this.$axios.post('/user/mobile/check_mobile/', {
mobile: this.mobile
}).then(res => {
this.$message.info('您已经注册过,直接登录即可')
this.$emit('go')
}).catch(res => {
this.$message.success('改手机号可以正常注册')
this.is_send = true
})
},
send_sms() {
// this.is_send必须允许发生验证码,才可以往下执行逻辑
if (!this.is_send) return;
// 按钮点一次立即禁用
this.is_send = false;
let sms_interval_time = 60;
this.sms_interval = "发送中...";
// 定时器: setInterval(fn, time, args)
setInterval(() => {
this.sms_interval = sms_interval_time - 1
sms_interval_time = this.sms_interval
if (this.sms_interval == 1) {
this.sms_interval = '发送验证码'
this.is_send = true;
}
}, 1000)
// 往后台发送验证码
this.$axios.get('/user/mobile/send_sms/?mobile=' + this.mobile).then(res => {
this.$message.success(res.msg)
}).catch(res => {
this.$message.error('发送失败')
})
},
register() {
if (!(this.mobile && this.sms && this.password)) {
this.$message({
message: '请填好手机、密码与验证码',
type: 'warning',
duration: 1500
});
return false // 直接结束逻辑
}
this.$axios.post('/user/register/', {
mobile: this.mobile,
code: this.sms,
password: this.password
}).then(res => {
this.$emit('go')
}).catch(res => {
this.$message.error('注册失败')
})
}
}
}
</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>
Header.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 && username.length>0">
<span>{{ username }}</span>
<span class="line">|</span>
<span @click="logout">退出</span>
</div>
<div v-else>
<span @click="go_login">登录</span>
<span class="line">|</span>
<span @click="go_register">注册</span>
</div>
</div>
<Login v-if="login_show" @close="close_login" @go="put_register"/>
<Register v-if="is_register" @close="close_register" @go="put_login"/>
</div>
</div>
</template>
<script>
import Login from "@/components/Login";
import Register from "@/components/Register";
export default {
name: "Header",
data() {
return {
url_path: sessionStorage.url_path || '/',
login_show: false, // 控制Login.vue 是否显示
is_register: false, // 控制Register.vue 是否显示
username: '',
icon: ''
}
},
methods: {
logout() {
console.log('sdsafss')
// 清除cookie
this.$cookies.set('username', '')
this.$cookies.set('icon', '')
this.$cookies.set('token', '')
// this.username和this.icon 值为空
this.username = ''
this.icon = ''
},
go_login() { // Header 组件中按钮点击触发
this.login_show = true
},
close_login() { // 子[Login.vue] 传父[Header.vue]-->控制不显示
this.login_show = false
// 取一下cookie中有没有用户名,如果有,说明用户登录了,就显示用户名
this.username = this.$cookies.get('username')
this.icon = this.$cookies.get('icon')
},
close_register() {
this.is_register = false
},
go_register() {
this.is_register = true
},
put_register() {
this.login_show = false
this.is_register = true
},
put_login() {
this.login_show = true
this.is_register = false
},
goPage(url_path) {
if (this.url_path !== url_path) {
this.$router.push(url_path);
}
sessionStorage.url_path = url_path;
},
},
created() {
sessionStorage.url_path = this.$route.path;
this.url_path = this.$route.path;
this.username = this.$cookies.get('username')
this.icon = this.$cookies.get('icon')
},
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;
display: block;
}
.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;
}
.search {
float: right;
position: relative;
margin-top: 22px;
margin-right: 10px;
}
.search input, .search button {
border: none;
outline: none;
background-color: white;
}
.search input {
border-bottom: 1px solid #eeeeee;
}
.search input:focus {
border-bottom-color: orange;
}
.search input:focus + button {
color: orange;
}
.search .tips {
position: absolute;
bottom: 3px;
left: 0;
}
.search .tips span {
border-radius: 11px;
background-color: #eee;
line-height: 22px;
display: inline-block;
padding: 0 7px;
margin-right: 3px;
cursor: pointer;
color: #aaa;
font-size: 14px;
}
.search .tips span:hover {
color: orange;
}
</style>
多方式登录前端
1 <template>
2 <div class="login">
3 <div class="box">
4 <i class="el-icon-close" @click="close_login"></i>
5 <div class="content">
6 <div class="nav">
7 <span :class="{active: login_method === 'is_pwd'}"
8 @click="change_login_method('is_pwd')">密码登录</span>
9 <span :class="{active: login_method === 'is_sms'}"
10 @click="change_login_method('is_sms')">短信登录</span>
11 </div>
12
13 <el-form v-if="login_method === 'is_pwd'">
14 <el-input
15 placeholder="用户名/手机号/邮箱"
16 prefix-icon="el-icon-user"
17 v-model="username"
18 clearable>
19 </el-input>
20 <el-input
21 placeholder="密码"
22 prefix-icon="el-icon-key"
23 v-model="password"
24 clearable
25 show-password>
26 </el-input>
27 <el-button type="primary" @click="login">登录</el-button>
28 </el-form>
29
30 <el-form v-if="login_method === 'is_sms'">
31 <el-input
32 placeholder="手机号"
33 prefix-icon="el-icon-phone-outline"
34 v-model="mobile"
35 clearable
36 @blur="check_mobile">
37 </el-input>
38 <el-input
39 placeholder="验证码"
40 prefix-icon="el-icon-chat-line-round"
41 v-model="sms"
42 clearable>
43 <template slot="append">
44 <span class="sms" @click="send_sms">{{ sms_interval }}</span>
45 </template>
46 </el-input>
47 <el-button @click="mobile_login" type="primary">登录</el-button>
48 </el-form>
49
50 <div class="foot">
51 <span @click="go_register">立即注册</span>
52 </div>
53 </div>
54 </div>
55 </div>
56 </template>
57
58 <script>
59 export default {
60 name: "Login",
61 data() {
62 return {
63 username: '',
64 password: '',
65 mobile: '',
66 sms: '', // 验证码
67 login_method: 'is_pwd',
68 sms_interval: '获取验证码',
69 is_send: false,
70 }
71 },
72 methods: {
73 close_login() {
74 this.$emit('close')
75 },
76 go_register() {
77 this.$emit('go')
78 },
79 change_login_method(method) {
80 this.login_method = method;
81 },
82 check_mobile() {
83 if (!this.mobile) return;
84 // js正则:/正则语法/
85 // '字符串'.match(/正则语法/)
86 if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
87 this.$message({
88 message: '手机号有误',
89 type: 'warning',
90 duration: 1000,
91 onClose: () => {
92 this.mobile = '';
93 }
94 });
95 return false;
96 }
97 // 后台校验手机号是否已存在
98
99 this.$axios({
100 url: 'user/mobile/check_mobile/',
101 method: 'post',
102 data: {
103 mobile: this.mobile
104 }
105 }).then(res => {
106 // 发生验证码按钮才可以被点击
107 this.is_send = true;
108 }).catch(() => {
109 this.$message({
110 type: "error",
111 message: '您还没注册呢,请先注册',
112 onClose: () => {
113 this.mobile = ''
114 this.$emit('go')
115 }
116
117 })
118 });
119 },
120 send_sms() {
121 // this.is_send必须允许发生验证码,才可以往下执行逻辑
122 if (!this.is_send) return;
123 // 按钮点一次立即禁用
124 this.is_send = false;
125
126 let sms_interval_time = 60;
127 this.sms_interval = "发送中...";
128
129 // 定时器: setInterval(fn, time, args)
130
131 // 往后台发送验证码
132 this.$axios({
133 url: '/user/mobile/send_sms/',
134 method: 'get',
135 params: {
136 mobile: this.mobile
137 }
138 }).then(res => {
139 let timer = setInterval(() => {
140 if (sms_interval_time <= 1) {
141 clearInterval(timer);
142 this.sms_interval = "获取验证码";
143 this.is_send = true; // 重新回复点击发送功能的条件
144 } else {
145 sms_interval_time -= 1;
146 this.sms_interval = `${sms_interval_time}秒后再发`;
147 }
148 }, 1000);
149
150 }).catch(() => {
151 this.sms_interval = "频率过快";
152 this.is_send = true;
153 })
154
155
156 },
157 login() {
158 // 用户名密码不能为空
159 if (!(this.username && this.password)) {
160 this.$message({
161 message: '请填好账号密码',
162 type: 'warning',
163 duration: 1500
164 });
165 return false // 直接结束逻辑
166 }
167 // 发送ajax请求登录
168 this.$axios.post('/user/login/mul_login/', {
169 username: this.username,
170 password: this.password
171 }).then(res => {
172 // 取出用户名,token和 icon,存到 cookie中
173 this.$cookies.set('token', res.token, '7d')
174 this.$cookies.set('username', res.username, '7d')
175 this.$cookies.set('icon', res.icon, '7d')
176 //模态框关掉
177 this.$emit('close')
178 }).catch(res => {
179 // console.log(res)
180 this.$message.error(res);
181 })
182
183 },
184 mobile_login() {
185 if (!(this.mobile && this.sms)) {
186 this.$message({
187 message: '请填好手机与验证码',
188 type: 'warning',
189 duration: 1500
190 });
191 return false // 直接结束逻辑
192 }
193
194 this.$axios({
195 url: '/user/login/sms_login/',
196 method: 'post',
197 data: {
198 mobile: this.mobile,
199 code: this.sms,
200 }
201 }).then(res => {
202 this.$cookies.set('username', res.username, '7d');
203 this.$cookies.set('token', res.token, '7d');
204 this.$cookies.set('icon', res.icon, '7d');
205 this.$emit('close');
206 }).catch(error => {
207 console.log(error.response.data)
208 })
209 }
210 }
211 }
212 </script>
213
214 <style scoped>
215 .login {
216 width: 100vw;
217 height: 100vh;
218 position: fixed;
219 top: 0;
220 left: 0;
221 z-index: 10;
222 background-color: rgba(0, 0, 0, 0.3);
223 }
224
225 .box {
226 width: 400px;
227 height: 420px;
228 background-color: white;
229 border-radius: 10px;
230 position: relative;
231 top: calc(50vh - 210px);
232 left: calc(50vw - 200px);
233 }
234
235 .el-icon-close {
236 position: absolute;
237 font-weight: bold;
238 font-size: 20px;
239 top: 10px;
240 right: 10px;
241 cursor: pointer;
242 }
243
244 .el-icon-close:hover {
245 color: darkred;
246 }
247
248 .content {
249 position: absolute;
250 top: 40px;
251 width: 280px;
252 left: 60px;
253 }
254
255 .nav {
256 font-size: 20px;
257 height: 38px;
258 border-bottom: 2px solid darkgrey;
259 }
260
261 .nav > span {
262 margin: 0 20px 0 35px;
263 color: darkgrey;
264 user-select: none;
265 cursor: pointer;
266 padding-bottom: 10px;
267 border-bottom: 2px solid darkgrey;
268 }
269
270 .nav > span.active {
271 color: black;
272 border-bottom: 3px solid black;
273 padding-bottom: 9px;
274 }
275
276 .el-input, .el-button {
277 margin-top: 40px;
278 }
279
280 .el-button {
281 width: 100%;
282 font-size: 18px;
283 }
284
285 .foot > span {
286 float: right;
287 margin-top: 20px;
288 color: orange;
289 cursor: pointer;
290 }
291
292 .sms {
293 color: orange;
294 cursor: pointer;
295 display: inline-block;
296 width: 70px;
297 text-align: center;
298 user-select: none;
299 }
300 </style>
redis介绍和安装
# redis 是什么?
-非关系型数据库:redis,mongodb,es,clickhouse,influxDB
no sql: not only sql
-关系型数据库:mysql,oracle,postgrasql,sqlserver,sqlite
-去IOE ,国产化
IBM:服务器
Oracle:数据库 达梦
EMC:存储
-redis 到底是什么?
redis是一个key-value存储系统【软件】,用c语言写的,c/s架构的软件,纯内存存储,可以持久化【断电数据可以恢复】
value:有5钟数据类型
string:字符串
hash:字典
list:列表
set:集合
zset:有序集合
# redis为什么这么快?
- qps :10w 6w左右
-1 纯内存操作,避免了io
-2 使用了io多路复用的网络模型--(epoll)
-3 数据操作是单线程单进程---【没有锁操作,没有线程间切换】
# 安装redis
-redis开源项目,社区不支持win
-使用的epoll模式,不能再win上运行的
-微软团队---》基于人家源码,修改+编译---》安装包--》可以装在win上
-最新:最新7.x
# win平台最新只有
-最新5.x版本 https://github.com/tporadowski/redis/releases/
-最新3.x版本 https://github.com/microsoftarchive/redis/releases
# 下载:Redis-x64-5.0.14.1.msi,一路下一步
# 启动redis服务端
-在服务中,启动redis即可
# 客户端安装
-cmd窗口
-redis-cli -h 127.0.0.1 -p 6379
-redis-cli
-resp
-安装链接
-Navicate 16
链接即可
-.....