目录
一、技术栈
二、项目展示
(一)服务端
(二)客户端
三、功能说明
(一)服务端:
服务端功能模块
-
工作台模块
-
实时展示当天的营业数据和订单数据,利用Spring Boot和Spring MVC框架提供快速访问店铺菜品及套餐总览的功能。
-
-
数据可视化统计
-
采用ECharts实现动态可视化图表引擎,直观展示不同时间段的数据,便于查询和后续业务需求分析。
-
-
订单管理
-
通过Spring Boot框架实现对不同状态的订单执行操作,如接单、派送、取消订单等,以优化订单处理流程。
-
-
实时播报
-
利用WebSocket技术实时接收客户端传来的订单信息和催单通知,便于商家进行有效管理。
-
-
数据管理
-
基础数据管理
-
采用Spring Data Redis实现套餐、菜品、分类、员工信息等核心数据域的CRUD操作。
-
利用MyBatis动态SQL构建多条件复合查询引擎,提高查询效率。
-
基于PageHelper实现物理分页机制,优化数据加载性能。
-
-
增强型功能设计
-
海量数据处理方案:实现批量删除的批处理优化,提高数据处理能力。
-
-
-
营业状态设置
-
基于Redis实现一键设置营业状态,同步至客户端,确保信息的实时更新。
-
-
导航控制模块
-
采用多层级导航菜单设计,左侧导航栏基于RBAC(基于角色的访问控制)权限模型实现模块化功能分区,包含多个管理模块。
-
-
用户会话管理
-
提供修改密码功能,增强账户安全性。
-
采用JWT令牌实现无状态退出机制,提高系统的安全性和可扩展性。
-
客户端功能模块
-
商家菜品套餐分类展示
-
主页展示商家菜品套餐的相关信息,利用VUE.js和ElementUI支持快速添加到购物车,优化用户体验。
-
-
商家信息展示
-
主页上方展示商家店铺名称、地址、营业状态、配送相关信息以及手机号,提供全面的商家信息。
-
-
购物车
-
客户可自主选择菜品的数量和口味,将其放入购物车。购物车提供选中菜品的数量操作以及一键清空功能,提高购物便捷性。
-
-
地址管理
-
可存储客户的多个地址并设置相关标签,通过设置默认地址来避免重复设置地址,优化客户体验。
-
接入百度地图相关接口实现客户地址与商家店铺地址的测距,若超过一定距离则无法下单,确保配送的可行性。
-
-
订单详细信息设置
-
提供订单备注、餐具选择功能,进一步优化客户体验。
-
-
支付功能
-
提供微信支付功能,简化支付流程,提高支付便捷性。
-
-
催单退单
-
提供用户对商家订单进行催单以及订单退单功能,完善用户需求,提高客户满意度。
-
-
个人中心
-
客户可快速查看并管理自己的地址以及历史订单的详细信息,增强账户管理的便捷性。
-
-
实时监控订单信息
-
提供订单状态的实时更新功能,并且超过支付时间未支付的订单会自动取消,确保订单处理的及时性。
-
-
菜品套餐缓存
-
对用户浏览过的信息进行Redis缓存,减轻数据库负担,同时商家对相关信息进行修改时即刻对客户端缓存进行清理,确保信息的实时性和准确性。
-
四、关于支付功能
由于我是个人注册的小程序而非企业,无法开通微信支付功能,所以本项目的代码里我稍作了修改跳过了微信支付,并将原本微信支付的代码注释掉了,具体修改如下:
/**
* 微信小程序前端代码中:pages/pay/index.js Row:207
*注释掉的代码是用作调用微信支付官方接口的
*而其下面一行则是重定向,点击支付按钮直接调用支付成功的接口
*/
methods: _objectSpread(_objectSpread({},
(0, _vuex.mapState)(['orderData'])), {}, {
// 支付详情
handleSave: function handleSave() {var _this = this;
if (this.timeout) {
(0, _api.cancelOrder)(this.orderId).then(function (res) {
});
uni.redirectTo({
url: '/pages/details/index?orderId=' + this.orderId });
} else {
// 如果支付成功进入成功页
clearTimeout(this.times);
var params = {
orderNumber: this.orderDataInfo.orderNumber,
payMethod: this.activeRadio === 0 ? 1 : 2 };
(0, _api.paymentOrder)(params).then(function (res) {
if (res.code === 1) {
// wx.requestPayment({
// nonceStr: res.data.nonceStr,
// package: res.data.packageStr,
// paySign: res.data.paySign,
// timeStamp: res.data.timeStamp,
// signType: res.data.signType,
// success:function(res){
// wx.showModal({
// title: '提示',
// content: '支付成功',
// success:function(){
// uni.redirectTo({url: '/pages/success/index?orderId=' + _this.orderId });
// }
// })
// console.log('支付成功!')
// }
// })
uni.redirectTo({url: '/pages/success/index?orderId=' + _this.orderId });
} else {
wx.showModal({
title: '提示',
content: res.msg
})
}
});
}
}
/**
* 后端代码:OrderUserServiceImpl.java Row:118
* 注释掉的代码与微信支付相关,这边直接修改订单相关信息
*/
public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
// 当前登录用户id
Long userId = BaseContext.getCurrentId();
User user = userMapper.findById(userId);
//调用微信支付接口,生成预支付交易单
// JSONObject jsonObject = weChatPayUtil.pay(
// ordersPaymentDTO.getOrderNumber(), //商户订单号
// new BigDecimal(0.01), //支付金额,单位 元
// "苍穹外卖订单", //商品描述
// user.getOpenid() //微信用户的openid
// );
//
// if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
// throw new OrderBusinessException("该订单已支付");
// }
JSONObject jsonObject = new JSONObject();
jsonObject.put("code","ORDERPAID");
OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
vo.setPackageStr(jsonObject.getString("package"));
Integer OrderPaidStatus = Orders.PAID;//支付状态,已支付
Integer OrderStatus = Orders.TO_BE_CONFIRMED; //订单状态,待接单
LocalDateTime check_out_time = LocalDateTime.now();//更新支付时间
orderMapper.updateStatus(OrderStatus, OrderPaidStatus, check_out_time, this.orders.getId());
Map map = new HashMap();
map.put("type", 1);//消息类型,1表示来单提醒
map.put("orderId", orders.getId());
map.put("content", "订单号:" + ordersPaymentDTO.getOrderNumber());
webSocketServer.sendToAllClient(JSON.toJSONString(map));
return vo;
}
/**
* 后端代码:OrderUserServiceImpl.java Row:213
* 这是退款功能,同上处理
*/
@Override
public void cancelOrder(Long id) throws Exception {
Orders orders = orderMapper.findById(id);
if (orders == null) {
throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
}
if (orders.getStatus() > 2) {
throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
}
if(orders.getStatus().equals(Orders.TO_BE_CONFIRMED)){
// //调用微信支付退款接口
// weChatPayUtil.refund(
// orders.getNumber(), //商户订单号
// orders.getNumber(), //商户退款单号
// new BigDecimal("0.01"),//退款金额,单位 元
// new BigDecimal("0.01"));//原订单金额
orders.setPayStatus(Orders.REFUND);
}
orders.setStatus(Orders.CANCELLED);
orders.setCancelReason("用户取消了订单");
orders.setCancelTime(LocalDateTime.now());
orderMapper.update(orders);
}
五、项目难点
这个项目是我做的第二个,历时7天,虽然时间较短,但在实施过程中遇到了一些挑战。
尽管数据表数量不是很多,总共只有11张,但项目的复杂度仍然不容小觑。
首先,项目中最大的问题之一就是涉及到多表查询的部分。因为多次需要进行不同数据表之间的联合查询,我必须提前梳理好逻辑和各表之间的关系。如果这一步没有做好,查询就会非常容易出错,导致性能问题或者数据不一致。
另一个较大的挑战是微信支付模块。微信支付部分涉及多个接口以及一系列方法,这些方法的逻辑关系错综复杂。由于我需要在本项目中跳过支付功能的实现,因此必须对微信支付的时序图有清晰的理解,以便能够做出合理的修改和调整。每个接口调用的顺序、参数的传递、以及可能的异常处理都需要深入了解。
值得一提的是,在这个项目中,我仅做了后端的开发工作。主要工作集中在一些典型的CRUD操作,但因为数据关系较为复杂,一些重复性的操作也需要精细化处理,保证代码的高效与可维护性。
总的来说,虽然这个项目的周期较短,但从需求分析到实施过程中的技术难点,都让我收获了不少经验。这些经历不仅让我在多表查询和支付系统的理解上有了更深入的认识,也提高了我处理较复杂业务逻辑的能力。
六、源码
~~码文不易,留个赞再走吧~~