springboot vue 开源 会员收银系统 (6) 收银台的搭建

前言

完整版演示

前面我们对会员系统 分类和商品的开发 完成了收银所需的基础信息 下面我们开始完成收银台的开发

简单画了一个收银的流程图大家参考下
收银流程图

从这张图我们可以分析一下几点

  • 可以选择会员或散客收银
  • 选择会员使用相应的会员价结算
  • 使用会员卡则在价格基础根据卡折扣结算

根据上述分析我搭建了一个简单的收银台
收银台

  • 左边显示会员和已选择的商品信息
  • 右边显示商品的价格信息
  • 商品选择后可以修改数字
  • 总金额自动计算
  • 后续完成挂单功能便于保证收银连续性

开发中运用的组件

  1. Tabs 标签页 和 Card 完成右侧的商品选择
  2. el-autocomplete 完成会员的检索
  3. InputNumber Table 完成购物车开发

收银台运用过多组件会导致页面很乱 我们后续需要进行组件的封装

<template>
  <div class="app-container"  style="border-box:box-sizing;">

<!--    left-->
    <el-row :gutter="30" style="">
      <el-col :span="10">

        <el-autocomplete
          style="width: 100%"
          popper-class="my-autocomplete"
          v-model="querySearchStr"
          :fetch-suggestions="querySearch"
          placeholder="会员检索"
          @select="handleSelect">
          <i
            class="el-icon-search el-input__icon"
            slot="suffix"
           >
          </i>
          <template slot-scope="{ item }">
            <div v-if="item.errorMsg">
              {{item.errorMsg}}
            </div>

            <template v-else>
              <div class="name">
                <i class="el-icon-user"></i>
                {{ item.memberName }}
              </div>
              <span class="addr">
                <i class="el-icon-phone"></i>
                {{ item.memberPhone }}
              </span>
            </template>
          </template>
        </el-autocomplete>

        <el-descriptions  border title="用户信息" v-if="member.memberId" style="margin-top: 20px;margin-bottom: 20px;">
          <el-descriptions-item label="用户名">{{member.memberName}}</el-descriptions-item>
          <el-descriptions-item label="手机号">{{member.memberPhone}}</el-descriptions-item>
          <el-descriptions-item label="备注">
             {{member.remark}}
          </el-descriptions-item>
        </el-descriptions>
        <el-descriptions  border title="用户信息" v-else style="margin-top: 20px;margin-bottom: 20px;">
          <el-descriptions-item label="用户名">散客</el-descriptions-item>
        </el-descriptions>
        <div class="grid-content bg-purple">
          <el-table

            border
            height="400"
            max-height="400"
            :data="shopCart"
            style="width: 100%;margin-bottom: 20px;">

        <el-table-column
          align="center"
          prop="categoryName"
          label="分类"
          width="100">
        </el-table-column>

        <el-table-column
          align="center"
          prop="productName"
          label="商品名"
          >
        </el-table-column>

        <el-table-column
          align="center"
          prop="productAmount"
          label="价格"
          width="100"
        >
          <template slot-scope="scope">
            <span v-if="app.isEmpty(member.memberId)" class="price">{{ scope.row.productAmount }}</span>
            <span v-else="member.memberId" class="price">{{ scope.row.productMemberAmount }}</span>
          </template>
        </el-table-column>

        <el-table-column
          align="center"
          prop="count"
          label="数量"
          width="200"
        >
          <template slot-scope="scope">
            <el-input-number size="mini" :min="0" :max="100" v-model="scope.row.count" @change="handleChange($event,scope)" ></el-input-number>
          </template>
        </el-table-column>

         <el-table-column
           align="center"
          prop="totalPrice"
          label="总金额"
          width="100"
         >
           <template slot-scope="scope">
             <span class="price">{{ scope.row.totalPrice }}</span>
           </template>
        </el-table-column>
      </el-table>
          <el-divider></el-divider>
          总金额: <span class="price">{{app.getFloatStr(getTotalPrice)}}</span>
          <el-divider></el-divider>

          <el-row>
            <el-button type="success">结算</el-button>
            <el-button type="warning">挂单</el-button>
            <el-button type="primary">取单</el-button>
          </el-row>
      </div>
      </el-col>
<!--right-->
      <el-col :span="14">
        <div class="grid-content bg-purple">
        <el-tabs  v-model="activeName" @tab-click="handleClick" type="border-card" style="height: calc(100vh - 180px);width: 100%;overflow: scroll;overflow:hidden;">
          <el-tab-pane
            v-for="(item, index) in categoryList"
            :key="item.categoryId"
            :label="item.categoryName"
            :name="item.categoryId"
          >
            <div>
                <el-row :gutter="20" style="" v-if="productList.length>0">
                <el-col @click.native="chooseProduct(item)" :span="6" v-for="item in productList" :key="item.productId" style="margin-top: 20px;cursor: pointer;">
                  <el-card :body-style="{ padding: '0px' }" style="height: 230px;">

                    <div style="height: 150px;display: flex;align-items: center;justify-content: center; 	box-sizing: border-box;padding-top: 10px;">
                      <img style="width:85%;height: 140px;border-radius: 5px;border: 1px solid #eee;" :src="baseUrl  + item.productImageUrl" class="image"/>
                    </div>
                    <div style="padding:10px 0 0 10px;font-size: 16px;">
                      {{item.productName}}
                    </div>
                    <div style="padding:5px 0 0 10px;">
                      <span style="font-size: 14px;"> 散客价 <span class="price">¥ {{item.productAmount}}</span></span><br/>
                      <span style="font-size: 14px;"> 会员价 <span class="price">¥ {{item.productMemberAmount}}</span></span>
                    </div>

                  </el-card>
                </el-col>
              </el-row>
              <div v-else>
                <el-empty description="该分类商品为空">
                </el-empty>
                </div>
            </div>
          </el-tab-pane>
        </el-tabs>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>
    import {accAdd, accMul,isEmpty} from "@/utils";
    import confirm from "@/utils/confirm";
    import {getCategoryList} from "@/api/business/category/category";
    import {getProductList} from "@/api/business/product/product";
    import {getMemberList} from "@/api/business/member/member";

    export default {
        name: "cashierDesk",
        data(){
          return{
            shopCart: [],
            categoryList: [],
            productList: [],
            activeName: "",
            member: {},
            querySearchStr: '',
          }
        },
      mounted() {
          this.getCategoryList()
      },
      computed:{
        getTotalPrice(){
          let totalPrice = 0;
          for(let product of this.shopCart){
            const noMember = isEmpty(this.member.memberId)
            let productTotalPrice
            if(noMember){
               productTotalPrice = accMul(product.productAmount,product.count)
            }else{
              productTotalPrice = accMul(product.productMemberAmount,product.count)
            }

            this.$set(product, 'totalPrice', productTotalPrice)
            totalPrice = accAdd(totalPrice,productTotalPrice);
          }
          return totalPrice;
        }
      },
      watch:{
        shopCart(newVal,oldVal){
          let showCardList = newVal
          console.log('这是监听属性新的')
        }
      },
      methods:{
        querySearch(queryString, cb) {
            if(queryString){
              getMemberList({querySearch:queryString}).then(res=>{
                // 调用 callback 返回建议列表的数据
                cb(res.data);
              })
            }else{
              cb([
                {errorMsg:'暂无数据'}
              ])
            }

          },
          getCategoryList(){
            getCategoryList().then(res=>{
              this.categoryList = res.data
              if(this.categoryList.length>0){
                this.activeName = this.categoryList[0].categoryId
                getProductList({categoryId:this.activeName }).then(res=>{
                  this.productList = res.data
                })
              }
            })
          },
         handleClick(e){
            //拿到分类id
           const categoryId = e.name
           getProductList({categoryId:categoryId}).then(res=>{
             this.productList = res.data
           })
         },
        handleChange(e,scope){
          console.log(e)
          console.log(scope.$index)
          if(e==0){
            confirm('要删除该条目吗?').then(res=>{
              if(res){
                this.shopCart.splice(scope.$index,1)
              }else{
                this.shopCart[scope.$index].count = 1
              }
            })
          }
        },
        chooseProduct(e){
            let product = e;
            let findProductIndex = this.shopCart.findIndex(p => p.productId ==  product.productId);
            console.log(findProductIndex)
            if(findProductIndex == -1){
              this.$set(product, 'count', 1)
              this.shopCart.push(product)
            }else{
              this.shopCart[findProductIndex].count += 1
            }
            console.log(this.shopCart)
        },
        handleSelect(e){
          console.log(e)
          this.member = e
        }
      }
    }
</script>

<style scoped>
  ::v-deep .el-tabs--border-card>.el-tabs__header .el-tabs__item{
    height: 50px;
    line-height: 50px;
    font-size: 14px;
  }

  .price{
    font-weight: bold;
    color: #ff5b57;
  }
</style>

代码地址
https://gitee.com/ddeatrr/memberShop
然后为了大家预览我把开发板也部署了 大家可以参考
http://store.gbadd.space/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/686361.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Day22 客户端添加IDialogService 弹窗服务

​ 本章节实现了首页点击待办事项或备忘录的时候,弹出一个对话服务窗口 当用户点击首页的“添加备忘录”或“待办事项”按钮时,系统应弹出一个对话框,以便用户执行相关的内容添加操作。下面就开始实现这个弹窗服务。 一.在Views文件夹中,再创建一个Dialog 文件夹,用于放置…

【Selenium+java环境配置】(超详细教程常见问题解决)

Seleniumjava环境配置 windows电脑环境搭建-chrome浏览器1. 下载chrome浏览器2. 查看chrome浏览器版本3. 下载chrome浏览器驱动4.配置系统环境变量PATH 验证环境是否搭建成功1. 创建java项目&#xff0c;添加pom文件中添加依赖2. 编写代码运行 常见问题&解决办法1.访问失败…

防病毒克星——白名单可信系统

白名单作为一种网络安全措施&#xff0c;其核心概念在于限制用户只能访问网络所有者定义的受信任内容。这种机制在保护系统免受恶意软件、病毒等攻击方面发挥着重要作用。然而&#xff0c;关于白名单是否可以防病毒的问题&#xff0c;实际上涉及了多个方面的考虑。 首先&#x…

【C++题解】1074 - 小青蛙回来了

问题&#xff1a;1074 - 小青蛙回来了 类型&#xff1a;需要找规律的循环 题目描述&#xff1a; 关于小青蛙爬井的故事&#xff0c;你应该早就听过了&#xff1a;井深10 尺&#xff0c;小青蛙从井底向上爬&#xff0c;每个白天向上爬 3 尺&#xff0c;每个晚上又滑下来 2 尺&…

基于Sentry+OpenTelemetry实现微服务前后端全链路监控

文章目录 前⾔背景技术⽅案Sentry私有化部署部署环境准备 项目集成前端后端agent探针集成sentry sdk集成增强探针为⽇志注⼊TraceID异常处理SDK⾃定义开发sentry sdk⾃定义开发⾃定义SentryEvent注⼊otel追踪信息⾃定义全局异常上报issue事件新增动态过滤功能 Java Agent Exten…

c++ 里函数选择的优先级:普通函数、模板函数、万能引用,编译器选择哪个执行呢?

看大师写的代码时&#xff0c;除了在类里定义了 copy 构造函数&#xff0c;移动构造函数&#xff0c;还定义了对形参采取万能引用的构造函数&#xff0c;因此有个疑问&#xff0c;这时候的构造函数优先级是什么样的呢&#xff1f;简化逻辑测试一下&#xff0c;如下图&#xff0…

MySQL主从同步优化指南:架构、瓶颈与解决方案

前言 ​ 在现代数据库架构中&#xff0c;MySQL 主从同步是实现高可用性和负载均衡的关键技术。本文将深入探讨主从同步的架构、延迟原因以及优化策略&#xff0c;并提供专业的监控建议。 MySQL 主从同步架构 ​ 主从复制流程&#xff1a; 从库生成两个线程&#xff0c;一个…

语言大模型qwen1.5全流程解析:微调,量化与推理

在前一篇文章中&#xff0c;主要使用llama-factory封装的推理模块对速度进行了测试&#xff0c;vllm速度快些&#xff0c;但仍没有传说中的快3-5倍&#xff0c;需要单独测试。这里使用qwen1.5-1.8B作为测试模型。 qwen1.5是qwen2的先行版&#xff0c;24年2月发布&#xff0c;与…

俯视角2D游戏_02 子弹对象池

[!NOTE] 对象池 应用场合:这种做法常用于子弹这种会大量产生的对象 &#xff0c;目的是减少性能的损耗 基本思路:产生的对象是有限的&#xff0c;并且加入到"对象池"的数组中不进行销毁&#xff0c;当需要使用时&#xff0c;再从对象池中提取对象循环利用&#xff0c…

玩物科技:引领物联网时代的创新先锋

在深圳这座充满活力和创新精神的城市&#xff0c;有一家年轻而充满潜力的公司正在悄然改变我们的日常生活。深圳市玩物科技有限公司自2017年成立以来&#xff0c;凭借其卓越的技术和创新理念&#xff0c;逐渐成为物联网时代的先锋力量。 玩物科技的愿景与使命 玩物科技的核心…

【Linux】进程(7):地址空间

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解Linux进程&#xff08;7&#xff09;&#xff1a;地址空间&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 &#xff08;A&#xff09; 直接看代码&…

MATLAB基础应用精讲-【数模应用】二元Logit分析(最终篇)(附python、MATLAB和R语言代码实现)

目录 算法原理 SPSSAU 1、二元logistic分析思路说明 2、如何使用SPSSAU进行二元logistic操作 3、二元logistic相关问题 算法流程 一、分析前准备 1、确定分析项 2.多重共线性判断 3.数据预处理 二、回归基本情况分析 三、模型拟合评价 1、似然比检验 2、拟合优…

Linux - 深入理解/proc虚拟文件系统:从基础到高级

文章目录 Linux /proc虚拟文件系统/proc/self使用 /proc/self 的优势/proc/self 的使用案例案例1&#xff1a;获取当前进程的状态信息案例2&#xff1a;获取当前进程的命令行参数案例3&#xff1a;获取当前进程的内存映射案例4&#xff1a;获取当前进程的文件描述符 /proc中进程…

【GIS教程】土地利用转移矩阵

随着科技社会的不断进步&#xff0c;人类活动对地理环境的影响与塑造日益明显&#xff0c;土地不断的侵蚀与改变也导致一系列的环境问题日益突出。土地利用/覆盖&#xff08;LUCC&#xff09;作为全球环境变化研究的重点问题为越来越多的国际研究机构所重视&#xff0c;研究它的…

酷开系统丨酷开科技智慧AI 让家庭智能化近在眼前

科技改变生活&#xff0c;从3G-4G-5G&#xff0c;再到即将突破的6G&#xff1b;从传统有人驾驶的车辆到现在的无人驾驶车辆&#xff1b;从九十年代的大哥大“砖头”便携电话&#xff0c;到蓝绿屏按键手机、触摸屏手机&#xff0c;再到智能手机&#xff1b;从传统数字密码到现在…

信息系统项目管理师0146:输入(9项目范围管理—9.3规划范围管理—9.3.1输入)

点击查看专栏目录 文章目录 9.3 规划范围管理9.3.1 输入9.3 规划范围管理 规划范围管理是为了记录如何定义、确认和控制项目范围及产品范围,而创建范围管理计划的过程。本过程的主要作用是在整个项目期间对如何管理范围提供指南和方向。本过程仅开展一次或仅在项目的预定义点开…

【RuoYi】框架中使用wangdietor富文本编辑器

一、前言 在上篇博客中&#xff0c;介绍了RuoYi中如何实现文件的上传与下载&#xff0c;那么这篇博客讲一下如何在RuoYi中使用富文本编辑器&#xff0c;这部分的内容是向&#xff22;站程序员青戈学习的&#xff0c;当然我这里就会把学到的内容做一个总结&#xff0c;当然也会说…

信息系统项目管理师0147:工具与技术(9项目范围管理—9.3规划范围管理—9.3.2工具与技术)

点击查看专栏目录 文章目录 9.3.2 工具与技术 9.3.2 工具与技术 专家判断 规划范围管理过程中&#xff0c;应征求具备如下领域相关专业知识或接受过相关培训的个人或小组 的意见&#xff0c;涉及的领域包括&#xff1a;以往类似项目&#xff1b;特定行业、学科和应用领域的信息…

服务器远程连接工具有哪些?

【天联】是一款功能强大的服务器远程连接工具&#xff0c;它可以让用户通过网络远程连接到目标服务器&#xff0c;实现远程操作和管理。【天联】的使用场景非常广泛&#xff0c;特别适用于以下几个领域&#xff1a; 零售、收银软件应用的远程管理&#xff1a;【天联】可以结合医…

Stable Diffusion【应用篇】【图片修复】:模糊头像照片的高清修复

本文主要是回复一下后台小伙伴留言的问题。经小伙伴本人同意后&#xff0c;允许使用待修复的照片。 我们先看一下待修复的照片。 在向我咨询之前&#xff0c;小伙伴也自己进行了尝试&#xff0c;如果直接使用Stable Diffusion的后期处理功能&#xff0c;出来的图片效果是这样的…