diff --git a/sky/sky-server/src/main/java/com/sky/SkyServerApplication.java b/sky/sky-server/src/main/java/com/sky/SkyServerApplication.java new file mode 100644 index 0000000..7d35984 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/SkyServerApplication.java @@ -0,0 +1,30 @@ +package com.sky; + +import com.sky.utils.AliOssUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.socket.config.annotation.EnableWebSocket; + +@SpringBootApplication() // 启用Spring Boot的自动配置和组件扫描 +@EnableTransactionManagement // 开启注解方式的事务管理 +@Slf4j // 启用Lombok日志功能,自动生成log对象 +@EnableConfigurationProperties // 允许@ConfigurationProperties注解使用,用于从配置文件加载属性 +@EnableCaching // 启用Spring的缓存机制 +@EnableScheduling // 启用定时任务功能 +public class SkyServerApplication { + + // 程序的入口点,启动Spring Boot应用 + public static void main(String[] args) { + SpringApplication.run(SkyServerApplication.class, args); // 启动Spring Boot应用 + log.info("server started"); // 输出应用启动的日志信息 + } +} diff --git a/sky/sky-server/src/main/java/com/sky/annotation/AutoFill.java b/sky/sky-server/src/main/java/com/sky/annotation/AutoFill.java new file mode 100644 index 0000000..b99dab1 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/annotation/AutoFill.java @@ -0,0 +1,33 @@ +package com.sky.annotation; + +import com.sky.enumeration.OperationType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义注解 AutoFill,用于在方法上标记操作类型,以实现公共字段的自动填充功能。 + * + * 主要用途: + * - 标记需要自动填充公共字段(如创建时间、更新时间、操作人等)的业务方法。 + * - 结合切面编程(AOP)实现自动填充逻辑。 + * + * 使用方式: + * 在需要自动填充公共字段的方法上添加该注解,并指定操作类型。 + * 示例: + * {@code @AutoFill(OperationType.INSERT)} + */ +@Target(ElementType.METHOD) // 指定该注解只能应用于方法上 +@Retention(RetentionPolicy.RUNTIME) // 指定该注解在运行时可用(用于运行时动态处理) +public @interface AutoFill { + + /** + * 操作类型,用于指定当前方法的数据库操作类型。 + * 必须通过 {@link OperationType} 枚举指定,支持 INSERT 和 UPDATE 等操作。 + * + * @return 操作类型 + */ + OperationType value(); +} diff --git a/sky/sky-server/src/main/java/com/sky/config/WebSocketConfiguration.java b/sky/sky-server/src/main/java/com/sky/config/WebSocketConfiguration.java new file mode 100644 index 0000000..5044769 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/config/WebSocketConfiguration.java @@ -0,0 +1,29 @@ +package com.sky.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * WebSocketConfiguration 是一个 Spring 配置类,用于配置 WebSocket 服务端。 + * 该类通过 @Configuration 注解告知 Spring 容器,这是一个配置类,主要用于初始化和配置 WebSocket 相关的 Bean。 + */ +@Configuration +public class WebSocketConfiguration { + + /** + * 创建并返回一个 ServerEndpointExporter Bean,该 Bean 用于支持 WebSocket 的端点。 + * + * 说明: + * ServerEndpointExporter 是 Spring 提供的一个 WebSocket 端点导出器,它负责将使用 @ServerEndpoint 注解标注的 WebSocket 端点暴露为可用的服务。 + * + * 这个方法是 Spring 配置类的一部分,用于在容器启动时注册 WebSocket 端点。 + * + * @return ServerEndpointExporter Bean + */ + @Bean + public ServerEndpointExporter serverEndpointExporter(){ + // 返回 ServerEndpointExporter 实例,Spring 会自动注册 WebSocket 端点 + return new ServerEndpointExporter(); + } +} diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java new file mode 100644 index 0000000..62a8ba3 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java @@ -0,0 +1,166 @@ +package com.sky.controller.admin; + +import com.sky.constant.JwtClaimsConstant; +import com.sky.context.BaseContext; +import com.sky.dto.EmployeeDTO; +import com.sky.dto.EmployeeLoginDTO; +import com.sky.dto.EmployeePageQueryDTO; +import com.sky.entity.Employee; +import com.sky.properties.JwtProperties; +import com.sky.result.PageResult; +import com.sky.result.Result; +import com.sky.service.EmployeeService; +import com.sky.utils.JwtUtil; +import com.sky.vo.EmployeeLoginVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.DigestUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 员工管理控制器 + * 该类提供了关于员工的增删改查以及登录等功能接口,支持管理端的员工操作。 + * 使用了 Swagger 注解,提供 API 文档支持。 + */ +@RestController +@RequestMapping("/admin/employee") +@Slf4j +@Api(tags = "员工相关接口") +public class EmployeeController { + + @Autowired + private EmployeeService employeeService; // 注入员工服务类,用于处理员工相关业务 + @Autowired + private JwtProperties jwtProperties; // 注入 JWT 配置类,用于生成 JWT 令牌 + + /** + * 员工登录接口 + * 接收员工登录请求,验证身份,并生成 JWT 令牌返回给前端。 + * + * @param employeeLoginDTO 登录信息 + * @return 返回登录信息以及生成的 JWT 令牌 + */ + @PostMapping("/login") + @ApiOperation(value = "员工登录") + public Result login(@RequestBody EmployeeLoginDTO employeeLoginDTO) { + log.info("员工登录:{}", employeeLoginDTO); // 记录登录请求日志 + + // 调用员工服务进行登录验证 + Employee employee = employeeService.login(employeeLoginDTO); + + // 登录成功后,生成 JWT 令牌 + Map claims = new HashMap<>(); + claims.put(JwtClaimsConstant.EMP_ID, employee.getId()); // 将员工ID放入JWT的claims部分 + String token = JwtUtil.createJWT( + jwtProperties.getAdminSecretKey(), // 获取密钥 + jwtProperties.getAdminTtl(), // 获取有效期 + claims); // 设置 JWT claims + + // 将登录者的 ID 设置到当前线程上下文中,以便其他地方使用 + BaseContext.setCurrentId(employee.getId()); + + // 构造员工登录响应对象 + EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder() + .id(employee.getId()) + .userName(employee.getUsername()) + .name(employee.getName()) + .token(token) + .build(); + + return Result.success(employeeLoginVO); // 返回成功结果 + } + + /** + * 员工退出接口 + * 目前该接口仅用于前端退出后显示成功,后端暂未涉及退出逻辑。 + * + * @return 返回退出成功的结果 + */ + @PostMapping("/logout") + @ApiOperation("员工退出") + public Result logout() { + return Result.success(); // 直接返回成功 + } + + /** + * 新增员工接口 + * 用于管理员新增员工。 + * + * @param employeeDTO 员工信息 + * @return 返回操作结果 + */ + @PostMapping + @ApiOperation("新增员工") + public Result save(@RequestBody EmployeeDTO employeeDTO) { + log.info("新增员工:{}", employeeDTO); // 记录新增员工请求日志 + employeeService.save(employeeDTO); // 调用服务层保存员工数据 + return Result.success(); // 返回成功结果 + } + + /** + * 员工分页查询接口 + * 支持根据分页参数查询员工信息。 + * + * @param employeePageQueryDTO 分页查询条件 + * @return 返回分页查询结果 + */ + @GetMapping("/page") + @ApiOperation("员工分页查询") + public Result pageQuery(EmployeePageQueryDTO employeePageQueryDTO){ + log.info("员工分页查询,参数为:{}", employeePageQueryDTO); // 记录分页查询请求日志 + PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO); // 调用服务层进行分页查询 + return Result.success(pageResult); // 返回分页查询结果 + } + + /** + * 启用或禁用员工账号 + * 管理员可以通过该接口启用或禁用员工账号。 + * + * @param status 启用或禁用的状态,1表示启用,0表示禁用 + * @param id 员工ID + * @return 返回操作结果 + */ + @PostMapping("/status/{status}") + @ApiOperation("启用或禁用员工账号") + public Result startOrStop(@PathVariable Integer status, Long id) { + log.info("启用禁用员工账号{},{}", status, id); // 记录启用禁用请求日志 + employeeService.startOrStop(status, id); // 调用服务层启用或禁用员工账号 + return Result.success(); // 返回成功结果 + } + + /** + * 根据员工ID查询员工信息 + * 用于获取指定员工的详细信息。 + * + * @param id 员工ID + * @return 返回员工信息 + */ + @GetMapping("/{id}") + @ApiOperation("通过id查询员工信息") + public Result getById(@PathVariable Long id) { + Employee employee = employeeService.getById(id); // 调用服务层查询员工 + return Result.success(employee); // 返回查询结果 + } + + /** + * 编辑员工信息接口 + * 用于修改员工信息。 + * + * @param employeeDTO 员工信息 + * @return 返回操作结果 + */ + @PutMapping + @ApiOperation("编辑员工信息") + public Result update(@RequestBody EmployeeDTO employeeDTO) { + log.info("编辑员工信息:{}", employeeDTO); // 记录编辑员工信息请求日志 + employeeService.update(employeeDTO); // 调用服务层更新员工信息 + return Result.success(); // 返回成功结果 + } + +} diff --git a/sky/sky-server/src/main/java/com/sky/controller/admin/ShopController.java b/sky/sky-server/src/main/java/com/sky/controller/admin/ShopController.java new file mode 100644 index 0000000..a379e2f --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/admin/ShopController.java @@ -0,0 +1,67 @@ +package com.sky.controller.admin; + +import com.sky.result.Result; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.web.bind.annotation.*; + +/** + * 管理员店铺控制器 + * 提供了与店铺营业状态相关的接口,用于设置和查询店铺的营业状态。 + * 使用 Redis 存储店铺状态,便于跨请求共享数据。 + */ +@RestController("adminShopController") +@Slf4j +@Api("管理员店铺相关接口") +@RequestMapping("/admin/shop") +public class ShopController { + + @Autowired + private RedisTemplate redisTemplate; // 注入 RedisTemplate 用于操作 Redis 数据库 + private static final String key = "SHOP_STATUS"; // 定义 Redis 中保存店铺状态的键 + + /** + * 设置店铺营业状态 + * 该接口用于设置店铺的营业状态,通过传入状态值(1 表示营业中,0 表示打烊中)进行设置。 + * + * @param status 店铺的营业状态(1: 营业中, 0: 打烊中) + * @return 返回操作结果 + */ + @PutMapping("/{status}") + @ApiOperation("设置店铺营业状态") + public Result setStatus(@PathVariable Integer status) { + // 记录设置店铺状态的日志信息 + log.info("设置店铺营业状态为:{}", status == 1 ? "营业中" : "打烊中"); + + // 获取 Redis 的 ValueOperations 操作对象 + ValueOperations valueOperations = redisTemplate.opsForValue(); + // 将店铺状态保存到 Redis 中 + valueOperations.set(key, status); + + return Result.success(); // 返回成功结果 + } + + /** + * 查询店铺营业状态 + * 该接口用于查询店铺的当前营业状态,返回值为 1 表示营业中,0 表示打烊中。 + * + * @return 返回店铺的营业状态 + */ + @GetMapping("/status") + @ApiOperation("查询店铺营业状态") + public Result queryStatus() { + // 获取 Redis 的 ValueOperations 操作对象 + ValueOperations valueOperations = redisTemplate.opsForValue(); + // 从 Redis 中获取店铺状态 + Integer status = (Integer) valueOperations.get(key); + + // 记录查询店铺状态的日志信息 + log.info("店铺状态为:{}", status == 1 ? "营业中" : "打烊中"); + + return Result.success(status); // 返回查询结果 + } +} diff --git a/sky/sky-server/src/main/java/com/sky/controller/user/CategoryController.java b/sky/sky-server/src/main/java/com/sky/controller/user/CategoryController.java new file mode 100644 index 0000000..f947348 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/user/CategoryController.java @@ -0,0 +1,48 @@ +package com.sky.controller.user; + +import com.sky.entity.Category; +import com.sky.result.Result; +import com.sky.service.CategoryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 用户端-分类控制器 + * 处理与分类相关的接口请求,用户可以通过该接口查询分类信息。 + */ +@RestController("userCategoryController") +@RequestMapping("/user/category") +@Api(tags = "C端-分类接口") +@Slf4j +public class CategoryController { + + @Autowired + private CategoryService categoryService; // 注入 CategoryService 服务,用于查询分类信息 + + /** + * 查询分类 + * 该接口根据传入的 type 类型参数,查询分类信息,并返回分类列表。 + * + * @param type 分类类型,用于筛选不同类型的分类 + * @return 返回分类信息的列表 + */ + @GetMapping("/list") + @ApiOperation("查询分类") + public Result> list(Integer type) { + // 记录查询分类操作的日志,输出传入的分类类型参数 + log.info("查询分类{}", type); + + // 调用 categoryService 查询分类信息 + List list = categoryService.query(type); + + // 返回查询结果,封装在 Result 对象中 + return Result.success(list); + } +} diff --git a/sky/sky-server/src/main/java/com/sky/controller/user/ShopController.java b/sky/sky-server/src/main/java/com/sky/controller/user/ShopController.java new file mode 100644 index 0000000..99809d2 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/controller/user/ShopController.java @@ -0,0 +1,48 @@ +package com.sky.controller.user; + +import com.sky.result.Result; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.web.bind.annotation.*; + +/** + * 用户端-店铺控制器 + * 提供了与店铺营业状态相关的接口,用户可以查询店铺当前的营业状态。 + * 使用 Redis 存储店铺状态,以便跨请求共享数据。 + */ +@RestController("userShopController") +@Slf4j +@Api("用户店铺相关接口") +@RequestMapping("/user/shop") +public class ShopController { + + @Autowired + private RedisTemplate redisTemplate; // 注入 RedisTemplate 用于操作 Redis 数据库 + private static final String key = "SHOP_STATUS"; // 定义 Redis 中保存店铺状态的键 + + /** + * 查询店铺营业状态 + * 该接口用于查询店铺当前的营业状态。状态值为 1 表示营业中,0 表示打烊中。 + * + * @return 返回店铺的营业状态 + */ + @GetMapping("/status") + @ApiOperation("查询店铺营业状态") + public Result queryStatus() { + // 获取 Redis 的 ValueOperations 操作对象 + ValueOperations valueOperations = redisTemplate.opsForValue(); + + // 从 Redis 中获取店铺状态 + Integer status = (Integer) valueOperations.get(key); + + // 记录查询店铺状态的日志信息 + log.info("店铺状态为:{}", status == 1 ? "营业中" : "打烊中"); + + // 返回查询结果,封装在 Result 对象中 + return Result.success(status); + } +} diff --git a/sky/sky-server/src/main/java/com/sky/interceptor/JwtTokenAdminInterceptor.java b/sky/sky-server/src/main/java/com/sky/interceptor/JwtTokenAdminInterceptor.java new file mode 100644 index 0000000..2b612c3 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/interceptor/JwtTokenAdminInterceptor.java @@ -0,0 +1,69 @@ +package com.sky.interceptor; + +import com.sky.constant.JwtClaimsConstant; +import com.sky.constant.MessageConstant; +import com.sky.context.BaseContext; +import com.sky.properties.JwtProperties; +import com.sky.utils.JwtUtil; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * JWT 令牌校验拦截器 + * 该拦截器用于校验用户请求中的 JWT 令牌,确保用户是经过身份验证的。 + * 如果令牌无效或未提供,返回 401 错误,提示用户未登录。 + */ +@Component +@Slf4j +public class JwtTokenAdminInterceptor implements HandlerInterceptor { + + @Autowired + private JwtProperties jwtProperties; // 注入 JWT 配置属性,获取密钥和令牌名称 + + /** + * 校验 JWT 令牌 + * 在请求进入 Controller 方法前进行拦截,校验请求头中的 JWT 令牌是否有效。 + * + * @param request 当前请求 + * @param response 当前响应 + * @param handler 当前处理器(即被拦截的 Controller 方法) + * @return 如果令牌有效,返回 true,继续执行后续操作;如果令牌无效,返回 false,终止请求处理 + * @throws Exception 异常 + */ + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + // 判断当前拦截到的是 Controller 的方法还是其他资源 + if (!(handler instanceof HandlerMethod)) { + // 当前拦截到的不是动态方法,直接放行 + return true; + } + + HandlerMethod handlerMethod = (HandlerMethod) handler; + + // 1、从请求头中获取 JWT 令牌 + String token = request.getHeader(jwtProperties.getAdminTokenName()); + + // 2、校验令牌 + try { + log.info("JWT 校验: {}", token); + Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token); // 解析 JWT + Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString()); // 获取员工 ID + BaseContext.setCurrentId(empId); // 设置当前员工 ID 到上下文中 + log.info("当前员工 ID: {}", empId); + + // 3、校验通过,放行请求 + return true; + } catch (Exception ex) { + // 4、校验失败,返回 401 状态码,表示未授权 + log.error(MessageConstant.USER_NOT_LOGIN); // 打印未登录错误日志 + response.setStatus(401); // 设置响应状态为 401 + return false; // 拦截请求,不继续执行 + } + } +} diff --git a/sky/sky-server/src/main/java/com/sky/mapper/DishMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/DishMapper.java new file mode 100644 index 0000000..3cb22e5 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/DishMapper.java @@ -0,0 +1,115 @@ +package com.sky.mapper; + +import com.github.pagehelper.Page; +import com.sky.annotation.AutoFill; +import com.sky.dto.DishPageQueryDTO; +import com.sky.entity.Dish; +import com.sky.entity.DishFlavor; +import com.sky.entity.Setmeal; +import com.sky.entity.SetmealDish; +import com.sky.enumeration.OperationType; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Mapper // 标记为 MyBatis 的 Mapper 接口,表明这是 MyBatis 对数据库操作的接口 +public interface DishMapper { + + /** + * 菜品分页查询 + * + * @param dishPageQueryDTO 传入的分页查询条件 + * @return 返回符合条件的菜品分页结果 + */ + Page pageQuery(DishPageQueryDTO dishPageQueryDTO); + + /** + * 保存菜品数据 + * + * @param dish 待保存的菜品对象 + */ + @AutoFill(OperationType.INSERT) // 自动填充操作,标记为插入操作 + void save(Dish dish); + + /** + * 批量插入口味数据 + * + * @param flavors 需要插入的口味数据列表 + */ + void insertBatchFlavors(List flavors); + + /** + * 批量删除菜品 + * + * @param ids 需要删除的菜品 ID 列表 + */ + void deleteBatch(ArrayList ids); + + /** + * 根据菜品 ID 批量获取菜品 + * + * @param ids 菜品 ID 列表 + * @return 返回多个菜品对象 + */ + ArrayList getByIdBatch(ArrayList ids); + + /** + * 根据菜品 ID 判断是否有菜品被套餐绑定 + * + * @param ids 菜品 ID 列表 + * @return 返回绑定套餐的数量 + */ + Integer countMealDish(ArrayList ids); + + /** + * 修改菜品 + * + * @param dish 需要修改的菜品对象 + */ + @AutoFill(OperationType.UPDATE) // 自动填充操作,标记为更新操作 + void updateDish(Dish dish); + + /** + * 批量删除菜品口味 + * + * @param flavors 需要删除的口味数据列表 + */ + void deleteBatchFlavors(List flavors); + + /** + * 根据菜品 ID 获取菜品口味 + * + * @param id 菜品 ID + * @return 返回对应菜品的口味数据列表 + */ + ArrayList getFlavorById(Long id); + + /** + * 根据分类 ID 获取菜品 + * + * @param categoryId 分类 ID + * @param status 菜品状态(启用或禁用) + * @return 返回对应分类下的菜品列表 + */ + ArrayList getByCategoryId(Long categoryId, Integer status); + + /** + * 根据菜品 ID 获取单个菜品 + * + * @param id 菜品 ID + * @return 返回对应的菜品对象 + */ + @Select("select * from dish where id=#{id}") + Dish getById(Long id); + + /** + * 根据条件统计菜品数量 + * + * @param map 查询条件的键值对集合 + * @return 返回符合条件的菜品数量 + */ + Integer countByMap(Map map); +} diff --git a/sky/sky-server/src/main/java/com/sky/mapper/ReportMapper.java b/sky/sky-server/src/main/java/com/sky/mapper/ReportMapper.java new file mode 100644 index 0000000..c33bc72 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/mapper/ReportMapper.java @@ -0,0 +1,73 @@ +package com.sky.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; + +@Mapper // 标记为 MyBatis 的 Mapper 接口,用于与数据库交互 +public interface ReportMapper { + + /** + * 统计营业额 + * 根据订单状态和结算时间范围,计算营业额。 + * + * @param map 包含订单状态、开始时间和结束时间的查询参数 + * @return 返回营业额总和 + */ + @Select("select sum(amount) from orders where status=#{status} and checkout_time>#{begin} and checkout_time<#{end}") + Double sumByMap(HashMap map); + + /** + * 用户统计 + * 根据创建时间范围,统计新增用户数量。 + * + * @param map 包含开始时间和结束时间的查询参数 + * @return 返回新增用户数量 + */ + @Select("select count(id) from user where create_time>#{begin} and create_time<#{end}") + Integer sumUserByDay(HashMap map); + + /** + * 总用户统计 + * 统计截至指定时间的总用户数量。 + * + * @param map 包含结束时间的查询参数 + * @return 返回总用户数量 + */ + @Select("select count(*) from user where create_time<#{end}") + Integer sumUser(HashMap map); + + /** + * 订单统计 + * 根据指定时间范围,统计当天产生的订单总数。 + * + * @param map 包含开始时间和结束时间的查询参数 + * @return 返回当天订单总数 + */ + @Select("select count(*) from orders where order_time>#{begin} and order_time<#{end}") + Integer sumNewOrder(HashMap map); + + /** + * 有效订单统计 + * 根据结算时间范围和订单状态,统计当天的有效订单总数。 + * + * @param map 包含开始时间、结束时间和订单状态的查询参数 + * @return 返回当天有效订单总数 + */ + @Select("select count(*) from orders where checkout_time>#{begin} and checkout_time<#{end} and status=#{status}") + Integer sumOrder(HashMap map); + + /** + * 销量前十统计 + * 根据订单时间范围和订单状态,统计销量前十的菜品。 + * + * @param map 包含订单时间范围和订单状态的查询参数 + * @return 返回销量前十的菜品列表 + */ + @Select("select od.name name, sum(od.number) number from order_detail od, orders o where od.order_id=o.id and status=#{status} and o.order_time>#{begin} and o.order_time<#{end} " + + "group by name order by number desc") + ArrayList> salesTop10Report(HashMap map); +} diff --git a/sky/sky-server/src/main/java/com/sky/service/CategoryService.java b/sky/sky-server/src/main/java/com/sky/service/CategoryService.java new file mode 100644 index 0000000..22eb8ed --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/CategoryService.java @@ -0,0 +1,68 @@ +package com.sky.service; + +import com.sky.dto.CategoryDTO; +import com.sky.dto.CategoryPageQueryDTO; +import com.sky.entity.Category; +import com.sky.result.PageResult; + +import java.util.List; + +public interface CategoryService { + + /** + * 分类分页查询 + * + * 根据传入的分页查询条件,分页查询分类数据。 + * + * @param categoryPageQueryDTO 包含分页条件的查询对象 + * @return 返回分页查询结果,包含分类数据和总数 + */ + PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO); + + /** + * 根据类型查询分类 + * + * 根据分类类型查询分类列表。类型可以是菜品类型、套餐类型等。 + * + * @param type 分类的类型(例如:1 表示菜品类型,2 表示套餐类型等) + * @return 返回指定类型的分类列表 + */ + List query(Integer type); + + /** + * 删除分类 + * + * 根据分类的 ID 删除分类数据。 + * + * @param id 分类的 ID + */ + void delete(Long id); + + /** + * 修改分类 + * + * 根据传入的分类 DTO 对象,更新分类信息。 + * + * @param categoryDTO 包含更新信息的分类 DTO + */ + void updateCategory(CategoryDTO categoryDTO); + + /** + * 启用或禁用分类 + * + * 根据传入的状态(启用或禁用)更新分类的状态。 + * + * @param status 分类的状态,1 表示启用,0 表示禁用 + * @param id 分类的 ID + */ + void startOrStop(Integer status, Long id); + + /** + * 新增分类 + * + * 根据传入的分类 DTO 对象,新增一个分类。 + * + * @param categoryDTO 包含分类信息的 DTO + */ + void save(CategoryDTO categoryDTO); +} diff --git a/sky/sky-server/src/main/java/com/sky/service/OrderService.java b/sky/sky-server/src/main/java/com/sky/service/OrderService.java new file mode 100644 index 0000000..e3d6bb1 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/OrderService.java @@ -0,0 +1,159 @@ +package com.sky.service; + +import com.sky.dto.*; +import com.sky.result.PageResult; +import com.sky.vo.OrderPaymentVO; +import com.sky.vo.OrderStatisticsVO; +import com.sky.vo.OrderSubmitVO; +import com.sky.vo.OrderVO; + +import java.util.ArrayList; + +public interface OrderService { + + /** + * 完成订单 + * + * 更新订单状态为已完成,并进行相关后续操作(如更新库存、调整账户余额等)。 + * + * @param id 订单 ID + */ + void complete(Long id); + + /** + * 派送订单 + * + * 将订单状态更新为已派送,并进行相关的配送操作。 + * + * @param id 订单 ID + */ + void delivery(Long id); + + /** + * 商家取消订单 + * + * 商家在订单确认前取消订单,更新订单状态为取消。 + * + * @param ordersCancelDTO 取消订单所需的相关信息(包含订单 ID 和取消原因) + * @throws Exception 可能会抛出异常,需处理 + */ + void cancel(OrdersCancelDTO ordersCancelDTO) throws Exception; + + /** + * 拒单 + * + * 商家拒绝用户订单,更新订单状态为拒绝。 + * + * @param ordersRejectionDTO 拒单所需的相关信息(包含订单 ID 和拒单原因) + * @throws Exception 可能会抛出异常,需处理 + */ + void rejection(OrdersRejectionDTO ordersRejectionDTO) throws Exception; + + /** + * 接单 + * + * 商家确认并接收用户订单,更新订单状态为已接单。 + * + * @param ordersConfirmDTO 确认订单所需的相关信息(包含订单 ID) + */ + void confirm(OrdersConfirmDTO ordersConfirmDTO); + + /** + * 各个状态的订单数量统计 + * + * 返回一个订单统计视图对象,包含不同状态下订单的数量(如待支付、待派送、已完成等)。 + * + * @return 订单状态统计信息 + */ + OrderStatisticsVO statistics(); + + /** + * 条件搜索订单 + * + * 根据订单的不同条件(如状态、日期范围等)进行搜索并返回分页结果。 + * + * @param ordersPageQueryDTO 包含搜索条件的分页查询对象 + * @return 返回符合条件的订单分页结果 + */ + PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO); + + /** + * 用户取消订单 + * + * 用户主动取消订单,更新订单状态为已取消。 + * + * @param id 订单 ID + * @throws Exception 可能会抛出异常,需处理 + */ + void userCancelById(Long id) throws Exception; + + /** + * 查询订单详情 + * + * 获取指定订单的详细信息,包含订单商品、状态、配送信息等。 + * + * @param id 订单 ID + * @return 返回订单的详细信息 + */ + OrderVO details(Long id); + + /** + * 用户下单 + * + * 用户提交订单,创建新订单并返回提交结果。 + * + * @param ordersDTO 用户提交的订单信息 + * @return 返回订单提交的结果,包括订单 ID、支付信息等 + */ + OrderSubmitVO submit(OrdersDTO ordersDTO); + + /** + * 订单支付 + * + * 用户支付订单,处理支付过程并返回支付结果。 + * + * @param ordersPaymentDTO 包含支付信息的 DTO + * @return 返回支付结果,包括支付状态和相关支付信息 + * @throws Exception 可能会抛出异常,需处理 + */ + OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception; + + /** + * 支付成功,修改订单状态 + * + * 在支付成功后,根据支付平台的返回信息更新订单状态为已支付。 + * + * @param outTradeNo 外部支付订单号 + */ + void paySuccess(String outTradeNo); + + /** + * 用户催单 + * + * 用户催促商家尽快处理订单,发送催单请求。 + * + * @param id 订单 ID + */ + void reminder(Long id); + + /** + * 用户端订单分页查询 + * + * 用户查看自己的订单,支持按状态分页查询订单。 + * + * @param page 当前页数 + * @param pageSize 每页条数 + * @param status 订单状态(如待支付、已接单等) + * @return 返回分页查询结果 + */ + PageResult pageQuery4User(int page, int pageSize, Integer status); + + /** + * 再来一单 + * + * 用户重复下单,基于某个已完成的订单生成新的订单。 + * + * @param id 已完成的订单 ID + */ + void repetition(Long id); +} diff --git a/sky/sky-server/src/main/java/com/sky/service/UserService.java b/sky/sky-server/src/main/java/com/sky/service/UserService.java new file mode 100644 index 0000000..6abe2e4 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/UserService.java @@ -0,0 +1,19 @@ +package com.sky.service; + +import com.sky.dto.UserLoginDTO; +import com.sky.entity.User; + +public interface UserService { + + /** + * 微信登录 + * + * 通过微信登录验证用户信息,并返回用户对象。此方法通常用于与微信平台进行身份验证, + * 获取用户的基本信息(如昵称、头像、openid等),并在系统中创建或查找用户记录。 + * + * @param userLoginDTO 包含微信登录所需的用户信息(如微信的登录凭证、用户信息等) + * @return 返回经过验证的用户对象,如果用户不存在则可能创建新用户 + */ + User wxLogin(UserLoginDTO userLoginDTO); + +} diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/AddressBookServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/AddressBookServiceImpl.java new file mode 100644 index 0000000..c22f033 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/AddressBookServiceImpl.java @@ -0,0 +1,94 @@ +package com.sky.service.impl; + +import com.sky.context.BaseContext; +import com.sky.entity.AddressBook; +import com.sky.mapper.AddressBookMapper; +import com.sky.service.AddressBookService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service // 该注解表示该类是一个服务层的 Bean +@Slf4j // 提供日志功能 +public class AddressBookServiceImpl implements AddressBookService { + + @Autowired // 自动注入 AddressBookMapper + private AddressBookMapper addressBookMapper; + + /** + * 条件查询 + * 根据传入的 AddressBook 对象中的条件进行查询地址列表。 + * + * @param addressBook 查询条件 + * @return 返回满足条件的地址列表 + */ + public List list(AddressBook addressBook) { + return addressBookMapper.list(addressBook); // 调用 mapper 查询数据库 + } + + /** + * 新增地址 + * 在添加地址时,设置当前用户的 ID,并将该地址设为非默认地址。 + * + * @param addressBook 地址信息 + */ + public void save(AddressBook addressBook) { + addressBook.setUserId(BaseContext.getCurrentId()); // 设置当前用户的 ID + addressBook.setIsDefault(0); // 设置地址为非默认地址 + addressBookMapper.insert(addressBook); // 调用 mapper 插入新地址 + } + + /** + * 根据id查询 + * 根据地址的 ID 查询地址详情。 + * + * @param id 地址 ID + * @return 返回对应的 AddressBook 对象 + */ + public AddressBook getById(Long id) { + return addressBookMapper.getById(id); // 调用 mapper 根据 ID 查询地址 + } + + /** + * 根据id修改地址 + * 根据传入的地址信息更新数据库中的地址。 + * + * @param addressBook 更新后的地址信息 + */ + public void update(AddressBook addressBook) { + addressBookMapper.update(addressBook); // 调用 mapper 更新地址 + } + + /** + * 设置默认地址 + * 1. 将当前用户的所有地址的 `is_default` 设置为非默认地址。 + * 2. 将指定地址的 `is_default` 设置为默认地址。 + * 使用事务保证操作的原子性。 + * + * @param addressBook 默认地址 + */ + @Transactional // 声明事务,确保操作的原子性 + public void setDefault(AddressBook addressBook) { + // 1. 将当前用户的所有地址修改为非默认地址 + addressBook.setIsDefault(0); + addressBook.setUserId(BaseContext.getCurrentId()); + addressBookMapper.updateIsDefaultByUserId(addressBook); // 更新所有地址为非默认 + + // 2. 将当前地址改为默认地址 + addressBook.setIsDefault(1); + addressBookMapper.update(addressBook); // 更新当前地址为默认 + } + + /** + * 根据id删除地址 + * 根据传入的地址 ID 删除对应的地址。 + * + * @param id 地址 ID + */ + public void deleteById(Long id) { + addressBookMapper.deleteById(id); // 调用 mapper 删除地址 + } +} diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java new file mode 100644 index 0000000..7793e3b --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.java @@ -0,0 +1,156 @@ +package com.sky.service.impl; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.sky.constant.MessageConstant; +import com.sky.constant.PasswordConstant; +import com.sky.constant.StatusConstant; +import com.sky.context.BaseContext; +import com.sky.dto.EmployeeDTO; +import com.sky.dto.EmployeeLoginDTO; +import com.sky.dto.EmployeePageQueryDTO; +import com.sky.entity.Employee; +import com.sky.exception.AccountLockedException; +import com.sky.exception.AccountNotFoundException; +import com.sky.exception.PasswordErrorException; +import com.sky.mapper.EmployeeMapper; +import com.sky.result.PageResult; +import com.sky.service.EmployeeService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.DigestUtils; + +import java.time.LocalDateTime; +import java.util.List; + +@Service // 该类标记为服务层的 Bean +public class EmployeeServiceImpl implements EmployeeService { + + @Autowired // 自动注入 EmployeeMapper + private EmployeeMapper employeeMapper; + + /** + * 员工登录 + * + * 处理员工登录的流程:包括校验用户名、密码,检查账号是否被锁定。 + * + * @param employeeLoginDTO 登录参数 + * @return 登录成功后返回员工信息 + * @throws AccountNotFoundException 如果账号不存在 + * @throws PasswordErrorException 如果密码错误 + * @throws AccountLockedException 如果账号被锁定 + */ + public Employee login(EmployeeLoginDTO employeeLoginDTO) { + String username = employeeLoginDTO.getUsername(); + String password = employeeLoginDTO.getPassword(); + + // 1. 根据用户名查询数据库中的员工信息 + Employee employee = employeeMapper.getByUsername(username); + + // 2. 处理各种异常情况 + if (employee == null) { + // 账号不存在 + throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND); + } + + // 密码比对 + password = DigestUtils.md5DigestAsHex(password.getBytes()); // 对前端传过来的密码进行 md5 加密 + if (!password.equals(employee.getPassword())) { + // 密码错误 + throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR); + } + + if (employee.getStatus() == StatusConstant.DISABLE) { + // 账号被锁定 + throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED); + } + + // 3. 返回员工实体对象 + return employee; + } + + /** + * 新增员工 + * + * 通过 `employeeDTO` 创建新的员工,设置默认的状态和密码,然后插入数据库。 + * + * @param employeeDTO 员工信息 + */ + public void save(EmployeeDTO employeeDTO) { + Employee employee = new Employee(); + BeanUtils.copyProperties(employeeDTO, employee); // 将 DTO 中的数据复制到 Employee 实体中 + + employee.setStatus(StatusConstant.ENABLE); // 设置员工的状态为启用 + employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes())); // 设置默认密码 + + employeeMapper.save(employee); // 调用 Mapper 插入员工数据 + } + + /** + * 分页查询员工 + * + * 使用 PageHelper 进行分页查询,返回分页结果。 + * + * @param employeePageQueryDTO 查询参数,包含页码和每页显示的条数 + * @return 返回分页结果 + */ + public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) { + // 使用 PageHelper 开启分页 + PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize()); + + // 执行分页查询 + Page pageQuery = employeeMapper.pageQuery(employeePageQueryDTO); + + // 构建分页结果 + PageResult pageResult = new PageResult(); + pageResult.setTotal(pageQuery.getTotal()); // 总记录数 + pageResult.setRecords(pageQuery.getResult()); // 当前页的记录 + + return pageResult; + } + + /** + * 启用或禁用员工账号 + * + * 根据传入的员工 ID 和新的状态,更新员工的账号状态。 + * + * @param status 新的账号状态 + * @param id 员工 ID + */ + public void startOrStop(Integer status, Long id) { + Employee employee = Employee.builder() + .status(status) // 设置新的账号状态 + .id(id) // 设置员工 ID + .build(); + employeeMapper.update(employee); // 调用 Mapper 更新员工状态 + } + + /** + * 通过 ID 查询员工信息 + * + * 查询员工信息并返回,在返回时,密码信息被隐藏(使用 `*****` 替代)。 + * + * @param id 员工 ID + * @return 返回员工信息 + */ + public Employee getById(Long id) { + Employee employee = employeeMapper.getById(id); // 根据 ID 查询员工信息 + employee.setPassword("*****"); // 隐藏密码 + return employee; + } + + /** + * 编辑员工信息 + * + * 更新员工信息,包括用户名、职位等。 + * + * @param employeeDTO 更新后的员工信息 + */ + public void update(EmployeeDTO employeeDTO) { + Employee employee = new Employee(); + BeanUtils.copyProperties(employeeDTO, employee); // 将 DTO 转换为实体对象 + + employeeMapper.update(employee); // 调用 Mapper 更新员工数据 + } +} diff --git a/sky/sky-server/src/main/java/com/sky/service/impl/ShoppingCartServiceImpl.java b/sky/sky-server/src/main/java/com/sky/service/impl/ShoppingCartServiceImpl.java new file mode 100644 index 0000000..3400ce8 --- /dev/null +++ b/sky/sky-server/src/main/java/com/sky/service/impl/ShoppingCartServiceImpl.java @@ -0,0 +1,128 @@ +package com.sky.service.impl; + +import com.sky.context.BaseContext; +import com.sky.dto.ShoppingCartDTO; +import com.sky.entity.Dish; +import com.sky.entity.Setmeal; +import com.sky.entity.ShoppingCart; +import com.sky.mapper.DishMapper; +import com.sky.mapper.SetmealMapper; +import com.sky.mapper.ShoppingCartMapper; +import com.sky.service.ShoppingCartService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; + +@Service // 标记为服务层的 Bean +public class ShoppingCartServiceImpl implements ShoppingCartService { + + @Autowired // 自动注入购物车相关的 Mapper + ShoppingCartMapper shoppingCartMapper; + + @Autowired + DishMapper dishMapper; + + @Autowired + SetmealMapper setmealMapper; + + /** + * 添加商品到购物车 + * + * 根据传入的购物车 DTO,判断购物车中是否已经存在该商品,如果存在则增加数量,否则新增购物车项。 + * + * @param shoppingCartDTO 包含商品或套餐的购物车数据 + */ + @Override + public void add(ShoppingCartDTO shoppingCartDTO) { + ShoppingCart shoppingCart = new ShoppingCart(); + BeanUtils.copyProperties(shoppingCartDTO, shoppingCart); // 将 DTO 中的属性复制到 ShoppingCart 实体中 + shoppingCart.setUserId(BaseContext.getCurrentId()); // 设置当前用户 ID + + // 如果购物车中已经有该商品,则只需要将该商品的数量加 1 + List shoppingCarts = shoppingCartMapper.list(shoppingCart); + if (shoppingCarts.size() > 0) { + Integer number = shoppingCarts.get(0).getNumber(); + shoppingCarts.get(0).setNumber(number + 1); // 增加商品数量 + shoppingCartMapper.update(shoppingCarts.get(0)); // 更新购物车 + } else { + // 否则,插入一个新的购物车项 + Long dishId = shoppingCartDTO.getDishId(); + Long setmealId = shoppingCartDTO.getSetmealId(); + + // 如果是菜品 + if (dishId != null) { + Dish dish = dishMapper.getById(dishId); // 根据菜品 ID 查询菜品信息 + shoppingCart.setName(dish.getName()); // 设置商品名称 + shoppingCart.setAmount(dish.getPrice()); // 设置商品价格 + shoppingCart.setImage(dish.getImage()); // 设置商品图片 + } else { + // 如果是套餐 + Setmeal bySetmealId = setmealMapper.getBySetmealId(setmealId); // 根据套餐 ID 查询套餐信息 + shoppingCart.setAmount(bySetmealId.getPrice()); // 设置套餐价格 + shoppingCart.setName(bySetmealId.getName()); // 设置套餐名称 + shoppingCart.setImage(shoppingCart.getImage()); // 设置套餐图片 + } + + shoppingCart.setNumber(1); // 设置商品数量为 1 + shoppingCart.setCreateTime(LocalDateTime.now()); // 设置创建时间 + + shoppingCartMapper.insert(shoppingCart); // 插入新商品到购物车 + } + } + + /** + * 获取当前用户的购物车数据 + * + * 根据当前用户 ID 查询购物车中的商品。 + * + * @return 返回用户的购物车列表 + */ + @Override + public List list() { + ShoppingCart shoppingCart = new ShoppingCart(); + shoppingCart.setUserId(BaseContext.getCurrentId()); // 设置当前用户 ID + return shoppingCartMapper.list(shoppingCart); // 返回购物车数据 + } + + /** + * 从购物车中删除商品 + * + * 根据购物车 DTO 删除商品,如果数量大于 1,则减少数量;如果数量为 1,则删除该商品。 + * + * @param shoppingCartDTO 包含商品或套餐的购物车数据 + */ + @Override + public void delete(ShoppingCartDTO shoppingCartDTO) { + ShoppingCart shoppingCart = new ShoppingCart(); + BeanUtils.copyProperties(shoppingCartDTO, shoppingCart); // 将 DTO 中的属性复制到 ShoppingCart 实体中 + shoppingCart.setUserId(BaseContext.getCurrentId()); // 设置当前用户 ID + + // 查询购物车中的商品 + List list = shoppingCartMapper.list(shoppingCart); + Integer number = list.get(0).getNumber(); // 获取商品数量 + + // 如果数量大于 1,则将数量减 1 + if (number > 1) { + list.get(0).setNumber(number - 1); + shoppingCartMapper.update(list.get(0)); // 更新购物车 + } else { + // 如果数量为 1,则从购物车中删除该商品 + shoppingCartMapper.delete(list.get(0)); // 删除商品 + } + } + + /** + * 清空购物车 + * + * 清除当前用户购物车中的所有商品。 + */ + @Override + public void clean() { + ShoppingCart shoppingCart = new ShoppingCart(); + shoppingCart.setUserId(BaseContext.getCurrentId()); // 设置当前用户 ID + shoppingCartMapper.delete(shoppingCart); // 删除该用户的所有购物车项 + } +}