目录标题

  • 一:前台首页组件编写
    • 1.1 HomeView.vue
    • 1.2 Header.vue
    • 1.3 Banner.vue
    • 1.4 Footer.vue
  • 二: 首页轮播图功能前后端打通
    • 2.1 Banner.vue
  • 三:登录注册功能设计
  • 四: cgi fastcig WSGI uwsgi uWSGI
  • 五: 首页中间部分样式
  • 六: 多方式登录接口
    • 视图类
    • 序列化类
    • 路由
  • 七:手机号是否存在接口
    • 视图类
  • 八:腾讯云短信介绍和申请
    • 什么是api,什么是sdk
  • 九: 登录注册模态框分析
    • Login.vue
    • Header.vue
  • 十: 登录注册前端页面复制
    • Header.vue
    • Login.vue
    • Register.vue
  • 十一:腾讯短信功能二次封装
    • 封装v3版本
    • # 把发送短信封装成包
  • 十二: 短信验证码接口
  • 十三:短信登录接口
  • 十四: 短信注册接口
  • 十五:补充知识点

一:前台首页组件编写

# HomeView.vue 页面组件
# Header.vue   头部组件
# Banner.vue   轮播图组件
# Footer.vue   尾部组件

1.1 HomeView.vue

<template><div class="home"><Header></Header><Banner></Banner><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><Footer></Footer></div>
</template><script>
import Header from '@/components/Header'
import Banner from '@/components/Banner'
import Footer from '@/components/Footer'export default {name: 'HomeView',data() {return {}},components: {Header, Banner, Footer}}
</script>

1.2 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><span>登录</span><span class="line">|</span><span>注册</span></div></div></div></div></template><script>
export default {name: "Header",data() {return {url_path: sessionStorage.url_path || '/',}},methods: {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.paththis.url_path = this.$route.path}
}
</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>

1.3 Banner.vue

<template><div class="banner"><el-carousel :interval="5000" arrow="always" height="400px"><el-carousel-item v-for="item in bannerList" :key="item.title"><div v-if="item.image.indexOf('http')==-1"><router-link :to="item.link"><img :src="item.image" alt=""></router-link></div><div v-else><a :href="item.link"><img :src="item.image" alt=""></a></div></el-carousel-item></el-carousel></div></template><script>
export default {name: "Banner",data() {return {bannerList: []}},created() {this.$axios.get(this.$settings.BASE_URL + 'home/banner/').then(res => {this.bannerList = res.data.result})}
}
</script><style scoped>
.el-carousel__item {height: 400px;min-width: 1200px;
}.el-carousel__item img {height: 400px;margin-left: calc(50% - 1920px / 2);
}.el-carousel__item h3 {color: #475669;font-size: 18px;opacity: 0.75;line-height: 300px;margin: 0;
}.el-carousel__item:nth-child(2n) {background-color: #99a9bf;
}.el-carousel__item:nth-child(2n+1) {background-color: #d3dce6;
}
</style>

1.4 Footer.vue

<template><div class="footer"><ul><li>关于我们</li><li>联系我们</li><li>商务合作</li><li>帮助中心</li><li>意见反馈</li><li>新手指南</li></ul><p>Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p></div>
</template><script>
export default {name: "Footer"
}
</script><style scoped>
.footer {width: 100%;height: 128px;background: #25292e;color: #fff;}.footer ul {margin: 0 auto 16px;padding-top: 38px;width: 810px;}.footer ul li {float: left;width: 112px;margin: 0 10px;text-align: center;font-size: 14px;}.footer ul::after {content: "";display: block;clear: both;}.footer p {text-align: center;font-size: 12px;}
</style>

二: 首页轮播图功能前后端打通

2.1 Banner.vue

<template><div class="banner"><el-carousel :interval="5000" arrow="always" height="400px"><el-carousel-item v-for="item in bannerList" :key="item.title"><div v-if="item.image.indexOf('http')==-1"><router-link :to="item.link"><img :src="item.image" alt=""></router-link></div><div v-else><a :href="item.link"><img :src="item.image" alt=""></a></div></el-carousel-item></el-carousel></div></template><script>
export default {name: "Banner",data() {return {bannerList: []}},created() {this.$axios.get(this.$settings.BASE_URL + 'home/banner/').then(res => {this.bannerList = res.data.result})}
}
</script><style scoped>
.el-carousel__item {height: 400px;min-width: 1200px;
}.el-carousel__item img {height: 400px;margin-left: calc(50% - 1920px / 2);
}.el-carousel__item h3 {color: #475669;font-size: 18px;opacity: 0.75;line-height: 300px;margin: 0;
}.el-carousel__item:nth-child(2n) {background-color: #99a9bf;
}.el-carousel__item:nth-child(2n+1) {background-color: #d3dce6;
}
</style>

三:登录注册功能设计

# 后端接口1 账号/手机号/邮箱+密码登录接口2 手机号+验证码登录接口3 发送手机验证码接口  (第三方发送短信)4 注册接口--》手机号,验证码,密码5 判断手机号是否存在接口

四: cgi fastcig WSGI uwsgi uWSGI

1 cgi fastcig WSGI uwsgi uWSGI  # cgi:通用网关接口(Common Gateway Interface/CGI)是一种重要的互联网技术,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI描述了服务器和请求处理程序之间传输数据的一种标准。一句话总结: 一个标准,定义了客户端服务器之间如何传数据# fastcig:快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本一句话总结: CGI的升级版常用的fastcgi软件: Apache HTTP Server (部分)    :LAMP  LNMPNginx(主流):nginx是一个符合fastcgi协议的软件,处于浏览器和web程序之间,主要做请求转发和负载均衡,也可以称之为服务器中间件Microsoft IIS:windows server# WSGI:Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口一句话总结: 为Python定义的web服务器和web框架之间的接口标准wsgiref:性能很低,python实现的,django内置了,测试阶段用,上线不用uWSIG:性能高,c实现的gunicorn:python实现的# uWSGI: 符合wsgi协议的web服务器,上面标准的具体实现# uwsgi:uWSGI服务器,自有协议3 Apache-Apache 公司-Apache  web服务器-Apache  开源协议-Kafka :apache顶级开源项目-echars:原来是百度开发的,交给了apache孵化

五: 首页中间部分样式

<div class="course"><el-row><el-col :span="6" v-for="(o, index) in 8" :key="o" class="course_detail"><el-card :body-style="{ padding: '0px' }"><img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g0zd133mj20l20a875i.jpg"class="image"><div style="padding: 14px;"><span>推荐课程</span><div class="bottom clearfix"><time class="time">价格:999</time><el-button type="text" class="button">查看详情</el-button></div></div></el-card></el-col></el-row></div><img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h1g112oiclj224l0u0jxl.jpg" alt="" width="100%" height="500px"><style scoped>
.time {font-size: 13px;color: #999;
}.bottom {margin-top: 13px;line-height: 12px;
}.button {padding: 0;float: right;
}.image {width: 100%;display: block;
}.clearfix:before,
.clearfix:after {display: table;content: "";
}.clearfix:after {clear: both
}.course_detail {padding: 50px;
}
</style>

六: 多方式登录接口

# 登录注册1 多方式登录 【用户名、邮箱、手机号+密码】4 校验手机号是否存在2 验证码登录3 发送验证码5 手机号注册接口# 多方式登录-{username:用户名/邮箱/手机号,password:123}---->post请求-之前写的逻辑,校验用户,是写在视图类的方法中-今天写:咱们把逻辑写在序列化类中

视图类

# post--->查询--->自动生成路由,action装饰器可以在视图类中写多个函数
from rest_framework.viewsets import ViewSet, GenericViewSet, ViewSetMixin
from rest_framework.decorators import action
from .models import UserInfo
from .serializer import UserMulLoginSerializerfrom utils.response import APIResponseclass UserView(ViewSet):@action(methods=['POST'], detail=False)def mul_login(self, request):# 1 老写法# username=request.data.get('username')# password=request.data.get('password')# # 查询用户,# UserInfo.objects.filter(username=username,password=password)# # 签发token# # 返回# 2 新写法:使用序列化类ser = UserMulLoginSerializer(data=request.data)# jwt 模块的登录就是这么写的ser.is_valid(raise_exception=True)  # 会执行:序列化类字段自己的校验规则,局部钩子,全局钩子# 用户名密码校验通过了,在序列化类中--》签发tokentoken = ser.context.get('token')username = ser.context.get('username')icon = ser.context.get('icon')  # icon是个对象  字符串return APIResponse(token=token, username=username,icon=icon)  # 前端看到的样子{code:100,msg:成功,token:adsfa,username:root,icon:http://adsfasd.png}

序列化类

from rest_framework import serializers
from .models import UserInfo
import re
from django.contrib.auth import authenticate
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.settings import api_settingsjwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER# 这个序列类,只用来做登录校验,不做序列化,不做反序列化
class UserMulLoginSerializer(serializers.ModelSerializer):username = serializers.CharField()  # 重写,优先用现在的,就没有unique的限制了class Meta:model = UserInfofields = ['username', 'password']# 封装之隐藏属性  __表示隐藏, _并不是隐藏,公司里约定俗成用 _ 表示只在内部用,如果外部想用,也可以用def _get_user(self, attrs):# attrs 是校验过后的数据:字段自己的规则【字段自己有规则:坑】和局部钩子username = attrs.get('username')password = attrs.get('password')# username可能是用户名,邮箱,手机号---》使用正则判断if re.match(r'^1[3-9][0-9]{9}$', username):user = authenticate(mobile=username, password=password)elif re.match(r'^.+@.+$', username):  # adsa@adsf  会有bug,用户名中如果有@,登录不了了user = authenticate(email=username, password=password)else:user = authenticate(username=username, password=password)if user:return userelse:raise ValidationError('用户名或密码错误')def _get_token(self, user):try:payload = jwt_payload_handler(user)token = jwt_encode_handler(payload)return tokenexcept Exception as e:raise ValidationError(str(e))# 还要写别的def validate(self, attrs):# 1  取出用户名和密码,校验用户是否存在user = self._get_user(attrs)# 2 签发tokentoken = self._get_token(user)# 3 把token放到序列化类对象中self.context['token'] = tokenself.context['username'] = user.usernameself.context['icon'] = 'http://127.0.0.1:8000/media/'+str(user.icon) # 这是个对象,可能会有问题# self.context['icon'] = user.icon  # 这是个对象,可能会有问题# 以后如果有问题,都抛异常# 如没有问题,返回attrsreturn attrs

路由

from django.contrib import admin
from django.urls import path, re_path
from home import views
from django.views.static import serve
from django.conf import settings
from . import viewsfrom rest_framework.routers import SimpleRouterrouter = SimpleRouter()
# 127.0.0.1:8080/api/v1/userinfo/user/mul_login
router.register('user', views.UserView, 'user')urlpatterns = [
]
urlpatterns += router.urls

七:手机号是否存在接口

# get请求:  127.0.0.1:8080/api/v1/userinfo/user/mobile/?mobile=132222222

视图类

class UserView(ViewSet):@action(methods=['GET'], detail=False)def mobile(self, request):try:mobile = request.query_params.get('mobile')UserInfo.objects.get(mobile=mobile)  # 有且只有一个才不报错,return APIResponse(msg='手机号存在')  # {code:100,msg:手机号存在}except Exception as e:raise APIException('手机号不存在')  # {code:999,msg:手机号不存在}

八:腾讯云短信介绍和申请

# 咱们要写发送短信接口,我们要发短信,借助于短信运营商# 腾讯云开放平台,有很多开放的接口供咱们使用,咱们用的是短信-注册平台---》找到短信-https://console.cloud.tencent.com/smsv2# 申请使用腾讯云短信:1 创建签名:使用公众号申请-网站:备案:工信部备案-申请个人一个公众号:-https://mp.weixin.qq.com/-等审核通过2 申请模板:发送短信的模板 {1}  {2} 后期用代码填上3 免费赠送100条4 代码发送短信:参照文档写代码:https://cloud.tencent.com/document/product/382/13444-v2 老一些-v3 最新

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Ndh0Ibc-1668434974686)(C:\Users\Administrator\Desktop\学期笔记库\luffyday567.assets\image-20221110121519296.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lXqvJ8GI-1668434974688)(C:\Users\Administrator\Desktop\学期笔记库\luffyday567.assets\image-20221110120341171.png)]

什么是api,什么是sdk

# API文档-之前学的接口文档的概念-使用api调用,比较麻烦,固定输入,接受固定的返回-使用postman都可以测试,携带你的认证的秘钥。# SDK:Software Development Kit 软件开发工具包-分语言的-基于API,使用某个编程语言封装的包-例如python:pip install 包-包.发短信(参数)-一般厂商都会提供各大主流语言的sdk# 腾讯短信sdk使用步骤1 已开通短信服务,创建签名和模板并通过审核    # 开了2 如需发送国内短信,需要先 购买国内短信套餐包。 #赠送了3 已准备依赖环境:Python 2.7 - 3.6 版本。    #我们有4 已在访问管理控制台 >API密钥管理页面获取 SecretID 和 SecretKey。SecretID 用于标识 API 调用者的身份。SecretKey 用于加密签名字符串和服务器端验证签名字符串的密钥,SecretKey 需妥善保管5 短信的调用地址为sms.tencentcloudapi.com。

九: 登录注册模态框分析

# 如果是跳转新的页面-路由中配置一个路由-写一个视图组件# 弹窗,盖在主页上---》模态框

Login.vue

<template><div class="login"><span @click="handleClose">X</span></div>
</template><script>
export default {name: "Login",methods:{handleClose(){this.$emit('close')}}
}
</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>

Header.vue

<div class="right-part"><div><span @click="goLogin">登录</span><span class="line">|</span><span>注册</span></div><Login v-if="loginShow" @close="closeLogin"></Login>
</div>export default {name: "Header",data() {return {url_path: sessionStorage.url_path || '/',loginShow: false}},methods: {goPage(url_path) {// 已经是当前路由就没有必要重新跳转if (this.url_path !== url_path) {// 传入的参数,如果不等于当前路径,就跳转this.$router.push(url_path)}sessionStorage.url_path = url_path;},goLogin() {this.loginShow = true},closeLogin() {this.loginShow = false}},created() {sessionStorage.url_path = this.$route.paththis.url_path = this.$route.path},components: {Login}
}

十: 登录注册前端页面复制

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><span @click="put_login">登录</span><span class="line">|</span><span @click="put_register">注册</span></div><Login v-if="is_login" @close="close_login" @go="put_register"></Login><Register v-if="is_register" @close="close_register" @go="put_login"></Register></div></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 || '/',is_login: false,is_register: false,}},methods: {goPage(url_path) {// 已经是当前路由就没有必要重新跳转if (this.url_path !== url_path) {// 传入的参数,如果不等于当前路径,就跳转this.$router.push(url_path)}sessionStorage.url_path = url_path;},goLogin() {this.loginShow = true},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;},close_register() {this.is_register = false;}},created() {sessionStorage.url_path = this.$route.paththis.url_path = this.$route.path},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>

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-inputplaceholder="用户名/手机号/邮箱"prefix-icon="el-icon-user"v-model="username"clearable></el-input><el-inputplaceholder="密码"prefix-icon="el-icon-key"v-model="password"clearableshow-password></el-input><el-button type="primary">登录</el-button></el-form><el-form v-if="login_method === 'is_sms'"><el-inputplaceholder="手机号"prefix-icon="el-icon-phone-outline"v-model="mobile"clearable@blur="check_mobile"></el-input><el-inputplaceholder="验证码"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);}}
}
</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>

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-inputplaceholder="手机号"prefix-icon="el-icon-phone-outline"v-model="mobile"clearable@blur="check_mobile"></el-input><el-inputplaceholder="密码"prefix-icon="el-icon-key"v-model="password"clearableshow-password></el-input><el-inputplaceholder="验证码"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>

十一:腾讯短信功能二次封装

封装v3版本

# sdk:https://cloud.tencent.com/document/product/382/43196#
# 使用步骤:-下载模块:pip3 install tencentcloud-sdk-python
# -*- coding: utf-8 -*-
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
from tencentcloud.sms.v20210111 import sms_client, models# 导入可选配置类
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfiletry:cred = credential.Credential("AKIDTXcdXG6u5C9ycAd7WyFex9ED5VwPpBXp", "LZgaKxTOI0VowVs22qTvDKDtLcfWCiqm")httpProfile = HttpProfile()httpProfile.reqMethod = "POST"  # post请求(默认为post请求)httpProfile.reqTimeout = 30  # 请求超时时间,单位为秒(默认60秒)httpProfile.endpoint = "sms.tencentcloudapi.com"  # 指定接入地域域名(默认就近接入)# 非必要步骤:# 实例化一个客户端配置对象,可以指定超时时间等配置clientProfile = ClientProfile()clientProfile.signMethod = "TC3-HMAC-SHA256"  # 指定签名算法clientProfile.language = "en-US"clientProfile.httpProfile = httpProfileclient = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)req = models.SendSmsRequest()req.SmsSdkAppId = "1400763090" # 腾讯短信创建app把app的id号复制过来https://console.cloud.tencent.com/smsv2/app-manage# 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名# 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看req.SignName = "关于金鹏公众号"# 模板 ID: 必须填写已审核通过的模板 ID# 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看req.TemplateId = "1603526"# 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空req.TemplateParamSet = ["8888",'100']# 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]# 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号req.PhoneNumberSet = ["+8615386800417"]# 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回req.SessionContext = ""req.ExtendCode = ""req.SenderId = ""resp = client.SendSms(req)# 输出json格式的字符串回包print(resp.to_json_string(indent=2))except TencentCloudSDKException as err:print(err)

# 把发送短信封装成包

# 后期别的项目,也要使用发送短信----》只要把包copy到项目中即可# 封装包:-目录结构send_tx_sms  #包名__init__.pysettings.py #配置文件sms.py      # 核心文件###__init__.py
from .sms import get_code,send_sms_by_phone
####  settings.py
SECRET_ID = ''
SECRET_KEY = ''
APP_ID = ''
SIGN_NAME=''
TEMPLATE_ID=''#####sms.py
# 核心代码
import randomfrom tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
from tencentcloud.sms.v20210111 import sms_client, models# 导入可选配置类
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from . import settings# 获取n位随机数组验证码的函数
def get_code(num=4):code = ''for i in range(num):random_num = random.randint(0, 9)code += str(random_num)return code# 发送短信函数
def send_sms_by_phone(mobile, code):try:cred = credential.Credential(settings.SECRET_ID, settings.SECRET_KEY)httpProfile = HttpProfile()httpProfile.reqMethod = "POST"  # post请求(默认为post请求)httpProfile.reqTimeout = 30  # 请求超时时间,单位为秒(默认60秒)httpProfile.endpoint = "sms.tencentcloudapi.com"  # 指定接入地域域名(默认就近接入)# 非必要步骤:# 实例化一个客户端配置对象,可以指定超时时间等配置clientProfile = ClientProfile()clientProfile.signMethod = "TC3-HMAC-SHA256"  # 指定签名算法clientProfile.language = "en-US"clientProfile.httpProfile = httpProfileclient = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)req = models.SendSmsRequest()req.SmsSdkAppId = settings.APP_ID  # 腾讯短信创建app把app的id号复制过来https://console.cloud.tencent.com/smsv2/app-manage# 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名# 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看req.SignName = settings.SIGN_NAME# 模板 ID: 必须填写已审核通过的模板 ID# 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看req.TemplateId = settings.TEMPLATE_ID# 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空req.TemplateParamSet = [code, '1']# 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]# 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号req.PhoneNumberSet = ["+86" + mobile, ]# 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回req.SessionContext = ""req.ExtendCode = ""req.SenderId = ""resp = client.SendSms(req)# 输出json格式的字符串回包# 字符串类型print(type(resp.to_json_string(indent=2)))return Trueexcept TencentCloudSDKException as err:return False

十二: 短信验证码接口

# 前端通过 get  http://127.0.0.1:8000/api/v1/userinfo/user/send_sms/?mobile=12324344
class UserView(ViewSet):@action(methods=['GET'], detail=False)def send_sms(self, request):mobile = request.query_params.get('mobile')if re.match(r'^1[3-9][0-9]{9}$', mobile):code = get_code()print(code)  # 保存验证码---》能存,不能丢,后期能取---》缓存--》django自带缓存框架# 放在内存中了,只要重启就没了----》后期学完redis,放到redis中,重启项目,还在cache.set('sms_code_%s' % mobile, code)# cache.get('sms_code_%s'%mobile)res = send_sms_by_phone(mobile, code)if res:return APIResponse(msg='发送短信成功')else:# raise APIException('发送短信失败')return APIResponse(msg='发送短信失败', code=101)else:return APIResponse(msg='手机号不合法', code=102)

十三:短信登录接口

# 手机号+验证码---{mobile:12333,code:7878}---->post--->/api/v1/userinfo/user/mobile_login/3672

十四: 短信注册接口

# 手机号+验证码+密码---》post---》{mobile:111111,password:1234,code:8888}# 注册的序列化类,用户名没有:用手机号作为用户名

十五:补充知识点

1 python的深浅copy浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。2 __new__和__init__的区别2.1.首先用法不同,__new__()用于创建实例,所以该方法是在实例创建之前被调用,它是类级别的方法,是个静态方法;而 __init__() 用于初始化实例,所以该方法是在实例对象创建后被调用,它是实例级别的方法,用于设置对象属性的一些初始值。__new__()在__init__() 之前被调用。如果__new__() 创建的是当前类的实例,会自动调用__init__()函数,通过return调用的__new__()的参数cls来保证是当前类实例,如果是其他类的类名,那么创建返回的是其他类实例,就不会调用当前类的__init__()函数。2.2.其次传入参数不同__new__()至少有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别;__init__()至少有一个参数self,就是这个__new__()返回的实例,__init__()在__new__()的基础上完成一些初始化的操作。2.3.返回值不同__new__()必须有返回值,返回实例对象;__init__()不需要返回值。3 把一个文件夹,子文件夹下所有的folder.ini删除
4 python 是值传递还是引用传递python不允许程序员选择采用传值还是传引用。python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(字典、列表)的引用,就能修改对象的原始值--相当于‘传引用’来传递对象。如果函数收到的是一个不可变对象(数字、字符或元组)的引用,就不能直接修改原始对象--相当于通过‘值传递’来传递对象。
5 python 可变与不可变可变类型:数据值发生变化,内存地址不变不可变类型:数据值发生变化,内存地址也发生变化

我的项目day04:首页,轮播图前后端,登录注册功能设计,cgi,uwsgi,多方式登录接口,手机号是否存在接口,腾讯云短信,模态框,腾讯短信功能二次封装,短信验证接口,短信注册接口,断行注册接口相关推荐

  1. vue2.0 + vux (五)api接口封装 及 首页 轮播图制作

    1.安装 jquery 和 whatwg-fetch (优雅的异步请求API) npm install jquery --save npm install whatwg-fetch --save 2. ...

  2. 项目轮播图功能实现和导航栏的实现

    项目轮播图功能实现和导航栏的实现 轮播图功能 安装依赖模块 上传文件相关配置 注册home子应用 创建轮播图的model模型 创建Banner的序列化器 创建Banner的视图类 配置Banner的路 ...

  3. 《锋迷商城》——首页:轮播图

    <锋迷商城>系列项目 链接: <一> 项目搭建 链接: <二>数据库的创建 链接: <三>业务流程设计 链接: <四>业务流程实现:用户管理 ...

  4. 轮播图高度自适应_干货!弘成教你写轮播图全自动适应封装代码

    点击蓝字 关注我们 在弘成教育任UI讲师,带了几十个班数百个学生了,我发现学生们最头疼的不是网站界面的设计,各种网站的设计,专题页,详情页,店铺装修,他们都能设计得漂漂亮亮.也不是HTML+CSS的静 ...

  5. html轮播图向左改为向下,jQuery之轮播图向左滚动动画【原创】

    最近在做项目时遇到轮播图的问题.一开始只是做了淡入淡出的效果,设计师要求是背景图不动,中间内容向左滚动.效果图如下: 主要的思路:就是设置一个大的div,把几张banner图从左往右排列.外面的大di ...

  6. JavaScript模拟轮播图效果

    轮播图 相信小伙伴们应该不会陌生吧~ 就是网站中间的那个 会定时切换的商品图 今天咱们就来模拟一个轮播图~当然效果不是那么美观小伙伴们不要嫌弃哈~ 那么咱们开动了,额~先准备好几章轮播图片(直接在网上 ...

  7. 使用Bootstrap做轮播图

    什么是Bootstrap? - Bootstrap 是当下最流行的前端框架(界面工具集): -特点就是灵活简洁,代码优雅,美观大方: - 其目的是为了让 Web 开发更敏捷:   - 是 Twitte ...

  8. 小程序倒计时轮播图、导航切换轮播

    最近项目需要实现轮播图有倒计时圆点然后自动切换图片加导航点击切换轮播内容的需求,项目结束,在这里总结一下 先上效果图,让各位兄弟看看是不是也符合各自需要的那种需求,相互学习 我是把这写在一个组件里面的 ...

  9. jQuery实现一个简单的轮播图

    一.轮播图内容组成 包括:4张图片,图片标号,向左翻页,向右翻页的几个部分,如下图所示: 二.实现功能 1.加载页面后,4张图片默认从第一张图片开始轮播,索引值为1. 2.当把鼠标over到图片上时, ...

  10. android 炫酷轮播图,一个很Nice的Android Banner轮播图库

    Android小白一枚,最近项目中有一个轮播图的需求,网上搜了很多资料,也看了多开源库,但不是bug多就是库不维护.后来在GitHub上找到一个很棒的轮播图–BannerViewPager库推荐个大家 ...

最新文章

  1. java 正则 捕获_Java通过正则表达式捕获组中的文本
  2. sublime text3注册激活及失效解决办法
  3. C++ 经典面试题
  4. How-to: 利用Visual Studio升级Windows Phone 7工程
  5. 戴尔完成600亿美元与EMC并购交易 戴尔科技正式成立
  6. 如何获取集合里面的下标_怎样获取list集合中的最后一个对象中的值
  7. Android HttpClient Session保持
  8. PHP生成腾讯云API签名
  9. 接呀呀云实时语音SDK总结
  10. Xposed FrameWork v89 安装
  11. 大数据技术在我们日常生活中的应用
  12. N张图片合成一个最终图片(像素图片)
  13. Unity--游戏字幕
  14. 使用亚博智能K210实现人脸特征提取和识别
  15. python路线寻优_基于DEAP库的Python进化算法从入门到入土 --(四)遗传算法的改进...
  16. TDW计算引擎解析——Scheduler
  17. 常用工具类 Math:数学计算 Random:生成伪随机数 SecureRandom:生成安全的随机数 2020-2-13
  18. Linux进程的创建
  19. 【操作教程】如何正确使用海康demo工具配置通道上线?
  20. 原来我们看到的世界地图竟这样震撼!多年的地理白学了...

热门文章

  1. C语言二级操作题满分班(2015年9月方法篇)-叶冬冬-专题视频课程
  2. STM32CUBEIDE中修改FLASH起始地址的方法
  3. EditText实现输入自定义表情
  4. UE4 创建开始游戏界面UI
  5. JDK官方下载(旧版本,以前老版本)
  6. Silverlight实用窍门系列:1.Silverlight读取外部XML加载配置---(使用WebClient读取XAP包同目录下的XML文件))【附带实例源码】...
  7. STM32之EXTI——外部中断
  8. 【股票】融资融券基本概念
  9. “ji32k7au4a83”是一个弱密码?
  10. 协会元宇宙产业园基地孵化器授牌案例:循环经济元宇宙加速基地