springboot vue 开源 会员收银系统 (6) 收银台的搭建
前言
完整版演示
前面我们对会员系统 分类和商品的开发 完成了收银所需的基础信息 下面我们开始完成收银台的开发
简单画了一个收银的流程图大家参考下

从这张图我们可以分析一下几点
- 可以选择会员或散客收银
- 选择会员使用相应的会员价结算
- 使用会员卡则在价格基础根据卡折扣结算
根据上述分析我搭建了一个简单的收银台

- 左边显示会员和已选择的商品信息
- 右边显示商品的价格信息
- 商品选择后可以修改数字
- 总金额自动计算
- 后续完成挂单功能便于保证收银连续性
开发中运用的组件
- Tabs 标签页 和 Card 完成右侧的商品选择
- el-autocomplete 完成会员的检索
- InputNumber Table 完成购物车开发
收银台运用过多组件会导致页面很乱 我们后续需要进行组件的封装
<template><div class="app-container" style="border-box:box-sizing;"><!-- left--><el-row :gutter="30" style=""><el-col :span="10"><el-autocompletestyle="width: 100%"popper-class="my-autocomplete"v-model="querySearchStr":fetch-suggestions="querySearch"placeholder="会员检索"@select="handleSelect"><iclass="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-tableborderheight="400"max-height="400":data="shopCart"style="width: 100%;margin-bottom: 20px;"><el-table-columnalign="center"prop="categoryName"label="分类"width="100"></el-table-column><el-table-columnalign="center"prop="productName"label="商品名"></el-table-column><el-table-columnalign="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-columnalign="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-columnalign="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-panev-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 productTotalPriceif(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 = newValconsole.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.dataif(this.categoryList.length>0){this.activeName = this.categoryList[0].categoryIdgetProductList({categoryId:this.activeName }).then(res=>{this.productList = res.data})}})},handleClick(e){//拿到分类idconst categoryId = e.namegetProductList({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/
相关文章:
springboot vue 开源 会员收银系统 (6) 收银台的搭建
前言 完整版演示 前面我们对会员系统 分类和商品的开发 完成了收银所需的基础信息 下面我们开始完成收银台的开发 简单画了一个收银的流程图大家参考下 从这张图我们可以分析一下几点 可以选择会员或散客收银选择会员使用相应的会员价结算使用会员卡则在价格基础根据卡折扣…...
重排和重绘的区别,什么情况下会触发这两种情况
重排(Reflow)和重绘(Repaint)是Web前端开发中关于浏览器渲染机制的两个核心概念。它们之间的主要区别以及触发条件如下: 重排(Reflow) 定义: 重排也称为布局(Layout&a…...
亮点回顾|智能汽车芯片创新技术应用与质量研讨会
5月29日,2024汽车软件与通信大会——智能汽车芯片创新技术应用与质量研讨会在江苏苏州狮山国际会议中心举行。本次会议由中国中检所属中国汽车工程研究院股份有限公司(简称:中国汽研)主办,旨在为智能汽车芯片的技术创新…...
特征工程,减小过拟合
目录 特征工程 减小过拟合 图像增强方法 特征工程是机器学习和数据分析中不可或缺的一环,其重要性不言而喻。以下是关于特征工程的详细回答: 一、定义 特征工程是将原始数据转化为更好的表达问题本质的特征的过程,旨在发现对因变量y有明显影响作用的特征(通常称自变量…...
STM32-16-ADC
STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 STM32-13-MPU STM32-14-FSMC_LCD STM32-15-DMA…...
单例模式(C语言)
C语言的设计模式(单例模式) 单例模式(Singleton Pattern)是一种设计模式,目的是确保一个类只有一个实例,并提供一个全局访问点。 #include "stdio.h" #include "stdlib.h"// 定义一个…...
js前端格式化日期函数
开发需求 在前端中我们通常使用new Date()函数获取到的日期时间是下面这种样子:Thu Jun 06 2024 17:29:11 GMT0800 (中国标准时间),我们想要把它转换成常见的指定格式,比如 年-月-日 时:分:秒年/月/日 时:分:秒年-月-日年/月/日 所以就封装…...
五个超实用的 ChatGPT-4o 提示词
GPT-4o 是 OpenAI 最近推出的最新人工智能模型,不仅具备大语言模型的能力,而且拥有多模态模型的看、读、说等能力,而且速度比 GPT-4 更快。下面我们就来介绍几个超实用的 GPT-4o 提示词,帮助大家更好地了解 GPT-4o 的功能和应用场…...
基于51单片机多功能防盗报警proteus仿真( proteus仿真+程序+设计报告+原理图+讲解视频)
基于51单片机多功能防盗报警系统 1. 主要功能:2. 讲解视频:3. 仿真4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单&&下载链接 基于51单片机多功能防盗报警系统( proteus仿真程序设计报告原理图讲解视频) 仿真图proteus8.9及以上…...
gitee和github的协同
假设gitee上zhaodezan有一个开发库,但是从andeyeluguo上拉取最新的(从github上同步过来最新的) git remote add dbgpt_in_gitee https://gitee.com/andeyeluguo/DB-GPT.git remote -v git pull --rebase dbgpt_in_gitee main 有冲突可能需要…...
压力测试-性能指标-Jmeter使用-压力测试报告
文章目录 1.压测目的2.性能指标3.Jmeter3.1Jmeter使用3.1.1 运行Jmeter3.1.2 添加线程组3.1.3设置HTTP请求3.1.4 设置监视器 3.2 查看Jmeter压测结果3.2.1 查看结果树3.2.2 查看汇总报告3.2.3 查看聚合报告3.2.4 查看汇总图 1.压测目的 内存泄漏:OOM,重…...
通过Slf4j中的MDC实现在日志中添加用户IP功能
一、slf4j中MDC是什么 slf4j除了trace、debug、info、warn、error这几个日志接口外,还可以配合MDC将数据写入日志。换句话说MDC也是用来记录日志的,但它的使用方式与使用日志接口不同。 在使用日志接口时我们一般这么做 log.debug("log debug"…...
代码随想录算法训练营第四十九天| 139.单词拆分、背包问题总结
139.单词拆分 题目链接:139.单词拆分 文档讲解:代码随想录/单词拆分 视频讲解:视频讲解-单词拆分 状态:已完成(0遍) 解题过程 这几天博主忙着面试和入职,一晃已经周四了,这个礼拜…...
STM32F103VE和STM32F407VE的引脚布局
STM32F103VE vs STM32F407VE 引脚对比表 引脚 STM32F103VE STM32F407VE 备注 1 VSS VSS 地 2 VDD VDD 电源 3 VSSA VSSA 模拟地 4 VDDA VDDA 模拟电源 5 OSC_IN OSC_IN 外部时钟输入 6 OSC_OUT OSC_OUT 外部时钟输出 7 NRST NRST 复位 8 PC13 (GPIO) PC13 (GPIO) GPIO 9 PC14 (…...
搜维尔科技:使用 Xsens 动作捕捉技术创建栩栩如生的动画
使用Xsens 动作捕捉技术创建栩栩如生的动画 搜维尔科技:使用 Xsens 动作捕捉技术创建栩栩如生的动画...
鸿蒙开发 一 (三)、ArkTS开发实战上
ArkTS 从 TypeScript 优化而来, 但有些用法又不太一样, 在开发中, 经常会出现一些报错提示,下面我们也汇总一些常见错误,捡一些常见的整理一下 Promise 的用法: //TypeScript 写法:private load…...
TensorRT教程(1)初探TensorRT
1. TensorRT简要介绍 TensorRT(NVIDIA TensorRT)是 NVIDIA 开发的一个用于深度学习推理的高性能推理引擎。它可以针对 NVIDIA GPU 进行高效的深度学习推理加速,提供了许多优化技术,使得推理速度更快,并且可以在生产环境…...
多表连接查询和子查询
一、连接查询 连接查询是SQL语言最强大的功能之一,它可以执行查询时动态的将表连接起来,然后从中查询数据。 1.1、连接两表的方法 在SQL中连接两表可以有两种方法,一种是无连接规则连接,另一种是有连接规则连接。 无连接规则连…...
数据挖掘与机器学习——聚类算法
目录 无监督学习 聚类算法 概念: 功能: 应用场景: 评判标准: 划分聚类: K-means聚类 逻辑实现: 聚类方式 问题: 解决: 可能存在的问题: 1.初始值对K-means聚…...
QT快速下载
去QT官网之后,如下图所示 比如要下载qt-opensource-windows-x86-5.14.2.exe,进入5.14对应的文件夹,找到对应的版本 点击Details, 下载对应的种子,然后通过迅雷下载 个人实测,家庭网络平均18M的速率...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...
MeshGPT 笔记
[2311.15475] MeshGPT: Generating Triangle Meshes with Decoder-Only Transformers https://library.scholarcy.com/try 真正意义上的AI生成三维模型MESHGPT来袭!_哔哩哔哩_bilibili GitHub - lucidrains/meshgpt-pytorch: Implementation of MeshGPT, SOTA Me…...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...
