ゼロから、シンプルなショッピングプラットフォームを構築します(17)フロントエンドモールパーツ:
https ://blog.csdn.net/time_____/article/details/108893925
プロジェクトのソースコード(継続的な更新):https://gitee.com/ DieHunter / myCode / tree / master / Shopping
前回の記事では、ショッピングカートについて簡単に紹介しました。モールの基本機能はすべて実装されています。この記事では、ユーザー情報と注文関連機能の実装を紹介します。ユーザー情報のログインは、バックエンド管理で実装されています。登録機能とメール確認機能を実装します。具体的な実装については、以前のブログまたはこの記事を参照してください。
実装の効果は次のとおりです。ユーザー名とパスワードを使用したログイン、電子メールによる確認を使用したログイン、および登録
ログインセクション
アカウントパスワードのログインは、バックグラウンド管理システムのログインと同じです。ユーザーがユーザー名とパスワードを入力して正常にログインすると、ユーザー情報の一部がトークンに暗号化されてフロントエンドに送信され、ローカルに保存されます。トークン値がバックエンドに送信されるたびに、操作が続行されます。
電子メールによる確認
サーバー構成ファイルに新しいEmailTransporter静的変数を作成して、メールボックスの送信に使用されるnodemailerモジュールを構成します
EmailTransporter: {
// service: "qq", // 运营商 qq邮箱 网易 若使用QQ邮箱,则只需配置service:qq
host: "smtp.163.com",// 若使用网易邮箱,则只需配置host:smtp.163.com
port: 465, //端口
auth: {
user: "132*****[email protected]", //发送方的邮箱
pass: "WAQM******WQEFKB", // pop3 授权码
},
},
次に、新しい電子メール検証コードを作成して、EmailConfigを構成します
EmailConfig: {
time: 5,//验证码有效期,单位分钟
codeLength: 4,//验证码长度
sendTime: 1 * 60 * 1000,//后端验证码允许再次发送时间间隔,单位毫秒
targetTime: 5 * 60 * 1000,//验证码有效期,单位毫秒
title: "零食商贩",//验证码标题
},
次に、Utilsでランダムな検証コードを生成する関数を記述します
/* 生成随机
* @method codeLength 函数名
* @for Utils 附属于哪个类
* @param {number/string} len 随机数长度
* @return {string} _count 生成len个随机数
*/
static codeLength(len) {
let _count = "";
for (let i = 0; i < len; i++) {
_count += Math.floor(Math.random() * 10); //生成len个随机数
}
return _count;
}
Utilsでタイムスタンプ関数を生成し、検証コードと検証コードの送信時間と有効時間を記録します
/* 生成时间戳
* @method randomCode
* @for Utils
* @param
* @return {object} _count 生成len个随机数
*/
static randomCode() {
return {
code: this.codeLength(EmailConfig.codeLength), //生成的随机数
sendTime: new Date().getTime() + EmailConfig.sendTime, //发送时间
targetTime: new Date().getTime() + EmailConfig.targetTime, //截止时间
};
}
Utilsフォルダーの下に新しいSendMail.jsを作成し、新しい送信メールモジュールを作成して、utilsで呼び出します。
const nodemailer = require("nodemailer");
const Config = require("../config/config");
module.exports = class SendMail {
static transporter = nodemailer.createTransport(Config.EmailTransporter); //邮箱配置项
static mailOptions = null; //邮箱配置
/* 发送邮件模块
* @method sendEmail
* @for SendMail
* @param {String} mail 用户邮箱号
* @param {String} title 邮件标题
* @param {String} content 邮件内容
* @return {Boolean} 是否发送成功
*/
static async sendEmail(mail, title, content) {
this.mailOptions = {
from: '"邮箱验证" <' + Config.EmailTransporter.auth.user + ">",
to: mail,
subject: title,
text: content,
};
try {
let result = await this.transporter.sendMail(this.mailOptions);
console.log("发送成功");
return true;
} catch (error) {
console.log(error);
console.log("发送失败");
return false;
}
}
};
utilsでメールコンテンツを生成するための新しい関数を作成します
/* 生成邮件内容
* @method sendEmailCode
* @for Utils
* @param {String} code 验证码内容
* @param {String} email 用户邮箱
*/
static async sendEmailCode(code, email) {
return await SendMail.sendEmail(
email,
EmailConfig.title,
`您的验证码为:${code},${EmailConfig.time}分钟内有效`
);
}
最後に、utilsで非同期にメールを送信する関数を記述します
/* 异步发送邮箱验证
* @method createEmailCode
* @for Utils
* @param {Object} codeList 邮箱验证码列表
* @param {String} email 用户邮箱
* @param {Object} findRes 数据库搜寻到的用户信息
* @return {Boolean} isSuccess 是否发送成功
*/
static async createEmailCode(codeList, email, findRes) {
if (!codeList[email] || new Date().getTime() > codeList[email].sendTime) {
//已过1分钟,防止多次请求邮箱
codeList[email] = this.randomCode();
codeList[email].info = findRes;
return await this.sendEmailCode(codeList[email].code, email);
} else {
//未过1分钟
return false;
}
}
電子メールを送信するための完全なモジュールが完了しました。次のステップは、確認コードを確認することです。
/* 核对验证码
* @method checkEmailCode
* @for Utils
* @param {Object} codeList 用户验证码列表
* @param {String} key 用户邮箱
* @param {Object} _data 用户提交的表单信息
* @return {Object} res 请求响应返回值
*/
static checkEmailCode(codeList, key, _data) {
if (!codeList[key]) {
//未发送验证码
return {
result: 0,
msg: "验证码错误",
};
} else if (
new Date().getTime() < codeList[key].targetTime &&
_data.mailcode == codeList[key].code
) {
//验证码校对成功
let _obj = {
result: 1,
token: Utils.createToken(
codeList[key].info.userType || "",
codeList[key].info.username || "",
_data.remember || ""
),
msg: "操作成功",
};
codeList[key] = null;
return _obj;
} else if (new Date().getTime() > codeList[key].targetTime) {
//验证码超时
return {
result: 0,
msg: "验证码超时",
};
} else {
return {
result: 0,
msg: "验证失败",
};
}
}
このステップでは、確認コードの準備がすべて完了しました。次のステップは、登録とログイン機能の実装です。ログインには2つの方法があります。メールアドレスは登録時に必要な値であるため、メール確認方法を使用してログインできます。
サーバー側は、codeTypeを介して検証コードインターフェイスを取得し、ユーザーログインを区別して検証コードを取得し、登録して検証コードを取得します。
router.get(Config.ServerApi.getMailCode, async (_req, res) => {
//用户邮箱验证
let _data = Util.getCrypto(Util.parseUrl(_req, res).crypto);//解密参数
//查询用户是否存在,若未找到用户,则返回错误响应值,否则异步发送邮件验证码
let findRes = await findData(Mod, {
mailaddress: _data.username.split('@')[0],
mailurl: '@' + _data.username.split('@')[1],
});
if ((!findRes.length || !findRes) && _data.codeType !== 'reg') {//过滤区分用户注册登录
res.send({
result: 0,
msg: "用户未注册"
});
return;
}
await Util.createEmailCode(userCodeList, _data.username, findRes[0] || {}) ? res.send({
result: 1,
msg: "发送成功",
}) : res.send({
result: 0,
msg: "发送失败"
});
});
登録部分を実装する前に、検証コードのカウントダウン用のツールメソッドを作成する必要があります。この間、ユーザーはクリックしてリクエストを再送信できません。
import Vue from "vue";
import Config from "../config/config";
const { GetCodeTime, CodeText } = Config;
class TimeTick {
static timer = GetCodeTime / 1000;//倒计时时间
static _timeTick = null;//定时器
static timeTick(fn) {
if (!TimeTick._timeTick) {
TimeTick._timeTick = setInterval(() => {
if (TimeTick.timer-- <= 1) {
// 重置倒计时和发送邮箱验证开关
TimeTick.clearTick();
fn({ content: CodeText, res: 1 });//倒计时归零
} else {
fn({ content: TimeTick.timer + "S", res: 0 });//倒计时中,阻止用户重复点击
}
}, 1000);
}
}
static clearTick() {
//清除定时器
clearInterval(TimeTick._timeTick);
TimeTick._timeTick = null;
}
}
Vue.prototype.$timeTick = TimeTick;
ユーザー登録インターフェース
<template>
<div class="login">
<div>
<mt-field
placeholder="请输入用户名"
:state="userInfo.username.length ? 'success' : 'error'"
v-model="userInfo.username"
></mt-field>
<mt-field
placeholder="请输入密码"
:state="userInfo.password.length ? 'success' : 'error'"
v-model="userInfo.password"
type="password"
></mt-field>
<mt-field
placeholder="请重复输入密码"
:state="
userInfo.repassword.length && userInfo.password == userInfo.repassword
? 'success'
: 'error'
"
v-model="userInfo.repassword"
type="password"
></mt-field>
<mt-field
placeholder="请输入邮箱"
v-model="userInfo.mailaddress"
:state="userInfo.mailaddress.length ? 'success' : 'error'"
>
<mt-button class="btn" @click="selectMail">{
{
userInfo.mailurl
}}</mt-button>
</mt-field>
<mt-field
placeholder="请输入验证码"
:state="userInfo.mailcode.length == 4 ? 'success' : 'error'"
v-model="userInfo.mailcode"
type="number"
>
<mt-button class="btn" :disabled="canGetCode" @click="getCode">{
{
codeTime
}}</mt-button>
</mt-field>
<mt-button class="btn" type="primary" @click="submit">注册</mt-button>
<div class="shopPicker"></div>
<ShopPicker :ShopMaxCount="address" pickerTitle="邮箱类型"></ShopPicker>
</div>
</div>
</template>
<script>
import Config from "../../config/config";
import Mail from "../../config/mail";
import ShopPicker from "../shopPicker/shopPicker";
import { Field, Button, Picker, Popup } from "mint-ui";
import RegBussiness from "./bussiness";
const { GetCodeTime, EventName, CodeText } = Config;
const { address } = Mail;
export default {
components: {
ShopPicker,
},
data() {
return {
codeTime: CodeText, //获取验证码按钮显示值
address, //邮箱默认地址
canGetCode: false, //防止重复点击开关
userInfo: {
//注册表单默认数据
username: "",
password: "",
repassword: "",
mailurl: address[0],
mailaddress: "",
mailcode: "",
},
};
},
created() {
this.regBussiness = new RegBussiness(this);
this.$events.onEvent(EventName.ChangeCount, (_count) => {
this.userInfo.mailurl = _count; //切换邮箱地址
});
},
destroyed() {
this.$events.offEvent(EventName.ChangeCount);
},
methods: {
selectMail() {
this.$events.emitEvent(EventName.ShowPicker);
},
getCode() {
if (this.canGetCode) {
//是否允许发送邮箱验证
return;
}
this.regBussiness.sendCode().then((res) => {
this.canGetCode = true;//关闭点击开关
this.$timeTick.timeTick((state) => {
this.codeTime = state.content;
switch (state.res) {
case 0:
this.canGetCode = false;//允许用户点击
break;
}
});
});
},
submit() {
this.regBussiness.submitData();
},
},
};
</script>
<style lang="less" scoped>
@import "../../style/init.less";
.login {
.btn {
.f_s(34);
width: 100%;
.h(100);
}
}
</style>
ビジネスロジック部分bussiness.jsを登録します
import Vue from 'vue'
import {
Toast
} from "mint-ui";
import config from "../../config/config"
const {
ServerApi,
StorageName,
EventName
} = config
export default class LoginBussiness extends Vue {
constructor(_vueComponent) {
super()
this.vueComponent = _vueComponent
}
sendCode() {
return new Promise((resolve, reject) => {
if (!this.vueComponent.userInfo.mailaddress.length) {//过滤邮箱长度为0
Toast('请填写正确的邮箱');
return
}
this.$axios
.get(ServerApi.user.getMailCode, {
params: {
crypto: this.$crypto.setCrypto({
codeType: "reg",//区分注册登录类型
username: this.vueComponent.userInfo.mailaddress + this.vueComponent.userInfo.mailurl
})
},
}).then(res => {
switch (res.result) {
case 1:
Toast(res.msg);
resolve(res)
break;
default:
reject(res)
break;
}
}).catch(err => {
reject(err)
})
})
}
submitData() {
for (const key in this.vueComponent.userInfo) {
if (this.vueComponent.userInfo.hasOwnProperty(key) && !this.vueComponent.userInfo[key].length) {//过滤表单项长度为0
Toast('请填写完整的信息');
return
}
}
this.$axios
.post(ServerApi.user.userReg, {
crypto: this.$crypto.setCrypto({
...this.vueComponent.userInfo
})
}).then(res => {
//成功后重置用户信息
this.vueComponent.userInfo.password = "";
this.vueComponent.userInfo.repassword = "";
this.vueComponent.userInfo.mailcode = "";
switch (res.result) {
case 1:
Toast(res.msg);
history.go(-1)//返回登录页面
break;
default:
break;
}
})
}
}
登録部分が完了しました。ログイン機能は登録機能と同様です。これはサーバー側トークンの生成のみです。
管理システムログイン、電子メール認証ログインの追加、管理者ログインとユーザーログインの区別など、サーバーuser.jsのインターフェイスを変更します
router.post(Config.ServerApi.userLogin, async (req, res) => {
let _data = Util.getCrypto(Util.parseUrl(req, res).crypto); //解密前端入参
switch (_data.loginType) {
case "code"://验证码登录,验证邮箱验证码
res.send(Util.checkEmailCode(userCodeList, _data.username, _data));
break;
case "psd"://密码登录
default:
let findRes = await findData(Mod, {
$or: [
{
mailaddress: _data.username.split("@")[0],
mailurl: "@" + _data.username.split("@")[1],
},
{
username: _data.username,
},
{
phoneNum: _data.username,
},
],
});
if (findRes && findRes.length > 0) {
Util.checkBcrypt(_data.password, findRes[0].password)
? res.send({
result: 1,
token: Util.createToken(//生成前端token
findRes[0].userType,
findRes[0].username,
_data.remember
),
msg: "登录成功",
})
: res.send({
result: 0,
msg: "密码错误",
});
return;
}
res.send({
result: 0,
msg: "用户不存在",
});
break;
}
});
まとめ
この記事では、基本的にユーザーの登録とログインのメール確認機能を実装しています。主な機能は、前回のメール確認と登録済みブログへのログインです。記事の焦点は、登録とログインと組み合わせて使用されるメール確認機能モジュールです。登録すると、新しいユーザーが追加されてログインします。次に、トークン値を更新します。次の記事では、ユーザー情報の変更を紹介し、その後の注文生成および表示機能を実現します。