ゼロから、シンプルなショッピングプラットフォームを構築します(18)フロントエンドモール部分

ゼロから、シンプルなショッピングプラットフォームを構築します(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;
  }
});

まとめ
この記事では、基本的にユーザーの登録とログインのメール確認機能を実装しています。主な機能は、前回のメール確認と登録済みブログへのログインです。記事の焦点は、登録とログインと組み合わせて使用​​されるメール確認機能モジュールです。登録すると、新しいユーザーが追加されてログインします。次に、トークン値を更新します。次の記事では、ユーザー情報の変更を紹介し、その後の注文生成および表示機能を実現します。

おすすめ

転載: blog.csdn.net/time_____/article/details/108918489