SSM-Vue前后端分离式项目开发

SSM-Vue前后端分离式项目开发

1、后端SSM项目搭建

1.1 项目基础设置

1.2 数据库设计

  • 用户表t_user

  • 商品表t_product

  • 商品类型表t_product_type

  • 购物车表t_cart

  • 订单表t_order

  • 订单详情表t_orderinfo

1.3 编写后端代码

  • 使用Mybatis逆向工程自动生成pojo、mapper、mapper.xml等项目所需代码
  • 根据项目需求,编写业务逻辑层的接口,然后在编写对应接口的实现类
  • 根据各个接口的实现类,来手动添加或修改逆向工程中没有自动生成的mapper接口和mapper.xml
  • 如有问题,可参考博客:https://www.cnblogs.com/mc-blog/p/15208197.html

2、前端Vue项目搭建

  • 创建一个基于webpack模板的项目

    • vue init webpack 项目名
  • 安装组件(插件)axios、vue-router、element-ui、vuex

    • npm install axios -s

    • npm install vue-router --save-dev

    • npm i element-ui -S

    • npm install vuex --save

  • 安装依赖

    • npm install(cnpm install)

说明:几种安装方式的区别

1.安装到项目目录node_module。不会添加任何依赖。(不会写入package.json)
npm install axios

2.安装到全局。磁盘目录为配置的npm config prefix处
npm install -g axios

3和4 一样.安装到项目目录node_modules。添加依赖(写入package.json)。添加依赖的作用是:比如项目上传到git中。其他成员下载项目时会直接下载依赖中有的插件

3.生产环境下载的包。
npm install -save axios

4.开发环境下载的包。 只在开发的模式下使用。
npm install -save-dev axios
  • 引用各个组件

    import Vue from 'vue'
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css';
    import VueRouter from 'vue-router'
    import axios from 'axios'
    
    Vue.use(ElementUI);
    Vue.use(VueRouter);
    Vue.prototype.axios = axios;
    
  • 配置路由router/index.js

    点击查看代码
      import Vue from 'vue'
      import Router from 'vue-router'
      import ProductInfo from "../components/ProductInfo";
      import Home from "../components/Home";
      import Cart from "../components/Cart";
      import Orders from "../components/Orders";
      import Login from "../components/Login";
      import Pay from "../components/Pay";
      import CartForm from "../components/CartForm";
      Vue.use(Router);
      
      export default new Router({
          mode: 'history',
          routes: [
              {
                  path: '/home',
                  name: 'Home',
                  component: Home
              },
              {
                  path: '/productInfo',
                  name: 'ProductInfo',
                  component: ProductInfo
              },
              {
                  path: '/cart',
                  name: 'Cart',
                  component: Cart,
                  children: [{
                      path: '/cartForm',
                      name: 'CartForm',
                      component: CartForm
                  }]
              },
              {
                  path: '/orders',
                  name: 'Orders',
                  component: Orders
              },
              {
                  path: '/login',
                  name: 'Login',
                  component: Login
              },
              {
                  path: '/pay',
                  name: 'Pay',
                  component: Pay
              }
          ]
      });
    
    

2.1 登录页面搭建

点击查看代码
<template>
  <div class="login-box">
    <el-form ref="form" status-icon :model="form" :rules="rules" label-width="80px">
      <h3 class="login-title">欢迎登录</h3>

      <el-form-item label="手机号码" prop="userTel">
        <el-input v-model="form.userTel" type="number" placeholder="请输入手机号码"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="userPwd">
        <el-input v-model="form.userPwd" type="password" placeholder="请输入密码"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="resetForm('form')">重置</el-button>
        <el-button type="success" @click="onSubmit('form')">登录</el-button>
      </el-form-item>

    </el-form>

  </div>
</template>

<script>
    export default {
        name: "Login",
        data() {
            return {
                form: {
                    userTel: '',
                    userPwd: ''
                },
                rules: {
                    userTel: [
                        {required: true, message: '请输入手机号码', trigger: 'blur'},
                        {min: 11, max: 11, message: '长度必须是11个数字', trigger: 'blur'}
                    ],
                    userPwd: [
                        {required: true, message: '请输入密码', trigger: 'blur'},
                        {min: 6, max: 50, message: '长度在 6 到 50 个字符', trigger: 'blur'}
                    ]
                }
            }
        },
        methods: {
            onSubmit(formName) {
                this.$refs[formName].validate((valid) => {
                    var vm = this;
                    if (valid) {
                        //表单验证成功,要发送登录请求
                        this.axios({
                            method: 'GET',
                            url: 'http://localhost:8090/user/login?userTel=' + vm.form.userTel + '&userPwd=' + vm.form.userPwd
                        }).then(function (resp) {
                            if (resp.data.result) {
                                var user = resp.data.data;
                                sessionStorage.setItem("isLogin", "true")
                                //往vuex里存放一个user对象
                                //先要有user对象
                                //再存到vuex里
                                vm.$store.dispatch('asyncUpdateUser', user);

                                //再在home.vue里获取vuex对象里的user对象的内容。
                                vm.$message({
                                    message: "登录成功",
                                    type: 'success'
                                });
                                setTimeout(function () {
                                    vm.$router.push("/home");
                                }, 2000)
                            } else {
                                vm.$message.error("登录失败");
                            }
                        })
                    } else {
                        this.$message({
                            message: '电话号码或密码不能为空!',
                            type: 'warning'
                        });
                        return false;
                    }
                });
            },
            resetForm(form) {
                this.$refs[form].resetFields();
            }
        }
    }
</script>

<style scoped>
  .login-box {
    width: 500px;
    height: 300px;
    border: 1px solid #DCDFE6;
    margin: 150px auto;
    padding: 20px 55px 20px 30px;
    border-radius: 20px;
    box-shadow: 0px 0px 20px #DCDFE6;
  }

  .login-title {
    text-align: center;
    margin-bottom: 40px;
  }
    .el-button{
        margin: 15px 60px 0px 55px;
    }
</style>

2.2 首页搭建

点击查看代码
<template>
  <div>
    <el-container>
      <el-row>
        <el-col :span="12">
          <div class="grid-content bg-purple-dark">
            <div class="nav nav-1">
              <el-link type="info">首页</el-link>
            </div>
            <div class="nav">
              <el-link type="info">官网</el-link>
            </div>
          </div>
        </el-col>
        <el-col v-if="!islogin" :span="6">
          <div class="grid-content bg-purple-dark">
            <div class="nav nav-1">
              <el-link type="info" @click="$router.push('/login')">请登录</el-link>
            </div>
            <div class="nav">
              <el-link type="info">注册</el-link>
            </div>
          </div>
        </el-col>
        <el-col v-if="islogin" :span="6">
          <div class="grid-content bg-purple-dark">
            <div class="nav nav-1">
              <el-link type="info"><span>欢迎你,{{username}}</span></el-link>
            </div>
            <div class="nav">
              <el-link type="info" @click="$router.push('/logout')">注销</el-link>
            </div>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="grid-content bg-purple-dark">
            <div class="nav">
              <el-link type="info">我的订单</el-link>
            </div>
            <div class="nav">
              <el-link type="info">购物车</el-link>
            </div>
          </div>
        </el-col>
      </el-row>

      <el-header height="80px">
        <div class="grid-content bg-purple" align="left" style="float: left">
          <img src="../assets/logo.png" style="width: 205px; height: 36px;margin: 25px 0px 0px 150px">
        </div>
        <div style="float: left; margin-top: 10px;width: 75%">
          <div style="float: left; margin-left: 150px">商品名称:
            <input v-model="proName" class="select select-input"/>
          </div>
          <div style="float: left; margin-left: 30px">
            商品类型:<select v-model="selectedTypeId" class="select select-option">
            <option v-for="option in options" v-bind:value="option.typeId">{{option.typeName}}</option>
          </select>&nbsp;&nbsp;&nbsp;
            价格区间:<input v-model="lprice" class="select select-input-price"/>-<input v-model="hprice"
                                                                                    class="select select-input-price"/>
            <el-button type="primary" icon="el-icon-search"
                       @click="getList()"></el-button>
          </div>
        </div>
      </el-header>

      <el-main>
        <div style="width: 99%;border: 1px solid #000;margin-bottom: 8px"></div>

        <div class="block">
          <el-carousel indicator-position="none" height="350px">
            <el-carousel-item v-for="item in imgs" :key="item">
              <img :src="item" style="width: 800px;height: 400px;">
            </el-carousel-item>
          </el-carousel>
        </div>

        <div style="width: 99%;border: 1px solid #000;margin-top: 8px"></div>

        <div class="products">
          <div v-for="pro in pros" class="product">
            <img :src="pro.pimg"/><br/>
            <p style="font-size: larger;">{{pro.pname}}</p>
            <p style="font-size: larger;color: red;">¥{{pro.price}}</p>
            <el-button type="primary" @click="getProInfo(pro.pid)">立即购买</el-button>
          </div>
        </div>

        <div class="block" style="margin-bottom: 20px;margin-top: 20px">
          <el-pagination
                  @size-change="handleSizeChange"
                  @current-change="handleCurrentChange"
                  :current-page.sync="currentPage"
                  :page-sizes="[8,16,24,32]"
                  :page-size="pageSize"
                  layout="total, sizes, prev, pager, next, jumper"
                  :total="listTotal">
          </el-pagination>
        </div>
        <div style="width: 99%;border: 1px solid #000000;"></div>
      </el-main>

      <el-footer height="420px">
        <el-row>
          <el-col :span="6">
            <div class="footer-content">
              <i class="el-icon-star-off" style="float: left;font-size: 40px;margin-top: 20px;margin-left: 45px"></i>
              <div style="float:left; font-size: 25px;margin-top: 10px;margin-left: 10px">百强企业 品质保证</div>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="footer-content">
              <i class="el-icon-date" style="float: left;font-size: 40px;margin-top: 20px;margin-left: 45px"></i>
              <div style="float:left; font-size: 25px;margin-top: 10px;margin-left: 10px">7天退货 15天换货</div>
            </div>
          </el-col>

          <el-col :span="6">
            <div class="footer-content">
              <i class="el-icon-shopping-bag-2"
                 style="float: left;font-size: 40px;margin-top: 20px;margin-left: 45px"></i>
              <div style="float:left; font-size: 25px;margin-top: 10px;margin-left: 10px">48元起免运费</div>
            </div>
          </el-col>
          <el-col :span="6">
            <div class="footer-content">
              <i class="el-icon-location-information" style="float: left;font-size: 40px;margin-top: 20px;"></i>
              <div style="float:left; font-size: 25px;margin-top: 10px;margin-left: 10px">2000家服务店 全国联保</div>
            </div>
          </el-col>
        </el-row>

        <el-row>
          <el-col :span="3">
            <div class="footer-content-1">
              <span style="font-size: large">购物相关</span>
              <span>购物指南</span>
              <span>配送方式</span>
              <span>支付方式</span>
              <span>常见问题</span>
            </div>
          </el-col>

          <el-col :span="3">
            <div class="footer-content-1">
              <span style="font-size: large">保修与退换货</span>
              <span>保修政策</span>
              <span>退换货政策</span>
              <span>保修状态查询</span>
              <span>配件防伪查询</span>
            </div>
          </el-col>

          <el-col :span="3">
            <div class="footer-content-1">
              <span style="font-size: large;margin-left: 20px">维修与技术支持</span>
              <span>服务店</span>
              <span>预约维修</span>
              <span>手机寄修</span>
              <span>备件价格查询</span>
              <span>上门服务</span>
            </div>
          </el-col>

          <el-col :span="3">
            <div class="footer-content-1">
              <span style="font-size: large">特色服务</span>
              <span>防伪查询</span>
              <span>补购保障</span>
              <span>以旧换新</span>
              <span>补品包装</span>
            </div>
          </el-col>

          <el-col :span="3">
            <div class="footer-content-1">
              <span style="font-size: large">关于我们</span>
              <span>公司介绍</span>
              <span>华为商城简介</span>
              <span>华为零售店</span>
              <span>商家中心</span>
              <span>意见反馈</span>
            </div>
          </el-col>

          <el-col :span="3">
            <div class="footer-content-1">
              <span style="font-size: large">友情链接</span>
              <span>华为集团</span>
              <span>华为CBG官网</span>
              <span>花粉俱乐部</span>
              <span>华为云</span>
              <span>华为应用市场</span>
            </div>
          </el-col>

          <el-col :span="6">
            <div class="footer-content-1" style="line-height: 70px;">
              <span style="padding-left: 90px;padding-top: 30px">950805</span>
              <span style="margin-bottom: 20px">7x24小时客服热线(仅收市话费)</span>
              <div style="border-radius: 40px;height: 40px;line-height: 40px;margin-left: 80px; width: 200px;background: #000000;color: #ffffff">
                <i class="el-icon-headset"></i>在线客服
              </div>
            </div>
          </el-col>

          <el-col :span="24">
            <div class="footer-content" style="height: 120px">
              <el-col :span="2">
                <div class="footer-content-2" style="height: 120px">
                  <img src="static/wLelYbpMVWbj9Xpaa5Fk.png" style="margin-top: 20px;height: 25px;margin-left: 10px;">
                </div>
              </el-col>

              <el-col :span="16">
                <div class="footer-content-2" style="padding-top: 10px;">
                  <span>华为集团 | 华为CBG官网 | 花粉俱乐部 | 华为应用市场 | HarmonyOS | 华为终端云空间 | 开发者联盟 | 华为商城手机版 | 网站地图</span><br/>
                  <a>隐私声明</a><a>&nbsp;服务协议</a><a>&nbsp;COOKIES</a><a>&nbsp; Copyright © 2012-</a><a> 华为终端有限公司
                  版权所有 </a><a>&nbsp;粤ICP备19015064号</a><a> | 粤公网安备 44190002003939号</a>
                  <br/><em>增值电信业务经营许可证:粤B2-20190762 | 备案主体编号:44201919072182 | 粤新出网备(2021)2号</em><br/>
                  <a>互联网药品信息服务资格证(粤)-非经营性-2020-0102 | 粤东食药监械经营备20203930</a>
                </div>
              </el-col>

              <el-col :span="6">
                <div class="footer-content-2">
                  <img src="static/20160226162415360.png" style="margin-top: 20px;height: 35px;margin-left: 120px;">
                </div>
              </el-col>
            </div>
          </el-col>
        </el-row>
      </el-footer>

    </el-container>
  </div>
</template>

<script>
    import Qs from 'qs'
    export default {
        name: 'Home',
        data() {
            return {
                proName: '',
                selectedTypeId: '',
                lprice: '',
                hprice: '',
                options: [{
                    typeId: 1,
                    typeName: "手机"
                }],
                imgs: [
                    "/static/pad.png",
                    "/static/computer.jpg",
                    "/static/huacp.png",
                    "/static/huaph.png"
                ],
                pros: [{
                    tpId: 1,
                    pid: 1001,
                    pname: "",
                    price: 3333,
                    pimg: ""
                }],
                username: this.$store.getters.getUser.userNickname,
                islogin: this.$store.getters.getUser == null ? false : true,
                currentPage:1,//初始页
                listTotal: 0,//数据总量
                pageSize:8//每页多少条数据
            }
        },
        created() {
            this.getList();
            this.getType();
        },
        methods: {
            handleSizeChange: function (size) { // 下拉框选择分页的大小
                this.pageSize = size;
                this.getList();
            },
            handleCurrentChange: function(currentPage){ //点击跳转第几页
                this.currentPage = currentPage;
                this.getList();
            },
            getList:function() { // 获取商品列表
                var vm = this;
                var choice = {
                    proName: vm.proName,
                    selectedTypeId: vm.selectedTypeId,
                    lprice: vm.lprice,
                    hprice: vm.hprice,
                    pageNum: vm.currentPage,
                    pageSize:vm.pageSize
                };
                this.axios({
                    method: 'POST',
                    url: 'http://localhost:8090/product/list',
                    transformRequest: [function (data) {
                        return Qs.stringify(data)
                    }],
                    data: choice
                }).then( function (resp) {
                    vm.pros = resp.data.list;
                    vm.listTotal = resp.data.total;
                });
            },
            getProInfo(pid) {
                var p = {
                    options: this.options,
                    pid: pid
                };
                this.$router.push({name: 'ProductInfo', params: p});
            },
            getType: function () {  // 获取商品类型
                var vm = this;
                this.axios({
                    method: 'GET',
                    url: 'http://localhost:8090/productType/list'
                }).then(function (resp) {
                    vm.options = resp.data;
                    // console.log(vm.options.typeName);
                });
            },
            select() {
                var vm = this;
                var choice = {
                    proName: vm.proName,
                    selectedTypeId: vm.selectedTypeId,
                    lprice: vm.lprice,
                    hprice: vm.hprice,
                };
                console.log(choice);
            }
        }
    }
</script>

<style scoped>
  .el-header, .el-footer {
    background-color: #ffffff;
    color: #333;
    text-align: center;
    line-height: 60px;
  }

  .el-main {
    color: #333;
    text-align: center;
    padding: 10px 0px 50px 0px;
  }

  .product {
    display: inline-block;
    width: 350px;
    margin-top: 20px;
    margin-bottom: 10px;
    padding-bottom: 10px;
    /*border-bottom: 1px solid red;*/
  }

  .product img {
    width: 220px;
    height: 280px;
  }

  .bg-purple-dark {
    background: #000000;
  }

  .grid-content {
    min-height: 36px;
    height: 45px;
  }

  .nav {
    float: left;
    margin: 10px 0px 0px 30px;
  }

  .nav-1 {
    margin-left: 200px;
  }

  .select {
    border-radius: 5px;
    border: #E9EEF3;
    height: 35px;
    border: 1px solid #000000;
  }

  .select-input {
    width: 160px;
  }

  .select-option {
    margin-right: 10px;
    width: 125px;
  }

  .select-input-price {
    width: 75px;
  }

  .footer-content {
    height: 80px;
  }

  .footer-content-1 {
    height: 220px;
  }

  .footer-content-1 span {
    letter-spacing: 3px;
    display: block;
    text-align: left;
    line-height: 40px;
    margin-left: 40px;
    height: 35px;
    font-size: 16px;
  }

  .footer-content-2 {
    height: 110px;
    line-height: 24px;
    text-align: left;
  }
</style>

2.3 商品详情页面搭建

点击查看代码
<template>
  <div>
    <el-container>
      <el-row>
        <el-col :span="12">
          <div class="grid-content bg-purple-dark">
            <div class="nav nav-1">
              <el-link type="info">首页</el-link>
            </div>
            <div class="nav">
              <el-link type="info">官网</el-link>
            </div>
          </div>
        </el-col>

        <el-col v-if="!islogin" :span="6">
          <div class="grid-content bg-purple-dark">
            <div class="nav nav-1">
              <el-link type="info" @click="$router.push('/login')">请登录</el-link>
            </div>
            <div class="nav">
              <el-link type="info">注册</el-link>
            </div>
          </div>
        </el-col>

        <el-col v-if="islogin" :span="6">
          <div class="grid-content bg-purple-dark">
            <div class="nav nav-1">
              <el-link type="info"><span>欢迎你,{{username}}</span></el-link>
            </div>
            <div class="nav">
              <el-link type="info" @click="$router.push('/logout')">注销</el-link>
            </div>
          </div>
        </el-col>

        <el-col :span="6">
          <div class="grid-content bg-purple-dark">
            <div class="nav">
              <el-link type="info">我的订单</el-link>
            </div>
            <div class="nav">
              <el-link type="info">购物车</el-link>
            </div>
          </div>
        </el-col>
      </el-row>

      <el-header height="80px">
        <div class="grid-content bg-purple" align="left" style="float: left">
          <img src="../assets/logo.png" style="width: 205px; height: 36px;margin: 25px 0px 0px 150px">
        </div>
        <div style="float: left; margin-top: 10px;width: 75%">
          <div style="float: left; margin-left: 150px">商品名称:
            <input v-model="proName" class="select select-input"/>
          </div>
          <div style="float: left; margin-left: 30px">
            商品类型:<select v-model="selectedTypeId" class="select select-option">
            <option v-for="option in options" v-bind:value="option.typeId">{{option.typeName}}</option>
          </select>&nbsp;&nbsp;&nbsp;
            价格区间:<input v-model="lprice" class="select select-input-price"/>-<input v-model="hprice"
                                                                                    class="select select-input-price"/>
            <el-button type="primary" icon="el-icon-search"
                       @click="select()"></el-button>
          </div>
        </div>

      </el-header>
      <div style="width: 99%;border: 1px solid #000;margin-bottom: 8px"></div>
      <el-container>

        <el-aside width="550px">
          <el-row>
            <el-col :span="8">
              <div class="bg-purple">
                <img class="proimg" :src="pro.pimg">
              </div>
            </el-col>
          </el-row>
        </el-aside>

        <el-main>
          <div style="margin-left: 80px;line-height: 80px">
            <div><h3>商品名称:{{pro.pname}}</h3></div>
            <div><h3>商品价格:<span style="color: red;color: red">¥{{pro.price}}</span></h3></div>
            <div><h3>商品数量:{{pcount}}</h3></div>


            <div>
              <el-input-number v-model="pcount" :step="1" :min="1"></el-input-number>
              <el-button type="danger" @click="gtCart()">加入购物车</el-button>
            </div>
          </div>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
    export default {
        name: "ProductInfo",
        data() {
            return {
                pid: this.$route.params.pid,
                pro: {
                    pimg: ''
                },
                options: this.$route.params.options,
                selectedTypeId: '',
                proName: '',
                lprice: '',
                hprice: '',
                pcount: 1,
                username: this.$store.getters.getUser.userNickname,
                islogin: this.$store.getters.getUser == null ? false : true
            }
        },
        created() {
            this.getProduct();
        },
        methods: {
            getProduct() {
                var vm = this;
                this.axios({
                    method: 'GET',
                    url: 'http://localhost:8090/product/getProductBypid?pid=' + vm.pid
                }).then(function (resp) {
                    vm.pro = resp.data;
                })
            },
            gtCart: function () {
                var p = {
                    userId: this.$store.getters.getUser.userId,
                    pid: this.pro.pid,
                    pcount: this.pcount,
                    options: this.options
                };
                this.$router.push({name: 'Cart', params: p});
            }
        }
    }
</script>

<style scoped>
  .el-header, .el-footer {
    color: #333;
    text-align: center;
    line-height: 60px;
  }

  .proimg {
    width: 400px;
    height: 500px;
  }

  .el-main {
    color: #333;
    text-align: left;
    padding: 10px 0px 50px 0px;
  }

  .el-button {
    margin-left: 30px;
  }

  .el-aside {
    padding-left: 80px;
  }

  .bg-purple-dark {
    background: #000000;
  }

  .grid-content {
    min-height: 36px;
    height: 45px;
  }

  .nav {
    float: left;
    margin: 10px 0px 0px 30px;
  }

  .nav-1 {
    margin-left: 200px;
  }

  .select {
    border-radius: 5px;
    border: #E9EEF3;
    height: 35px;
    border: 1px solid #000000;
  }

  .select-input {
    width: 160px;
  }

  .select-option {
    margin-right: 10px;
    width: 125px;
  }

  .select-input-price {
    width: 75px;
  }

</style>

2.4 购物车页面搭建

点击查看代码
<template>
  <el-container>
    <el-row>
      <el-col :span="12">
        <div class="grid-content bg-purple-dark">
          <div class="nav nav-1">
            <el-link type="info">首页</el-link>
          </div>
          <div class="nav">
            <el-link type="info">官网</el-link>
          </div>
        </div>
      </el-col>

      <el-col v-if="!islogin" :span="6">
        <div class="grid-content bg-purple-dark">
          <div class="nav nav-1">
            <el-link type="info" @click="$router.push('/login')">请登录</el-link>
          </div>
          <div class="nav">
            <el-link type="info">注册</el-link>
          </div>
        </div>
      </el-col>

      <el-col v-if="islogin" :span="6">
        <div class="grid-content bg-purple-dark">
          <div class="nav nav-1">
            <el-link type="info"><span>欢迎你,{{username}}</span></el-link>
          </div>
          <div class="nav">
            <el-link type="info" @click="$router.push('/logout')">注销</el-link>
          </div>
        </div>
      </el-col>

      <el-col :span="6">
        <div class="grid-content bg-purple-dark">
          <div class="nav">
            <el-link type="info">我的订单</el-link>
          </div>
          <div class="nav">
            <el-link type="info">购物车</el-link>
          </div>
        </div>
      </el-col>
    </el-row>

    <el-header height="80px">
      <div class="grid-content bg-purple" align="left" style="float: left">
        <img src="../assets/logo.png" style="width: 205px; height: 36px;margin: 25px 0px 0px 150px">
      </div>
      <div style="float: left; margin-top: 10px;width: 75%">
        <div style="float: left; margin-left: 150px">商品名称:
          <input v-model="proName" class="select select-input"/>
        </div>
        <div style="float: left; margin-left: 30px">
          商品类型:<select v-model="selectedTypeId" class="select select-option">
          <option v-for="option in options" v-bind:value="option.typeId">{{option.typeName}}</option>
        </select>&nbsp;&nbsp;&nbsp;
          价格区间:<input v-model="lprice" class="select select-input-price"/>-<input v-model="hprice"
                                                                                  class="select select-input-price"/>
          <el-button type="primary" icon="el-icon-search"
                     @click="select()"></el-button>
        </div>
      </div>
    </el-header>

    <el-main>
      <h2>我的购物车信息</h2>
      <div align="center">
        <el-table
                ref="multipleTable"
                :data="tableData"
                tooltip-effect="dark"
                style="width:820px"
                :header-cell-style="{'text-align':'center'}"
                :cell-style="{'text-align':'center'}"
                @selection-change="handleSelectionChange">
          <el-table-column
                  type="selection"
                  width="100">
          </el-table-column>

          <el-table-column
                  prop="pname"
                  label="商品名称"
                  width="300">
          </el-table-column>

          <el-table-column
                  prop="price"
                  label="商品价格"
                  width="200">
          </el-table-column>

          <el-table-column
                  prop="pcount"
                  label="商品数量"
                  width="200"
                  show-overflow-tooltip>
          </el-table-column>
        </el-table>
      </div>

      <div align="left">
        <el-button class="el-button--success" @click="">管理(删除订单)</el-button>
        <el-button class="el-button--danger" @click="open">结算(提交订单)</el-button>
      </div>
      <router-view></router-view>
    </el-main>

  </el-container>

</template>

<script>

    export default {
        name: "Cart",
        data() {
            return {
                tableData: [{
                    pname: 'HUAWEI P30',
                    price: '6778',
                    pcount: 2
                }],
                multipleSelection: [],
                userId: this.$route.params.userId,
                pid: this.$route.params.pid,
                pcount: this.$route.params.pcount,
                totalMoney: 0,
                options: this.$route.params.options,
                selectedTypeId: '',
                lprice: '',
                hprice: '',
                proName: '',
                username: this.$store.getters.getUser.userNickname,
                islogin: this.$store.getters.getUser == null ? false : true
            }
        },
        created() {
            this.getTableDate();
        },
        methods: {
            handleSelectionChange(val) {
                //当多选框变化是调用的函数
                this.totalMoney = 0;
                this.multipleSelection = val;
                // console.log(this.multipleSelection)
                this.multipleSelection.forEach(row => {
                    //获取选中的每一行的数据
                    // console.log(row);
                    this.totalMoney += row.price * row.pcount;
                })
            },
            getTableDate() {
                var vm = this;
                this.axios({
                    method: 'GET',
                    url: 'http://localhost:8090/cart/addCart?userId=' + vm.userId + '&pid=' + vm.pid + '&pcount=' + vm.pcount
                }).then(function (resp) {
                    console.log(resp.data);
                    vm.tableData = resp.data
                })
            },
            open() { // 打开提交订单的表单
                var p = {
                    uId: this.userId,
                    totalMoney: this.totalMoney,
                    pIds: [],
                    opt: this.options,
                };
                //获取选中的每一行的商品的id
                var i = 0;
                this.multipleSelection.forEach(row => {
                    p.pIds[i] = row.pid;
                    i++;
                });
                this.$router.push({name: 'CartForm', params: p});
            }
        }
    }
</script>

<style scoped>

  .el-header, .el-footer {
    color: #333;
    text-align: center;
    line-height: 60px;
  }


  .bg-purple-dark {
    background: #000000;
  }

  .grid-content {
    min-height: 36px;
    height: 45px;
  }

  .el-main {
    color: #333;
    text-align: center;
    /*line-height: 560px;*/
    /*height: 800px;*/
    padding: 10px 0px 50px 0px;
  }

  .nav {
    float: left;
    margin: 10px 0px 0px 30px;
  }

  .nav-1 {
    margin-left: 200px;
  }

  .select {
    border-radius: 5px;
    border: #E9EEF3;
    height: 35px;
    border: 1px solid #000000;
  }

  .select-input {
    width: 160px;
  }

  .select-option {
    margin-right: 10px;
    width: 125px;
  }

  .select-input-price {
    width: 75px;
  }

  .el-button--success {
    margin: 30px 200px 30px 500px;
  }

</style>

2.5 订单页面搭建

点击查看代码
<template>
  <el-container>
    <el-row>
      <el-col :span="12">
        <div class="grid-content bg-purple-dark">
          <div class="nav nav-1">
            <el-link type="info">首页</el-link>
          </div>
          <div class="nav">
            <el-link type="info">官网</el-link>
          </div>
        </div>
      </el-col>

      <el-col v-if="!islogin" :span="6">
        <div class="grid-content bg-purple-dark">
          <div class="nav nav-1">
            <el-link type="info" @click="$router.push('/login')">请登录</el-link>
          </div>
          <div class="nav">
            <el-link type="info">注册</el-link>
          </div>
        </div>
      </el-col>

      <el-col v-if="islogin" :span="6">
        <div class="grid-content bg-purple-dark">
          <div class="nav nav-1">
            <el-link type="info"><span>欢迎你,{{username}}</span></el-link>
          </div>
          <div class="nav">
            <el-link type="info" @click="$router.push('/logout')">注销</el-link>
          </div>
        </div>
      </el-col>

      <el-col :span="6">
        <div class="grid-content bg-purple-dark">
          <div class="nav">
            <el-link type="info">我的订单</el-link>
          </div>
          <div class="nav">
            <el-link type="info">购物车</el-link>
          </div>
        </div>
      </el-col>
    </el-row>

    <el-header height="80px">
      <div class="grid-content bg-purple" align="left" style="float: left">
        <img src="../assets/logo.png" style="width: 205px; height: 36px;margin: 25px 0px 0px 150px">
      </div>
      <div style="float: left; margin-top: 10px;width: 75%">
        <div style="float: left; margin-left: 150px">商品名称:
          <input v-model="proName" class="select select-input"/>
        </div>
        <div style="float: left; margin-left: 30px">
          商品类型:<select v-model="selectedTypeId" class="select select-option">
          <option v-for="option in options" v-bind:value="option.typeId">{{option.typeName}}</option>
        </select>&nbsp;&nbsp;&nbsp;
          价格区间:<input v-model="lprice" class="select select-input-price"/>-<input v-model="hprice"
                                                                                  class="select select-input-price"/>
          <el-button type="primary" icon="el-icon-search"
                     @click="select()"></el-button>
        </div>
      </div>
    </el-header>

    <el-main>
      <div v-for="order in orders" align="center" style="border: 1px solid black;margin-bottom: 10px;">
        <el-table
                :data="order.products"
                highlight-current-row
                :header-cell-style="{'text-align':'center'}"
                :cell-style="{'text-align':'center'}"
                style="width: 98%">

          <el-table-column type="expand">

            <el-table
                    :data="order.products"
                    :header-cell-style="{'text-align':'center'}"
                    style="width: 95%">

              <el-table-column label="商品名称" width="400">
                <template slot-scope="scope">
                  <span style="margin-left: 10px;margin-left: 100px;">{{ scope.row.pname }}</span>
                </template>
              </el-table-column>

              <el-table-column label="商品价格" width="200" align="center">
                <template slot-scope="scope">
                  <span size="medium">{{ scope.row.price }}</span>
                </template>
              </el-table-column>

              <el-table-column label="商品数量" width="200" align="center">
                <template slot-scope="scope">
                  <span size="medium">{{ scope.row.pcount }}</span>
                </template>
              </el-table-column>

              <el-table-column label="操作" width="450" align="center">
                <template slot-scope="scope">
                  <el-button
                          size="mini"
                          type="danger"
                          @click="handleDelete(scope.$index, scope.row)">删除</el-button>
                  <el-button
                          size="mini"
                          type="primary"
                          @click="pay(order)">支付</el-button>
                </template>
              </el-table-column>
            </el-table>

          </el-table-column>


          <el-table-column :label="'订单创建时间:'+order.createdTime"/>

          <el-table-column :label="'订单编号:'+order.orderId"/>

          <el-table-column :label="'订单总金额:¥'+order.orderPrice"/>

          <el-table-column label="订单支付"/>

        </el-table>
      </div>

    </el-main>
  </el-container>
</template>

<script>

    export default {
        name: "Orders",
        data() {
            return {
                user: this.$store.getters.getUser,
                payImgSrc: '',
                orderId: '',
                orders: [{
                    createTime: '',
                    order_id: '',
                    orderPrice: 4777,
                    products: [{
                        pname: '',
                        price: 0,
                        pcount: 0
                    }]
                }],
                falg: '',
                selectedTypeId: '',
                options: this.$route.params.op,
                lprice: '',
                hprice: '',
                proName: '',
                username: this.$store.getters.getUser.userNickname,
                islogin: this.$store.getters.getUser == null ? false : true
            }
        },
        created() {
            this.getData();
        },
        methods: {
            getData() {
                var vm = this;
                this.axios({
                    method: 'GET',
                    url: 'http://localhost:8090/order/list?userId=' + vm.user.userId
                }).then(function (resp) {
                    vm.orders = resp.data;
                      console.log(vm.orders[0]["products"][0]);
                });
            },
            pay(order) {
                var d = {
                    orderId: order.orderId,
                    orderPrice: order.orderPrice
                };
                this.$router.push({name: 'Pay', params: d})
            }
        }
    }
</script>

<style scoped>
  .el-header {
    background-color: #ffffff;
    color: #333;
    text-align: center;
    line-height: 60px;
  }

  .bg-purple-dark {
    background: #000000;
  }

  .grid-content {
    min-height: 36px;
    height: 45px;
  }

  .nav {
    float: left;
    margin: 10px 0px 0px 30px;
  }

  .nav-1 {
    margin-left: 200px;
  }

  .select {
    border-radius: 5px;
    border: #E9EEF3;
    height: 35px;
    border: 1px solid #000000;
  }

  .select-input {
    width: 160px;
  }

  .select-option {
    margin-right: 10px;
    width: 125px;
  }

  .select-input-price {
    width: 75px;
  }

</style>

2.6 解决VUEX中刷新数据不存在的问题

前端页面中要显示的当前登录的用户名,可通过后端接口得到,也可直接从浏览器中获取(登录成功后),此处介绍后者使用情况,在实现过程中如果遇到用户名刷新页面即丢失的情况,可按照如下步骤解决!

使用SessionStorage进行解决!

  • SessionStorage浏览器提供的用于会话管理的空间

  • 如何操作这片空间,在js中:

    • sessionStorage.setItem("键","值")
    • sessionStorage.getItem("键"):值
    • sessionStorage.clear() 清空

使用步骤:

  • 在src文件夹下创建store/index.js

    点击查看代码
     import Vue from 'vue'
     import Vuex from 'vuex'
     
     Vue.use(Vuex);
     
     // 全局 state 对象,用于保存所有组件的公共数据
     const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
         user: {
             username: ''
         }
     };
     
     // 实时监听 state 值的最新状态,注意这里的 getters 可以理解为计算属性
     const getters = {
         // 在组件中是通过 this.$store.getters.getUser 来获取
         getUser(state) {
             return state.user;
         }
     };
     
     // 定义改变 state 初始值的方法,这里是唯一可以改变 state 的地方,缺点是只能同步执行
     const mutations = {
         // 在组件中是通过 this.$store.commit('updateUser', user); 方法来调用 mutations
         updateUser(state, user) {
             state.user = user;
         }
     };
     
     // 定义触发 mutations 里函数的方法,可以异步执行 mutations 里的函数
     const actions = {
         // 在组件中是通过 this.$store.dispatch('asyncUpdateUser', user); 来调用 actions
         asyncUpdateUser(context, user) {
             context.commit('updateUser', user);
         }
     };
     
     export default new Vuex.Store({
         state,
         getters,
         mutations,
         actions
     });
    

  • 在main.js中添加如下配置

    点击查看代码
      // 在跳转前执行
      router.beforeEach((to, form, next) => {
          // 获取用户登录状态
          let isLogin = sessionStorage.getItem('isLogin');
          // 注销
          if (to.path == '/logout') {
              // 清空
              sessionStorage.clear();
              // 跳转到登录
              next({path: '/login'});
          }
          // 如果请求的是登录页
          else if (to.path == '/login') {
              if (isLogin != null) {
                  // 跳转到首页
                  next({path: '/home'});
              }
          }
          // 如果为非登录状态
          else if (isLogin == null) {
              // 跳转到登录页
              next({path: '/login'});
          }
          // 下一个路由
          next();
      });
    
  • 在登录Login.vue组件中添加

    var user = resp.data.data;
    sessionStorage.setItem("isLogin", "true")
    //往vuex里存放一个user对象
    //先要有user对象
    //再存到vuex里
    vm.$store.dispatch('asyncUpdateUser', user);
    
  • 再在首页Home.vue组件里获取vuex对象里的user对象的内容

    username: this.$store.getters.getUser.userNickname
    

3、前后端建立连接的桥梁--->接口文档的编写

注:访问密码---->123456

posted @ 2021-08-31 16:14  W-D-G  阅读(631)  评论(0编辑  收藏  举报