vue+Element-ui快餐店pos系统

视频地址:vue 2.0项目-快餐店pos系统

1.项目搭建

1.新建项目

新建一个空文件夹AwesomePos并在VScode中打开。

首先安装一下vue-cli

npm install vue-cli -g

要验证是否安装成功的话输入:vue -V,如果出现版本号说明安装成功。

然后是用脚手架初始化项目(因为项目文件夹已经建好了所以webpack后面不用再跟参数了):

vue init webpack

然后是进行一些初始化的项目配置:项目名(要小写),项目作者等等。

Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
// 别的一些配置全部回车即可

接着执行一下npm install下载一些依赖包。

最后可以执行npm run dev来看一下项目初始化完成了没,如果能在浏览器中正常打开页面,说明安装正确。

2.修改部分文件

修改一下index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>AwesomePOS快餐店收银系统</title> // 重命名一下网页标题
    <style>
      html,body,#app{height:100%;padding: 0;margin:0;} //重新调整一下css样式
    </style>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

还可以把App.vue中的vue的logo图给删掉:

<template>
  <div id="app">
    <!-- <img src="./assets/logo.png"> --> //vuelogo图
    <router-view/>
  </div>
</template>
...
3.新建组件Pos.vue

components文件夹下新建一个Pos.vue作为入口文件然后写出vue模板的基本架构即可:

<template>
    <div class="pos">
        Hello AwesomePOS Demo.
    </div>
</template>

<script>
export default {
  name: 'pos'
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

4.修改路由文件

修改一下路由配置文件,让入口变成Pos组件:

import Vue from 'vue'
import Router from 'vue-router'
import Pos from '@/components/Pos'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Pos',
      component: Pos
    }
  ]
})

至此为止,项目的基本配置运行环境全部完成。

2.项目图标

图标采用的是阿里巴巴矢量图标库里的天猫图标库,步骤如下:

  • 在图标库中选择你想要的图标,添加至购物车。然后添加到项目,如果没有就自己新建一个。在这里插入图片描述
  • 如果选择在线使用的话,就生成在线链接,然后将链接在你要使用的页面中通过Link引入:
    在这里插入图片描述
<title>AwesomePOS快餐店收银系统</title>
<link rel="stylesheet" href="http://at.alicdn.com/t/font_2351615_fprn7byotcn.css">

接着就可以在App.vue中使用i标签来引入图标了:

<i class="icon iconfont icon-dianpu"></i>
// icon iconfont 这两个类名都是固定的,最后一个根据图标的不同而不同

注意如果后面又加入了几个图标,那么需要重新将新增的图标添加至项目,然后更新在线链接,并重新引入链接才能使用新图标。

3.侧边栏导航组件

首先在components文件夹下新建两个文件夹commonpage

  • common文件夹用来放共用组件,下面写的leftNav.vue组件就放到这里。
  • page文件夹用来放页面模板组件,页面的模板文件放到这里。将Hello.vuePos.vue放在这里面。

然后编写leftNav.vue

<template>
  <div class="left-nav">
        <ul>
            <li>
                <i class="icon iconfont icon-goumai"></i>
                <div>收银</div>
            </li>

            <li>
                <i class="icon iconfont icon-dianpu"></i>
                <div>店铺</div>
            </li>

            <li>
                <i class="icon iconfont icon-hanbao"></i>
                <div>商品</div>
            </li>

                <li>
                <i class="icon iconfont icon-huiyuanqia"></i>
                <div>会员</div>
            </li>


            <li>
                <i class="icon iconfont icon-gongnengjianyi"></i>
                <div>统计</div>
            </li>
        </ul>
  </div>
</template>

<script>
export default {
  name: 'leftNav',
  data () {
    return {
    }
  }
}
</script>
<style>
.left-nav{
       color:#fff;
       font-size:10px;
       height:100%;
       background-color: #1D8ce0;
       float:left;
       width:5%;
    }
    .iconfont{
       font-size:24px;
    }
    .left-nav ul{
        padding:0px;
        margin: 0px;
    }
    .left-nav li{
        list-style: none;
        text-align: center;
        border-bottom:1px solid #20a0ff;
        padding:10px;
    }
</style>

然后就是将leftNav.vue引入到App.vue中去并写到页面上:

<template>
  <div id="app">
    <!-- <img src="./assets/logo.png"> -->
    <!--左侧导航-->

        <leftNav></leftNav>

    <!--操作区域-->
    <div class="main">
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
import leftNav from '@/components/common/leftNav'
export default {
  name: 'App',
  components:{
    leftNav
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  height: 100%;
  /* margin-top: 60px; */
}
.main {
  float: left;
  width: 95%;
  background-color: #3FF2F7;
  height:100%;
  overflow: auto;
}
</style>

至此为止,侧边导航栏已经基本完成。

4.Element组件库

Element是一套基于 Vue 2.0 的桌面端组件库。

首先安装一下element-ui,使用下面的命令:

npm install element-ui --save

接着导入:

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
// 如果出现报错,检查路径是否正确,视频中写的是theme-default,但是现在好像已经更新为了theme-chalk

element-ui使用的是栅格化布局,能适应多端页面显示。可以在Pos.vue中尝试一下布局:

<div>
    <el-row >
        <el-col :span='7' class="pos-order">
        	我是订单栏
        </el-col>
        <!--商品展示-->
        <el-col :span="17">
        	我是产品栏
        </el-col>
    </el-row>
</div>

然后调整一下css样式:

.pos-order {
  background-color: #F9FAFC;
  border-right: 1px solid #C0CCDA;
}

但是实际显示的效果的高度并不是100%在css样式中也调整不了height的值

这个时候要用到js以及钩子函数mounted来调整高度100%

<template>
    <div class="pos">
        <el-row>
          <el-col :span="7" class="pos-order" id="order-list">
            我是订单栏
          </el-col>
          <el-col :span="17">
            我是产品栏
          </el-col>
        </el-row>
    </div>
</template>

<script>
export default {
  name: 'pos',
  mounted:function(){ //等全部的虚拟DOM(ElementUI)加载完成之后调整高度
    var orderHeight = document.body.clientHeight;
    // console.log(orderHeight);
    document.getElementById('order-list').style.height=orderHeight+'px';
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.pos-order {
  background-color: #F9FAFC;
  border-right: 1px solid #C0CCDA;
}
</style>

最终实现效果如下图:

在这里插入图片描述

最左侧的是导航栏,中间的是订单栏,右侧的是产品栏。

5.利用Element快速布局-1

1.el-tabs标签页组件
<el-col :span="7" class="pos-order" id="order-list">
    <el-tabs type="card"> //如果对标签页的样式不满意可以自己调整,例如type="card"
        <el-tab-pane label="点餐"> //label属性的值就是标签页的名字
        	点餐 //这里就是"点餐"标签页中的内容
        </el-tab-pane>
        <el-tab-pane label="挂单">
        	挂单
        </el-tab-pane>
        <el-tab-pane label="外卖">
        	外卖
        </el-tab-pane>
    </el-tabs>
</el-col>
2.el-table表格组件
<el-table :data="tableData" border style="width:100%" stripe :cell-style="rowClass"  :header-cell-style="headClass">
    <el-table-column prop="goodsName" label="名称" width="150"></el-table-column>
    <el-table-column prop="goodsCount" label="数量"></el-table-column>
    <el-table-column prop="goodsPrice" label="金额"></el-table-column>
    <el-table-column label="操作" fixed="right">
    	<template slot-scope="scope">
            <el-button type="text" size="small">删除</el-button>
            <el-button type="text" size="small">增加</el-button>
    	</template>
    </el-table-column>
</el-table>
<script>
export default {
  name: 'pos',
  data(){
    return {
      tableData: [{
          goodsName: '可口可乐',
          goodsPrice: 8,
          goodsCount:1
        }, {

          goodsName: '香辣鸡腿堡',
          goodsPrice: 15,
          goodsCount:1
        }, {

          goodsName: '爱心薯条',
          goodsPrice: 8,
          goodsCount:1
        }, {

          goodsName: '甜筒',
          goodsPrice: 8,
          goodsCount:1
        }]
    }
  },
  mounted:function(){ //等全部的虚拟DOM(ElementUI)加载完成之后调整高度
    var orderHeight = document.body.clientHeight;
    // console.log(orderHeight);
    document.getElementById('order-list').style.height=orderHeight+'px';
  },
   methods: {
      // 表头样式设置
      headClass () {
          return 'text-align: center;' //文字居中
      },
      // 表格样式设置
      rowClass () {
          return 'text-align: center;' //文字居中
      }
   }
}
</script>

在上面的代码中,:data="tableData"用来绑定表格中的数据源(这里是先在js中写死);:cell-style="rowClass" :header-cell-style="headClass"以及在js中的methods中的两个方法headClass,rowClass用来让表格的表头以及内容文字居中fixed="right"的作用是将最后一列操作列固定在右侧,使得表格内容在滑动时,右侧的操作栏始终不动

注意,在写<template slot-scope="scope">的时候,如果slot-scope="scope"(scope="scope"已经不适配最新版Vue)报错,进入VScode设置,把Vetur>Validation:Template的勾给去掉。如下图:

在这里插入图片描述

3.el-button 按钮组件

接下去就是在表格的下方增加三个功能按钮

<div class="div-btn">
    <el-button type="warning">挂单</el-button>
    <el-button type="danger">删除</el-button>
    <el-button type="success">结账</el-button>
</div>
...
<style scoped>
.div-btn {
  margin-top: 10px;
}
</style>

6.利用Element快速布局-2

接下去就是进行产品栏的布局。

1.常用商品
<div class="often-goods">
    <div class="title">常用商品</div>
    <div class="often-goods-list">
        <ul>
            <li>
                <span>香辣鸡腿堡</span>
                <span class="o-price">¥15元</span>
            </li>
        </ul>
    </div>
</div>
...
<style scoped>
.pos-order {
  background-color: #F9FAFC;
  border-right: 1px solid #C0CCDA;
}
.div-btn {
  margin-top: 10px;
}
.title{
  height: 20px;
  border-bottom:1px solid #D3DCE6;
  background-color: #F9FAFC;
  padding:10px;
  text-align: center;
}
.often-goods-list ul li{
  list-style: none;
  float:left;
  border:1px solid #E5E9F2;
  padding:10px;
  margin:5px;
  background-color:#fff;
}
.o-price{
  color:#58B7FF; 
}
</style>

然后可以在js中申明多个数据列表并渲染到页面中去:

<li v-for="oftenGood in oftenGoods">
    <span>{{oftenGood.goodsName}}</span>
    <span class="o-price">💰{{oftenGood.price}}</span>
</li>
...
oftenGoods:[
    {
        goodsId:1,
        goodsName:'香辣鸡腿堡',
        price:18
    }, {
        goodsId:2,
        goodsName:'田园鸡腿堡',
        price:15
    }, {
        goodsId:3,
        goodsName:'和风汉堡',
        price:15
    }, {
        goodsId:4,
        goodsName:'快乐全家桶',
        price:80
    }, {
        goodsId:5,
        goodsName:'脆皮炸鸡腿',
        price:10
    }, {
        goodsId:6,
        goodsName:'魔法鸡块',
        price:20
    }, {
        goodsId:7,
        goodsName:'可乐大杯',
        price:10
    }, {
        goodsId:8,
        goodsName:'雪顶咖啡',
        price:18
    }, {
        goodsId:9,
        goodsName:'大块鸡米花',
        price:15
    }, {
        goodsId:20,
        goodsName:'香脆鸡柳',
        price:17
    }
]
2.分类商品
<div class="goods-type">
    <el-tabs type="border-card">
        <el-tab-pane label="汉堡">
            <div>
                <ul class='cookList'>
                    <li v-for="goods in type0Goods">
                        <span class="foodImg"><img :src="goods.goodsImg" width="100%"></span>
                        <span class="foodName">{{goods.goodsName}}</span>
                        <span class="foodPrice">¥{{goods.price}}元</span>
                    </li>
                </ul>
            </div>
        </el-tab-pane>
        <el-tab-pane label="小食">
        	小食
        </el-tab-pane>
        <el-tab-pane label="饮料">
        	饮料
        </el-tab-pane>
        <el-tab-pane label="套餐">
        	套餐
        </el-tab-pane>
    </el-tabs>
</div>
...
type0Goods:[
    {
        goodsId:1,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'香辣鸡腿堡',
        price:18
    }, {
        goodsId:2,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'田园鸡腿堡',
        price:15
    }, {
        goodsId:3,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'和风汉堡',
        price:15
    }, {
        goodsId:4,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'快乐全家桶',
        price:80
    }, {
        goodsId:5,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'脆皮炸鸡腿',
        price:10
    }, {
        goodsId:6,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'魔法鸡块',
        price:20
    }, {
        goodsId:7,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'可乐大杯',
        price:10
    }, {
        goodsId:8,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'雪顶咖啡',
        price:18
    }, {
        goodsId:9,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'大块鸡米花',
        price:15
    }, {
        goodsId:20,
        goodsImg:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2506175111,2572218063&fm=26&gp=0.jpg",
        goodsName:'香脆鸡柳',
        price:17
    }
]
...
.goods-type {
	clear: both;
}
.cookList li{
    list-style: none;
    width:23%;
    border:1px solid #E5E9F2;
    height: auot;
    overflow: hidden;
    background-color:#fff;
    padding: 2px;
    float:left;
    margin: 2px;
}
.cookList li span{
    display: block;
    float:left;
}
.foodImg{
	width: 40%;
}
.foodName{
    font-size: 18px;
    padding-left: 10px;
    color:brown;
}
.foodPrice{
    font-size: 16px;
    padding-left: 10px;
    padding-top:10px;
}

常用商品和分类商品编写逻辑和格式其实差不多,至此为止页面布局已经全部完成(页面内的数据目前仍然是写死的)。接下去就是动态获取到数据渲染到页面中。

7.Axios从远程获取数据

首先安装一下Axios,使用命令:

npm n install axios --save

或者

npm install --save axios

接着在Pos.vue中引入:

import axios from 'axios'

然后用钩子函数通过服务端获取数据,方法如下:

created(){
    axios.get('后端接口地址')
    .then(response=>{
        console.log(response);
        this.oftenGoods=response.data;
    })
    .catch(error=>{
        console.log(error);
        alert('网络错误,不能访问');
    })
},

如果自己没有后端接口地址,那么可以用vue-mock来自己建立一个简单的后端数据接口来模拟请求。

8.逻辑功能的实现

1.添加商品到订单页面

添加商品的功能具体描述就是:点击常用商品或者分类商品中的某个商品,会把它添加到左侧点餐栏处,如果相同商品点击第二次那么该商品的数量会+1。

addOrderList(goods) {
    let isHave = false; //默认不存在
    // 判断商品是否已经存在于点餐栏中
    for(let i = 0;i<this.tableData.length;i++) {
        if(this.tableData[i].goodsId==goods.goodsId) {
        	isHave=true;     
    	}
    }
    if(isHave) {  //如果有,商品对应的数量+1
        let arr = this.tableData.filter(o=>o.goodsId == goods.goodsId)
        arr[0].goodsCount ++;
    } else {  //如果没有,商品添加到点餐栏中
        let newGoods = {goodsId:goods.goodsId,goodsName:goods.goodsName,goodsPrice:goods.goodsPrice,goodsCount:1} //新商品   
        this.tableData.push(newGoods);         
    }
}

在对应的商品元素上绑定好方法(包括常用商品和分类商品中的所有):

<ul>
    <li v-for="oftenGood in oftenGoods" @click="addOrderList(oftenGood)">
        <span>{{oftenGood.goodsName}}</span>
        <span class="o-price">💰{{oftenGood.goodsPrice}}</span>
    </li>
</ul>
2.操作栏中的增加功能

在操作栏中的增加功能只需要调用同样的方法就可以了:

<el-button type="text" size="small" @click="addOrderList(scope.row)">增加</el-button>

scope.row是elementUI中规定的语法,相当于就是把这一行的对象数据作为参数传递过去。

3.操作栏中的删除功能

因为删除完成后,商品的总数量和总金额都得重新计算,所以把计算总数量和总金额封装在一个方法中:

getAllMoney(){                        //汇总数量和金额
    this.totalCount=0;
    this.totalMoney=0;
    if(this.tableData){
        this.tableData.forEach((element) => {
        this.totalCount+=element.goodsCount;
        this.totalMoney=this.totalMoney+(element.goodsPrice*element.goodsCount);   
    	});
    }
}

然后写删除商品的逻辑

<el-button type="text" size="small" @click="delOrderList(scope.row)">增加</el-button>
...
delOrderList(goods) {                 //删除商品
    console.log(goods);
    this.tableData=this.tableData.filter(o => o.goodsId !=goods.goodsId);
    this.getAllMoney();
},
4.全部删除功能
<el-button type="danger" @click="delAllGoods">删除</el-button>
...
//删除所有商品
delAllGoods() {
    this.tableData = [];
    this.getAllMoney();
},
5.结账功能
<el-button type="success" @click="checkout">结账</el-button>
...
checkout() {
    if (this.totalCount!=0) {
        this.tableData = [];
        this.totalCount = 0;
        this.totalMoney = 0;
        this.$message({
            message: '结账成功,感谢你又为店里出了一份力!',
            type: 'success'
        });
    }else{
        this.$message.error('不能空结。老板了解你急切的心情!');
    }
}

9.项目打包和上线

关于打包路径的一些设置在config文件夹下的index.js文件中的build属性中:

  build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',

    /**
     * Source Maps
     */

    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }

把里面的assetsPublicPath: '/',改成:

assetsPublicPath: './',

这样才能保证我们打包出去的项目可以正常预览。

打包使用到的命令为:

npm run build

打包成功后的提示为:

在这里插入图片描述

完成之后会在项目目录下生成一个dist文件夹,双击打开里面的index.html文件就是刚完成的页面,如果能成功打开并且测试也成功,说明打包成功了。
最终实现效果如下图:
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偶尔躲躲乌云_0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值