DineGoSystem餐厅点餐系统(控制台版本)
描述
简单模拟一个餐厅的点餐过程,用户可以查看菜品,加入购物车,模拟支付,查看订单等。
功能模块
- 点餐
- 查看购物车
- 订单记录
技术说明
使用 golang 语言开发,后台使用 gorm 框架连接数据库,使用 MVC 三层实现的一个控制台的小程序。
由于所涉及的文件太多,这里就只展示连接数据库Dao层、业务逻辑层Service、handler 的实现。
1. 点餐
菜品只做了查询操作,数据从数据库中获取。
Dao层
// QueryMenu
// @LastUpdateTime 2024/3/12 22:06:00
// @Description 查询菜品列表
// @Demand Version V1.0
func (dao *MenuDao) QueryMenu(menus *[]model.Menu) error {
return model.DB.Where("del_flag = 0").
Find(&menus).Error
}
Service层
package service
import (
"dine_go_system/dao"
"dine_go_system/model"
)
type MenuService struct {
menuDao *dao.MenuDao
}
// NewMenuService
// @LastUpdateTime 2024/3/12 22:08:00
// @Description 构造函数
// @Demand Version V1.0
func NewMenuService() *MenuService {
return &MenuService{menuDao: &dao.MenuDao{}}
}
// QueryMenu
// @LastUpdateTime 2024/3/12 22:11:00
// @Description 查询菜品列表数据集
// @Demand Version V1.0
func (s *MenuService) QueryMenu() []model.Menu {
var menus []model.Menu
// 查询菜品列表数据集
if err := s.menuDao.QueryMenu(&menus); err != nil {
return nil
}
return menus
}
handler
package handler
import (
"dine_go_system/model"
"dine_go_system/service"
"dine_go_system/tool"
"fmt"
"strconv"
"time"
)
type MenuHandler struct {
menuService *service.MenuService
orderService *service.OrderService
}
// NewMenuHandler
// @LastUpdateTime 2024/3/13 22:08:00
// @Description 构造函数
// @Demand Version V1.0
func NewMenuHandler() *MenuHandler {
return &MenuHandler{
menuService: service.NewMenuService(),
orderService: service.NewOrderService(),
}
}
// DisplayMenu
// @LastUpdateTime 2024/3/13 22:09:00
// @Description 展示菜单列表
// @Demand Version V1.0
func (h *MenuHandler) DisplayMenu() {
// 清空控制台
tool.ClearConsole()
// 获取菜品数据
menus := h.menuService.QueryMenu()
if len(menus) > 0 {
// 标题
fmt.Println("╔═════════════════════════════════════════════════╗")
fmt.Printf(" ")
fmt.Printf(" %s%-4s%-8s%-5s%-8s%-9s%s\n", model.Green, "编号", "菜名", "数量", "价格(元)", "描述", model.Reset)
// 输出数据
for _, item := range menus {
fmt.Printf(" ")
fmt.Printf(" %-6s%-7s%-7s%-9s%-20s\n", strconv.Itoa(item.MenuId), item.MenuName, strconv.Itoa(item.Quantity), "¥"+strconv.FormatFloat(item.Price, 'f', 2, 32), item.Desc)
}
fmt.Println("╚═════════════════════════════════════════════════╝")
}
// 选择菜品
var orderDts []model.OrderDts
for {
// 获取控制台输入
var menuChoice int
fmt.Printf("请输入菜品编号(0 结束点餐):")
fmt.Scanln(&menuChoice)
// 如果是 0 直接退出
if menuChoice == 0 {
if len(orderDts) > 0 {
_, msg := h.orderService.SaveOrder(orderDts)
fmt.Println(msg)
}
break
}
// 检查是否找到了菜品
var findMenu model.Menu
var found bool
for _, menuItem := range menus {
if menuItem.MenuId == menuChoice {
findMenu = menuItem
found = true
break
}
}
if !found {
fmt.Println("您选择的菜品不存在!")
}
// 选择数量
var quantityInput int
fmt.Printf("请输入数量:")
fmt.Scanln(&quantityInput)
if quantityInput > findMenu.Quantity {
fmt.Println("数量不可大于【" + strconv.Itoa(findMenu.Quantity) + "】!")
continue
}
fmt.Println("您选择的菜品是【" + model.Green + findMenu.MenuName + model.Reset + "】,单价为【" + model.Green + strconv.FormatFloat(findMenu.Price, 'f', 2, 32) + model.Reset +
"】元,数量为【" + model.Green + strconv.Itoa(quantityInput) + model.Reset +
"】,合计价格为【" + model.Green + strconv.FormatFloat(findMenu.Price*float64(quantityInput), 'f', 2, 32) + model.Reset + "】元")
// 组装明细数据
orderDts = append(orderDts, model.OrderDts{
MenuId: findMenu.MenuId,
Quantity: quantityInput,
Price: findMenu.Price,
CreateAt: time.Now(),
})
}
}
2. 查看购物车和查看订单
- 第一步点餐,已经实现将菜品放到购物车了,这一步就一起说一下这一部分,查看购物车和查看订单我采用的方法大致一样,都是查询的 Order 和 OrderDts 这两个表。
- 其中我将 Order 中的状态 Status 为 0 的定义为购物车里面的数据,也就是未支付的。
- 然后 Status 为 1 的代表已支付,就作为订单部分展示。
Dao层
package dao
import "dine_go_system/model"
type OrderDao struct {
}
// SaveOrder
// @LastUpdateTime 2024/3/14 21:08:00
// @Description 保存订单(加入购物车)
// @Demand Version V1.0
func (dao *OrderDao) SaveOrder(order model.Order, orderDts []model.OrderDts) error {
// 开启事务
tx := model.DB.Begin()
// 保存订单主表
if err := tx.Create(&order).Error; err != nil {
tx.Rollback()
return err
}
// 订单明细表,给每个订单明细的 OrderId字段赋值为订单的Id
for i := range orderDts {
orderDts[i].OrderId = order.OrderId
}
// 保存到数据库
if err := tx.Create(&orderDts).Error; err != nil {
tx.Rollback()
return err
}
// 提交事务
tx.Commit()
return nil
}
// QueryOrder
// @LastUpdateTime 2024/3/15 11:44:00
// @Description 查询订单
// @Demand Version V1.0
func (dao *OrderDao) QueryOrder(paidStatus int, results *[]model.OrderQueryResult) error {
return model.DB.Raw("CALL dine_query_orders(?)", paidStatus).Scan(&results).Error
}
// ChangePaidAmount
// @LastUpdateTime 2024/3/17 17:25:00
// @Description 模拟付款
// @Demand Version V1.0
func (dao *OrderDao) ChangePaidAmount(orderId int, paidAmount float64) error {
return model.DB.Model(&model.Order{}).Where("order_id = ?", orderId).Updates(model.Order{PaidAmount: paidAmount, Status: 1}).Error
}
Service层
package service
import (
"dine_go_system/dao"
"dine_go_system/model"
"dine_go_system/tool"
"time"
)
type OrderService struct {
orderDao *dao.OrderDao
}
// NewOrderService
// @LastUpdateTime 2024/3/14 21:35:00
// @Description 构造函数
// @Demand Version V1.0
func NewOrderService() *OrderService {
return &OrderService{orderDao: &dao.OrderDao{}}
}
// SaveOrder
// @LastUpdateTime 2024/3/14 22:37:00
// @Description 保存订单成功
// @Demand Version V1.0
func (s *OrderService) SaveOrder(dts []model.OrderDts) (bool, string) {
var order model.Order
// 主表
order.OrderCode = tool.GenerateOrderCode()
var totalAmount float64
for _, item := range dts {
totalAmount += item.Price * float64(item.Quantity)
}
order.DueAmount = totalAmount
order.Status = 0
order.CreateAt = time.Now()
if err := s.orderDao.SaveOrder(order, dts); err != nil {
return false, err.Error()
}
return true, "加入购物车成功"
}
// QueryOrder
// @LastUpdateTime 2024/3/15 13:55:00
// @Description 查询订单
// @Demand Version V1.0
func (s *OrderService) QueryOrder(paidStatus int) []model.OrderQueryResult {
var orderResults []model.OrderQueryResult
// 查询购物车
if err := s.orderDao.QueryOrder(paidStatus, &orderResults); err != nil {
return nil
}
return orderResults
}
// ChangePaidAmount
// @LastUpdateTime 2024/3/17 17:28:00
// @Description 模拟付款
// @Demand Version V1.0
func (s *OrderService) ChangePaidAmount(orderId int, paidAmount float64) (bool, string) {
if orderId == 0 {
return false, "订单不存在"
}
if paidAmount == 0 {
return false, "付款金额为0"
}
if err := s.orderDao.ChangePaidAmount(orderId, paidAmount); err != nil {
return false, "付款失败,错误信息:" + err.Error()
}
return true, "付款成功"
}
Handler
package handler
import (
"dine_go_system/model"
"dine_go_system/service"
"dine_go_system/tool"
"fmt"
"strconv"
)
type OrderHandler struct {
orderService *service.OrderService
}
// NewOrderHandler
// @LastUpdateTime 2024/3/15 14:17:00
// @Description 构造函数
// @Demand Version V1.0
func NewOrderHandler() *OrderHandler {
return &OrderHandler{
orderService: service.NewOrderService(),
}
}
// DisplayCart
// @LastUpdateTime 2024/3/15 15:15:00
// @Description 查看购物车
// @Demand Version V1.0
func (h *OrderHandler) DisplayCart() {
// 清空控制台
tool.ClearConsole()
// 获取购物车数据
orderResults := h.orderService.QueryOrder(0)
if len(orderResults) > 0 {
orderDueAmount := orderResults[0].DueAmount
fmt.Println("--------------------------------")
fmt.Println(" 时 间:" + orderResults[0].CreateAt.Format("2006-01-02 15:04:05"))
fmt.Println(" 订 单 号:" + orderResults[0].OrderCode)
fmt.Println(" 应付金额:" + model.Green + strconv.FormatFloat(orderDueAmount, 'f', 2, 32) + model.Reset)
fmt.Println(" 支付状态:" + model.Red + model.StatusMap[orderResults[0].Status] + model.Reset)
fmt.Println("--------------------------------")
// 展示订单明细
fmt.Printf(" %s%-8s%-5s%-8s%s\n", model.Green, "菜名", "数量", "价格(元)", model.Reset)
// 输出数据
for _, item := range orderResults {
fmt.Printf(" %-7s%-7s%-9s\n", item.MenuName, strconv.Itoa(item.Quantity), "¥"+strconv.FormatFloat(item.Price, 'f', 2, 32))
}
fmt.Println("--------------------------------")
var amountInput float64
for {
fmt.Println("请输入应付款,(0 无付款退出):")
fmt.Scanln(&amountInput)
// 退出
if amountInput == 0 || amountInput == orderDueAmount {
break
}
if amountInput != orderDueAmount {
fmt.Println("您输入的金额与应付款不一致,请重新输入")
}
}
// 付款
if amountInput != 0 && amountInput == orderDueAmount {
isSuccess, msg := h.orderService.ChangePaidAmount(orderResults[0].OrderId, amountInput)
if !isSuccess {
fmt.Println(model.Red + msg + model.Reset)
}
fmt.Println(model.Green + msg + model.Reset)
}
} else {
fmt.Println("没有更多了!!")
}
}
// DisplayOrder
// @LastUpdateTime 2024/3/17 17:42:00
// @Description 展示订单
// @Demand Version V1.0
func (h *OrderHandler) DisplayOrder() {
// 清空控制台
tool.ClearConsole()
// 获取订单数据
orderResults := h.orderService.QueryOrder(1)
// 去重
mergedOrders := make(map[string]model.OrderQueryResult)
for _, order := range orderResults {
mergedOrders[order.OrderCode] = order
}
if len(mergedOrders) > 0 {
fmt.Println("╔═════════════════════════════════════════════════╗")
fmt.Printf(" %s%-18s%-8s%-5s%s\n", model.Green, "单号", "应付金额", "实付金额", model.Reset)
// 输出数据
for _, item := range mergedOrders {
fmt.Printf(" %-20s%-11s%-7s\n", item.OrderCode, "¥"+strconv.FormatFloat(item.DueAmount, 'f', 2, 32), "¥"+strconv.FormatFloat(item.PaidAmount, 'f', 2, 32))
}
fmt.Println("╚═════════════════════════════════════════════════╝")
}
fmt.Println("没有更多订单了!!")
}
最后来个展示效果图吧
菜单列表
1. 点餐
2. 查看购物车
查看订单
补充
对了,再附一下关于控制台字体颜色的输出。
这个是用了 ANSI 颜色码,我的是 window 系统,别的系统可能展示的颜色不同。
我先定义了几个颜色码:
// ANSI颜色码
const (
Reset = "\033[0m"
Green = "\033[32m"
Red = "\033[31m"
)
然后在 fmt.Println
中使用就就可以了
fmt.Println(model.Green + "你好" + model.Reset)
后面需要再加上这个 (\033[0m)
也就是上面的 model.Reset
是为了把颜色恢复到之前,不然到时候就会显示的整个控制台都是绿色了。
最后,代码写的肯定是不够好的,欢迎大家指正!!!!!!!