一、需求文档(登陆注册)
1、用户名登录 2、注册(检测手机号是否已经注册) 3、二维码登录 4、短信登录 5、判断登录状态,(登陆了之后才可以访问收藏页面) 6、用户退出登录 7、获取登陆后用户名和头像 8、用户个人信息页 9、修改用户个人信息
二、开发文档
网易云的API文档 https://neteasecloudmusicapi.vercel.app/#/?id=_1-%e6%89%8b%e6%9c%ba%e7%99%bb%e5%bd%95
三、接口文档 数据库设计
user
user_id | user_name | password | phone | user_img | |
---|---|---|---|---|---|
user_info
nickname | img | production | gender | birth | |
---|---|---|---|---|---|
address | id | ||||
四、进度安排
day1
1、路由注册100% 2、登录总页面100% 3、账号登录页面100%(egg后端+数据库) 4、用户注册页面实现(egg后端+数据库)100%
day2
1、实现二维码登录(网易云API)80% 2、实现短信登录(网易云API)80%
day3
1、二维码登录100% 2、短信登录100% 3、路由守卫拦截80% 4、登录成功后返回状态和信息50% 5、登录退出50%
day4
1、用户个人信息页面 2、用户信息修改(昵称,头像,手机号)
五、遇到的问题
1、路由接口的配置
2、跨域处理
前端: vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
port: 8080,
host: 'localhost',
// 可设置多个代理
proxy: { //目的是解决跨域,若测试环境不需要跨域,则不需要进行该配置
'/api': {
target: 'http://127.0.0.1:7001/', // 目标 API 地址
changeOrigin: true, //开启跨域
pathRewrite: {
'^/api': ''
}
}
}
},
lintOnSave: true
})
main.js
const http = axios.create({
timeout: 1000 * 1000000,
withCredentials: true,
BASE_URL: '/api',
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
后端:cconfig.default.js
//配置允许post请求
config.security = {
csrf: {
enable: false,
ignoreJSON: true,
}
}
//配置跨域
config.cors = {
// origin: '*',
origin:'http://localhost:8080',//cookie自带允许跨域
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',
credentials: true
};
3、路由拦截
4、二维码传值的时候,key值传递过来后,能打印出来,但是就是用不了,用的时候就是undefined
因为我在写axios.get方法时,没写params,导致这个问题,采用打印语句,一步一步找到答案
5 通过短信发送验证码的时候,最好采用form表单,便于后面检验验证码的状态,就是需要检验按钮的状态,按钮能否被选择,还有就是要做防抖和节流
6 今天上午网易云的api突然访问不了,不知道是什么原因,后期在解决
7 采用短信登录的时候,应该是验证码输入之后,点击登录才跳转,而不是验证码一输入成功就登录成功。
8 用axios的时候最好是res返回值写在.then里面,这样更好拿后端的值
9 封装axios
1
2
request.js
import axios from 'axios'
// 调用 axios.create() 函数,创建一个 axios 的实例对象,用 request 来接收
const request = axios.create({
// 指定请求的根路径
baseURL: 'https://netease-cloud-music-api-beta-lyart.vercel.app'
})
export default request
3 loginbyphone.js
// 通过电话号码登录相关的 API 接口
import request from '@/utils/request.js'
const qs = require('qs')
// 每次请求都带上时间戳 timestamp 参数 防止缓存
// withCredentials 请求为跨域类型时是否在请求中协带cookie
export const byPassword = function (phone, password) {
return request.post('/login/cellphone', qs.stringify({
phone: phone,
password: password,
timestamp: new Date().getTime()
}))
}
// 发送短信验证码
export const sendCode = function (phone) {
return request.get('/captcha/sent', {
params: {
phone: phone,
timestamp: new Date().getTime()
}
})
}
// 验证短信验证码
export const byCode = function (phone, captcha) {
return request.post('/captcha/verify', qs.stringify({
phone: phone,
captcha: captcha,
timestamp: new Date().getTime()
}))
}
4 loginebyphne.vue
<template>
<div class="bbox">
<div class="top">
<div class="topp">
登录
<i class="el-icon-close"></i>
</div>
</div>
<div class="mid">
<img src="https://p6.music.126.net/obj/wo3DlcOGw6DClTvDisK1/9647707645/c8e7/4d8d/1895/6dff82b63181104bbac7cf3743c8b613.png" alt=""style="width:286px;" >
<div id="form-container" style="margin:10px">
<!-- <el-input placeholder="请输入手机号" v-model="phoneNumber" class="input-with-select">
<i slot="prefix" class="el-input__icon el-icon-mobile-phone"></i>
</el-input> -->
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="auto" class="login-ruleFrom" style="margin:0 15px">
<el-form-item label="" prop="phoneNumber">
<el-input v-model="ruleForm.phoneNumber" placeholder="请输入手机号">
<i slot="prefix" class="el-input__icon el-icon-mobile-phone"></i>
</el-input>
<el-button size="mini" class="getCodeButton" :disabled="attcode" v-if="showBtn" @click="getCode">获取验证码</el-button>
<el-button class="getCodeButton" plain disabled v-else >{{codeMsg}}</el-button>
</el-form-item>
<el-form-item label="" prop="phoneCode">
<el-input v-model="ruleForm.phoneCode" placeholder="请输入验证码">
<i slot="prefix" class="el-input__icon el-icon-lock"></i>
</el-input>
</el-form-item>
<el-form-item label="" prop="type" style="margin-top:-10px">
<el-switch v-model="ruleForm.autoLogin" active-text="自动登录" ></el-switch>
</el-form-item>
<el-form-item style="margin-bottom:-20px">
<el-button type="primary" @click="submitForm('ruleForm')" style="width:100%;">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import { byCode, sendCode } from '@/api/LoginAndRegister/loginByPhone.js'
export default {
data () {
return {
// 获取验证码按钮是否禁用
attcode: true,
// 获取验证码按钮是否展示
showBtn: true,
codeMsg: '获取验证码',
// 倒计时
codeSec: 60,
ruleForm: {
phoneNumber: '',
phoneCode: '',
autoLogin: false
},
rules: {
phoneNumber: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/, message: '请正确填写您的手机号码', trigger: 'blur' }
],
phoneCode: [
{ required: true, message: '请输入验证码', trigger: 'blur' },
{ pattern: /^[0-9]{4}$/, message: '请填写有效的验证码', trigger: 'blur' }
]
}
}
},
watch: {
// 监听手机号 改变获取验证码按钮状态
'ruleForm.phoneNumber': function (value) {
const reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
const val = reg.test(value)
if (val) {
this.attcode = false
} else {
this.attcode = true
}
},
'ruleForm.phoneCode': async function (code) {
if (code.length === 4) {
// 自动请求并且登录
const { data: byCodeData } = await byCode(this.ruleForm.phoneNumber, this.ruleForm.phoneCode)
console.log(byCodeData)
if (byCodeData.code === 200) {
this.successLoginMsg()
sessionStorage.setItem("user", true);
this.$router.push("/");
// 保存信息到 Vuex 跳转页面
}
}
}
},
methods: {
// 错误提示信息
errorMsg () {
this.$message({
showClose: true,
message: '电话或验证码错误!',
type: 'error'
})
},
// 短信发送成功提示信息
successSendMsg () {
this.$message({
showClose: true,
message: '短信发送成功!',
type: 'success'
})
},
// 登录成功提示信息
successLoginMsg () {
this.$message({
showClose: true,
message: '登录成功!',
type: 'success'
})
console.log();
},
// 提交登录表单
async submitForm (formName) {
console.log(this.ruleForm.phoneNumber, this.ruleForm.phonePassword, this.ruleForm.autoLogin)
this.$refs[formName].validate(async (valid) => {
if (valid) {
// 发送请求
const byCodeData = await byCode(this.ruleForm.phoneNumber, this.ruleForm.phoneCode)
if (byCodeData.code === 200) {
// this.successLoginMsg()
sessionStorage.setItem("user", true);
this.$router.push("/");
// 保存信息到 Vuex 跳转页面
} else {
this.errorMsg()
}
} else {
console.log('error submit!!')
return false
}
})
},
// 发送验证码
async getCode () {
// 调用 sendCode 发送验证码
const sendCodeData = await sendCode(this.ruleForm.phoneNumber)
if (sendCodeData.code !== 200) this.successSendMsg()
// 修改页面样式
const timer = setInterval(() => {
this.codeSec = this.codeSec - 1
this.codeMsg = this.codeSec + 's后重试'
this.showBtn = false
if (this.codeSec === 0) {
clearInterval(timer)
this.codeSec = 60
this.showBtn = true
}
}, 1000)
}
}
};
</script>
<style lang="scss" scoped>
.bbox {
margin: auto;
position: relative;
width: 700px;
// height: 370px;
background-color: #fff;
border: #333 solid 1px;
}
.top {
width: 700px;
height: 50px;
background-color: rgb(49, 35, 35);
color: white;
}
.topp {
font-weight: bold;
margin-left: 18px;
margin-right: 18px;
padding-top: 16px;
display: flex;
justify-content: space-between;
}
.mid{
margin-top: 8px;
// margin-left: 52px;
padding-left: 93px;
padding-top: 21px;
padding-bottom: 10px;
margin: auto;
width: 400px;
display: flex;
flex-wrap:wrap;
align-items:center;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.mima{
margin-top: 20px;
}
.login{
background-color: rgb(49, 125, 200);
color: #fff;
margin-top: 10px;}
.mid img{
margin-bottom:10px ;
}
.send{
background-color: rgb(49, 125, 200);
color: #fff;
height: 29px;
margin-top: 19px;
}
.huoqu{
display: flex;
justify-content: space-between;
}
</style>